@ai-dossier/cli 0.58.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/batch-suite-runner.d.ts.map +1 -1
- package/dist/batch-suite-runner.js +21 -26
- package/dist/batch-suite-runner.js.map +1 -1
- package/dist/cap-envelope.d.ts +122 -0
- package/dist/cap-envelope.d.ts.map +1 -0
- package/dist/cap-envelope.js +211 -0
- package/dist/cap-envelope.js.map +1 -0
- package/dist/capability.d.ts +12 -0
- package/dist/capability.d.ts.map +1 -1
- package/dist/capability.js +20 -4
- package/dist/capability.js.map +1 -1
- package/dist/commands/cap.d.ts +4 -1
- package/dist/commands/cap.d.ts.map +1 -1
- package/dist/commands/cap.js +63 -16
- package/dist/commands/cap.js.map +1 -1
- package/dist/commands/sched.d.ts +11 -11
- package/dist/commands/sched.d.ts.map +1 -1
- package/dist/commands/sched.js +54 -51
- package/dist/commands/sched.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1585,6 +1585,7 @@ ai-dossier cap list [--json] # inspect .dossier/automation/manifest.yaml
|
|
|
1585
1585
|
ai-dossier cap run test.focused # execute one capability
|
|
1586
1586
|
ai-dossier cap run test.focused -- --grep auth # extra args are shell-quoted and appended
|
|
1587
1587
|
ai-dossier cap run test.focused --tail-bytes 4096 # bytes of output captured on a non-ok outcome (default 8192)
|
|
1588
|
+
ai-dossier cap run test.focused --envelope-file /tmp/env.json # also write the envelope atomically to a file (or set $DOSSIER_CAP_ENVELOPE_FILE)
|
|
1588
1589
|
```
|
|
1589
1590
|
|
|
1590
1591
|
A repo declares its deterministic, recurring operations — tests, lint, build, deps
|
|
@@ -1611,8 +1612,10 @@ Extra args after `--` are shell-quoted and appended (they are data, not shell sy
|
|
|
1611
1612
|
ai-dossier cap run test.focused -- --grep auth # → npm test -- --silent --grep auth
|
|
1612
1613
|
```
|
|
1613
1614
|
|
|
1614
|
-
`cap run` reports one of exactly four outcomes — the JSON envelope
|
|
1615
|
-
stdout line
|
|
1615
|
+
`cap run` reports one of exactly four outcomes — the JSON envelope (marked
|
|
1616
|
+
`"cap_envelope": 1`) is the **last stdout line** and, with `--envelope-file <path>` /
|
|
1617
|
+
`$DOSSIER_CAP_ENVELOPE_FILE`, is also written to that file (the channel machine consumers
|
|
1618
|
+
should read, #811); the exit code matches:
|
|
1616
1619
|
|
|
1617
1620
|
| Outcome | Exit | Meaning |
|
|
1618
1621
|
|---|---|---|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-suite-runner.d.ts","sourceRoot":"","sources":["../src/batch-suite-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EACL,KAAK,iBAAiB,EAGtB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"batch-suite-runner.d.ts","sourceRoot":"","sources":["../src/batch-suite-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EACL,KAAK,iBAAiB,EAGtB,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,KAAK,kBAAkB,EAA8C,MAAM,cAAc,CAAC;AAEnG,oFAAoF;AACpF,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,cAAc,CAAC;AAajD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAU5E;AAED,kGAAkG;AAClG,eAAO,MAAM,sBAAsB,SAAU,CAAC;AAE9C,mGAAmG;AACnG,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAgO7C;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAChC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,iBAAiB,KAAK,WAAW,CAyD5D"}
|
|
@@ -47,6 +47,7 @@ const node_fs_1 = __importDefault(require("node:fs"));
|
|
|
47
47
|
const node_path_1 = __importDefault(require("node:path"));
|
|
48
48
|
const sched_1 = require("@ai-dossier/sched");
|
|
49
49
|
const worktree_pool_1 = require("@ai-dossier/worktree-pool");
|
|
50
|
+
const cap_envelope_1 = require("./cap-envelope");
|
|
50
51
|
const capability_1 = require("./capability");
|
|
51
52
|
/** The repo-declared batch gate (#777) — preferred over `test.full` when active. */
|
|
52
53
|
exports.BATCH_GATE_CAPABILITY = 'gate.batch';
|
|
@@ -159,15 +160,18 @@ function runCommand(argv, worktree, source, timeoutMs, env) {
|
|
|
159
160
|
function runCapabilitySuite(capabilityId, worktree, capabilityTimeoutMs, env) {
|
|
160
161
|
const source = `cap run ${capabilityId}`;
|
|
161
162
|
const start = Date.now();
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
// #811: the envelope comes from `cap run`'s dedicated envelope file, not
|
|
164
|
+
// stdout's last line — output that lands after the envelope (or a tail lost
|
|
165
|
+
// on exit) must never turn a green gate into "no envelope". `spawnCapRun`
|
|
166
|
+
// only returns an envelope whose outcome agrees with `cap run`'s own exit
|
|
167
|
+
// code, which the capability's command cannot forge (#562 review).
|
|
168
|
+
const run = (0, cap_envelope_1.spawnCapRun)(capabilityId, worktree, {
|
|
165
169
|
// The inner capability owns this budget; the outer watchdog has bounded setup grace.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
...(env !== undefined ? { env } : {}),
|
|
170
|
+
timeoutMs: capabilityTimeoutMs + exports.CAP_RUN_SETUP_GRACE_MS,
|
|
171
|
+
env,
|
|
169
172
|
});
|
|
170
|
-
|
|
173
|
+
const { spawned } = run;
|
|
174
|
+
if (spawned.error && !run.exitedWithVerdict) {
|
|
171
175
|
if (spawned.error.code === 'ETIMEDOUT') {
|
|
172
176
|
const elapsedMs = Date.now() - start;
|
|
173
177
|
return {
|
|
@@ -184,23 +188,13 @@ function runCapabilitySuite(capabilityId, worktree, capabilityTimeoutMs, env) {
|
|
|
184
188
|
return 'unavailable';
|
|
185
189
|
}
|
|
186
190
|
const stdout = spawned.stdout ?? '';
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
envelope = JSON.parse(lastLine);
|
|
191
|
-
}
|
|
192
|
-
catch {
|
|
193
|
-
envelope = null;
|
|
194
|
-
}
|
|
195
|
-
if (envelope?.outcome === 'capability-unavailable')
|
|
191
|
+
const fields = run.envelope !== null ? (0, cap_envelope_1.envelopeFields)(run.envelope) : null;
|
|
192
|
+
if (fields?.outcome === 'capability-unavailable')
|
|
196
193
|
return 'unavailable';
|
|
197
|
-
|
|
198
|
-
// capability's command writes to stdout, unlike the envelope's `outcome`
|
|
199
|
-
// field. Both must agree before this is trusted as green (#562 review).
|
|
200
|
-
const ok = envelope?.outcome === 'ok' && spawned.status === 0;
|
|
194
|
+
const ok = fields?.outcome === 'ok' && spawned.status === 0;
|
|
201
195
|
const readable = (0, sched_1.isReadableVitestReport)(stdout);
|
|
202
196
|
const failing = readable ? (0, sched_1.parseVitestJson)(stdout) : [];
|
|
203
|
-
const timedOut =
|
|
197
|
+
const timedOut = fields?.reason === (0, capability_1.timeoutReasonSpent)(capabilityTimeoutMs);
|
|
204
198
|
return {
|
|
205
199
|
source,
|
|
206
200
|
terminal: timedOut,
|
|
@@ -208,13 +202,14 @@ function runCapabilitySuite(capabilityId, worktree, capabilityTimeoutMs, env) {
|
|
|
208
202
|
ok,
|
|
209
203
|
failing,
|
|
210
204
|
readable: ok || readable,
|
|
211
|
-
detail:
|
|
212
|
-
? `${source}: outcome=${
|
|
213
|
-
(
|
|
214
|
-
(
|
|
205
|
+
detail: fields !== null
|
|
206
|
+
? `${source}: outcome=${fields.outcome} exit_code=${fields.exitCode ?? 'unknown'}` +
|
|
207
|
+
(fields.reason ? ` reason=${fields.reason}` : '') +
|
|
208
|
+
(fields.durationMs !== null ? ` elapsed ${fields.durationMs}ms` : '') +
|
|
215
209
|
(!ok && readable ? ` (${failing.length} failing)` : '') +
|
|
210
|
+
` [${run.diagnostics}]` +
|
|
216
211
|
(!ok && !readable ? stderrTail(spawned.stderr) : '')
|
|
217
|
-
: `${source}: task-failed (exit ${spawned.status ?? 'unknown'}), harness produced no envelope${stderrTail(spawned.stderr)}`,
|
|
212
|
+
: `${source}: task-failed (exit ${spawned.status ?? 'unknown'}), harness produced no envelope [${run.diagnostics}]${stderrTail(spawned.stderr)}`,
|
|
218
213
|
},
|
|
219
214
|
};
|
|
220
215
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-suite-runner.js","sourceRoot":"","sources":["../src/batch-suite-runner.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;;;;;;
|
|
1
|
+
{"version":3,"file":"batch-suite-runner.js","sourceRoot":"","sources":["../src/batch-suite-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `cap run` outcome-envelope channel (#811).
|
|
3
|
+
*
|
|
4
|
+
* `ai-dossier cap run <id>` reports its four-way outcome as a JSON envelope.
|
|
5
|
+
* Machine consumers (the batch suite runner, the per-member gate runner) used
|
|
6
|
+
* to read only stdout's LAST line — which silently failed when that line was
|
|
7
|
+
* not the envelope:
|
|
8
|
+
*
|
|
9
|
+
* - `cap run` re-emitted the capability's captured output and then exited
|
|
10
|
+
* with `process.exit()` while a large stdout write was still queued on the
|
|
11
|
+
* pipe; the tail (envelope included) was discarded. A green 33-minute
|
|
12
|
+
* `gate.batch` came back as exit 0 + no envelope → `suite-unreadable`.
|
|
13
|
+
* - anything that inherited the same stdout and wrote after `cap run`
|
|
14
|
+
* printed its envelope pushed the envelope off the last line.
|
|
15
|
+
*
|
|
16
|
+
* The fix is a dedicated channel: the consumer hands `cap run` a private file
|
|
17
|
+
* path via {@link CAP_ENVELOPE_FILE_ENV} (or `--envelope-file`), `cap run`
|
|
18
|
+
* writes the envelope there before exiting, and the consumer reads the file.
|
|
19
|
+
* Stdout keeps the envelope for humans and older consumers; when the file is
|
|
20
|
+
* absent (an older `ai-dossier` on PATH that ignores the env var) the stdout
|
|
21
|
+
* is scanned bottom-up for a line carrying the {@link CAP_ENVELOPE_MARKER}
|
|
22
|
+
* key, then the legacy last line.
|
|
23
|
+
*
|
|
24
|
+
* Whatever the source, an envelope is only trusted when `cap run`'s own exit
|
|
25
|
+
* status agrees with its `outcome` — the exit code is the one signal the
|
|
26
|
+
* capability's command cannot forge (#562 review).
|
|
27
|
+
*/
|
|
28
|
+
import { type SpawnSyncReturns } from 'node:child_process';
|
|
29
|
+
import { CAP_ENVELOPE_FILE_ENV, type CapabilityOutcome } from './capability';
|
|
30
|
+
export { CAP_ENVELOPE_FILE_ENV };
|
|
31
|
+
/** Marker key present (value `1`) on every envelope `cap run` emits. */
|
|
32
|
+
export declare const CAP_ENVELOPE_MARKER = "cap_envelope";
|
|
33
|
+
/**
|
|
34
|
+
* Consumer-side stdout buffer for `cap run`: the capability layer captures up
|
|
35
|
+
* to {@link MAX_CAPABILITY_OUTPUT_BYTES} of its command's output and re-emits
|
|
36
|
+
* it before the envelope, so a consumer buffer no larger than that turns a
|
|
37
|
+
* chatty-but-green run into ENOBUFS. Derived, not restated, so the two cannot drift.
|
|
38
|
+
*/
|
|
39
|
+
export declare const CAP_RUN_MAX_BUFFER_BYTES: number;
|
|
40
|
+
/** The raw envelope object; every field is `unknown` until narrowed by {@link envelopeFields}. */
|
|
41
|
+
export interface CapEnvelope {
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
/** The typed fields consumers read off an envelope — `null` when absent or of the wrong type. */
|
|
45
|
+
export interface CapEnvelopeFields {
|
|
46
|
+
outcome: CapabilityOutcome | null;
|
|
47
|
+
exitCode: number | null;
|
|
48
|
+
reason: string | null;
|
|
49
|
+
durationMs: number | null;
|
|
50
|
+
outputTail: string | null;
|
|
51
|
+
}
|
|
52
|
+
/** `true` when `value` is one of the four `cap run` outcomes. */
|
|
53
|
+
export declare function isCapabilityOutcome(value: unknown): value is CapabilityOutcome;
|
|
54
|
+
/** Narrow an envelope's fields by type — one place, so every consumer reads it identically. */
|
|
55
|
+
export declare function envelopeFields(envelope: CapEnvelope): CapEnvelopeFields;
|
|
56
|
+
/**
|
|
57
|
+
* Find the envelope in `cap run`'s stdout: the LAST line (scanning
|
|
58
|
+
* bottom-up) that parses as a JSON object carrying the marker key; failing
|
|
59
|
+
* that, the legacy contract — the last non-empty line, parsed as-is (an
|
|
60
|
+
* older `cap run` that predates the marker). `null` when neither parses.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseCapEnvelope(stdout: string): CapEnvelope | null;
|
|
63
|
+
/** What {@link readCapEnvelopeFile} found: nothing, something unusable, or a marked envelope. */
|
|
64
|
+
export type CapEnvelopeFileRead = {
|
|
65
|
+
state: 'absent';
|
|
66
|
+
} | {
|
|
67
|
+
state: 'invalid';
|
|
68
|
+
preview: string;
|
|
69
|
+
} | {
|
|
70
|
+
state: 'ok';
|
|
71
|
+
envelope: CapEnvelope;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Read an envelope file written by `cap run`. `invalid` (present but not a
|
|
75
|
+
* marked envelope) is kept distinct from `absent` — it means version skew or
|
|
76
|
+
* a writer bug, not "an older CLI that never wrote one".
|
|
77
|
+
*/
|
|
78
|
+
export declare function readCapEnvelopeFile(file: string): CapEnvelopeFileRead;
|
|
79
|
+
/**
|
|
80
|
+
* Write `json` (one envelope) to `file` atomically — a reader never sees a
|
|
81
|
+
* half-written envelope. The temp sibling has an unguessable name and is
|
|
82
|
+
* opened exclusively (`wx`, mode 0600), so a pre-planted file or symlink in a
|
|
83
|
+
* shared directory is refused rather than written through; it is removed if
|
|
84
|
+
* the write or rename fails. Throws on I/O failure; the caller decides
|
|
85
|
+
* whether that is fatal.
|
|
86
|
+
*/
|
|
87
|
+
export declare function writeCapEnvelopeFile(file: string, json: string): void;
|
|
88
|
+
/** Result of {@link spawnCapRun}: the raw spawn plus the verdict it produced, if any. */
|
|
89
|
+
export interface CapRunSpawn {
|
|
90
|
+
spawned: SpawnSyncReturns<string>;
|
|
91
|
+
/**
|
|
92
|
+
* The envelope — from the dedicated file, else from stdout (see
|
|
93
|
+
* {@link parseCapEnvelope}) — and only when `cap run`'s exit status agrees
|
|
94
|
+
* with its `outcome`. `null` when no trustworthy envelope was recovered.
|
|
95
|
+
*/
|
|
96
|
+
envelope: CapEnvelope | null;
|
|
97
|
+
/** Where {@link envelope} came from; `'none'` when it is `null`. */
|
|
98
|
+
envelopeSource: 'file' | 'stdout' | 'none';
|
|
99
|
+
/**
|
|
100
|
+
* `cap run` exited on its own with a trusted verdict. When this is `true`
|
|
101
|
+
* a spawn error (ETIMEDOUT) is NOT the gate timing out: a descendant still
|
|
102
|
+
* held the inherited stdout pipe, so `spawnSync` kept waiting past its
|
|
103
|
+
* timeout after `cap run` had already recorded its exit status.
|
|
104
|
+
*/
|
|
105
|
+
exitedWithVerdict: boolean;
|
|
106
|
+
/** Human-readable account of how the envelope was (or was not) recovered — for `detail`/`reason`. */
|
|
107
|
+
diagnostics: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Spawn `ai-dossier cap run <capabilityId>` in `cwd` with a dedicated
|
|
111
|
+
* envelope file in a fresh private (0700) temp directory, and return the
|
|
112
|
+
* spawn result plus the verdict. Always sets {@link CAP_ENVELOPE_FILE_ENV}
|
|
113
|
+
* (overriding any value in `env`, which otherwise defaults to the inherited
|
|
114
|
+
* environment) and uses {@link CAP_RUN_MAX_BUFFER_BYTES} as `maxBuffer`. The
|
|
115
|
+
* temp directory — and any stray temp file a killed `cap run` left in it — is
|
|
116
|
+
* always removed.
|
|
117
|
+
*/
|
|
118
|
+
export declare function spawnCapRun(capabilityId: string, cwd: string, opts: {
|
|
119
|
+
timeoutMs: number;
|
|
120
|
+
env?: NodeJS.ProcessEnv;
|
|
121
|
+
}): CapRunSpawn;
|
|
122
|
+
//# sourceMappingURL=cap-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cap-envelope.d.ts","sourceRoot":"","sources":["../src/cap-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,KAAK,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAKtE,OAAO,EACL,qBAAqB,EAErB,KAAK,iBAAiB,EAEvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,qBAAqB,EAAE,CAAC;AAEjC,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAElD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAAiD,CAAC;AAEvF,kGAAkG;AAClG,MAAM,WAAW,WAAW;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,iGAAiG;AACjG,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE9E;AAED,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,GAAG,iBAAiB,CAQvE;AAgBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAUnE;AAED,iGAAiG;AACjG,MAAM,MAAM,mBAAmB,GAC3B;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,CAAC;AAI3C;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAUrE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CASrE;AAED,yFAAyF;AACzF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAClC;;;;OAIG;IACH,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,oEAAoE;IACpE,cAAc,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C;;;;;OAKG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qGAAqG;IACrG,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,GACnD,WAAW,CAmBb"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The `cap run` outcome-envelope channel (#811).
|
|
4
|
+
*
|
|
5
|
+
* `ai-dossier cap run <id>` reports its four-way outcome as a JSON envelope.
|
|
6
|
+
* Machine consumers (the batch suite runner, the per-member gate runner) used
|
|
7
|
+
* to read only stdout's LAST line — which silently failed when that line was
|
|
8
|
+
* not the envelope:
|
|
9
|
+
*
|
|
10
|
+
* - `cap run` re-emitted the capability's captured output and then exited
|
|
11
|
+
* with `process.exit()` while a large stdout write was still queued on the
|
|
12
|
+
* pipe; the tail (envelope included) was discarded. A green 33-minute
|
|
13
|
+
* `gate.batch` came back as exit 0 + no envelope → `suite-unreadable`.
|
|
14
|
+
* - anything that inherited the same stdout and wrote after `cap run`
|
|
15
|
+
* printed its envelope pushed the envelope off the last line.
|
|
16
|
+
*
|
|
17
|
+
* The fix is a dedicated channel: the consumer hands `cap run` a private file
|
|
18
|
+
* path via {@link CAP_ENVELOPE_FILE_ENV} (or `--envelope-file`), `cap run`
|
|
19
|
+
* writes the envelope there before exiting, and the consumer reads the file.
|
|
20
|
+
* Stdout keeps the envelope for humans and older consumers; when the file is
|
|
21
|
+
* absent (an older `ai-dossier` on PATH that ignores the env var) the stdout
|
|
22
|
+
* is scanned bottom-up for a line carrying the {@link CAP_ENVELOPE_MARKER}
|
|
23
|
+
* key, then the legacy last line.
|
|
24
|
+
*
|
|
25
|
+
* Whatever the source, an envelope is only trusted when `cap run`'s own exit
|
|
26
|
+
* status agrees with its `outcome` — the exit code is the one signal the
|
|
27
|
+
* capability's command cannot forge (#562 review).
|
|
28
|
+
*/
|
|
29
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
30
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
|
+
};
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.CAP_RUN_MAX_BUFFER_BYTES = exports.CAP_ENVELOPE_MARKER = exports.CAP_ENVELOPE_FILE_ENV = void 0;
|
|
34
|
+
exports.isCapabilityOutcome = isCapabilityOutcome;
|
|
35
|
+
exports.envelopeFields = envelopeFields;
|
|
36
|
+
exports.parseCapEnvelope = parseCapEnvelope;
|
|
37
|
+
exports.readCapEnvelopeFile = readCapEnvelopeFile;
|
|
38
|
+
exports.writeCapEnvelopeFile = writeCapEnvelopeFile;
|
|
39
|
+
exports.spawnCapRun = spawnCapRun;
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const node_crypto_1 = require("node:crypto");
|
|
42
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
43
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
44
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
45
|
+
const capability_1 = require("./capability");
|
|
46
|
+
Object.defineProperty(exports, "CAP_ENVELOPE_FILE_ENV", { enumerable: true, get: function () { return capability_1.CAP_ENVELOPE_FILE_ENV; } });
|
|
47
|
+
/** Marker key present (value `1`) on every envelope `cap run` emits. */
|
|
48
|
+
exports.CAP_ENVELOPE_MARKER = 'cap_envelope';
|
|
49
|
+
/**
|
|
50
|
+
* Consumer-side stdout buffer for `cap run`: the capability layer captures up
|
|
51
|
+
* to {@link MAX_CAPABILITY_OUTPUT_BYTES} of its command's output and re-emits
|
|
52
|
+
* it before the envelope, so a consumer buffer no larger than that turns a
|
|
53
|
+
* chatty-but-green run into ENOBUFS. Derived, not restated, so the two cannot drift.
|
|
54
|
+
*/
|
|
55
|
+
exports.CAP_RUN_MAX_BUFFER_BYTES = capability_1.MAX_CAPABILITY_OUTPUT_BYTES + 16 * 1024 * 1024;
|
|
56
|
+
/** `true` when `value` is one of the four `cap run` outcomes. */
|
|
57
|
+
function isCapabilityOutcome(value) {
|
|
58
|
+
return typeof value === 'string' && Object.hasOwn(capability_1.CAPABILITY_EXIT_CODES, value);
|
|
59
|
+
}
|
|
60
|
+
/** Narrow an envelope's fields by type — one place, so every consumer reads it identically. */
|
|
61
|
+
function envelopeFields(envelope) {
|
|
62
|
+
return {
|
|
63
|
+
outcome: isCapabilityOutcome(envelope.outcome) ? envelope.outcome : null,
|
|
64
|
+
exitCode: typeof envelope.exit_code === 'number' ? envelope.exit_code : null,
|
|
65
|
+
reason: typeof envelope.reason === 'string' ? envelope.reason : null,
|
|
66
|
+
durationMs: typeof envelope.duration_ms === 'number' ? envelope.duration_ms : null,
|
|
67
|
+
outputTail: typeof envelope.output_tail === 'string' ? envelope.output_tail : null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function parseObject(text) {
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(text);
|
|
73
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
74
|
+
return null;
|
|
75
|
+
return parsed;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function isMarked(envelope) {
|
|
82
|
+
return envelope !== null && envelope[exports.CAP_ENVELOPE_MARKER] === 1;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Find the envelope in `cap run`'s stdout: the LAST line (scanning
|
|
86
|
+
* bottom-up) that parses as a JSON object carrying the marker key; failing
|
|
87
|
+
* that, the legacy contract — the last non-empty line, parsed as-is (an
|
|
88
|
+
* older `cap run` that predates the marker). `null` when neither parses.
|
|
89
|
+
*/
|
|
90
|
+
function parseCapEnvelope(stdout) {
|
|
91
|
+
const lines = stdout.split('\n');
|
|
92
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
93
|
+
const line = lines[i].trim();
|
|
94
|
+
if (!line.startsWith('{'))
|
|
95
|
+
continue;
|
|
96
|
+
const candidate = parseObject(line);
|
|
97
|
+
if (isMarked(candidate))
|
|
98
|
+
return candidate;
|
|
99
|
+
}
|
|
100
|
+
const lastLine = stdout.trim().split('\n').pop() ?? '';
|
|
101
|
+
return parseObject(lastLine.trim());
|
|
102
|
+
}
|
|
103
|
+
const INVALID_PREVIEW_CHARS = 200;
|
|
104
|
+
/**
|
|
105
|
+
* Read an envelope file written by `cap run`. `invalid` (present but not a
|
|
106
|
+
* marked envelope) is kept distinct from `absent` — it means version skew or
|
|
107
|
+
* a writer bug, not "an older CLI that never wrote one".
|
|
108
|
+
*/
|
|
109
|
+
function readCapEnvelopeFile(file) {
|
|
110
|
+
let text;
|
|
111
|
+
try {
|
|
112
|
+
text = node_fs_1.default.readFileSync(file, 'utf-8');
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return { state: 'absent' };
|
|
116
|
+
}
|
|
117
|
+
const envelope = parseObject(String(text).trim());
|
|
118
|
+
if (isMarked(envelope))
|
|
119
|
+
return { state: 'ok', envelope };
|
|
120
|
+
return { state: 'invalid', preview: String(text).slice(0, INVALID_PREVIEW_CHARS) };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Write `json` (one envelope) to `file` atomically — a reader never sees a
|
|
124
|
+
* half-written envelope. The temp sibling has an unguessable name and is
|
|
125
|
+
* opened exclusively (`wx`, mode 0600), so a pre-planted file or symlink in a
|
|
126
|
+
* shared directory is refused rather than written through; it is removed if
|
|
127
|
+
* the write or rename fails. Throws on I/O failure; the caller decides
|
|
128
|
+
* whether that is fatal.
|
|
129
|
+
*/
|
|
130
|
+
function writeCapEnvelopeFile(file, json) {
|
|
131
|
+
const tmp = `${file}.${(0, node_crypto_1.randomUUID)()}.tmp`;
|
|
132
|
+
try {
|
|
133
|
+
node_fs_1.default.writeFileSync(tmp, `${json}\n`, { flag: 'wx', mode: 0o600 });
|
|
134
|
+
node_fs_1.default.renameSync(tmp, file);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
node_fs_1.default.rmSync(tmp, { force: true });
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Spawn `ai-dossier cap run <capabilityId>` in `cwd` with a dedicated
|
|
143
|
+
* envelope file in a fresh private (0700) temp directory, and return the
|
|
144
|
+
* spawn result plus the verdict. Always sets {@link CAP_ENVELOPE_FILE_ENV}
|
|
145
|
+
* (overriding any value in `env`, which otherwise defaults to the inherited
|
|
146
|
+
* environment) and uses {@link CAP_RUN_MAX_BUFFER_BYTES} as `maxBuffer`. The
|
|
147
|
+
* temp directory — and any stray temp file a killed `cap run` left in it — is
|
|
148
|
+
* always removed.
|
|
149
|
+
*/
|
|
150
|
+
function spawnCapRun(capabilityId, cwd, opts) {
|
|
151
|
+
const dir = node_fs_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), 'ai-dossier-cap-'));
|
|
152
|
+
const envelopeFile = node_path_1.default.join(dir, 'envelope.json');
|
|
153
|
+
try {
|
|
154
|
+
const spawned = (0, node_child_process_1.spawnSync)('ai-dossier', ['cap', 'run', capabilityId], {
|
|
155
|
+
cwd,
|
|
156
|
+
encoding: 'utf-8',
|
|
157
|
+
timeout: opts.timeoutMs,
|
|
158
|
+
maxBuffer: exports.CAP_RUN_MAX_BUFFER_BYTES,
|
|
159
|
+
env: { ...(opts.env ?? process.env), [capability_1.CAP_ENVELOPE_FILE_ENV]: envelopeFile },
|
|
160
|
+
});
|
|
161
|
+
return resolveVerdict(spawned, readCapEnvelopeFile(envelopeFile));
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
try {
|
|
165
|
+
node_fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// Best effort — a leftover private temp dir is harmless.
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function resolveVerdict(spawned, fileRead) {
|
|
173
|
+
const notes = [];
|
|
174
|
+
let candidate = null;
|
|
175
|
+
let source = 'file';
|
|
176
|
+
if (fileRead.state === 'ok') {
|
|
177
|
+
candidate = fileRead.envelope;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
notes.push(fileRead.state === 'invalid'
|
|
181
|
+
? `envelope file invalid: ${JSON.stringify(fileRead.preview)}`
|
|
182
|
+
: 'envelope file not written (an `ai-dossier` on PATH older than #811?)');
|
|
183
|
+
candidate = spawned.stdout ? parseCapEnvelope(spawned.stdout) : null;
|
|
184
|
+
source = 'stdout';
|
|
185
|
+
if (candidate === null)
|
|
186
|
+
notes.push('stdout scan found no envelope');
|
|
187
|
+
}
|
|
188
|
+
let envelope = null;
|
|
189
|
+
if (candidate !== null) {
|
|
190
|
+
const outcome = envelopeFields(candidate).outcome;
|
|
191
|
+
if (outcome !== null && spawned.status === capability_1.CAPABILITY_EXIT_CODES[outcome]) {
|
|
192
|
+
envelope = candidate;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
notes.push(`envelope from ${source} rejected: outcome=${String(candidate.outcome)} disagrees with cap run exit ${spawned.status ?? 'none'}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const envelopeSource = envelope !== null ? source : 'none';
|
|
199
|
+
const exitedWithVerdict = spawned.status !== null && envelope !== null;
|
|
200
|
+
if (exitedWithVerdict && spawned.error) {
|
|
201
|
+
notes.push(`verdict accepted although the spawn reported ${spawned.error.code ?? spawned.error.message} — a descendant held cap run's stdout after it exited`);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
spawned,
|
|
205
|
+
envelope,
|
|
206
|
+
envelopeSource,
|
|
207
|
+
exitedWithVerdict,
|
|
208
|
+
diagnostics: [`envelope=${envelopeSource}`, ...notes].join('; '),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=cap-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cap-envelope.js","sourceRoot":"","sources":["../src/cap-envelope.ts"],"names":[],"mappings":"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"}
|
package/dist/capability.d.ts
CHANGED
|
@@ -41,6 +41,18 @@ export declare const DEFAULT_OUTPUT_TAIL_BYTES = 8192;
|
|
|
41
41
|
* both sides of the contract.
|
|
42
42
|
*/
|
|
43
43
|
export declare const timeoutReasonSpent: (timeoutMs: number) => string;
|
|
44
|
+
/** `spawnSync`'s own default `maxBuffer` (1 MiB) is too small for a real test/build command's combined stdout+stderr — raised so output volume alone never causes a false `automation-broken` (#583 review). Consumers of `cap run` size their own buffer above this (`cap-envelope.ts`). */
|
|
45
|
+
export declare const MAX_CAPABILITY_OUTPUT_BYTES: number;
|
|
46
|
+
/** Environment variable naming the file `cap run` writes its envelope to (#811). */
|
|
47
|
+
export declare const CAP_ENVELOPE_FILE_ENV = "DOSSIER_CAP_ENVELOPE_FILE";
|
|
48
|
+
/**
|
|
49
|
+
* The environment every process `cap run` spawns on a capability's behalf
|
|
50
|
+
* (assumption probes and the command itself) runs with: the inherited one
|
|
51
|
+
* minus {@link CAP_ENVELOPE_FILE_ENV}. The envelope channel belongs to
|
|
52
|
+
* `cap run`, not to the command it runs — the command is never handed the
|
|
53
|
+
* path, so it cannot write (or clobber) the verdict (#811).
|
|
54
|
+
*/
|
|
55
|
+
export declare function capabilityChildEnv(): NodeJS.ProcessEnv;
|
|
44
56
|
/** Supported tool-version comparison operators (single source of truth). */
|
|
45
57
|
declare const TOOL_VERSION_OPS: readonly [">=", ">", "<=", "<", "==", "="];
|
|
46
58
|
type ToolVersionOp = (typeof TOOL_VERSION_OPS)[number];
|
package/dist/capability.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,oFAAoF;AACpF,eAAO,MAAM,cAAc,wBAAwB,CAAC;AACpD,+DAA+D;AAC/D,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,MAAM,MAAM,iBAAiB,GACzB,IAAI,GACJ,aAAa,GACb,mBAAmB,GACnB,wBAAwB,CAAC;AAE7B,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEtD,4DAA4D;AAC5D,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAKnE,CAAC;AAcF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAE9C;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,KAAG,MACb,CAAC;
|
|
1
|
+
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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"}
|
package/dist/capability.js
CHANGED
|
@@ -22,7 +22,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.CapManifestError = exports.timeoutReasonSpent = exports.DEFAULT_OUTPUT_TAIL_BYTES = exports.CAPABILITY_EXIT_CODES = exports.MANIFEST_FILE = exports.AUTOMATION_DIR = void 0;
|
|
25
|
+
exports.CapManifestError = exports.CAP_ENVELOPE_FILE_ENV = exports.MAX_CAPABILITY_OUTPUT_BYTES = exports.timeoutReasonSpent = exports.DEFAULT_OUTPUT_TAIL_BYTES = exports.CAPABILITY_EXIT_CODES = exports.MANIFEST_FILE = exports.AUTOMATION_DIR = void 0;
|
|
26
|
+
exports.capabilityChildEnv = capabilityChildEnv;
|
|
26
27
|
exports.loadCapabilityManifest = loadCapabilityManifest;
|
|
27
28
|
exports.parseCapabilityManifest = parseCapabilityManifest;
|
|
28
29
|
exports.evaluateProbe = evaluateProbe;
|
|
@@ -72,8 +73,21 @@ exports.DEFAULT_OUTPUT_TAIL_BYTES = 8192;
|
|
|
72
73
|
*/
|
|
73
74
|
const timeoutReasonSpent = (timeoutMs) => `command timed out after ${timeoutMs}ms`;
|
|
74
75
|
exports.timeoutReasonSpent = timeoutReasonSpent;
|
|
75
|
-
/** `spawnSync`'s own default `maxBuffer` (1 MiB) is too small for a real test/build command's combined stdout+stderr — raised so output volume alone never causes a false `automation-broken` (#583 review). */
|
|
76
|
-
|
|
76
|
+
/** `spawnSync`'s own default `maxBuffer` (1 MiB) is too small for a real test/build command's combined stdout+stderr — raised so output volume alone never causes a false `automation-broken` (#583 review). Consumers of `cap run` size their own buffer above this (`cap-envelope.ts`). */
|
|
77
|
+
exports.MAX_CAPABILITY_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
78
|
+
/** Environment variable naming the file `cap run` writes its envelope to (#811). */
|
|
79
|
+
exports.CAP_ENVELOPE_FILE_ENV = 'DOSSIER_CAP_ENVELOPE_FILE';
|
|
80
|
+
/**
|
|
81
|
+
* The environment every process `cap run` spawns on a capability's behalf
|
|
82
|
+
* (assumption probes and the command itself) runs with: the inherited one
|
|
83
|
+
* minus {@link CAP_ENVELOPE_FILE_ENV}. The envelope channel belongs to
|
|
84
|
+
* `cap run`, not to the command it runs — the command is never handed the
|
|
85
|
+
* path, so it cannot write (or clobber) the verdict (#811).
|
|
86
|
+
*/
|
|
87
|
+
function capabilityChildEnv() {
|
|
88
|
+
const { [exports.CAP_ENVELOPE_FILE_ENV]: _envelopeFile, ...childEnv } = process.env;
|
|
89
|
+
return childEnv;
|
|
90
|
+
}
|
|
77
91
|
/** Supported tool-version comparison operators (single source of truth). */
|
|
78
92
|
const TOOL_VERSION_OPS = ['>=', '>', '<=', '<', '==', '='];
|
|
79
93
|
const TOOL_VERSION_OPS_DISPLAY = [...TOOL_VERSION_OPS].sort().join(' ');
|
|
@@ -280,6 +294,7 @@ function evaluateProbe(probe, cwd) {
|
|
|
280
294
|
encoding: 'utf-8',
|
|
281
295
|
timeout: PROBE_TIMEOUT_MS,
|
|
282
296
|
windowsHide: true,
|
|
297
|
+
env: capabilityChildEnv(),
|
|
283
298
|
});
|
|
284
299
|
const output = `${res.stdout ?? ''}${res.stderr ?? ''}`;
|
|
285
300
|
if (res.error || res.status !== 0) {
|
|
@@ -389,7 +404,8 @@ function runCapability(manifest, id, args, cwd, tailBytes = exports.DEFAULT_OUTP
|
|
|
389
404
|
cwd,
|
|
390
405
|
encoding: 'utf-8',
|
|
391
406
|
timeout: timeoutMs,
|
|
392
|
-
maxBuffer: MAX_CAPABILITY_OUTPUT_BYTES,
|
|
407
|
+
maxBuffer: exports.MAX_CAPABILITY_OUTPUT_BYTES,
|
|
408
|
+
env: capabilityChildEnv(),
|
|
393
409
|
});
|
|
394
410
|
if (res.stdout)
|
|
395
411
|
process.stdout.write(res.stdout);
|