@open-agent-toolkit/cli 0.2.45 → 0.2.47

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.45"
3
+ "oatVersion": "0.2.47"
4
4
  }
@@ -92,6 +92,25 @@ still fail closed with the owning pack's install or update command. See
92
92
  [Writing Skills → Portable sibling reads](../contributing/skills.md#portable-sibling-reads-skills-and-agents)
93
93
  for the full contract.
94
94
 
95
+ Skills that read a fixed canonical workflows role use a different, local
96
+ `${AGENT_PROVIDER_ROOT}` binding. They try the loaded skill's provider root,
97
+ then `${HOME}/.agents`, then the repository's `.agents` root. The loaded tier
98
+ qualifies only when the exact unsuffixed `agents/<canonical-name>.md` target is
99
+ the same-scope canonical Markdown file or a symlink resolving exactly to it.
100
+ Copies, broken or escaping links, Cursor model/effort variants, and Codex TOML
101
+ roles are misses; resolution continues to the next tier.
102
+
103
+ That binding only locates canonical source instructions for the one owning
104
+ dependency. It does not select a provider, model, effort, variant, route, or
105
+ native agent. Resolve simultaneous pack dependencies independently. If every
106
+ workflows candidate misses, stop before fallback dispatch and report the
107
+ intended-scope recovery explicitly:
108
+
109
+ ```bash
110
+ oat tools install workflows --scope <user|project>
111
+ oat tools update --pack workflows --scope <user|project>
112
+ ```
113
+
95
114
  The packs remain independently installable. If the workflows adapter is
96
115
  present without the utility contracts, it fails closed and reports the missing
97
116
  dependency instead of inventing a fallback route. Non-project analytical
@@ -140,6 +159,12 @@ Two independent facts describe a pack:
140
159
  release manifest declares for that pack and scope, its presence, and its
141
160
  version or content digest.
142
161
 
162
+ Versioned skills and agents must match on both version metadata and canonical
163
+ content. A same-version content change is therefore reported as outdated rather
164
+ than current. Content comparison ignores the executable-bit normalization OAT
165
+ intentionally applies while materializing managed scripts, but still detects
166
+ file content, entry-type, and symlink-target changes.
167
+
143
168
  Commands report both. `oat tools list` and `oat tools info` show placement,
144
169
  intent source, and completeness. `oat status` and `oat doctor` report drift
145
170
  between intent and inventory with a scoped recovery command.
@@ -182,11 +207,12 @@ without qualification. Install the pack at **project scope** when you need its
182
207
  agents; `oat tools update` cannot repair this, because it is a scope limitation
183
208
  rather than drift.
184
209
 
185
- Repository templates under `.oat/templates/` are **owner overrides**. Once a
186
- project-scope template exists, OAT will not rewrite it: the managed default now
187
- lives at user scope and in the bundle. Delete the repository copy to resume
188
- managed-default behavior. `oat status` and `oat doctor` report retained
189
- overrides so the divergence is visible rather than silent.
210
+ Repository templates under `.oat/templates/` are **owner-owned seeds**. OAT
211
+ compares a source-backed seed with its bundled default: a byte-equivalent copy
212
+ is reported as current, while an edited copy is retained and reported as a
213
+ `retained-override`. OAT will not rewrite the retained copy. Delete a repository
214
+ template only when you intentionally want the bundled default seeded again;
215
+ never delete edited mutable seed content merely to clear the diagnostic.
190
216
 
191
217
  ### Evolving pack membership
192
218
 
@@ -454,8 +480,15 @@ Key behavior:
454
480
  - Every pack's fresh-install default is user scope (`defaultScope` in the release manifest); existing installs keep their current placement on re-install, so a re-install never moves a pack between scopes or creates a second copy at the other one. This applies to the per-pack subcommands too: a bare `oat tools install docs` in a repository where `docs` is already at project scope stays at project scope, and only an explicit `--scope` overrides that
455
481
  - Removing a pack from a scope happens only when you explicitly choose a narrower end-state in the interactive flow (e.g. a pack at `both` set to `project` only). All staged removals are shown in a single change summary and applied only after one batch confirmation — declining makes no changes
456
482
  - Non-interactive installs (including `--scope project`, `--scope user`, and the default pack set) are strictly additive and never remove a pack from a scope. Removal is interactive-only
457
- - Tracks installed vs bundled skill versions and reports outdated skills
483
+ - Tracks installed versus bundled skill and agent versions and canonical
484
+ content, reporting same-version content drift as outdated while ignoring
485
+ expected executable-bit normalization
458
486
  - Writes pack intent into the config file for the scope you installed into: a project install sets `tools.<pack>: true` in `.oat/config.json`, and a user install sets it in `~/.oat/config.json`. A user-only install never writes repository config
487
+ - When a project install discovers existing project-scoped packs whose intent
488
+ is missing, it writes those exact intents in canonical pack order. Human
489
+ output prints `Adopted project tool pack: <pack>` once per adopted pack;
490
+ JSON output adds `adoptedPacks` only when the list is non-empty. This is pack
491
+ intent reconciliation, not repository PJM adoption
459
492
  - A user-only install needs no Git repository and performs no repository writes
460
493
  - Refreshes the managed `OAT tools` section in the repository-root `AGENTS.md` **only for project-scope runs of the aggregate `oat tools install`**. The per-pack subcommands (`oat tools install workflows`, `oat tools install docs`, and the rest) never write `AGENTS.md`, at either scope
461
494
  - Repository `AGENTS.md` guidance for project management is owned by adoption, not by pack placement. Installing the `project-management` pack no longer upserts a managed `OAT project-management` section; `oat pjm init` writes that repository guidance when the repository actually adopts PJM
@@ -474,12 +507,17 @@ Key behavior:
474
507
 
475
508
  - Accepts a tool name, `--pack <pack>`, or `--all` (mutually exclusive)
476
509
  - With no target, exits without mutation and suggests the explicit bulk command `oat tools update --all`; invalid packs and conflicting targets keep their own targeted diagnostics
477
- - Compares installed versions against bundled versions and copies updated assets
510
+ - Compares installed versions and canonical content against bundled assets and
511
+ copies updates; equal version metadata does not hide content drift
478
512
  - For `--pack <pack>` and `--all`, an already-installed pack is reconciled to the **current** release membership in the scopes where it is installed, adding newly bundled skills, agents, templates, and scripts
479
513
  - A pack whose managed assets are all missing but whose intent is still declared is repaired from intent rather than skipped
480
514
  - Managed template and script companions are refreshed at **user** scope. A project-scope repository template is an owner override and is left alone
481
515
  - Non-versioned assets are compared by content digest, so an identical refresh is a no-op instead of a rewrite
482
516
  - Update persists inferred legacy intent only after a successful explicit mutation, so a read never rewrites your config
517
+ - A successful project-scope update reports the exact newly adopted legacy pack
518
+ intents in canonical order. Human output uses
519
+ `Adopted project tool pack: <pack>`; JSON output adds the optional
520
+ `adoptedPacks` array only when at least one intent was written
483
521
  - `--scope all` outside a Git repository completes the user-scope work instead of failing. Unlike `oat status` and `oat doctor`, update skips project scope silently and does not name it in the result; an explicitly requested `--scope project` outside a repository is still a hard failure
484
522
  - Dry-run mode with `--dry-run`; auto-sync after mutations by default
485
523
  - Use `--no-sync` to skip auto-sync
@@ -735,8 +773,9 @@ Removal and migration use the symmetric contract: the follow-up sync prunes exac
735
773
  User-scope tool packs and explicit PJM adoption changed several defaults and
736
774
  exit codes. Nothing here is data-destructive, and legacy config keeps working —
737
775
  `tools.<pack>: false` still parses, complete pre-adoption PJM scaffolds are
738
- grandfathered as `inferred-legacy`, and no CLI flag was removed or renamed. But
739
- several commands you already run behave differently.
776
+ grandfathered as `inferred-legacy`, and existing installs remain additive. One
777
+ inert per-pack install flag was removed, and several commands you already run
778
+ behave differently.
740
779
 
741
780
  ### Install scope defaults flipped to user
742
781
 
@@ -781,6 +820,26 @@ is not installed. Test for a truthy value instead. Legacy `false` values that
781
820
  already exist in a config file are still read (see
782
821
  [Legacy `false` intent](#legacy-false-intent)) — they are just never written.
783
822
 
823
+ Direct config writes now enforce the same true-or-absent contract.
824
+ `oat config set tools.<pack> false` exits `1` without changing the config. To
825
+ remove a project-scoped pack and clear its intent, run:
826
+
827
+ ```bash
828
+ oat tools remove --pack <pack> --scope project
829
+ ```
830
+
831
+ Existing legacy `false` values remain readable migration input.
832
+
833
+ ### Per-pack install `--force` was removed
834
+
835
+ `oat tools install <pack> --force` is now rejected as an unknown option. The
836
+ flag was inert in the unified additive lifecycle. To reconcile installed
837
+ assets, use the scoped update command instead:
838
+
839
+ ```bash
840
+ oat tools update --pack <pack> --scope <scope>
841
+ ```
842
+
784
843
  ### Per-pack install `--json` changed shape
785
844
 
786
845
  The per-pack subcommands (`oat tools install docs`, `oat tools install
@@ -803,6 +862,12 @@ above. The previous single-scope payload's `scope`, `targetRoot`, `assetsRoot`,
803
862
  keying on them reads `undefined` rather than failing. Read `scopes` for the
804
863
  scopes acted on, and `results[].request.scopeRoot` for the target root of each.
805
864
 
865
+ When a project-scope aggregate install, direct pack install, or update adopts
866
+ missing legacy pack intents, the same single payload also contains
867
+ `"adoptedPacks": ["docs", "workflows"]`. The field is omitted when nothing was
868
+ adopted, and entries follow the manifest's canonical pack order. Human output
869
+ reports the same set as one `Adopted project tool pack: <pack>` line per pack.
870
+
806
871
  ### Other behavior changes worth knowing
807
872
 
808
873
  - `oat tools remove --pack <pack>` deletes every managed asset the release
@@ -51,6 +51,37 @@ Probe each candidate for the exact target and use the first match. If none
51
51
  exists, name the missing sibling, give an actionable install or update command,
52
52
  and stop that workflow branch instead of improvising the sibling's process.
53
53
 
54
+ ### Skills bind canonical agent reads through a local provider root
55
+
56
+ When a skill must read one fixed canonical role instruction, bind a local
57
+ `${AGENT_PROVIDER_ROOT}` for that dependency in this order:
58
+
59
+ 1. Derive `${SKILL_DIR}/../..` from the loaded skill path, but admit it only
60
+ when the exact unsuffixed `agents/<canonical-name>.md` target is the
61
+ same-scope canonical Markdown file or a symlink whose real path is exactly
62
+ that file.
63
+ 2. Try the user-scope root at `${HOME}/.agents`.
64
+ 3. Fall back to the project-scope root at `<repo-root>/.agents`.
65
+
66
+ An invalid loaded target is a candidate miss, so resolution continues to the
67
+ user and project roots. Regular provider copies, broken or escaping symlinks,
68
+ transformed content, other role names, model/effort/variant-suffixed files, and
69
+ `.codex/agents/*.toml` are never canonical candidates. Claude and Cursor base
70
+ role symlinks can qualify when they resolve exactly to the same-scope canonical
71
+ file; Cursor materialized variants cannot.
72
+
73
+ `${AGENT_PROVIDER_ROOT}` is local authored-instruction notation, not a global
74
+ environment variable or a provider-native role selector. It has no authority
75
+ over provider, model, effort, variant, route, or dispatch choice. Resolve every
76
+ owning pack independently, even when multiple role dependencies coexist. If
77
+ all candidates miss for a workflows-owned role, stop before fallback launch
78
+ and report both recovery forms for the intended scope:
79
+
80
+ ```bash
81
+ oat tools install workflows --scope <user|project>
82
+ oat tools update --pack workflows --scope <user|project>
83
+ ```
84
+
54
85
  ### Materialized agents resolve in two steps
55
86
 
56
87
  Canonical agents are materialized into provider-specific views — Codex receives
@@ -88,21 +119,26 @@ dependency.
88
119
 
89
120
  ### The ratchet allows only exact historical baselines
90
121
 
91
- Do not use a bare `.agents/skills/<sibling>/SKILL.md`, `./.agents/...`, or
92
- `../.agents/...` path for an executable read in any user-default skill or
93
- agent. The bundled-docs contract test enforces this over the whole
94
- manifest-derived surface and reports each violation as exact
95
- `source -> target` evidence.
96
-
97
- The only exemption is a pinned historical baseline: non-executable evidence
98
- such as a dogfood transcript or a fixture README, recorded by exact source
99
- file, target skill, and target path. There is no wildcard, directory-wide, or
100
- skill-wide allowance, and no temporary migration allowlist — executable debt is
101
- fixed at the caller instead of being exempted. The same assertions run against
102
- the bundled CLI copies of both skills and agents, and the sync contract test
103
- re-checks the roles it materializes for Codex, so a canonical fix must survive
104
- bundling and Codex sync as well. No test yet gates the generated `.claude` or
105
- `.cursor` agent views, so regenerate and spot-check those by hand.
122
+ Do not use a bare `.agents/skills/<sibling>/SKILL.md`,
123
+ `.agents/agents/<canonical-name>.md`, dot-relative equivalent, or repeated-parent
124
+ canonical `agents/<canonical-name>.md` hop for an executable read in any
125
+ user-default skill or agent. The bundled-docs contract test enforces this over
126
+ the whole manifest-derived surface and reports each violation as exact
127
+ `source -> target` evidence. Executable agent findings have a zero baseline, so
128
+ every bare canonical-agent read fails the ratchet. Portable
129
+ `${AGENT_PROVIDER_ROOT}/agents/...` reads and legitimate `.claude` or `.cursor`
130
+ provider-view examples are classified as non-findings.
131
+
132
+ The pinned historical baseline applies only to skill findings: its six exact
133
+ entries are non-executable evidence such as dogfood transcripts or fixture
134
+ READMEs, recorded by source file, target skill, and target path. There is no
135
+ wildcard, directory-wide, or skill-wide allowance, and no temporary migration
136
+ allowlist — executable debt is fixed at the caller instead of being exempted.
137
+ The same assertions run against the bundled CLI copies of both skills and
138
+ agents, and the sync contract test re-checks the roles it materializes for
139
+ Codex, so a canonical fix must survive bundling and Codex sync as well. No test
140
+ yet gates the generated `.claude` or `.cursor` agent views, so regenerate and
141
+ spot-check those by hand.
106
142
 
107
143
  ## Contract components
108
144
 
@@ -77,8 +77,10 @@ Use [Instruction Sync](../provider-sync/instruction-sync.md) for the full strate
77
77
 
78
78
  - Run `oat init tools` to install/update bundled OAT tool packs.
79
79
  - In TTY mode, select which outdated skills to update when prompted.
80
- - In non-interactive mode, rerun the relevant pack subcommand with `--force` if you want to overwrite outdated installed skills.
81
- - For pack-level drift rather than a single skill, prefer the scoped command doctor prints: `oat tools update --pack <pack> --scope <scope>`.
80
+ - In non-interactive mode, run the scoped command doctor prints:
81
+ `oat tools update --pack <pack> --scope <scope>`.
82
+ - Per-pack install commands no longer accept the previously inert `--force`
83
+ option.
82
84
 
83
85
  ## `sync` reports an unsafe provider parent
84
86
 
@@ -147,18 +149,23 @@ Both commands report managed pack state with a scoped recovery command:
147
149
 
148
150
  - `partial` — some managed assets are missing, or intent is declared with none
149
151
  installed. Fix with `oat tools update --pack <pack> --scope <scope>`.
150
- - `stale` — installed assets are behind the bundled release. Same fix.
152
+ - `stale` — installed assets are behind the bundled release, or a managed skill
153
+ or agent has the bundled version metadata but different canonical content.
154
+ Expected executable-bit normalization on managed scripts is ignored. Fix with
155
+ the same scoped update command.
151
156
  - `newer` — installed assets are ahead of the bundle. This is informational and
152
157
  usually means the CLI is older than the assets; update the CLI rather than
153
158
  downgrading the pack.
154
- - `retained-override` — an owner-owned seeded asset exists at the scope, so the
155
- managed default is intentionally not applied there. This covers repository
156
- templates under `.oat/templates/` **and** seeded content such as
157
- `.oat/ideas/backlog.md` and `.oat/ideas/scratchpad.md`. Deleting the file is
158
- the right move only for a **template** you want OAT to manage again; never
159
- delete seeded content you have edited, because the next install or update
160
- reseeds the bundled default in its place and your edits are gone. The finding
161
- is informational and carries no recovery command for exactly that reason.
159
+ - `retained-override` — a source-backed owner-owned seed differs from its
160
+ bundled default, so OAT retains the edited copy instead of overwriting it. A
161
+ bundle-equal seed is current and does not produce this finding. Retained
162
+ overrides cover repository templates under `.oat/templates/` **and** seeded
163
+ content such as `.oat/ideas/backlog.md` and `.oat/ideas/scratchpad.md`.
164
+ Deleting the file is the right move only for a **template** you intentionally
165
+ want OAT to seed from the bundle again; never delete seeded content you have
166
+ edited, because the next install or update reseeds the bundled default in its
167
+ place and your edits are gone. The finding is informational and carries no
168
+ recovery command for exactly that reason.
162
169
  - `user-agent-unmaterialized` — the pack installed canonical agents into
163
170
  `~/.agents/agents/`, but user scope materializes no provider view for them
164
171
  beyond the bundled managed role files. `oat tools update` cannot fix this.
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.45",
3
- "docs-config": "0.2.45",
4
- "docs-theme": "0.2.45",
5
- "docs-transforms": "0.2.45"
2
+ "cli": "0.2.47",
3
+ "docs-config": "0.2.47",
4
+ "docs-theme": "0.2.47",
5
+ "docs-transforms": "0.2.47"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-implement
3
- version: 2.3.0
3
+ version: 2.3.1
4
4
  description: Use when plan.md is ready for execution. Dispatches one phase implementer per phase, owns independent phase review and bounded fix routing, and supports plan-declared worktree-isolated parallel phases.
5
5
  oat_gateable: true
6
6
  argument-hint: '[--retry-limit <N>] [--dry-run]'
@@ -13,6 +13,32 @@ canonical.
13
13
 
14
14
  ### Step 0.5: Capability Detection and Tier Selection
15
15
 
16
+ **Canonical fallback role instructions:** Before a fresh-child fallback can
17
+ read either workflows-owned role, independently resolve each exact target. For
18
+ `oat-phase-implementer`, bind the first valid root to
19
+ `${IMPLEMENTER_AGENT_PROVIDER_ROOT}`; for `oat-reviewer`, bind the first valid
20
+ root to `${REVIEWER_AGENT_PROVIDER_ROOT}`. For each role independently probe
21
+ candidates in this order: `${SKILL_DIR}/../..`, `${HOME}/.agents`, then
22
+ `<repo-root>/.agents`. Do not reuse one role's resolved root for the other.
23
+
24
+ Each loaded candidate is valid only when the exact unsuffixed role target is
25
+ the same-scope canonical file or a symlink whose realpath is exactly that
26
+ canonical file. Treat a missing, broken, escaping, copied, transformed,
27
+ suffixed, wrong-role, or otherwise noncanonical candidate as a miss and
28
+ continue to the next candidate. If either required role misses every candidate,
29
+ name that role, stop before the fresh-child fallback, and report
30
+ `oat tools install workflows --scope <user|project>` or
31
+ `oat tools update --pack workflows --scope <user|project>` for the intended
32
+ scope.
33
+
34
+ These canonical role instructions cannot change the immutable target,
35
+ provider, model, effort, or variant fields selected by the resolver. Native
36
+ dispatch sends the exact resolver-selected variant or `agent_type` first. A
37
+ fresh child is allowed only after an explicit pre-start native role-selection
38
+ rejection before any child starts. Once accepted, continue only through the existing
39
+ handle; terminal results, including `BLOCKED`, never authorize replacement or
40
+ fallback.
41
+
16
42
  **Mandatory target-first order:** Complete Dispatch Policy Preflight and
17
43
  resolve the concrete managed target before probing generic agent availability
18
44
  or locking Tier 1/Tier 2. A concrete target takes precedence over tier
@@ -22,9 +48,10 @@ native spawn API as native `agent_type`; spawn acceptance plus the constructed
22
48
  launcher payload is configured invocation evidence, and independent runtime
23
49
  telemetry or agent self-report is not required. Launch a fresh Codex child
24
50
  pinned to the resolver target's explicit model, reasoning effort, and
25
- canonical role instructions from `.agents/agents/oat-phase-implementer.md` or
26
- `.agents/agents/oat-reviewer.md` only after a native role-selection rejection
27
- as defined below.
51
+ canonical role instructions from
52
+ `${IMPLEMENTER_AGENT_PROVIDER_ROOT}/agents/oat-phase-implementer.md` or
53
+ `${REVIEWER_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md` only after a native
54
+ role-selection rejection as defined below.
28
55
  If that fresh child cannot be launched, fail closed and block; never
29
56
  substitute a base or coordinator role for a managed phase target. Inline
30
57
  execution is allowed only with verified equivalent current-host model and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-plan-writing
3
- version: 1.2.19
3
+ version: 1.2.20
4
4
  description: Use when authoring or mutating plan.md in any OAT workflow. Defines canonical format invariants — stable task IDs, required sections, review table rules, and resume guardrails.
5
5
  disable-model-invocation: true
6
6
  user-invocable: false
@@ -197,6 +197,25 @@ for an exception. A `## Dispatch Profile` row alone cannot authorize reviewer
197
197
  lowering; only a separate reviewed contract may define a bounded lower
198
198
  candidate exception.
199
199
 
200
+ Before the artifact-review exception can read canonical reviewer instructions,
201
+ resolve the workflows-owned role locally. Probe candidates in this order:
202
+ `${SKILL_DIR}/../..`, `${HOME}/.agents`, then `<repo-root>/.agents`. The loaded
203
+ candidate is valid only when the exact unsuffixed `agents/oat-reviewer.md` is
204
+ the same-scope canonical file or a symlink whose realpath is exactly that
205
+ canonical file. Treat a missing, broken, escaping, copied, transformed,
206
+ suffixed, or otherwise noncanonical candidate as a miss and continue to the
207
+ next candidate. Bind the first valid root to
208
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}`; never use ambient discovery.
209
+
210
+ If every candidate misses, name `oat-reviewer`, stop before the artifact-review
211
+ fresh-child fallback dispatch, and report
212
+ `oat tools install workflows --scope <user|project>` or
213
+ `oat tools update --pack workflows --scope <user|project>` for the intended
214
+ scope. Canonical role instructions cannot change the immutable target,
215
+ provider, model, effort, or variant fields selected by the resolver. The exact
216
+ registered native reviewer variant remains first; only an explicit pre-start
217
+ native role-selection rejection before a child starts unlocks the fresh child.
218
+
200
219
  For the exception route, bind every concrete managed reviewer target to the
201
220
  actual provider invocation before probing generic reviewer availability or
202
221
  selecting execution mechanics. A concrete managed Codex target takes precedence
@@ -207,10 +226,11 @@ over generic tier availability.
207
226
  reviewer variant as native `agent_type`. Only a recorded actual pre-start
208
227
  native role-selection rejection permits a fresh Codex child with the resolver
209
228
  target's explicit model, reasoning effort, and canonical role instructions
210
- from `.agents/agents/oat-reviewer.md`. A separately pre-selected CLI route is
211
- allowed only when native dispatch cannot express the complete target and no
212
- child has started. If another route cannot preserve the target, use only a
213
- verified-equivalent inline route or block the review.
229
+ from `${WORKFLOWS_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md`. A separately
230
+ pre-selected CLI route is allowed only when native dispatch cannot express
231
+ the complete target and no child has started. If another route cannot
232
+ preserve the target, use only a verified-equivalent inline route or block the
233
+ review.
214
234
  - Claude: require a non-empty `providers.claude.dispatchArgs.model` and put
215
235
  that exact value in the actual provider invocation as its `model` argument.
216
236
  - Cursor: require a non-empty `providers.cursor.dispatchArgs.variant` and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-review-provide
3
- version: 1.5.1
3
+ version: 1.5.2
4
4
  description: Use when the user explicitly asks to review an OAT project — e.g. "review project", "review the project", "run project review", or confirms a previously offered review. Do NOT auto-invoke on completed work alone. Resolves a project review scope and offers before running.
5
5
  disable-model-invocation: false
6
6
  user-invocable: true
@@ -624,6 +624,26 @@ Build the "Review Scope" metadata for the reviewer:
624
624
 
625
625
  ### Step 6: Execute Review (3-Tier Capability Model)
626
626
 
627
+ **Canonical reviewer instructions:** Before a direct reviewer-definition read or
628
+ fresh-child fallback, resolve the workflows-owned role locally. Probe candidates
629
+ in this order: `${SKILL_DIR}/../..`, `${HOME}/.agents`, then
630
+ `<repo-root>/.agents`. The loaded candidate is valid only when the exact
631
+ unsuffixed `agents/oat-reviewer.md` is the same-scope canonical file or a
632
+ symlink whose realpath is exactly that canonical file. Treat a missing, broken,
633
+ escaping, copied, transformed, suffixed, or otherwise noncanonical candidate as
634
+ a miss and continue to the next candidate. Bind the first valid root to
635
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}`; never use ambient discovery.
636
+
637
+ If every candidate misses, name `oat-reviewer`, stop before launching the
638
+ fresh-child fallback, and report
639
+ `oat tools install workflows --scope <user|project>` or
640
+ `oat tools update --pack workflows --scope <user|project>` for the intended
641
+ scope. Canonical role instructions cannot change the immutable target,
642
+ provider, model, effort, or variant fields selected by the resolver. Native
643
+ dispatch with the exact resolver-selected role remains first. Only an explicit
644
+ pre-start native role-selection rejection before a reviewer starts unlocks a
645
+ fresh child that preserves those fields.
646
+
627
647
  **Step 6.0: Resolve the managed reviewer target**
628
648
 
629
649
  Before capability-tier selection, resolve the same reviewer contract used by
@@ -669,7 +689,8 @@ Build the actual provider invocation before reporting the target as enforced:
669
689
  explicit host rejection of that exact `agent_type` before any reviewer or
670
690
  child starts. Only after that pre-start rejection may the workflow launch a
671
691
  fresh Codex child with the resolver target's explicit model, reasoning
672
- effort, canonical role instructions from `.agents/agents/oat-reviewer.md`,
692
+ effort, canonical role instructions from
693
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md`,
673
694
  and the same Review Scope payload. If neither exact route is available, use
674
695
  only a verified-equivalent inline route or block the review.
675
696
  - Claude requires a non-empty `providers.claude.dispatchArgs.model`; the actual
@@ -912,7 +933,8 @@ If running inline (Tier 3), execute the review and write artifact.
912
933
  6. For final scope: explicitly disposition deferred Medium ledger items (fix now vs accept defer)
913
934
  7. Write artifact with file:line references and fix guidance
914
935
 
915
- **Review artifact template:** (see `.agents/agents/oat-reviewer.md` for full format)
936
+ **Review artifact template:** (see
937
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md` for full format)
916
938
 
917
939
  Shared ad-hoc companion reference (non-project mode): the `oat-review-provide`
918
940
  review artifact template. Independently probe each required `<name>/SKILL.md`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-review-provide-remote
3
- version: 1.1.0
3
+ version: 1.1.1
4
4
  description: Use when reviewing a GitHub PR opened on another machine for an active OAT project and posting findings back as a single PR review. Resolves the project from the PR diff, reads project artifacts for mode-aware review, and posts via gh api.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -116,7 +116,31 @@ Severity conventions:
116
116
  - `medium`: Meaningful but non-blocking quality/maintainability issue.
117
117
  - `minor`: Cosmetic/style/documentation issue.
118
118
 
119
- `file` and `line` are both set (inline finding) or both `null` (reviewer-level finding that lands in the top-level body). Checklist + severity model + the `StructuredFindings` schema source of truth: `.agents/agents/oat-reviewer.md` and `design.md` → Data Models → StructuredFindings.
119
+ Before reading the canonical reviewer definition or starting a fresh-child
120
+ fallback, resolve the workflows-owned role locally. Probe candidates in this
121
+ order: `${SKILL_DIR}/../..`, `${HOME}/.agents`, then `<repo-root>/.agents`.
122
+ The loaded candidate is valid only when the exact unsuffixed
123
+ `agents/oat-reviewer.md` is the same-scope canonical file or a symlink whose
124
+ realpath is exactly that canonical file. Treat a missing, broken, escaping,
125
+ copied, transformed, suffixed, or otherwise noncanonical candidate as a miss
126
+ and continue to the next candidate. Bind the first valid root to
127
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}`; never use ambient discovery.
128
+
129
+ If every candidate misses, name `oat-reviewer`, stop before starting the
130
+ fresh-child fallback, and report
131
+ `oat tools install workflows --scope <user|project>` or
132
+ `oat tools update --pack workflows --scope <user|project>` for the intended
133
+ scope. Canonical role instructions cannot change the immutable target,
134
+ provider, model, effort, or variant fields selected by the resolver. Native
135
+ dispatch with the exact resolver-selected role remains first. Only an explicit
136
+ pre-start native role-selection rejection before a reviewer starts unlocks a
137
+ fresh child that preserves those fields.
138
+
139
+ `file` and `line` are both set (inline finding) or both `null` (reviewer-level
140
+ finding that lands in the top-level body). Checklist + severity model + the
141
+ `StructuredFindings` schema source of truth:
142
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md` and `design.md` → Data
143
+ Models → StructuredFindings.
120
144
 
121
145
  ## Process
122
146
 
@@ -312,7 +336,10 @@ Detection:
312
336
 
313
337
  Build the dispatch payload and spawn the reviewer in structured-output mode. This mirrors the tested wrapper at `packages/cli/src/review-remote/reviewer-dispatch.ts` (`buildDispatchPayload` / `dispatchStructuredReview`):
314
338
 
315
- - Set `oat_output_mode: structured` in the dispatch payload (the flag `.agents/agents/oat-reviewer.md` recognizes). In this mode the reviewer returns a `StructuredFindings` object in-memory and writes NO artifact under `reviews/`.
339
+ - Set `oat_output_mode: structured` in the dispatch payload (the flag
340
+ `${WORKFLOWS_AGENT_PROVIDER_ROOT}/agents/oat-reviewer.md` recognizes). In
341
+ this mode the reviewer returns a `StructuredFindings` object in-memory and
342
+ writes NO artifact under `reviews/`.
316
343
  - Include the project context (`oat_project`, `oat_review_scope`, `oat_review_head_sha`), the Review Scope metadata block, a pointer to the posted-review-body schema (`design.md` → Data Models → Posted-review-body), and the resolved narrowing range (`<prior_sha>..<HEAD>` or none).
317
344
  - If a worktree was resolved in Step 2, include its path so the reviewer reads from the checkout.
318
345
  - For Cursor concrete managed dispatch, invoke
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAmBzC,OAAO,EAML,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAgBhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0GpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kCAAkC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7E,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,mCAAmC,EAAE,OAAO,mCAAmC,CAAC;IAChF,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAgkFD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsKT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAmBzC,OAAO,EAML,KAAK,SAAS,EACd,KAAK,cAAc,EAGnB,KAAK,UAAU,EAgBhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,mCAAmC,EACnC,0BAA0B,EAC3B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0GpC,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kCAAkC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7E,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,EAAE,CAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7C,mCAAmC,EAAE,OAAO,mCAAmC,CAAC;IAChF,0BAA0B,EAAE,OAAO,0BAA0B,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAqkFD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAsKT"}
@@ -1701,8 +1701,11 @@ async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, d
1701
1701
  }
1702
1702
  if (key.startsWith('tools.')) {
1703
1703
  const packName = key.slice('tools.'.length);
1704
+ if (rawValue.trim().toLowerCase() !== 'true') {
1705
+ throw new Error(`Pack intent '${key}' can only be declared with true. To remove the pack and clear its intent, run: oat tools remove --pack ${packName} --scope project`);
1706
+ }
1704
1707
  const tools = { ...config.tools };
1705
- tools[packName] = rawValue.trim().toLowerCase() === 'true';
1708
+ tools[packName] = true;
1706
1709
  await dependencies.writeOatConfig(repoRoot, {
1707
1710
  ...config,
1708
1711
  tools,
@@ -60,6 +60,7 @@ export interface InitToolsDependencies {
60
60
  interface InitToolsRunMetadata {
61
61
  affectedScopes: ConcreteScope[];
62
62
  appliedScopes: ConcreteScope[];
63
+ adoptedPacks: ToolPack[];
63
64
  }
64
65
  interface PackScopeChange {
65
66
  pack: ToolPack;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/init/tools/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/init/tools/index.ts"],"names":[],"mappings":"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"}
@@ -411,15 +411,19 @@ function buildPackEndStateChoices(pack, currentLocation, defaultEndState) {
411
411
  const rest = annotated.filter((choice) => choice.value !== defaultEndState);
412
412
  return defaultChoice ? [defaultChoice, ...rest] : annotated;
413
413
  }
414
- function reportSuccess(context, packs, syncScopes) {
414
+ function reportSuccess(context, packs, syncScopes, adoptedPacks) {
415
415
  if (context.json) {
416
416
  context.logger.json({
417
417
  status: 'ok',
418
418
  installedPacks: packs,
419
419
  syncScopes,
420
+ ...(adoptedPacks.length > 0 ? { adoptedPacks } : {}),
420
421
  });
421
422
  return;
422
423
  }
424
+ for (const pack of adoptedPacks) {
425
+ context.logger.info(`Adopted project tool pack: ${pack}`);
426
+ }
423
427
  context.logger.info(`Installed tool packs: ${packs.map(({ pack, scope }) => `${pack} (${formatInstalledLocation(scope)})`).join(', ')}`);
424
428
  syncScopes.forEach((scope, index) => {
425
429
  context.logger.info(`${index === 0 ? 'Run' : 'Also run'}: oat sync --scope ${scope}`);
@@ -515,7 +519,11 @@ export async function runInitTools(context, dependencies) {
515
519
  selectedPacks.push('project-management');
516
520
  }
517
521
  if (selectedPacks.length === 0) {
518
- lastRunInitToolsMetadata = { affectedScopes: [], appliedScopes: [] };
522
+ lastRunInitToolsMetadata = {
523
+ affectedScopes: [],
524
+ appliedScopes: [],
525
+ adoptedPacks: [],
526
+ };
519
527
  if (!context.json) {
520
528
  context.logger.info('No tool packs selected.');
521
529
  }
@@ -838,11 +846,19 @@ export async function runInitTools(context, dependencies) {
838
846
  const appliedScopes = [
839
847
  ...new Set(packScopeInfo.flatMap(({ scope }) => scopesForEndState(scope))),
840
848
  ];
849
+ const adoptedPacks = projectRoot && appliedScopes.includes('project')
850
+ ? (await reconcileProjectToolsConfig({
851
+ repoRoot: projectRoot,
852
+ cwd: context.cwd,
853
+ home: context.home,
854
+ }, dependencies)).adoptedPacks
855
+ : [];
841
856
  lastRunInitToolsMetadata = {
842
857
  affectedScopes: affectedScopesList,
843
858
  appliedScopes,
859
+ adoptedPacks,
844
860
  };
845
- reportSuccess(context, packScopeInfo, affectedScopesList);
861
+ reportSuccess(context, packScopeInfo, affectedScopesList, adoptedPacks);
846
862
  process.exitCode = 0;
847
863
  return selectedPacks;
848
864
  }
@@ -912,7 +928,7 @@ function createReconciledPackCommand(pack, dependencies) {
912
928
  const base = new Command(pack).description(descriptions[pack]);
913
929
  const packCommand = pack === 'core' ? base : withScopeOption(base);
914
930
  return packCommand
915
- .option('--force', 'Reconcile managed assets to bundled content')
931
+ .allowUnknownOption(false)
916
932
  .action(async (_options, command) => {
917
933
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
918
934
  try {
@@ -946,15 +962,26 @@ function createReconciledPackCommand(pack, dependencies) {
946
962
  // Project-scope placement installs capability only. The
947
963
  // project-management and decisions AGENTS sections are written by the
948
964
  // explicit adoption action (`oat pjm init`), never by pack placement.
965
+ const adoptedPacks = scopes.includes('project')
966
+ ? (await reconcileProjectToolsConfig({
967
+ repoRoot: await dependencies.resolveProjectRoot(context.cwd),
968
+ cwd: context.cwd,
969
+ home: context.home,
970
+ }, dependencies)).adoptedPacks
971
+ : [];
949
972
  if (context.json) {
950
973
  context.logger.json({
951
974
  status: 'ok',
952
975
  pack,
953
976
  scopes,
954
977
  results,
978
+ ...(adoptedPacks.length > 0 ? { adoptedPacks } : {}),
955
979
  });
956
980
  }
957
981
  else {
982
+ for (const adoptedPack of adoptedPacks) {
983
+ context.logger.info(`Adopted project tool pack: ${adoptedPack}`);
984
+ }
958
985
  context.logger.info(`Installed ${pack} tool pack.`);
959
986
  for (const result of results) {
960
987
  context.logger.info(`Scope: ${result.request.scope}`);
@@ -1045,10 +1072,12 @@ export function createInitToolsCommand(overrides = {}) {
1045
1072
  scanTools: dependencies.scanTools,
1046
1073
  }),
1047
1074
  ];
1048
- for (const packCommand of packCommands) {
1049
- packCommand.hook('postAction', async (_thisCommand, actionCommand) => {
1050
- await reconcileAfterInstall(actionCommand);
1051
- });
1075
+ if (!dependencies.reconcilePacks) {
1076
+ for (const packCommand of packCommands) {
1077
+ packCommand.hook('postAction', async (_thisCommand, actionCommand) => {
1078
+ await reconcileAfterInstall(actionCommand);
1079
+ });
1080
+ }
1052
1081
  }
1053
1082
  const command = new Command('tools').description('Install OAT tool packs (core, ideas, docs, workflows, utility, project-management, research, brainstorm)');
1054
1083
  for (const packCommand of packCommands) {
@@ -1059,7 +1088,6 @@ export function createInitToolsCommand(overrides = {}) {
1059
1088
  const selectedPacks = await runInitTools(context, dependencies);
1060
1089
  appliedScopesByCommand.set(actionCommand, lastRunInitToolsMetadata?.appliedScopes ?? []);
1061
1090
  setInstalledCanonicalPaths(actionCommand, canonicalPathsForPacks(selectedPacks));
1062
- await reconcileAfterInstall(actionCommand);
1063
1091
  });
1064
1092
  return command;
1065
1093
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pack-inventory.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/pack-inventory.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AAIvB,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EACA,uBAAuB,GACvB,iBAAiB,GACjB,0BAA0B,GAC1B,2BAA2B,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoLD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAmC9B;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAUT;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,aAAa,CAAC,CA0DxB"}
1
+ {"version":3,"file":"pack-inventory.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/pack-inventory.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AAIvB,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,mBAAmB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EACA,uBAAuB,GACvB,iBAAiB,GACjB,0BAA0B,GAC1B,2BAA2B,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC;IACvD,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA8QD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAmC9B;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAUT;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,aAAa,CAAC,CA0DxB"}
@@ -1,9 +1,9 @@
1
- import { lstat } from 'node:fs/promises';
1
+ import { lstat, readdir, readlink } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { compareVersions } from '../../init/tools/shared/version.js';
4
4
  import { getAgentVersion, getSkillVersion } from '../../shared/frontmatter.js';
5
5
  import { readOatConfig } from '../../../config/oat-config.js';
6
- import { resolveManagedScopeRoots, validateManagedPath, } from '../../../fs/paths.js';
6
+ import { resolveManagedScopeRoots, validateManagedPath, validateRealPathWithinScope, } from '../../../fs/paths.js';
7
7
  import { USER_SCOPE_MANAGED_AGENT_FILES, } from '../../../shared/types.js';
8
8
  import { digestDirectory, digestFile } from './content-digest.js';
9
9
  import { getPackDefinition } from './pack-manifest.js';
@@ -29,14 +29,62 @@ async function inventoryVersionedAsset(definition, installedPath, bundledPath) {
29
29
  readVersion(installedPath),
30
30
  readVersion(bundledPath),
31
31
  ]);
32
+ const versionStatus = compareVersions(installedVersion, bundledVersion);
33
+ const contentMatches = versionStatus !== 'current'
34
+ ? null
35
+ : definition.kind === 'skill'
36
+ ? await canonicalDirectoryMatches(installedPath, bundledPath)
37
+ : await canonicalFileMatches(installedPath, bundledPath);
32
38
  return {
33
39
  definition,
34
40
  path: installedPath,
35
- status: compareVersions(installedVersion, bundledVersion),
41
+ status: versionStatus === 'current' && !contentMatches
42
+ ? 'outdated'
43
+ : versionStatus,
36
44
  installedVersion,
37
45
  bundledVersion,
38
46
  };
39
47
  }
48
+ async function canonicalFileMatches(installedPath, bundledPath) {
49
+ const [installedDigest, bundledDigest] = await Promise.all([
50
+ digestFile(installedPath, 0o644),
51
+ digestFile(bundledPath, 0o644),
52
+ ]);
53
+ return installedDigest === bundledDigest;
54
+ }
55
+ async function canonicalDirectoryMatches(installedRoot, bundledRoot) {
56
+ const entries = await readdir(bundledRoot, { withFileTypes: true });
57
+ for (const entry of entries) {
58
+ const installedPath = join(installedRoot, entry.name);
59
+ const bundledPath = join(bundledRoot, entry.name);
60
+ if (!(await pathExists(installedPath)))
61
+ return false;
62
+ const installedMetadata = await lstat(installedPath);
63
+ if (entry.isDirectory()) {
64
+ if (!installedMetadata.isDirectory() ||
65
+ !(await canonicalDirectoryMatches(installedPath, bundledPath))) {
66
+ return false;
67
+ }
68
+ continue;
69
+ }
70
+ if (entry.isFile()) {
71
+ if (!installedMetadata.isFile() ||
72
+ !(await canonicalFileMatches(installedPath, bundledPath))) {
73
+ return false;
74
+ }
75
+ continue;
76
+ }
77
+ if (entry.isSymbolicLink()) {
78
+ if (!installedMetadata.isSymbolicLink() ||
79
+ (await readlink(installedPath)) !== (await readlink(bundledPath))) {
80
+ return false;
81
+ }
82
+ continue;
83
+ }
84
+ throw new Error(`Unsupported filesystem entry in pack asset: ${bundledPath}`);
85
+ }
86
+ return true;
87
+ }
40
88
  async function inventoryStaticAsset(definition, installedPath, bundledPath) {
41
89
  const [installedDigest, bundledDigest] = definition.kind === 'directory'
42
90
  ? await Promise.all([
@@ -72,28 +120,40 @@ async function inventoryAsset(definition, scope, scopeRoot, assetsRoot, managedR
72
120
  };
73
121
  }
74
122
  if (definition.ownership[scope] === 'seed-if-missing') {
75
- if (definition.generation === 'projects-config-default') {
76
- const config = await readOatConfig(scopeRoot);
123
+ if (definition.generation) {
124
+ if (definition.generation === 'projects-config-default') {
125
+ const config = await readOatConfig(scopeRoot);
126
+ return {
127
+ definition,
128
+ path: installedPath,
129
+ status: config.projects?.root?.trim() ? 'present' : 'outdated',
130
+ installedVersion: null,
131
+ bundledVersion: null,
132
+ };
133
+ }
77
134
  return {
78
135
  definition,
79
136
  path: installedPath,
80
- status: config.projects?.root?.trim() ? 'present' : 'outdated',
137
+ status: 'present',
81
138
  installedVersion: null,
82
139
  bundledVersion: null,
83
140
  };
84
141
  }
142
+ if (!definition.source) {
143
+ throw new Error(`Seeded pack asset ${definition.id} has no materialized source`);
144
+ }
145
+ const { realPath: bundledPath } = await validateRealPathWithinScope(join(assetsRoot, definition.source), assetsRoot);
146
+ const inventory = await inventoryStaticAsset(definition, realPath, bundledPath);
85
147
  return {
86
- definition,
148
+ ...inventory,
87
149
  path: installedPath,
88
- status: 'present',
89
- installedVersion: null,
90
- bundledVersion: null,
150
+ status: inventory.status === 'current' ? 'current' : 'present',
91
151
  };
92
152
  }
93
153
  if (!definition.source) {
94
154
  throw new Error(`Managed pack asset ${definition.id} has no materialized source`);
95
155
  }
96
- const bundledPath = join(assetsRoot, definition.source);
156
+ const { realPath: bundledPath } = await validateRealPathWithinScope(join(assetsRoot, definition.source), assetsRoot);
97
157
  if (definition.kind === 'skill' || definition.kind === 'agent') {
98
158
  const inventory = await inventoryVersionedAsset(definition, realPath, bundledPath);
99
159
  return { ...inventory, path: installedPath };
@@ -1,6 +1,6 @@
1
1
  import { type OatConfig } from '../../../config/oat-config.js';
2
2
  import { type ScanToolsOptions } from './scan-tools.js';
3
- import type { ToolInfo } from './types.js';
3
+ import type { PackName, ToolInfo } from './types.js';
4
4
  export interface ReconcileProjectToolsOptions {
5
5
  repoRoot: string;
6
6
  cwd: string;
@@ -12,5 +12,9 @@ export interface ProjectToolsConfigDependencies {
12
12
  readOatConfig: (repoRoot: string) => Promise<OatConfig>;
13
13
  writeOatConfig: (repoRoot: string, config: OatConfig) => Promise<void>;
14
14
  }
15
- export declare function reconcileProjectToolsConfig(options: ReconcileProjectToolsOptions, dependencies?: ProjectToolsConfigDependencies): Promise<'written' | 'unchanged'>;
15
+ export interface ReconcileProjectToolsResult {
16
+ action: 'written' | 'unchanged';
17
+ adoptedPacks: PackName[];
18
+ }
19
+ export declare function reconcileProjectToolsConfig(options: ReconcileProjectToolsOptions, dependencies?: ProjectToolsConfigDependencies): Promise<ReconcileProjectToolsResult>;
16
20
  //# sourceMappingURL=project-tools-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-tools-config.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/project-tools-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,8BAA8B;IAC7C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AASD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,EACrC,YAAY,GAAE,8BAAoD,GACjE,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CA2BlC"}
1
+ {"version":3,"file":"project-tools-config.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/project-tools-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,8BAA8B;IAC7C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,YAAY,EAAE,QAAQ,EAAE,CAAC;CAC1B;AASD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,EACrC,YAAY,GAAE,8BAAoD,GACjE,OAAO,CAAC,2BAA2B,CAAC,CA6BtC"}
@@ -1,5 +1,6 @@
1
1
  import { readOatConfig, writeOatConfig, } from '../../../config/oat-config.js';
2
2
  import { resolveAssetsRoot } from '../../../fs/assets.js';
3
+ import { PACK_NAMES } from './pack-manifest.js';
3
4
  import { scanTools } from './scan-tools.js';
4
5
  const defaultDependencies = {
5
6
  resolveAssetsRoot,
@@ -16,18 +17,19 @@ export async function reconcileProjectToolsConfig(options, dependencies = defaul
16
17
  });
17
18
  const config = await dependencies.readOatConfig(options.repoRoot);
18
19
  const tools = { ...config.tools };
19
- let changed = false;
20
+ const adopted = new Set();
20
21
  for (const tool of projectTools) {
21
22
  if (tool.scope === 'project' &&
22
23
  tool.pack !== 'custom' &&
23
24
  tools[tool.pack] !== true) {
24
25
  tools[tool.pack] = true;
25
- changed = true;
26
+ adopted.add(tool.pack);
26
27
  }
27
28
  }
28
- if (!changed) {
29
- return 'unchanged';
29
+ const adoptedPacks = PACK_NAMES.filter((pack) => adopted.has(pack));
30
+ if (adoptedPacks.length === 0) {
31
+ return { action: 'unchanged', adoptedPacks };
30
32
  }
31
33
  await dependencies.writeOatConfig(options.repoRoot, { ...config, tools });
32
- return 'written';
34
+ return { action: 'written', adoptedPacks };
33
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/update/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAK1C,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAKvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AAmBxB,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GAClD,MAAM,EAAE,CAaV;AAgCD,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CA6LT;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAS7E;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,GACnB,OAAO,CAOT;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GACd,MAAM,CAMR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/update/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAK1C,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAKvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AAmBxB,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GAClD,MAAM,EAAE,CAaV;AAgCD,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CA8MT;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAS7E;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,GACnB,OAAO,CAOT;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GACd,MAAM,CAMR"}
@@ -130,11 +130,12 @@ export function createToolsUpdateCommand(dependencies = defaultDependencies, syn
130
130
  const changedProjectScope = [...result.updated, ...result.current, ...result.newer].some(({ scope }) => scope === 'project') ||
131
131
  result.assetRefreshes.some(({ scope }) => scope === 'project') ||
132
132
  result.plans.some(({ scope }) => scope === 'project');
133
+ let adoptedPacks = [];
133
134
  if (assetsRoot &&
134
135
  result.notInstalled.length === 0 &&
135
136
  changedProjectScope) {
136
137
  const repoRoot = await resolveProjectRoot(context.cwd);
137
- await reconcileProjectToolsConfig({
138
+ adoptedPacks = (await reconcileProjectToolsConfig({
138
139
  repoRoot,
139
140
  cwd: context.cwd,
140
141
  home: context.home,
@@ -143,11 +144,16 @@ export function createToolsUpdateCommand(dependencies = defaultDependencies, syn
143
144
  scanTools: dependencies.scanTools,
144
145
  readOatConfig,
145
146
  writeOatConfig,
146
- });
147
+ })).adoptedPacks;
147
148
  }
148
149
  if (result.notInstalled.length > 0) {
149
150
  if (context.json) {
150
- logger.json({ target: describeTarget(target), dryRun, result });
151
+ logger.json({
152
+ target: describeTarget(target),
153
+ dryRun,
154
+ result,
155
+ ...(adoptedPacks.length > 0 ? { adoptedPacks } : {}),
156
+ });
151
157
  }
152
158
  else {
153
159
  logger.error(`Tool '${result.notInstalled[0]}' not found.`);
@@ -170,9 +176,17 @@ export function createToolsUpdateCommand(dependencies = defaultDependencies, syn
170
176
  }
171
177
  }
172
178
  if (context.json) {
173
- logger.json({ target: describeTarget(target), dryRun, result });
179
+ logger.json({
180
+ target: describeTarget(target),
181
+ dryRun,
182
+ result,
183
+ ...(adoptedPacks.length > 0 ? { adoptedPacks } : {}),
184
+ });
174
185
  return;
175
186
  }
187
+ for (const pack of adoptedPacks) {
188
+ logger.info(`Adopted project tool pack: ${pack}`);
189
+ }
176
190
  if (result.updated.length > 0) {
177
191
  for (const tool of result.updated) {
178
192
  logger.success(formatUpdatedToolMessage(tool, dryRun));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.2.45",
3
+ "version": "0.2.47",
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.45"
37
+ "@open-agent-toolkit/control-plane": "0.2.47"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.0",