@open-agent-toolkit/cli 0.3.6 → 0.3.8

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.
Files changed (82) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +38 -18
  3. package/assets/docs/cli-utilities/workflow-gates.md +37 -0
  4. package/assets/docs/contributing/updating-model-guidance.md +6 -6
  5. package/assets/docs/provider-sync/commands.md +6 -0
  6. package/assets/docs/provider-sync/providers.md +24 -0
  7. package/assets/docs/provider-sync/scope-and-surface.md +2 -0
  8. package/assets/docs/reference/cli-reference.md +2 -1
  9. package/assets/docs/workflows/projects/autonomy.md +1 -1
  10. package/assets/docs/workflows/projects/dispatch-ceiling.md +26 -20
  11. package/assets/docs/workflows/projects/evidence-layers.md +5 -1
  12. package/assets/docs/workflows/projects/retro.md +7 -0
  13. package/assets/public-package-versions.json +4 -4
  14. package/assets/skills/oat-agent-instructions-analyze/SKILL.md +1 -1
  15. package/assets/skills/oat-agent-instructions-analyze/scripts/resolve-providers.sh +17 -6
  16. package/assets/skills/oat-dispatch-subagents/SKILL.md +1 -1
  17. package/assets/skills/oat-dispatch-subagents/references/managed-claude-example.json +387 -0
  18. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +75 -0
  19. package/assets/skills/oat-doctor/SKILL.md +2 -2
  20. package/assets/skills/oat-project-autonomous/SKILL.md +2 -2
  21. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  22. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  23. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  24. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +24 -22
  25. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  26. package/assets/skills/oat-project-import-plan/SKILL.md +4 -4
  27. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
  28. package/assets/skills/oat-project-plan/SKILL.md +4 -4
  29. package/assets/skills/oat-project-plan-writing/SKILL.md +4 -4
  30. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  31. package/assets/skills/oat-project-quick-start/SKILL.md +4 -4
  32. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  33. package/assets/skills/oat-project-retro/SKILL.md +70 -6
  34. package/assets/skills/oat-project-review-provide/SKILL.md +3 -1
  35. package/assets/skills/oat-project-review-provide-remote/SKILL.md +3 -1
  36. package/dist/agents/canonical/resolve.d.ts +6 -4
  37. package/dist/agents/canonical/resolve.d.ts.map +1 -1
  38. package/dist/agents/canonical/resolve.js +6 -4
  39. package/dist/commands/config/index.d.ts.map +1 -1
  40. package/dist/commands/config/index.js +210 -28
  41. package/dist/commands/gate/index.d.ts.map +1 -1
  42. package/dist/commands/gate/index.js +51 -2
  43. package/dist/commands/gate/review-verdict.d.ts +22 -0
  44. package/dist/commands/gate/review-verdict.d.ts.map +1 -1
  45. package/dist/commands/gate/review-verdict.js +111 -0
  46. package/dist/commands/project/dispatch/canonical-role.d.ts +33 -0
  47. package/dist/commands/project/dispatch/canonical-role.d.ts.map +1 -0
  48. package/dist/commands/project/dispatch/canonical-role.js +114 -0
  49. package/dist/commands/project/dispatch/index.d.ts.map +1 -1
  50. package/dist/commands/project/dispatch/index.js +3 -1
  51. package/dist/commands/project/dispatch/record.d.ts.map +1 -1
  52. package/dist/commands/project/dispatch/record.js +146 -4
  53. package/dist/commands/sync/apply.d.ts.map +1 -1
  54. package/dist/commands/sync/apply.js +28 -21
  55. package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -1
  56. package/dist/commands/tools/shared/sync-evidence.js +32 -5
  57. package/dist/config/oat-config.d.ts +8 -0
  58. package/dist/config/oat-config.d.ts.map +1 -1
  59. package/dist/config/oat-config.js +116 -1
  60. package/dist/engine/compute-plan.d.ts.map +1 -1
  61. package/dist/engine/compute-plan.js +31 -3
  62. package/dist/providers/claude/dispatch-envelope.d.ts +53 -0
  63. package/dist/providers/claude/dispatch-envelope.d.ts.map +1 -1
  64. package/dist/providers/claude/dispatch-envelope.js +324 -48
  65. package/dist/providers/claude/rule-transform.js +1 -1
  66. package/dist/providers/copilot/rule-transform.js +1 -1
  67. package/dist/providers/cursor/rule-transform.js +1 -1
  68. package/dist/providers/identity/absolute-paths.d.ts +13 -0
  69. package/dist/providers/identity/absolute-paths.d.ts.map +1 -1
  70. package/dist/providers/identity/absolute-paths.js +27 -14
  71. package/dist/providers/identity/generic-dispatch-record.d.ts +212 -0
  72. package/dist/providers/identity/generic-dispatch-record.d.ts.map +1 -1
  73. package/dist/providers/identity/generic-dispatch-record.js +78 -19
  74. package/dist/providers/identity/oat-dispatch-record.d.ts +5 -0
  75. package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -1
  76. package/dist/providers/identity/oat-dispatch-record.js +11 -2
  77. package/dist/providers/shared/registry.d.ts +6 -0
  78. package/dist/providers/shared/registry.d.ts.map +1 -1
  79. package/dist/providers/shared/registry.js +30 -0
  80. package/dist/rules/canonical/parse.d.ts.map +1 -1
  81. package/dist/rules/canonical/parse.js +38 -3
  82. package/package.json +2 -2
@@ -5,7 +5,7 @@ disable-model-invocation: false
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Bash(git:*), Bash(jq:*), Bash(pnpm:*), Bash(oat config:*), Bash(oat decision:*), Bash(oat project log:*), Bash(oat project push:*), Bash(oat project scope:*), Bash(oat tools:*), Glob, Grep, AskUserQuestion
7
7
  metadata:
8
- version: 1.0.6
8
+ version: 1.0.7
9
9
  ---
10
10
 
11
11
  # Project Retrospective
@@ -53,8 +53,9 @@ OAT ▸ PROJECT RETRO
53
53
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
54
54
  ```
55
55
 
56
- Use `[1/6] Resolving project and mode…` through `[6/6] Formatting and
57
- committing…`. Name evidence inventory, synthesis, disposition, and project-log
56
+ Use `[1/7] Resolving project and mode…` through `[7/7] Walking through
57
+ register items…`, with `[6/7] Formatting and committing…` before the final
58
+ walkthrough. Name evidence inventory, synthesis, disposition, and project-log
58
59
  steps as they begin.
59
60
 
60
61
  ## Artifact Hygiene
@@ -165,7 +166,9 @@ provenance.
165
166
 
166
167
  ### Step 4: Resolve Post-Generation Consent
167
168
 
168
- Read effective `workflow.retro.apply` and `workflow.retro.filing` configuration.
169
+ Read effective `workflow.retro.apply`, `workflow.retro.filing.repo`, and
170
+ `workflow.retro.filing.upstream` configuration. Read each filing leaf key on its
171
+ own; the filing namespace has no single readable value.
169
172
 
170
173
  **Interactive run:**
171
174
 
@@ -173,16 +176,19 @@ Read effective `workflow.retro.apply` and `workflow.retro.filing` configuration.
173
176
  2. Ask whether to apply eligible RP apply-items now.
174
177
  3. If unfiled UP or RP file-items exist, offer the `oat-project-retro-file`
175
178
  skill.
179
+ 4. Close the run with the Step 7 walkthrough, whatever the user answered.
176
180
 
177
181
  **Non-interactive run:**
178
182
 
179
183
  - Apply only when `workflow.retro.apply` is `auto`.
180
184
  - `ask` or absent means propose-only.
181
- - Chain to `oat-project-retro-file` only when at least one
182
- `workflow.retro.filing` destination is explicitly configured; chaining means
185
+ - Chain to `oat-project-retro-file` only when `workflow.retro.filing.repo` or
186
+ `workflow.retro.filing.upstream` is explicitly configured; chaining means
183
187
  loading the current `oat-project-retro-file/SKILL.md` and following it, or
184
188
  dispatching a child that carries it.
185
189
  - Without filing config, file nothing and report that proposals remain.
190
+ - Close the run with the Step 7 walkthrough even though no one answered a
191
+ prompt.
186
192
 
187
193
  All applications follow the apply procedure. Filing remains owned by
188
194
  `oat-project-retro-file`; generate/apply mode does not file tracker items.
@@ -298,6 +304,61 @@ Commit the artifact, project-log append, and any approved apply outputs. Use
298
304
  one reviewed batch when items are tightly coupled; otherwise use one commit per
299
305
  item as described in the apply procedure. Never stage unrelated changes.
300
306
 
307
+ ### Step 7: Final Report Walkthrough
308
+
309
+ After the artifact passes Step 6 validation, end the final response with a
310
+ walkthrough of every `RP-*` and `UP-*` item so the user can decide what to apply
311
+ or file without opening the retro. Link the artifact by its repo-relative path
312
+ instead of reproducing it; the walkthrough explains items, it does not copy
313
+ their bodies.
314
+
315
+ For each item, state:
316
+
317
+ - its ID and a short title;
318
+ - a plain-language summary of what it proposes;
319
+ - why it matters for future runs;
320
+ - its current disposition and destination, read from the register fields after
321
+ every action in this run; and
322
+ - the next available action, or that none remains.
323
+
324
+ Group items in this order: apply items (RP `Disposition: apply`), repository
325
+ filing items (RP `Disposition: file`), and upstream filing items (UP). Give an
326
+ empty group a one-line "none" note rather than dropping it.
327
+
328
+ The walkthrough is required in interactive and non-interactive runs alike, and
329
+ whether apply or filing was performed, declined, deferred, skipped, automatic,
330
+ or unanswered. When both registers are empty, give an explicit no-items summary
331
+ such as "No repo improvements or upstream feedback items were proposed."
332
+
333
+ Worked example:
334
+
335
+ ```markdown
336
+ Retro: `.oat/projects/shared/example/references/project-retro.md`
337
+
338
+ **Apply items**
339
+
340
+ - **RP-01 — Isolate HOME in template tests.** Summary: run template-resolving
341
+ tests with a temporary HOME. Why it matters: they read the maintainer's user
342
+ templates and fail locally while passing in CI. Disposition: apply; Status:
343
+ applied; Applied-ref: `abc1234`. Next action: none.
344
+
345
+ **Repository filing items**
346
+
347
+ - **RP-02 — Document the cache-replay trap.** Summary: warn that a green turbo
348
+ run can be a cache replay. Why it matters: two sessions reported replays as
349
+ real passes. Disposition: file; Status: proposed; Destination: — because
350
+ filing was deferred, and `workflow.retro.filing.repo` routes it to the
351
+ backlog. Next action: run retro filing to create the backlog item.
352
+
353
+ **Upstream filing items**
354
+
355
+ - **UP-01 — Name the file in rule parse errors.** Summary: include the rule path
356
+ in canonical parse failures. Why it matters: the error named no file, so
357
+ diagnosis needed a full scan. Status: proposed; Destination: — because
358
+ `workflow.retro.filing.upstream` is unset. Next action: set that key or file
359
+ it interactively.
360
+ ```
361
+
301
362
  ## Success Criteria
302
363
 
303
364
  - The resolved mode matches explicit user/config intent.
@@ -311,3 +372,6 @@ item as described in the apply procedure. Never stage unrelated changes.
311
372
  - No promotion is applied or item filed without interactive approval or
312
373
  explicit non-interactive configuration.
313
374
  - The project log and commit preserve the outcome without unrelated changes.
375
+ - The final response walks through every `RP-*` and `UP-*` item, grouped into
376
+ apply, repository filing, and upstream filing items, or gives an explicit
377
+ no-items summary, and links the artifact instead of reproducing it.
@@ -5,7 +5,7 @@ disable-model-invocation: false
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Glob, Grep, Write, Edit, Bash(git:*), Bash(oat:*), Bash(pnpm:*), Bash(mkdir:*), Bash(date:*), Bash(realpath:*), Bash(awk:*), AskUserQuestion
7
7
  metadata:
8
- version: 1.5.10
8
+ version: 1.5.11
9
9
  ---
10
10
 
11
11
  # Request Review
@@ -1034,6 +1034,8 @@ When `oat gate review` invokes this skill, it includes gate-originated context i
1034
1034
 
1035
1035
  The gate prompt also supplies exact values for `oat_gate_run_id`, `oat_gate_target`, `oat_gate_runtime`, `oat_invocation_model`, `oat_invocation_reasoning_effort`, and `oat_invocation_source`. Copy all six values verbatim for gate-originated artifacts. These fields record OAT's configured invocation; do not derive them from `baseCommand`, the target id, model self-identification, or surrounding dispatch prose. Optional observed/self-reported identity is separate and non-authoritative.
1036
1036
 
1037
+ For gate-originated artifacts (`oat_review_invocation: gate`), write the Step 6.0 resolver stamp on a line labeled `**Dispatch audit (policy view):**`, with the stamp in one backtick pair so the literal `Dispatch:` token stays readable, for example ``**Dispatch audit (policy view):** `Dispatch: scope=p01 action=review role=reviewer …` ``. The resolver stamp records the project reviewer policy, and the six gate frontmatter fields record the gate's actual invocation; the label keeps both accurate. `oat gate review` checks every other reviewer audit stamp anywhere outside `## Findings`, the severity sections, and fenced code (for example in the metadata block, `## Dispatch Audit`, or `## Review Scope`), including a backtick-wrapped stamp followed only by punctuation or one parenthetical, against the frontmatter: its `target` must equal `oat_gate_target`, and its `effort_axis` must equal `selected:<oat_invocation_reasoning_effort>` when that effort is concrete. A disagreeing stamp fails the gate with `gate_dispatch_audit_mismatched`. Manual and auto reviews keep their audit line unlabeled.
1038
+
1037
1039
  For all other invocations (user-triggered, fresh session), use `manual`.
1038
1040
 
1039
1041
  Gate parsing contract:
@@ -5,7 +5,7 @@ disable-model-invocation: true
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Bash, Glob, Grep, Task, AskUserQuestion
7
7
  metadata:
8
- version: 1.1.7
8
+ version: 1.1.8
9
9
  ---
10
10
 
11
11
  # Remote Review Provide (Project-Scoped GitHub PR)
@@ -408,6 +408,8 @@ oat_gate_target: <exact configured gate target; omit for lifecycle>
408
408
 
409
409
  `oat_project` carries the resolved project path so machine A's `oat-project-review-receive-remote` routes findings into the right project's plan tasks. Preserve the current invocation lineage in the GitHub marker: omit `oat_gate_target` for lifecycle reviews and include the exact target for gate reviews. Verdict: `REQUEST_CHANGES` when any critical or high finding exists; `COMMENT` otherwise (including a clean, zero-findings review — never auto-`APPROVE`).
410
410
 
411
+ For gate reviews (`oat_review_invocation: gate`), write the resolver stamp in the posted review's dispatch audit metadata on a line labeled `**Dispatch audit (policy view):**`, with the stamp in one backtick pair so the literal `Dispatch:` token stays readable. The resolver stamp records the project reviewer policy, while `oat_gate_target` names the gate's actual invocation; the label keeps both accurate. Any other reviewer audit stamp outside `## Findings`, the severity sections, and fenced code must name `oat_gate_target` as its `target` and carry `effort_axis=selected:<effort>` for a concrete gate effort, because `oat gate review` rejects a disagreeing unlabeled stamp with `gate_dispatch_audit_mismatched`. Lifecycle reviews keep their audit line unlabeled.
412
+
411
413
  ### Step 8: Post the Review + Clean Up
412
414
 
413
415
  Probe `agent-reviews` for a posting flow with a non-mutating check (`npx agent-reviews --help`), cached for the run:
@@ -36,10 +36,12 @@ export interface ResolveCanonicalRoleInput {
36
36
  projectCanonicalRoot: string;
37
37
  }
38
38
  /**
39
- * Deliberately a library for skill-side callers: dispatch protocols resolve
40
- * role identity before the native launch and hand the resulting evidence to
41
- * `oat project dispatch record`, which validates it. There is intentionally no
42
- * production call site inside the CLI.
39
+ * Resolve canonical role identity before a native launch. Its production
40
+ * caller is `oat project dispatch canonical-role`
41
+ * (`commands/project/dispatch/canonical-role.ts`), which prints the evidence
42
+ * as a `canonical-role-resolution` event for `oat project dispatch record` to
43
+ * validate, so skill-side callers never hand-assemble redacted paths or a
44
+ * content digest.
43
45
  */
44
46
  export declare function resolveCanonicalRole(input: ResolveCanonicalRoleInput): CanonicalRoleEvidence;
45
47
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/agents/canonical/resolve.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,yBAAyB,CAAC;AAC9B,MAAM,MAAM,6BAA6B,GACrC,SAAS,GACT,gBAAgB,GAChB,kBAAkB,GAClB,mBAAmB,GACnB,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,6BAA6B,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,qBAAqB,GAC7B;IACE,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,uBAAuB,CAAC;IACpC,aAAa,EAAE,YAAY,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;CACrC,CAAC;AAEN,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAgLD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,yBAAyB,GAC/B,qBAAqB,CA0DvB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/agents/canonical/resolve.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAC9D,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,yBAAyB,CAAC;AAC9B,MAAM,MAAM,6BAA6B,GACrC,SAAS,GACT,gBAAgB,GAChB,kBAAkB,GAClB,mBAAmB,GACnB,cAAc,GACd,cAAc,CAAC;AAEnB,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,6BAA6B,CAAC;CACxC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,qBAAqB,GAC7B;IACE,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,uBAAuB,CAAC;IACpC,aAAa,EAAE,YAAY,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,GACD;IACE,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;CACrC,CAAC;AAEN,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAgLD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,yBAAyB,GAC/B,qBAAqB,CA0DvB"}
@@ -138,10 +138,12 @@ function resolveRoleIdentity(resolved, candidate, input, candidateMisses) {
138
138
  }
139
139
  }
140
140
  /**
141
- * Deliberately a library for skill-side callers: dispatch protocols resolve
142
- * role identity before the native launch and hand the resulting evidence to
143
- * `oat project dispatch record`, which validates it. There is intentionally no
144
- * production call site inside the CLI.
141
+ * Resolve canonical role identity before a native launch. Its production
142
+ * caller is `oat project dispatch canonical-role`
143
+ * (`commands/project/dispatch/canonical-role.ts`), which prints the evidence
144
+ * as a `canonical-role-resolution` event for `oat project dispatch record` to
145
+ * validate, so skill-side callers never hand-assemble redacted paths or a
146
+ * content digest.
145
147
  */
146
148
  export function resolveCanonicalRole(input) {
147
149
  const loadedRoot = resolve(input.skillDir, '..', '..');
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { readFile as readFileDefault } from 'node:fs/promises';
2
2
  import { isAbsolute, join } from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
3
4
  import { buildCommandContext } from '../../app/command-context.js';
4
5
  import { normalizeExcludedPaths } from '../instructions/instructions.utils.js';
5
6
  import { resolveProjectsRoot } from '../shared/oat-paths.js';
@@ -2353,6 +2354,14 @@ async function removeConfigPathOnDisk(configPath, path) {
2353
2354
  const { next, removed } = removeConfigPath(parsed, path);
2354
2355
  return removed ? next : null;
2355
2356
  }
2357
+ function warnBeforeReplacingCells(application, options, context) {
2358
+ if (options.dryRun ||
2359
+ context.json ||
2360
+ application.replacedCells.length === 0) {
2361
+ return;
2362
+ }
2363
+ context.logger.warn(`Replacing ${application.replacedCells.length} populated dispatch matrix cells from the bundled recommendation: ${application.replacedCells.join(', ')}.${application.droppedCells.length > 0 ? ` Whole-provider replacements remove: ${application.droppedCells.join(', ')}.` : ''} Use --keep-existing to preserve them or --dry-run to preview.`);
2364
+ }
2356
2365
  async function loadDispatchMatrixRecommendation(dependencies) {
2357
2366
  const assetsRoot = await dependencies.resolveAssetsRoot();
2358
2367
  const assetPath = join(assetsRoot, DISPATCH_MATRIX_RECOMMENDATION_ASSET);
@@ -2392,18 +2401,90 @@ async function validateRecommendationCells(repoRoot, recommendation, dependencie
2392
2401
  }
2393
2402
  }
2394
2403
  }
2395
- function applyDispatchMatrixRecommendation(workflow, recommendation) {
2404
+ function applyDispatchMatrixRecommendation(workflow, recommendation, replace) {
2396
2405
  const existingProviders = workflow?.dispatchCeiling?.providers ?? {};
2397
2406
  const providers = {
2398
2407
  ...recommendation.providers,
2399
2408
  };
2409
+ const filledCells = [];
2410
+ const preservedCells = [];
2411
+ const differingCells = [];
2412
+ const replacedCells = [];
2413
+ const droppedCells = [];
2414
+ for (const [provider, recommendedValue] of Object.entries(recommendation.providers)) {
2415
+ const path = `${DISPATCH_CEILING_PROVIDER_KEY_PREFIX}${provider}`;
2416
+ const existingValue = getOwnKey(existingProviders, provider);
2417
+ if (existingValue === undefined) {
2418
+ if (typeof recommendedValue === 'string') {
2419
+ filledCells.push(path);
2420
+ }
2421
+ else {
2422
+ filledCells.push(...Object.keys(recommendedValue).map((tier) => `${path}.${tier}`));
2423
+ }
2424
+ continue;
2425
+ }
2426
+ if (typeof recommendedValue === 'string' ||
2427
+ typeof existingValue === 'string') {
2428
+ if (!isDeepStrictEqual(existingValue, recommendedValue)) {
2429
+ differingCells.push(path);
2430
+ if (replace) {
2431
+ replacedCells.push(path);
2432
+ if (typeof recommendedValue === 'string' &&
2433
+ typeof existingValue !== 'string') {
2434
+ droppedCells.push(...Object.keys(existingValue).map((tier) => `${path}.${tier}`));
2435
+ }
2436
+ }
2437
+ else {
2438
+ preservedCells.push(path);
2439
+ }
2440
+ }
2441
+ else {
2442
+ preservedCells.push(path);
2443
+ }
2444
+ continue;
2445
+ }
2446
+ for (const [tier, recommendedCell] of Object.entries(recommendedValue)) {
2447
+ const cellPath = `${path}.${tier}`;
2448
+ const existingCell = getOwnKey(existingValue, tier);
2449
+ if (existingCell === undefined) {
2450
+ filledCells.push(cellPath);
2451
+ }
2452
+ else {
2453
+ if (!isDeepStrictEqual(existingCell, recommendedCell)) {
2454
+ differingCells.push(cellPath);
2455
+ if (replace) {
2456
+ replacedCells.push(cellPath);
2457
+ }
2458
+ else {
2459
+ preservedCells.push(cellPath);
2460
+ }
2461
+ }
2462
+ else {
2463
+ preservedCells.push(cellPath);
2464
+ }
2465
+ }
2466
+ }
2467
+ }
2400
2468
  // `existingProviders` is a `normalizeDispatchMatrix` product, which now
2401
2469
  // keeps a provider literally named `__proto__` as an own key, so
2402
2470
  // `Object.entries` yields it here and every access is own-key guarded. The
2403
2471
  // `{ ...recommendation.providers }` spread above is already safe.
2404
2472
  for (const [provider, existingValue] of Object.entries(existingProviders)) {
2405
2473
  const recommendedValue = getOwnKey(recommendation.providers, provider);
2406
- if (recommendedValue &&
2474
+ if (replace &&
2475
+ recommendedValue &&
2476
+ typeof recommendedValue !== 'string' &&
2477
+ typeof existingValue !== 'string') {
2478
+ setOwnKey(providers, provider, {
2479
+ ...existingValue,
2480
+ ...recommendedValue,
2481
+ });
2482
+ }
2483
+ else if (replace && recommendedValue !== undefined) {
2484
+ // A bare provider override is replaced as one configured cell.
2485
+ setOwnKey(providers, provider, recommendedValue);
2486
+ }
2487
+ else if (recommendedValue &&
2407
2488
  typeof recommendedValue !== 'string' &&
2408
2489
  typeof existingValue !== 'string') {
2409
2490
  setOwnKey(providers, provider, {
@@ -2415,13 +2496,31 @@ function applyDispatchMatrixRecommendation(workflow, recommendation) {
2415
2496
  setOwnKey(providers, provider, existingValue);
2416
2497
  }
2417
2498
  }
2499
+ const versionWritten = replace
2500
+ ? filledCells.length > 0 ||
2501
+ replacedCells.length > 0 ||
2502
+ workflow?.dispatchCeiling?.recommendationVersion !==
2503
+ recommendation.version
2504
+ : filledCells.length > 0 && differingCells.length === 0;
2505
+ const writeRequired = filledCells.length > 0 || replacedCells.length > 0 || versionWritten;
2418
2506
  return {
2419
- ...(workflow ?? {}),
2420
- dispatchCeiling: {
2421
- ...workflow?.dispatchCeiling,
2422
- recommendationVersion: recommendation.version,
2423
- providers,
2507
+ workflow: {
2508
+ ...(workflow ?? {}),
2509
+ dispatchCeiling: {
2510
+ ...workflow?.dispatchCeiling,
2511
+ ...(versionWritten
2512
+ ? { recommendationVersion: recommendation.version }
2513
+ : {}),
2514
+ providers,
2515
+ },
2424
2516
  },
2517
+ filledCells,
2518
+ preservedCells,
2519
+ differingCells,
2520
+ replacedCells,
2521
+ droppedCells,
2522
+ versionWritten,
2523
+ writeRequired,
2425
2524
  };
2426
2525
  }
2427
2526
  async function effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies) {
@@ -2443,45 +2542,92 @@ async function adoptDispatchMatrixRecommendation(repoRoot, userConfigDir, option
2443
2542
  if (source === 'user') {
2444
2543
  const userConfig = await dependencies.readUserConfig(userConfigDir);
2445
2544
  await validateRecommendationCells(repoRoot, recommendation, dependencies, context.logger.warn);
2446
- const workflow = applyDispatchMatrixRecommendation(userConfig.workflow, recommendation);
2447
- await dependencies.writeUserConfig(userConfigDir, {
2448
- ...userConfig,
2449
- workflow,
2450
- });
2545
+ const application = applyDispatchMatrixRecommendation(userConfig.workflow, recommendation, options.replace);
2546
+ warnBeforeReplacingCells(application, options, context);
2547
+ if (application.writeRequired && !options.dryRun) {
2548
+ await dependencies.writeUserConfig(userConfigDir, {
2549
+ ...userConfig,
2550
+ workflow: application.workflow,
2551
+ });
2552
+ }
2451
2553
  return {
2452
2554
  key: 'workflow.dispatchCeiling.providers',
2453
2555
  value: recommendation.version,
2454
2556
  source,
2455
- notices: await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2557
+ versionWritten: application.versionWritten && !options.dryRun,
2558
+ dryRun: options.dryRun,
2559
+ currentVersion: (options.dryRun
2560
+ ? userConfig.workflow?.dispatchCeiling?.recommendationVersion
2561
+ : application.workflow.dispatchCeiling?.recommendationVersion) ??
2562
+ null,
2563
+ filledCells: application.filledCells,
2564
+ preservedCells: application.preservedCells,
2565
+ differingCells: application.differingCells,
2566
+ replacedCells: application.replacedCells,
2567
+ droppedCells: application.droppedCells,
2568
+ notices: options.dryRun
2569
+ ? []
2570
+ : await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2456
2571
  };
2457
2572
  }
2458
2573
  if (source === 'local') {
2459
2574
  const localConfig = await dependencies.readOatLocalConfig(repoRoot);
2460
2575
  await validateRecommendationCells(repoRoot, recommendation, dependencies, context.logger.warn);
2461
- const workflow = applyDispatchMatrixRecommendation(localConfig.workflow, recommendation);
2462
- await dependencies.writeOatLocalConfig(repoRoot, {
2463
- ...localConfig,
2464
- workflow,
2465
- });
2576
+ const application = applyDispatchMatrixRecommendation(localConfig.workflow, recommendation, options.replace);
2577
+ warnBeforeReplacingCells(application, options, context);
2578
+ if (application.writeRequired && !options.dryRun) {
2579
+ await dependencies.writeOatLocalConfig(repoRoot, {
2580
+ ...localConfig,
2581
+ workflow: application.workflow,
2582
+ });
2583
+ }
2466
2584
  return {
2467
2585
  key: 'workflow.dispatchCeiling.providers',
2468
2586
  value: recommendation.version,
2469
2587
  source,
2470
- notices: await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2588
+ versionWritten: application.versionWritten && !options.dryRun,
2589
+ dryRun: options.dryRun,
2590
+ currentVersion: (options.dryRun
2591
+ ? localConfig.workflow?.dispatchCeiling?.recommendationVersion
2592
+ : application.workflow.dispatchCeiling?.recommendationVersion) ??
2593
+ null,
2594
+ filledCells: application.filledCells,
2595
+ preservedCells: application.preservedCells,
2596
+ differingCells: application.differingCells,
2597
+ replacedCells: application.replacedCells,
2598
+ droppedCells: application.droppedCells,
2599
+ notices: options.dryRun
2600
+ ? []
2601
+ : await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2471
2602
  };
2472
2603
  }
2473
2604
  const sharedConfig = await dependencies.readOatConfig(repoRoot);
2474
2605
  await validateRecommendationCells(repoRoot, recommendation, dependencies, context.logger.warn);
2475
- const workflow = applyDispatchMatrixRecommendation(sharedConfig.workflow, recommendation);
2476
- await dependencies.writeOatConfig(repoRoot, {
2477
- ...sharedConfig,
2478
- workflow,
2479
- });
2606
+ const application = applyDispatchMatrixRecommendation(sharedConfig.workflow, recommendation, options.replace);
2607
+ warnBeforeReplacingCells(application, options, context);
2608
+ if (application.writeRequired && !options.dryRun) {
2609
+ await dependencies.writeOatConfig(repoRoot, {
2610
+ ...sharedConfig,
2611
+ workflow: application.workflow,
2612
+ });
2613
+ }
2480
2614
  return {
2481
2615
  key: 'workflow.dispatchCeiling.providers',
2482
2616
  value: recommendation.version,
2483
2617
  source,
2484
- notices: await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2618
+ versionWritten: application.versionWritten && !options.dryRun,
2619
+ dryRun: options.dryRun,
2620
+ currentVersion: (options.dryRun
2621
+ ? sharedConfig.workflow?.dispatchCeiling?.recommendationVersion
2622
+ : application.workflow.dispatchCeiling?.recommendationVersion) ?? null,
2623
+ filledCells: application.filledCells,
2624
+ preservedCells: application.preservedCells,
2625
+ differingCells: application.differingCells,
2626
+ replacedCells: application.replacedCells,
2627
+ droppedCells: application.droppedCells,
2628
+ notices: options.dryRun
2629
+ ? []
2630
+ : await effectiveTerminalReviewerNotices(repoRoot, userConfigDir, dependencies),
2485
2631
  };
2486
2632
  }
2487
2633
  function formatList(values) {
@@ -2686,10 +2832,40 @@ async function runAdopt(templateArg, options, context, dependencies) {
2686
2832
  context.logger.json({
2687
2833
  status: 'ok',
2688
2834
  ...result,
2835
+ ...jsonWarnings(result.replacedCells.length > 0 && !result.dryRun
2836
+ ? [
2837
+ `Replaced ${result.replacedCells.length} populated dispatch matrix cells from the bundled recommendation.${result.droppedCells.length > 0 ? ` Removed whole-provider tier cells: ${result.droppedCells.join(', ')}.` : ''} Use --keep-existing to preserve them.`,
2838
+ ]
2839
+ : []),
2689
2840
  });
2690
2841
  }
2691
2842
  else {
2692
- context.logger.info(`Adopted dispatch matrix recommendation ${result.value} to ${result.source} config.`);
2843
+ if (result.dryRun) {
2844
+ context.logger.info(`Dry run for ${result.source} config using recommendation ${result.value}: would fill ${result.filledCells.length} cells and replace ${result.replacedCells.length} cells; no config changed.`);
2845
+ }
2846
+ else if (result.versionWritten ||
2847
+ result.filledCells.length > 0 ||
2848
+ result.replacedCells.length > 0) {
2849
+ context.logger.info(`Applied dispatch matrix recommendation ${result.value} to ${result.source} config: filled ${result.filledCells.length} cells and replaced ${result.replacedCells.length} cells.`);
2850
+ }
2851
+ else {
2852
+ context.logger.info(`No missing dispatch matrix cells in ${result.source} config; recommendation version remains ${result.currentVersion ?? 'unset'}.`);
2853
+ }
2854
+ if (result.replacedCells.length > 0) {
2855
+ context.logger.info(`${result.dryRun ? 'Would replace' : 'Replaced'}: ${result.replacedCells.join(', ')}.`);
2856
+ if (result.droppedCells.length > 0) {
2857
+ context.logger.warn(`${result.dryRun ? 'Would remove' : 'Removed'} whole-provider tier cells: ${result.droppedCells.join(', ')}.`);
2858
+ }
2859
+ }
2860
+ else if (result.differingCells.length > 0) {
2861
+ context.logger.warn(`Preserved cells differ from recommendation ${result.value}: ${result.differingCells.join(', ')}. Review and update those cells explicitly if you want the new ladder.`);
2862
+ }
2863
+ if (!result.dryRun &&
2864
+ !result.versionWritten &&
2865
+ result.filledCells.length > 0 &&
2866
+ result.differingCells.length > 0) {
2867
+ context.logger.warn(`Recommendation version remains ${result.currentVersion ?? 'unset'} because preserved cells differ from ${result.value}.`);
2868
+ }
2693
2869
  if (result.notices.length > 0) {
2694
2870
  context.logger.info(formatDispatchNotices(result.notices));
2695
2871
  }
@@ -2843,12 +3019,18 @@ export function createConfigCommand(overrides = {}) {
2843
3019
  .option('--shared', 'Write to the shared repo config (.oat/config.json)')
2844
3020
  .option('--local', 'Write to the repo-local config (.oat/config.local.json)')
2845
3021
  .option('--user', 'Write to the user-level config (~/.oat/config.json)')
2846
- .option('--yes', 'Compatibility flag; adoption always preserves explicit existing cells')
3022
+ .option('--yes', 'Compatibility flag; adoption does not require confirmation')
3023
+ .option('--keep-existing', 'Fill missing cells without replacing populated cells')
3024
+ .option('--dry-run', 'Preview cell changes without writing config')
2847
3025
  .action(async (template, options, command) => {
2848
3026
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
2849
3027
  try {
2850
3028
  const surface = resolveSurfaceFlags(options);
2851
- await runAdopt(template, { surface }, context, dependencies);
3029
+ await runAdopt(template, {
3030
+ surface,
3031
+ replace: !(options.keepExisting ?? false),
3032
+ dryRun: options.dryRun ?? false,
3033
+ }, context, dependencies);
2852
3034
  }
2853
3035
  catch (error) {
2854
3036
  const message = error instanceof Error ? error.message : String(error);
@@ -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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"}