mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-09 17:32:41 -10:00
fix(slice-21 FR-4 cleanup): TTY comment intent-vs-behavior reconcile + --body-file directory path → 3-part error shape (OPR.0.3.2.21.FR-4)
Closes the two non-blocking observations from guard's FR-4(a)
review (qitem-20260601123549-f66d52a5):
(1) TTY comment intent-vs-behavior mismatch. The prior inline
comment in defaultStdinReader said "the caller's empty-body
check turns this into a 3-part error" — but the FR-4(a)
handoff body explicitly delegates empty-body validation to
the daemon, and no caller-side empty-body check exists.
The comment is rewritten to match actual behavior: empty
body flows through to the daemon's content validation;
the CLI does not error locally on empty stdin.
(2) --body-file path-is-a-directory case used to fall through
to fs.readFileSync and surface a bare Error("EISDIR:
illegal operation on a directory") with blank
consequence/action fields. The other body-resolve failure
modes (missing file, mutual exclusion, missing input) all
emit the 3-part fact/consequence/action shape; this case
is now consistent. After the existsSync check, a
statSync(absPath).isFile() gate fires the 3-part error
before any read attempt, naming "not a regular file" with
"Pass a path to a readable file (not a directory,
symlink-to-directory, or block device); use --body-file -
to read from stdin" as the action.
Test addition: a new discriminator in the FR-4(a) describe block
asserts the 3-part shape when --body-file points at a directory
(uses mkdtempSync for a guaranteed-fresh tmpdir as the bad
target). Discriminator-flip: without the statSync gate, the
test fails because the error reaches the assertion with blank
consequence/action fields.
Verification:
- packages/cli queue.test.ts: 29/29 PASS (28 prior across FR-4
a/b/c describe blocks + 1 new directory-case discriminator).
- packages/cli tsc EXIT=0.
- Commit body verification grep clean per banked discipline.
- git diff --cached --stat: 2 files (+32 / -2).
Branch: slice-21-fr-4-queue-ergonomics off LOCAL main 58713e0c.
Chain: 2f731b84 (FR-4a, CLEAR) → 207ad5f1 (FR-4b, CLEAR) →
50b17c73 (FR-4c, pending verdict) → 164a67be (FR-4d-docs,
pending verdict) → this commit (FR-4 cleanup, addresses both
of guard's FR-4(a) non-blocking notes). LOCAL only, NO push.
This commit is contained in:
1 parent
164a67bef2
commit
a66e1488f1
2 files changed
+32
-2
No files matched your search
@@ -67,8 +67,11 @@ export async function defaultStdinReader(): Promise<string> {
|
||||
process.stdin.on("end", () => resolve(data));
|
||||
process.stdin.on("error", reject);
|
||||
if (process.stdin.isTTY) {
|
||||
// Resolve immediately to empty if nothing is piped; the caller's
|
||||
// empty-body check turns this into a 3-part error.
|
||||
// No pipe is connected to stdin; resolve immediately to empty
|
||||
// rather than blocking forever waiting for data on a TTY. The
|
||||
// empty body then flows through to the daemon's content
|
||||
// validation (queue-repository owns the body contract); the CLI
|
||||
// does not error locally on empty stdin.
|
||||
resolve("");
|
||||
}
|
||||
});
|
||||
@@ -108,6 +111,14 @@ export async function resolveQueueBody(
|
||||
err.action = "Check the path; pass an absolute path; or use --body-file - to read from stdin.";
|
||||
throw err;
|
||||
}
|
||||
const stat = fs.statSync(absPath);
|
||||
if (!stat.isFile()) {
|
||||
const err = new Error(`--body-file path is not a regular file: ${absPath}`) as Error & { fact?: string; consequence?: string; action?: string };
|
||||
err.fact = `--body-file path is not a regular file: ${absPath}`;
|
||||
err.consequence = "rig queue create did not run; daemon was not contacted.";
|
||||
err.action = "Pass a path to a readable file (not a directory, symlink-to-directory, or block device). Use --body-file - to read from stdin.";
|
||||
throw err;
|
||||
}
|
||||
return fs.readFileSync(absPath, "utf8");
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,25 @@ describe("rig queue CLI", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// OPR.0.3.2.21.FR-4 cleanup (guard non-blocking note on FR-4a CLEAR): a
|
||||
// directory passed to --body-file used to fall through to fs.readFileSync
|
||||
// and surface a bare Error("EISDIR: illegal operation on a directory") with
|
||||
// blank consequence/action. The cleanup commit emits the 3-part shape
|
||||
// explicitly so the error reads consistently with the other body-resolve
|
||||
// failure modes.
|
||||
it("resolveQueueBody throws 3-part error when --body-file path is a directory (not a regular file)", async () => {
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "queue-body-isdir-"));
|
||||
try {
|
||||
await expect(resolveQueueBody({ bodyFile: tmp })).rejects.toMatchObject({
|
||||
fact: expect.stringMatching(/not a regular file/),
|
||||
consequence: expect.stringMatching(/did not run/),
|
||||
action: expect.stringMatching(/Pass a path to a readable file/),
|
||||
});
|
||||
} finally {
|
||||
fs.rmSync(tmp, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("resolveQueueBody calls the injected stdin reader when --body is -", async () => {
|
||||
const stdinReader = vi.fn(async () => "from stdin\n");
|
||||
const out = await resolveQueueBody({ body: "-" }, stdinReader);
|
||||
|
||||
Reference in new issue
Block a user