@open-agent-toolkit/cli 0.2.47 → 0.2.49

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.
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "oatVersion": "0.2.47"
3
+ "oatVersion": "0.2.49"
4
4
  }
@@ -51,6 +51,17 @@ Fields:
51
51
  - `description` - optional context for the agent running the gate.
52
52
  - `maxAttempts` - retry bound for `block`; defaults to `2`.
53
53
 
54
+ When `oat gate set` recognizes a direct lifecycle `oat gate review` command,
55
+ it requires the canonical global option placement `oat --json gate review`.
56
+ Missing, late, repeated, or subcommand-scoped `--json` is rejected with exit 1
57
+ before the selected shared, local, or user config layer is changed. Arbitrary
58
+ wrappers, unrelated gate commands, and provider exec-target `baseCommand`
59
+ arrays remain outside this validator.
60
+
61
+ A valid command is stored byte-for-byte. `oat gate resolve` returns that exact
62
+ string, and the lifecycle executes it unchanged; OAT does not inject, reorder,
63
+ or rewrite its shell arguments.
64
+
54
65
  `oat-project-plan`, `oat-project-implement`, `oat-project-quick-start`, and
55
66
  `oat-project-import-plan` are currently gate-aware. Gate awareness is declared
56
67
  in skill frontmatter with `oat_gateable: true`, and
@@ -284,6 +295,7 @@ and disambiguate re-gate rounds:
284
295
  | `ok` | 0 | Review completed; gate passed at the threshold. |
285
296
  | `blocked` | 1 | Review completed; findings at/above the threshold. |
286
297
  | `review_failed` | ≠0 | The provider target exited non-zero; no verdict. |
298
+ | `artifact_missing` | 1 | The child exited cleanly without producing an artifact. |
287
299
  | `artifact_validation_failed` | 1 | Artifact format or configured invocation fields are invalid. |
288
300
  | `targeting_correlation_failed` | 1 | Identity did not correlate; do not run review-receive. |
289
301
 
@@ -296,6 +308,13 @@ For `artifact_validation_failed`, correct the artifact and rerun the gate; do
296
308
  not invoke review-receive until the gate successfully revalidates it as `ok` or
297
309
  `blocked`.
298
310
 
311
+ `artifact_missing` means the accepted headless child completed without any
312
+ review artifact. It sets `receiveEligible: false`, `remediable: false`, and
313
+ `handoff: null`. Fix the reviewer so review work, artifact creation, and
314
+ bookkeeping finish inline or through a synchronously awaited child, then start
315
+ a new gate run. Do not use review-fix retries or review-receive for the failed
316
+ run.
317
+
299
318
  `ok` and `blocked` also include `receiveEligible: true`, `outcome`,
300
319
  `artifactPath`, `counts`, `scope`, `handoff`, `gateInvocation`, and
301
320
  `corroboration`. Invoke review-receive only when all three conditions hold:
@@ -262,9 +262,11 @@ The Gate Execution step should:
262
262
  2. Treat `null` as "no gate configured."
263
263
  3. Export the resolved path with `export PROJECT_PATH` before launching the
264
264
  command shell.
265
- 4. For `oat gate review`, require the configured command to include
266
- `--project "$PROJECT_PATH"`; do not append it at runtime, because the resolved
267
- command must execute exactly as configured.
265
+ 4. For `oat gate review`, require the configured command to use
266
+ `oat --json gate review --project "$PROJECT_PATH" ...`, with the global
267
+ `--json` option before `gate review`. Do not inject, append, or reorder
268
+ arguments at runtime, because the resolved command must execute exactly as
269
+ configured.
268
270
  5. Run the resolved `command` as the skill's last step and use its exit code as
269
271
  the pass/fail signal.
270
272
  6. Follow the gate's `onFailure` policy:
@@ -273,7 +275,7 @@ The Gate Execution step should:
273
275
  - `warn` - record the failure and continue.
274
276
 
275
277
  For OAT review gates, prefer putting
276
- `oat gate review --project "$PROJECT_PATH" "<prompt>"` in the configured gate
278
+ `oat --json gate review --project "$PROJECT_PATH" "<prompt>"` in the configured gate
277
279
  command rather than hard-coding a provider CLI directly in the skill. Use
278
280
  `oat gate cross-provider-exec "<prompt>"` for generic cross-runtime commands
279
281
  that should report only the child process status, not review findings.
@@ -126,7 +126,7 @@ Notable commands introduced in the current CLI surface:
126
126
  - `oat project validate-plan --project-path <path>` - validates `oat_plan_parallel_groups` metadata in `plan.md`; exits non-zero on invalid. See [Implementation Execution](../workflows/projects/implementation-execution.md#parallel-phase-groups).
127
127
  - `oat project log append|check|synthesize|rollup` - manage the optional append-only project observation log: append validated judgment or structural entries, inspect grammar and synthesis status, complete end-of-run synthesis, and roll observations into `summary.md` plus the configured repository ledger. See [Project Log](../cli-utilities/project-log.md).
128
128
  - `oat project set-mode` — deprecated no-op. Execution mode is no longer user-selectable; emits a deprecation warning and preserves the `--json` contract.
129
- - `oat gate review <prompt...>` - run a stateful, headless OAT review through the target registry, parse the produced review artifact, and exit nonzero for configured blocking findings. `--timeout-ms <milliseconds>` overrides target, `workflow.gateTimeouts`, environment, and scope defaults; accepted values are 1,000–14,400,000. Final/phase/range code reviews default to 30 minutes, while task code and artifact reviews default to 15 minutes. With `--json`, the result envelope on exit is the canonical completion signal: `status` is `ok` | `blocked` | `review_failed` | `artifact_validation_failed` | `targeting_correlation_failed`, alongside `runId`, `generatedAt`, and `artifactPath` when available. For `targeting_correlation_failed`, do not run review-receive even if an artifact path is present. For `artifact_validation_failed`, correct the artifact and rerun the gate until it revalidates as `ok` or `blocked`. Invoke `oat-project-review-receive` only when all three conditions hold: `status` is `ok` or `blocked`, `receiveEligible` is `true`, and `handoff` is non-null. `review_failed` may include structured `refusal`, `noOutputProduced`, and metadata-only `activityEvidence`; these diagnostic fields never make a run receive-eligible. After a timeout, a validated run-correlated artifact returns the ordinary `ok` or `blocked` envelope with additive `lateCompletion: true`. Duplicate run-ID matches or a changed artifact with a mismatched run ID retain `targeting_correlation_failed` and `receiveEligible: false`. Orchestrators should read the structured result rather than poll the filesystem. See [Workflow Gates](../cli-utilities/workflow-gates.md).
129
+ - `oat gate review <prompt...>` - run a stateful, headless OAT review through the target registry, parse the produced review artifact, and exit nonzero for configured blocking findings. `--timeout-ms <milliseconds>` overrides target, `workflow.gateTimeouts`, environment, and scope defaults; accepted values are 1,000–14,400,000. Final/phase/range code reviews default to 30 minutes, while task code and artifact reviews default to 15 minutes. With `--json`, the result envelope on exit is the canonical completion signal: `status` is `ok` | `blocked` | `review_failed` | `artifact_missing` | `artifact_validation_failed` | `targeting_correlation_failed`, alongside `runId`, `generatedAt`, and `artifactPath` when available. `artifact_missing` means an accepted child exited cleanly without an artifact; fix synchronous review/artifact completion and start a new run, without review-receive or same-run remediation. For `targeting_correlation_failed`, correct the project declaration or artifact routing and start a new run; do not run review-receive even if an artifact path is present. For `artifact_validation_failed`, correct the artifact and rerun the gate until it revalidates as `ok` or `blocked`. Invoke `oat-project-review-receive` only when all three conditions hold: `status` is `ok` or `blocked`, `receiveEligible` is `true`, and `handoff` is non-null. `review_failed` may include structured `refusal`, `noOutputProduced`, and metadata-only `activityEvidence`; these diagnostic fields never make a run receive-eligible. After a timeout, a validated run-correlated artifact returns the ordinary `ok` or `blocked` envelope with additive `lateCompletion: true`. Duplicate run-ID matches or a changed artifact with a mismatched run ID retain `targeting_correlation_failed` and `receiveEligible: false`. Orchestrators should read the structured result rather than poll the filesystem. See [Workflow Gates](../cli-utilities/workflow-gates.md).
130
130
  - `oat gate route --expect-runtime <runtime> --expect-model <model> --can-await <true|false> --json` - return the headless child route (`inline`, `delegate-sync`, or `refuse`) from provider-marker and model evidence. Ambiguous or contradictory evidence never routes inline.
131
131
  - `oat gate exec <prompt...>` / `oat gate cross-provider-exec <prompt...>` - run a generic target prompt. `--timeout-ms` uses the same validated CLI override; untyped runs otherwise retain the legacy default path.
132
132
  - `oat gate target set <id> --invocation-model <model|provider-default> --invocation-reasoning-effort <effort|provider-default>` - persist optional configured invocation metadata alongside an exec target without inferring it from the target command.
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.47",
3
- "docs-config": "0.2.47",
4
- "docs-theme": "0.2.47",
5
- "docs-transforms": "0.2.47"
2
+ "cli": "0.2.49",
3
+ "docs-config": "0.2.49",
4
+ "docs-theme": "0.2.49",
5
+ "docs-transforms": "0.2.49"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-design
3
- version: 2.3.1
3
+ version: 2.3.2
4
4
  description: Use when discovery is complete and implementation-ready decisions are needed. Runs a collaborative, selective collaborative, or draft-and-review design flow, confirms requirements and produces both `spec.md` and `design.md`, and commits artifacts before the user-review gate.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -658,11 +658,18 @@ gate as the last check before the completion boundary:
658
658
  ```
659
659
 
660
660
  If the resolved command invokes `oat gate review`, the configured review
661
- command must already include `--project "$PROJECT_PATH"` and must not include
662
- `--target <id>`. A valid reusable shape is
663
- `oat gate review --project "$PROJECT_PATH" ...`. If the declaration is
664
- missing, stop and migrate the stored gate command; do not inject or append
665
- arguments at execution time.
661
+ command must already include `--project "$PROJECT_PATH"` as part of the
662
+ structured-output contract. Its canonical form is:
663
+
664
+ ```bash
665
+ oat --json gate review --project "$PROJECT_PATH" ...
666
+ ```
667
+
668
+ This requires global `--json` before `gate review`. Reusable declarations
669
+ must not include
670
+ `--target <id>`. Reject `oat gate review ...` without the global `--json`
671
+ placement. Stop and migrate an invalid stored declaration before execution;
672
+ never inject or append execution-time argv.
666
673
 
667
674
  3. Execute the resolved command exactly as configured. Capture stdout, stderr,
668
675
  the exit code, and the structured JSON result. A zero exit code means the
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-discover
3
- version: 2.2.1
3
+ version: 2.2.2
4
4
  description: Use when the user explicitly asks to continue discovery for an active spec-driven OAT project — e.g. "continue discovery", "run discovery", or confirms a previously offered discovery step. Do NOT auto-invoke for new ideas or quick-mode projects. Gathers requirements and context before spec/design.
5
5
  disable-model-invocation: false
6
6
  user-invocable: true
@@ -445,11 +445,18 @@ gate as the last check before the completion boundary:
445
445
  ```
446
446
 
447
447
  If the resolved command invokes `oat gate review`, the configured review
448
- command must already include `--project "$PROJECT_PATH"` and must not include
449
- `--target <id>`. A valid reusable shape is
450
- `oat gate review --project "$PROJECT_PATH" ...`. If the declaration is
451
- missing, stop and migrate the stored gate command; do not inject or append
452
- arguments at execution time.
448
+ command must already include `--project "$PROJECT_PATH"` as part of the
449
+ structured-output contract. Its canonical form is:
450
+
451
+ ```bash
452
+ oat --json gate review --project "$PROJECT_PATH" ...
453
+ ```
454
+
455
+ This requires global `--json` before `gate review`. Reusable declarations
456
+ must not include
457
+ `--target <id>`. Reject `oat gate review ...` without the global `--json`
458
+ placement. Stop and migrate an invalid stored declaration before execution;
459
+ never inject or append execution-time argv.
453
460
 
454
461
  3. Execute the resolved command exactly as configured. Capture stdout, stderr,
455
462
  the exit code, and the structured JSON result. A zero exit code means the
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-import-plan
3
- version: 1.4.10
3
+ version: 1.4.11
4
4
  description: Use when you have an external markdown plan to execute with OAT. Preserves the source plan and normalizes it into canonical plan.md format.
5
5
  argument-hint: '<path-to-plan.md> [--provider codex|cursor|claude] [--project <name>]'
6
6
  oat_gateable: true
@@ -460,7 +460,13 @@ Before reporting this skill as complete, run the configured gate as the final st
460
460
  export PROJECT_PATH
461
461
  ```
462
462
 
463
- If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` and must not include `--target <id>`. A valid reusable shape is `oat gate review --project "$PROJECT_PATH" ...`. If the declaration is missing, stop and migrate the stored gate command; do not inject or append arguments at execution time.
463
+ If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` as part of the structured-output contract. Its canonical form is:
464
+
465
+ ```bash
466
+ oat --json gate review --project "$PROJECT_PATH" ...
467
+ ```
468
+
469
+ This requires global `--json` before `gate review`. Reusable declarations must not include `--target <id>`. Reject `oat gate review ...` without the global `--json` placement. Stop and migrate an invalid stored declaration before execution; never inject or append execution-time argv.
464
470
 
465
471
  3. Resolve the current planning parent's model identity from session context.
466
472
  When that identity is non-empty and the resolved configured command invokes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-plan
3
- version: 1.4.5
3
+ version: 1.4.6
4
4
  description: Use when design.md is complete and executable implementation tasks are needed. Breaks design into bite-sized TDD tasks in canonical plan.md format.
5
5
  oat_gateable: true
6
6
  disable-model-invocation: true
@@ -544,7 +544,13 @@ the last check before the completion boundary:
544
544
  export PROJECT_PATH
545
545
  ```
546
546
 
547
- If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` and must not include `--target <id>`. A valid reusable shape is `oat gate review --project "$PROJECT_PATH" ...`. If the declaration is missing, stop and migrate the stored gate command; do not inject or append arguments at execution time.
547
+ If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` as part of the structured-output contract. Its canonical form is:
548
+
549
+ ```bash
550
+ oat --json gate review --project "$PROJECT_PATH" ...
551
+ ```
552
+
553
+ This requires global `--json` before `gate review`. Reusable declarations must not include `--target <id>`. Reject `oat gate review ...` without the global `--json` placement. Stop and migrate an invalid stored declaration before execution; never inject or append execution-time argv.
548
554
 
549
555
  3. Resolve the current planning parent's model identity from session context.
550
556
  When that identity is non-empty and the resolved configured command invokes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-quick-start
3
- version: 2.3.6
3
+ version: 2.3.7
4
4
  description: Use when a task is small enough for quick mode or rapid iteration is preferred. Scaffolds a lightweight OAT project from discovery directly to a runnable plan, with optional brainstorming and lightweight design.
5
5
  argument-hint: '<project-name> ["project description"]'
6
6
  oat_gateable: true
@@ -735,7 +735,13 @@ as the last check before plan and project completion:
735
735
  export PROJECT_PATH
736
736
  ```
737
737
 
738
- If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` and must not include `--target <id>`. A valid reusable shape is `oat gate review --project "$PROJECT_PATH" ...`. If the declaration is missing, stop and migrate the stored gate command; do not inject or append arguments at execution time.
738
+ If the resolved command invokes `oat gate review`, the configured review command must already include `--project "$PROJECT_PATH"` as part of the structured-output contract. Its canonical form is:
739
+
740
+ ```bash
741
+ oat --json gate review --project "$PROJECT_PATH" ...
742
+ ```
743
+
744
+ This requires global `--json` before `gate review`. Reusable declarations must not include `--target <id>`. Reject `oat gate review ...` without the global `--json` placement. Stop and migrate an invalid stored declaration before execution; never inject or append execution-time argv.
739
745
 
740
746
  3. Resolve the current planning parent's model identity from session context.
741
747
  When that identity is non-empty and the resolved configured command invokes
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-wave-execute
3
- version: 1.8.2
3
+ version: 1.9.0
4
4
  description: Use when executing a wave of external implementation plans as a wrapper OAT project — scaffolding, drift refresh, parallel worktree groups, briefs, gates, merge choreography, and closeout.
5
5
  argument-hint: '<wave-id> [plan-names...] (e.g. wave-2 http-listener-before-indexing ...)'
6
6
  disable-model-invocation: false
@@ -459,7 +459,8 @@ The mechanical caller constructs an `explainer-kit.run-request/v1` document whos
459
459
  required keys are exactly:
460
460
  `schemaVersion, recipe, slug, outputRoot, factBase, mode`. Set `recipe` to
461
461
  `{ "id": "program-recap", "version": "1" }`; this is an object with exactly
462
- `id` and `version`. Set `outputRoot` to `.oat/repo/explainers/<slug>/`. Bind the
462
+ `id` and `version`. Set `outputRoot` to
463
+ `.oat/repo/reference/explainers/<slug>/`. Bind the
463
464
  synthesized fact-base file through `factBase` with the required keys
464
465
  `mode, freshnessPolicy`, set `mode` to `"supplied"`, set `freshnessPolicy` to
465
466
  `"live-wins"`, and set `path` to that file.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-wave-program
3
- version: 1.4.0
3
+ version: 1.5.0
4
4
  description: Use when decomposing a corpus of external implementation plans into an ordered wave program — coverage inventory, dependency mapping, wave composition, and the durable execution-program artifact that oat-wave-execute consumes and updates.
5
5
  argument-hint: '[new|refresh|wave-close <wave-id>] (default: refresh against the current artifact)'
6
6
  disable-model-invocation: false
@@ -152,7 +152,8 @@ The mechanical caller constructs an `explainer-kit.run-request/v1` document whos
152
152
  required keys are exactly:
153
153
  `schemaVersion, recipe, slug, outputRoot, factBase, mode`. Set `recipe` to
154
154
  `{ "id": "program-recap", "version": "1" }`; this is an object with exactly
155
- `id` and `version`. Set `outputRoot` to `.oat/repo/explainers/<slug>/`. Bind the
155
+ `id` and `version`. Set `outputRoot` to
156
+ `.oat/repo/reference/explainers/<slug>/`. Bind the
156
157
  synthesized fact-base file through `factBase` with the required keys
157
158
  `mode, freshnessPolicy`, set `mode` to `"supplied"`, set `freshnessPolicy` to
158
159
  `"live-wins"`, and set `path` to that file.
@@ -8,6 +8,16 @@ const delayMs = Number(process.env.FAKE_GATE_DELAY_MS ?? '0');
8
8
  const exitCode = Number(process.env.FAKE_GATE_EXIT_CODE ?? '0');
9
9
  const artifactMode = process.env.FAKE_GATE_ARTIFACT ?? 'none';
10
10
  const transcriptIntervalMs = Number(process.env.FAKE_GATE_TRANSCRIPT_INTERVAL_MS ?? '0');
11
+ if (process.env.FAKE_GATE_INVOCATION_LOG) {
12
+ await appendFile(process.env.FAKE_GATE_INVOCATION_LOG, `${JSON.stringify({
13
+ pid: process.pid,
14
+ headless: process.env.OAT_GATE_HEADLESS ?? null,
15
+ nonInteractive: process.env.OAT_NON_INTERACTIVE ?? null,
16
+ runId: process.env.OAT_GATE_RUN_ID ?? null,
17
+ cliPath: process.env.OAT_GATE_CLI_PATH ?? null,
18
+ routeReceiptPath: process.env.OAT_GATE_ROUTE_RECEIPT_PATH ?? null,
19
+ })}\n`);
20
+ }
11
21
  function promptValue(key) {
12
22
  return prompt.match(new RegExp(`^${key}: (.+)$`, 'm'))?.[1] ?? 'unknown';
13
23
  }
@@ -0,0 +1,12 @@
1
+ export type GateCommandContractResult = {
2
+ kind: 'not-applicable';
3
+ } | {
4
+ kind: 'valid';
5
+ command: 'gate-review';
6
+ } | {
7
+ kind: 'invalid';
8
+ command: 'gate-review';
9
+ message: string;
10
+ };
11
+ export declare function validateConfiguredGateCommand(command: string): GateCommandContractResult;
12
+ //# sourceMappingURL=configured-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configured-command.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/configured-command.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,yBAAyB,GACjC;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAmIjE,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,GACd,yBAAyB,CAoB3B"}
@@ -0,0 +1,120 @@
1
+ const INVALID_GATE_REVIEW_COMMAND_MESSAGE = 'Configured oat gate review commands must use the structured-output contract `oat --json gate review ...`.';
2
+ function tokenizeCommand(command) {
3
+ const tokens = [];
4
+ let token = '';
5
+ let tokenStarted = false;
6
+ let quote = null;
7
+ let escaped = false;
8
+ for (let index = 0; index < command.length; index += 1) {
9
+ const character = command[index];
10
+ if (quote === "'") {
11
+ if (character === "'") {
12
+ quote = null;
13
+ }
14
+ else {
15
+ token += character;
16
+ }
17
+ continue;
18
+ }
19
+ if (escaped) {
20
+ if (character === '\n') {
21
+ return null;
22
+ }
23
+ token += character;
24
+ tokenStarted = true;
25
+ escaped = false;
26
+ continue;
27
+ }
28
+ if (character === '\\') {
29
+ escaped = true;
30
+ continue;
31
+ }
32
+ if (quote) {
33
+ if (character === quote) {
34
+ quote = null;
35
+ }
36
+ else {
37
+ if (character === '`' ||
38
+ (character === '$' && command[index + 1] === '(')) {
39
+ return null;
40
+ }
41
+ token += character;
42
+ }
43
+ continue;
44
+ }
45
+ if (character === '"' || character === "'") {
46
+ quote = character;
47
+ tokenStarted = true;
48
+ continue;
49
+ }
50
+ if (character === '\n' || character === '`') {
51
+ return null;
52
+ }
53
+ if (/\s/.test(character)) {
54
+ if (tokenStarted) {
55
+ tokens.push(token);
56
+ token = '';
57
+ tokenStarted = false;
58
+ }
59
+ continue;
60
+ }
61
+ if ('|;&<>'.includes(character) ||
62
+ (character === '$' && command[index + 1] === '(')) {
63
+ return null;
64
+ }
65
+ token += character;
66
+ tokenStarted = true;
67
+ }
68
+ if (escaped || quote) {
69
+ return null;
70
+ }
71
+ if (tokenStarted) {
72
+ tokens.push(token);
73
+ }
74
+ return tokens;
75
+ }
76
+ function isDirectGateReview(tokens) {
77
+ if (tokens[0] !== 'oat') {
78
+ return false;
79
+ }
80
+ let index = 1;
81
+ while (index < tokens.length) {
82
+ const token = tokens[index];
83
+ if (token === 'gate') {
84
+ return (tokens[index + 1] === 'review' ||
85
+ (tokens[index + 1] === '--json' && tokens[index + 2] === 'review'));
86
+ }
87
+ if (token === '--json' ||
88
+ token === '--verbose' ||
89
+ token.startsWith('--cwd=')) {
90
+ index += 1;
91
+ continue;
92
+ }
93
+ if (token === '--cwd') {
94
+ if (tokens[index + 1] === undefined) {
95
+ return false;
96
+ }
97
+ index += 2;
98
+ continue;
99
+ }
100
+ return false;
101
+ }
102
+ return false;
103
+ }
104
+ export function validateConfiguredGateCommand(command) {
105
+ const tokens = tokenizeCommand(command);
106
+ if (!tokens || !isDirectGateReview(tokens)) {
107
+ return { kind: 'not-applicable' };
108
+ }
109
+ if (tokens[1] === '--json' &&
110
+ tokens[2] === 'gate' &&
111
+ tokens[3] === 'review' &&
112
+ tokens.filter((token) => token === '--json').length === 1) {
113
+ return { kind: 'valid', command: 'gate-review' };
114
+ }
115
+ return {
116
+ kind: 'invalid',
117
+ command: 'gate-review',
118
+ message: INVALID_GATE_REVIEW_COMMAND_MESSAGE,
119
+ };
120
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,7 @@ import YAML from 'yaml';
21
21
  import { createGateActivityProbe, } from './activity-probes.js';
22
22
  import { createBranchLocalGateCli, currentGateCliLaunch, readGateRouteReceipt, removeBranchLocalGateCli, } from './branch-local-cli.js';
23
23
  import { runChildProcess, } from './child-process.js';
24
+ import { validateConfiguredGateCommand } from './configured-command.js';
24
25
  import { parseReviewGateVerdict, severityDisplayName, } from './review-verdict.js';
25
26
  import { createGateRouteCommand } from './route.js';
26
27
  const DEFAULT_DEPENDENCIES = {
@@ -71,6 +72,7 @@ const VALID_IDENTITY_PROVENANCES = [
71
72
  ];
72
73
  const REVIEW_GATE_CONTEXT_NOTE = [
73
74
  'This review is gate-originated. If you run `oat-project-review-provide`, set `oat_review_invocation: gate` in the review artifact. Write a canonical review artifact with `### Critical`, `### Important`, `### Medium`, and `### Minor` headings in that order, using `None` for empty sections.',
75
+ 'Complete the review, artifact write, and required bookkeeping inline or through a synchronously awaited child before this headless process exits. Do not start background tasks, monitors, or waiters that outlive this turn.',
74
76
  "Artifact hygiene contract: Before finishing or committing, format every file you created or edited. Use the concrete write/fix formatting command supplied by the governing plan, task, or brief. If none is usable, discover the repository's documented write/fix command from applicable `AGENTS.md`/`CLAUDE.md` instructions and relevant package manifests; do not infer or hardcode a formatter. Prefer a file-scoped invocation when supported, and avoid rewriting unrelated files. If no command is discoverable, warn once with `no format command discovered in repo instructions; skipping`, then continue.",
75
77
  ].join('\n\n');
76
78
  const GATE_CHECK_TIMEOUT_MS = 5_000;
@@ -1528,6 +1530,32 @@ function writeReviewGateArtifactValidationFailure(context, payload) {
1528
1530
  context.logger.error(`Review completed but artifact validation failed: ${payload.message}`);
1529
1531
  context.logger.error(payload.recovery);
1530
1532
  }
1533
+ function writeReviewGateArtifactMissing(context, payload) {
1534
+ const message = `Review target ${payload.target} completed without producing the required correlated review artifact.`;
1535
+ const recovery = 'Fix the accepted headless target so it can write and finalize the review artifact before the process exits, then start a new gate run.';
1536
+ if (context.json) {
1537
+ context.logger.json({
1538
+ status: 'artifact_missing',
1539
+ outcome: 'review_completed_artifact_missing',
1540
+ runId: payload.runId,
1541
+ target: payload.target,
1542
+ project: payload.project,
1543
+ projectResolutionSource: payload.projectResolutionSource,
1544
+ artifactPath: null,
1545
+ generatedAt: null,
1546
+ gateInvocation: payload.gateInvocation,
1547
+ dispatchReport: payload.dispatchReport,
1548
+ receiveEligible: false,
1549
+ remediable: false,
1550
+ handoff: null,
1551
+ message,
1552
+ recovery,
1553
+ });
1554
+ return;
1555
+ }
1556
+ context.logger.error(message);
1557
+ context.logger.error(recovery);
1558
+ }
1531
1559
  function writeReviewGateTargetingFailure(context, payload) {
1532
1560
  const corroboration = {
1533
1561
  run: payload.corroboration.run,
@@ -1712,6 +1740,12 @@ async function runGateSet(skillName, options, context, dependencies) {
1712
1740
  const layer = parseLayer(options.layer);
1713
1741
  const normalizedSkill = trimRequired(skillName, '<skill>');
1714
1742
  const gate = parseGateConfig(options);
1743
+ if (gate) {
1744
+ const validation = validateConfiguredGateCommand(gate.command);
1745
+ if (validation.kind === 'invalid') {
1746
+ throw new Error(validation.message);
1747
+ }
1748
+ }
1715
1749
  const warnings = gate
1716
1750
  ? detectDevBuildGateCommandWarnings(gate.command)
1717
1751
  : [];
@@ -2068,6 +2102,23 @@ async function runReviewGate(prompt, options, context, dependencies) {
2068
2102
  const producedArtifact = artifactResolution.artifact;
2069
2103
  if (!producedArtifact) {
2070
2104
  const diagnosticArtifact = artifactResolution.diagnosticArtifact;
2105
+ if (!diagnosticArtifact &&
2106
+ artifactResolution.matchingArtifactPaths.length === 0) {
2107
+ if (projectLogFinalization) {
2108
+ projectLogFinalization.status = 'artifact_missing';
2109
+ projectLogFinalization.exitCode = 1;
2110
+ }
2111
+ writeReviewGateArtifactMissing(context, {
2112
+ runId,
2113
+ target: selected.id,
2114
+ project: projectPath,
2115
+ projectResolutionSource: reviewProject.source,
2116
+ gateInvocation,
2117
+ dispatchReport,
2118
+ });
2119
+ process.exitCode = 1;
2120
+ return;
2121
+ }
2071
2122
  const message = artifactResolution.matchingArtifactPaths.length > 1
2072
2123
  ? `Multiple direct review artifacts carried gate run ID ${runId}.`
2073
2124
  : initialTargetCorroboration.run === 'mismatched'
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/doctor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AA4LlE,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,EAAE,CAAC,CAiVxB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/doctor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AA4MlE,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,EAAE,CAAC,CA2UxB"}
@@ -11,9 +11,25 @@ const ALLOWED_TOP_LEVEL_DIRECTORIES = new Set([
11
11
  'analysis',
12
12
  'reviews',
13
13
  ]);
14
- // A human-facing `README.md` at the repo-reference root is benign, so it is an
15
- // allowed top-level file alongside the canonical `AGENTS.md` (F5).
16
- const ALLOWED_TOP_LEVEL_FILES = new Set(['AGENTS.md', 'README.md']);
14
+ // Human/provider-facing companions to the canonical `AGENTS.md` are benign.
15
+ // Pointer correctness remains the responsibility of `oat instructions
16
+ // validate`; PJM doctor only classifies the repository layout.
17
+ const ALLOWED_TOP_LEVEL_FILES = new Set([
18
+ 'AGENTS.md',
19
+ 'CLAUDE.md',
20
+ 'README.md',
21
+ ]);
22
+ // `project-observations.md` is the documented append-only project-log ledger.
23
+ // The remaining names have dedicated migration/duplicate checks below, so the
24
+ // loose-reference classifier must not report them a second time.
25
+ const ALLOWED_REFERENCE_FILES = new Set([
26
+ 'AGENTS.md',
27
+ 'CLAUDE.md',
28
+ 'project-observations.md',
29
+ 'decision-record.md',
30
+ 'roadmap.md',
31
+ 'current-state.md',
32
+ ]);
17
33
  const LEGACY_MONOLITHS = ['reference/decision-record.md'];
18
34
  async function pathExists(path) {
19
35
  try {
@@ -265,10 +281,7 @@ export async function runPjmDoctorChecks(repoRoot, options = {}) {
265
281
  const referenceEntries = await listDirectoryNames(join(repoRoot, 'reference'));
266
282
  const looseReferenceFiles = referenceEntries
267
283
  .filter((name) => name.endsWith('.md'))
268
- .filter((name) => name !== 'AGENTS.md' &&
269
- name !== 'decision-record.md' &&
270
- name !== 'roadmap.md' &&
271
- name !== 'current-state.md')
284
+ .filter((name) => !ALLOWED_REFERENCE_FILES.has(name))
272
285
  .map((name) => `reference/${name}`);
273
286
  checks.push({
274
287
  name: 'pjm:loose_reference_files',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "private": false,
5
5
  "description": "Open Agent Toolkit CLI",
6
6
  "homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
@@ -34,7 +34,7 @@
34
34
  "ora": "^9.0.0",
35
35
  "yaml": "2.8.2",
36
36
  "zod": "^3.25.76",
37
- "@open-agent-toolkit/control-plane": "0.2.47"
37
+ "@open-agent-toolkit/control-plane": "0.2.49"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.0",