@open-agent-toolkit/cli 0.3.6 → 0.3.7
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/assets/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/configuration.md +23 -17
- package/assets/docs/contributing/updating-model-guidance.md +6 -6
- package/assets/docs/provider-sync/providers.md +4 -0
- package/assets/docs/workflows/projects/autonomy.md +1 -1
- package/assets/docs/workflows/projects/dispatch-ceiling.md +26 -20
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-doctor/SKILL.md +2 -2
- package/assets/skills/oat-project-autonomous/SKILL.md +2 -2
- package/assets/skills/oat-project-import-plan/SKILL.md +4 -4
- package/assets/skills/oat-project-plan/SKILL.md +4 -4
- package/assets/skills/oat-project-plan-writing/SKILL.md +4 -4
- package/assets/skills/oat-project-quick-start/SKILL.md +4 -4
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +210 -28
- package/package.json +2 -2
|
@@ -387,14 +387,14 @@ preference. For the full model, see
|
|
|
387
387
|
|
|
388
388
|
### Config keys
|
|
389
389
|
|
|
390
|
-
| Key | Values | Purpose
|
|
391
|
-
| ------------------------------------------------------ | ----------------------------------------------------- |
|
|
392
|
-
| `workflow.dispatchPolicy.mode` | `managed`, `inherit` | `managed` lets OAT select exact candidates; `inherit` leaves controls to the host
|
|
393
|
-
| `workflow.dispatchPolicy.policy` | `economy`, `balanced`, `high`, `frontier`, `uncapped` | Default named maximum or explicit managed uncapped state
|
|
394
|
-
| `workflow.dispatchCeiling.providers.<provider>` | tier map or legacy bare value | Reusable provider candidate column
|
|
395
|
-
| `workflow.dispatchCeiling.providers.<provider>.<tier>` | `candidates` cell, route, or legacy bare value | One named tier in the provider ladder
|
|
396
|
-
| `workflow.dispatchCeiling.recommendationVersion` | string |
|
|
397
|
-
| `workflow.dispatchCeiling.preset` | `balanced`, `maximum`, `cost-conscious` | Legacy policy setup alias
|
|
390
|
+
| Key | Values | Purpose |
|
|
391
|
+
| ------------------------------------------------------ | ----------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
392
|
+
| `workflow.dispatchPolicy.mode` | `managed`, `inherit` | `managed` lets OAT select exact candidates; `inherit` leaves controls to the host |
|
|
393
|
+
| `workflow.dispatchPolicy.policy` | `economy`, `balanced`, `high`, `frontier`, `uncapped` | Default named maximum or explicit managed uncapped state |
|
|
394
|
+
| `workflow.dispatchCeiling.providers.<provider>` | tier map or legacy bare value | Reusable provider candidate column |
|
|
395
|
+
| `workflow.dispatchCeiling.providers.<provider>.<tier>` | `candidates` cell, route, or legacy bare value | One named tier in the provider ladder |
|
|
396
|
+
| `workflow.dispatchCeiling.recommendationVersion` | string | Bundle version last written by adoption; does not prove the effective ladder matches |
|
|
397
|
+
| `workflow.dispatchCeiling.preset` | `balanced`, `maximum`, `cost-conscious` | Legacy policy setup alias |
|
|
398
398
|
|
|
399
399
|
### Adopt a complete ladder
|
|
400
400
|
|
|
@@ -406,14 +406,20 @@ oat config adopt dispatch-matrix --local
|
|
|
406
406
|
oat config adopt dispatch-matrix --user
|
|
407
407
|
```
|
|
408
408
|
|
|
409
|
-
Adoption
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
the
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
409
|
+
Adoption replaces populated cells from the bundled recommendation in the
|
|
410
|
+
chosen scope, fills missing cells, and keeps extra custom tier cells when
|
|
411
|
+
the bundled provider remains a tier map. A bundled provider-level scalar
|
|
412
|
+
replaces the whole provider, including its custom tiers. It warns about
|
|
413
|
+
replaced and removed cells and reports their paths in human and JSON output. Preview with
|
|
414
|
+
`oat config adopt dispatch-matrix --user --dry-run` before writing user defaults.
|
|
415
|
+
Add `--keep-existing` when you want only missing cells filled; a fill-only run
|
|
416
|
+
with no missing cells leaves the config and version unchanged. If it fills
|
|
417
|
+
missing cells while preserving differences, it leaves the version unchanged. Planning uses
|
|
418
|
+
`--keep-existing` after showing the complete bundle and asking for the owning
|
|
419
|
+
scope. If the resulting effective ladder remains incomplete, readiness blocks.
|
|
420
|
+
The version records the bundle last written by adoption, not whether the
|
|
421
|
+
effective ladder matches it. Dispatch targets, structured notices, and runtime
|
|
422
|
+
disclosure come from the effective ladder.
|
|
417
423
|
|
|
418
424
|
A recommended Fable target may require model access from the executing
|
|
419
425
|
provider. The adopting organization is responsible for confirming its
|
|
@@ -700,7 +706,7 @@ Workflow preference keys live under the `workflow.*` namespace:
|
|
|
700
706
|
- `workflow.dispatchCeiling.preset` — legacy compatibility alias (`balanced`, `maximum`, or `cost-conscious`) for capped managed policy setup.
|
|
701
707
|
- `workflow.dispatchCeiling.providers.<provider>` — dispatch matrix provider column or legacy bare provider target.
|
|
702
708
|
- `workflow.dispatchCeiling.providers.<provider>.<tier>` — one matrix cell for `economy`, `balanced`, `high`, or `frontier`.
|
|
703
|
-
- `workflow.dispatchCeiling.recommendationVersion` — version
|
|
709
|
+
- `workflow.dispatchCeiling.recommendationVersion` — bundle version last written by adoption; not an effective-ladder parity indicator.
|
|
704
710
|
- `workflow.gates.skills` / `workflow.gates.execTargets` — structured per-skill final gate commands and exec-target registry. Use `oat gate set`, `oat gate target set`, `oat gate review`, and `oat gate cross-provider-exec`; do not use `oat config set` for these objects.
|
|
705
711
|
- `workflow.gateTimeouts.code` / `workflow.gateTimeouts.artifact` — validated default gate-review budgets in milliseconds. Both resolve through `local > shared > user`.
|
|
706
712
|
|
|
@@ -108,11 +108,11 @@ Follow [Contributing Code](code.md) for the current validation and PR workflow.
|
|
|
108
108
|
|
|
109
109
|
## Adoption Is Separate
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
adopt dispatch-matrix --shared`, `--local`, or `--user`
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
111
|
+
A bundled ladder update does not mutate adopted user or repository config.
|
|
112
|
+
`oat config adopt dispatch-matrix --shared`, `--local`, or `--user` replaces
|
|
113
|
+
bundled cells in the chosen scope, with a warning and a `--dry-run` preview;
|
|
114
|
+
extra custom cells remain. Add `--keep-existing` to fill only missing cells.
|
|
115
|
+
The active project's named ceiling is a separate policy in its `state.md`;
|
|
116
|
+
a model update must not silently change it.
|
|
117
117
|
See [Dispatch Policy](../workflows/projects/dispatch-ceiling.md#ownership-and-adoption)
|
|
118
118
|
for config precedence and examples.
|
|
@@ -89,6 +89,10 @@ oat config adopt dispatch-matrix --local
|
|
|
89
89
|
oat config adopt dispatch-matrix --user
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
These commands replace bundled cells in the chosen scope and warn about
|
|
93
|
+
replacements. Add `--dry-run` to preview or `--keep-existing` to fill only
|
|
94
|
+
missing cells.
|
|
95
|
+
|
|
92
96
|
Project-config candidates materialize into the tracked, version-controlled
|
|
93
97
|
project `.codex` and `.cursor` views. User-config candidates materialize under
|
|
94
98
|
`~/.codex` and `~/.cursor`. OAT does not auto-ignore project output or create
|
|
@@ -83,7 +83,7 @@ provider-level scalar in that scope or remain shadowed by one at higher
|
|
|
83
83
|
precedence. It always tries the next authorized compatible candidate and stops
|
|
84
84
|
without mutation only when none remains.
|
|
85
85
|
|
|
86
|
-
The planner runs exactly one matching `oat config adopt dispatch-matrix`
|
|
86
|
+
The planner runs exactly one matching `oat config adopt dispatch-matrix --keep-existing`
|
|
87
87
|
command, records file-existence and compatibility evidence plus the selected
|
|
88
88
|
scope, and re-runs dispatch preflight. Existing explicit cells remain unchanged;
|
|
89
89
|
their provenance does not select the persistence scope. No authorized
|
|
@@ -58,27 +58,32 @@ oat config adopt dispatch-matrix --local
|
|
|
58
58
|
oat config adopt dispatch-matrix --user
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Adoption
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
Adoption replaces populated cells from the bundled recommendation in the
|
|
62
|
+
chosen scope, fills missing cells, and retains extra custom tiers when the
|
|
63
|
+
bundled provider remains a tier map. A bundled provider-level scalar replaces
|
|
64
|
+
the whole provider, including custom tiers. It warns about replaced or
|
|
65
|
+
removed cells and reports their paths. Use `--dry-run` to preview. For
|
|
66
|
+
fill-only setup, `--keep-existing` preserves populated cells; if it fills
|
|
67
|
+
nothing, both config and version remain unchanged. When it fills missing
|
|
68
|
+
cells but preserves divergent cells, the version also stays unchanged. Planning always uses
|
|
69
|
+
`--keep-existing` after showing the complete recommendation and asking which
|
|
70
|
+
scope should own it. If the resulting effective ladder remains incomplete,
|
|
71
|
+
planning blocks. The version identifies the bundle last written by adoption;
|
|
72
|
+
it does not prove the effective ladder matches it. OAT resolves the effective
|
|
73
|
+
ladder for dispatch targets and runtime disclosure.
|
|
70
74
|
|
|
71
75
|
### Upgrading to a newer recommendation version
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
already populated, re-running adoption will not give them to you. The existing
|
|
76
|
-
cell is kept intact rather than merged candidate by candidate. Removals are not
|
|
77
|
-
propagated either.
|
|
77
|
+
A new bundled recommendation does not change an adopted config by itself.
|
|
78
|
+
To update the chosen scope, first preview its affected cells:
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
```bash
|
|
81
|
+
oat config adopt dispatch-matrix --user --dry-run
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Run the same command without `--dry-run` to replace bundled cells. Use
|
|
85
|
+
`--shared` or `--local` instead when that scope owns the ladder. Add
|
|
86
|
+
`--keep-existing` to fill only missing cells and preserve existing choices.
|
|
82
87
|
|
|
83
88
|
Version `2026-09-25.1` is the current bundled recommendation. It prefers
|
|
84
89
|
GPT-6 Luna and Sol in Codex, then Sol xhigh, Astra high, and Astra xhigh in
|
|
@@ -96,9 +101,10 @@ Balanced, and Fable 5.1 thinking high replaces Fable 5 as Frontier's terminal
|
|
|
96
101
|
target. The ordering is an explicit user-directed preference informed by
|
|
97
102
|
vendor benchmarks and the model-selection matrix, not a local workload
|
|
98
103
|
comparison. Grok 4.5 and Fable 5 stay supported for explicit configurations.
|
|
99
|
-
Rerunning adoption
|
|
100
|
-
explicit older
|
|
101
|
-
procedure, see
|
|
104
|
+
Rerunning adoption replaces the bundled cells in the chosen scope; use
|
|
105
|
+
`--keep-existing` to preserve explicit older cells. For the complete
|
|
106
|
+
maintenance procedure, see
|
|
107
|
+
[Updating Model Guidance](../../contributing/updating-model-guidance.md).
|
|
102
108
|
|
|
103
109
|
The terminal Fable target may require model access from the executing provider.
|
|
104
110
|
The adopting organization is responsible for confirming its applicable
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
user-invocable: true
|
|
7
7
|
allowed-tools: Read, Bash, Glob, Grep, AskUserQuestion
|
|
8
8
|
metadata:
|
|
9
|
-
version: 2.0.
|
|
9
|
+
version: 2.0.1
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# OAT Doctor
|
|
@@ -111,7 +111,7 @@ Each finding is one line with an **area**, a **severity**, a one-line **summary*
|
|
|
111
111
|
- `activeProject` or `lastPausedProject` set to a path that does not exist → `error`; fix `oat config set activeProject ''` / `oat config set lastPausedProject ''` (the CLI refuses `unset` for these two lifecycle keys). `activeIdea` set to a missing path → `error`; fix `oat config unset activeIdea --local` (or `--user` for a user-level value).
|
|
112
112
|
- A set key whose `describe` entry carries `deprecated` → `warning`; summary names the key and its `deprecated.supersededBy`; when `deprecated.legacyValues` is present the finding fires only when the set value is one of those values; fix = the entry's `owningCommand` for the successor.
|
|
113
113
|
- A key set on a surface that is not one of the surfaces its `describe` entry's `file` names → `warning`; fix `oat config unset <key> --<surface>` then `oat config set <key> <value> --<right surface>`.
|
|
114
|
-
- The `
|
|
114
|
+
- The `project:dispatch_matrix` check (command 1, config area) reports target availability, not parity with the bundled recommendation. Do not infer parity from `workflow.dispatchCeiling.recommendationVersion`: it identifies the bundle last written by adoption. In the config dive, `oat config adopt dispatch-matrix --shared --keep-existing` fills missing cells and reports preserved differences; a direct adoption without `--keep-existing` replaces bundled cells in the chosen scope, so preview it with `--dry-run`.
|
|
115
115
|
- A documented key group with nothing set on any surface → one `info` per group, expanded only in the dive.
|
|
116
116
|
- Synced project health: `project:synced_tracked_artifacts`, `project:synced_gitignore`, `project:synced_projects`, `project:synced_editor_hint`, and per-project `project:synced_<slug>_<kind>` checks from command 1 → severity from status, summary from the message; report them without treating an absent checkout as proof that no synced project exists (an absent checkout is materialized by `oat project pull`, which the check's message names).
|
|
117
117
|
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
user-invocable: true
|
|
7
7
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, Task
|
|
8
8
|
metadata:
|
|
9
|
-
version: 1.0.
|
|
9
|
+
version: 1.0.17
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Autonomous OAT Project
|
|
@@ -375,7 +375,7 @@ provider scalar or is shadowed by one at higher precedence, and block without
|
|
|
375
375
|
mutation only when no authorized adoption-compatible scope remains. Existing
|
|
376
376
|
explicit matrix cells are preserved by adoption; their provenance does not
|
|
377
377
|
choose the persistence scope. Run exactly one matching
|
|
378
|
-
`oat config adopt dispatch-matrix` command and re-run the reviewer preflight.
|
|
378
|
+
`oat config adopt dispatch-matrix --keep-existing` command and re-run the reviewer preflight.
|
|
379
379
|
Block when the ladder remains incomplete after adoption.
|
|
380
380
|
|
|
381
381
|
At every required artifact or code review:
|
|
@@ -7,7 +7,7 @@ disable-model-invocation: true
|
|
|
7
7
|
user-invocable: true
|
|
8
8
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
9
9
|
metadata:
|
|
10
|
-
version: 1.4.
|
|
10
|
+
version: 1.4.18
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Import External Plan
|
|
@@ -291,9 +291,9 @@ show the complete bundled recommendation and ask for its owning scope before
|
|
|
291
291
|
running exactly one of:
|
|
292
292
|
|
|
293
293
|
```bash
|
|
294
|
-
oat config adopt dispatch-matrix --shared
|
|
295
|
-
oat config adopt dispatch-matrix --local
|
|
296
|
-
oat config adopt dispatch-matrix --user
|
|
294
|
+
oat config adopt dispatch-matrix --shared --keep-existing
|
|
295
|
+
oat config adopt dispatch-matrix --local --keep-existing
|
|
296
|
+
oat config adopt dispatch-matrix --user --keep-existing
|
|
297
297
|
```
|
|
298
298
|
|
|
299
299
|
Adoption preserves explicit cells. Re-run the resolver and completeness check.
|
|
@@ -6,7 +6,7 @@ disable-model-invocation: true
|
|
|
6
6
|
user-invocable: true
|
|
7
7
|
allowed-tools: Read, Write, Bash(git:*), Glob, Grep, AskUserQuestion
|
|
8
8
|
metadata:
|
|
9
|
-
version: 1.4.
|
|
9
|
+
version: 1.4.15
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Planning Phase
|
|
@@ -408,9 +408,9 @@ recommendation and ask the user to choose the owning scope before running
|
|
|
408
408
|
exactly one of:
|
|
409
409
|
|
|
410
410
|
```bash
|
|
411
|
-
oat config adopt dispatch-matrix --shared
|
|
412
|
-
oat config adopt dispatch-matrix --local
|
|
413
|
-
oat config adopt dispatch-matrix --user
|
|
411
|
+
oat config adopt dispatch-matrix --shared --keep-existing
|
|
412
|
+
oat config adopt dispatch-matrix --local --keep-existing
|
|
413
|
+
oat config adopt dispatch-matrix --user --keep-existing
|
|
414
414
|
```
|
|
415
415
|
|
|
416
416
|
Adoption fills missing cells but preserves explicit values. Re-run the resolver
|
|
@@ -5,7 +5,7 @@ disable-model-invocation: true
|
|
|
5
5
|
user-invocable: false
|
|
6
6
|
allowed-tools: Read, Write, Glob, Grep
|
|
7
7
|
metadata:
|
|
8
|
-
version: 1.2.
|
|
8
|
+
version: 1.2.33
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Plan Writing Contract
|
|
@@ -129,11 +129,11 @@ In an interactive run, ask the user to select the owning scope explicitly
|
|
|
129
129
|
before any adoption write:
|
|
130
130
|
|
|
131
131
|
1. **Shared repository** - team-owned `.oat/config.json`; run
|
|
132
|
-
`oat config adopt dispatch-matrix --shared`.
|
|
132
|
+
`oat config adopt dispatch-matrix --shared --keep-existing`.
|
|
133
133
|
2. **Repo-local checkout** - personal `.oat/config.local.json`; run
|
|
134
|
-
`oat config adopt dispatch-matrix --local`.
|
|
134
|
+
`oat config adopt dispatch-matrix --local --keep-existing`.
|
|
135
135
|
3. **User** - cross-repository `~/.oat/config.json`; run
|
|
136
|
-
`oat config adopt dispatch-matrix --user`.
|
|
136
|
+
`oat config adopt dispatch-matrix --user --keep-existing`.
|
|
137
137
|
4. **Do not adopt** - leave setup unresolved and block implementation
|
|
138
138
|
readiness.
|
|
139
139
|
|
|
@@ -7,7 +7,7 @@ disable-model-invocation: true
|
|
|
7
7
|
user-invocable: true
|
|
8
8
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
9
9
|
metadata:
|
|
10
|
-
version: 2.3.
|
|
10
|
+
version: 2.3.16
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Quick Start Project
|
|
@@ -659,9 +659,9 @@ show the full bundled recommendation and ask the user to select its owning
|
|
|
659
659
|
scope before running exactly one command:
|
|
660
660
|
|
|
661
661
|
```bash
|
|
662
|
-
oat config adopt dispatch-matrix --shared
|
|
663
|
-
oat config adopt dispatch-matrix --local
|
|
664
|
-
oat config adopt dispatch-matrix --user
|
|
662
|
+
oat config adopt dispatch-matrix --shared --keep-existing
|
|
663
|
+
oat config adopt dispatch-matrix --local --keep-existing
|
|
664
|
+
oat config adopt dispatch-matrix --user --keep-existing
|
|
665
665
|
```
|
|
666
666
|
|
|
667
667
|
The selected scope owns only the reusable ladders. A project-specific active
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"
|
|
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 (
|
|
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
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
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
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
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
|
-
|
|
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
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
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
|
-
|
|
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
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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, {
|
|
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);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
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.3.
|
|
37
|
+
"@open-agent-toolkit/control-plane": "0.3.7"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.0",
|