@execuro-sw-ecosystem/sw-ecosystem-agentic-harness 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,93 @@ release.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.8] - 2026-09-19
11
+
12
+ ### Changed
13
+
14
+ - **The lock file moved to `var/sw-ai-sdk/harness.lock.json`, and the
15
+ `.gitignore` line is gone with it.** A Shopware project ignores the whole of
16
+ `var/` through the `shopware/core` Flex recipe (`/var/*`, with a single
17
+ `!/var/.htaccess` negation) and already keeps its machine-local state there
18
+ — `var/cache`, `var/log` — so the installer no longer creates a directory in
19
+ the repository root and no longer writes to `.gitignore` at all. A root with
20
+ no `var/` (`--scope user` under $HOME, or a checkout that is not a Shopware
21
+ project) keeps `.sw-ai-sdk/` and its managed line, unchanged. Nothing here
22
+ reads a path outside the install root, on any platform.
23
+ **Migration is automatic and lossless:** a lock still at the old path is
24
+ read, rewritten to the new one, and the old file, its directory and the
25
+ managed `.gitignore` block are removed. Declined rules, recorded agents and
26
+ file hashes all survive, so the first run after upgrading reinstalls nothing
27
+ — it reports `migrated[]` in `--json` and one line in the human summary.
28
+ `lock_file` in every result body now carries the resolved path; anything
29
+ that hard-coded `.sw-ai-sdk/` should read that key instead.
30
+
31
+ ### Removed
32
+
33
+ - **BREAKING: the "extra component" mechanism is gone.** The CLI no longer
34
+ detects, installs, updates or removes the two optional visual editors
35
+ (Specs Editor, Tender Discovery Tool); each package installs its own skill,
36
+ orchestrated by the `sw-setup` skill. Removed with it: the
37
+ `extra_components[]` key from `status --json`, the `--no-extra-components`
38
+ flag on `install`/`plan`/`apply`, the `skipped` field from `plan`'s and
39
+ `apply`'s `summary` (nothing else could produce that state), the
40
+ `skill-copy` action kind, and the "Optional extra components" section of
41
+ `guide`. Anything reading `extra_components[]` or counting `summary.skipped`
42
+ must stop.
43
+ **Why:** the mechanism had never once worked. It spawned `npx --no-install
44
+ <pkg>@<pin> install-skill --print` and required stdout to begin with `---`,
45
+ but both editors document a `source:`/`next_step:` preamble before the skill
46
+ document, so the check could never pass and neither skill was ever installed.
47
+ `--no-install` also suppresses installing but not resolving, so every
48
+ `status`, `plan` and `apply` issued a real request to the npm registry —
49
+ `status` was never offline-safe, contrary to what the module claimed.
50
+ - The two editors are now invoked as `@latest` everywhere, including in the
51
+ `allowed-tools` permission grants of `sw-design-requirements`,
52
+ `sw-design-solution` and `sw-discover-tender`, which still named an exact
53
+ version and would therefore have denied the calls. The `@latest` check now
54
+ guards `allowed-tools` lines as well as prose.
55
+
56
+ ### Added
57
+
58
+ - `status --json` reports `skills_dir` per agent — the directory that agent
59
+ actually reads skills from, and the `--target` `sw-setup` hands to an
60
+ editor package's own `install-skill`/`uninstall-skill`.
61
+
62
+ ## [0.1.7] - 2026-09-19
63
+
64
+ ### Changed
65
+
66
+ - **BREAKING: `install`, `status`, `plan` and `uninstall` print a human
67
+ summary, not JSON.** Typing `install` and getting several hundred lines of
68
+ JSON made success unreadable; the result object is now rendered for a
69
+ person on stdout — what changed, grouped by coding agent, and the restart
70
+ each one needs. A run with nothing to do is one line. Conflicts, drift and
71
+ manual steps are never collapsed: each names its file and its remedy, and
72
+ an agent this project has not installed is never named at all. Pass
73
+ `--json` for the previous object, unchanged apart from the key rename
74
+ below, and `--verbose` for the per-file detail alongside the summary.
75
+ **Every skill, script or agent parsing this output must add `--json`.**
76
+ - **BREAKING: `--host` is now `--agent`, with no alias.** `--host` is
77
+ rejected as an unknown option (exit 2, with runnable `--agent` help), the
78
+ `hosts` key in every result body is now `agents`, and the lock file records
79
+ `agents`. A lock written by an earlier version under `hosts` is still read
80
+ and is rewritten as `agents` on the next run, so an existing install keeps
81
+ its recorded selection. Consistent with the earlier
82
+ `--no-companions` -> `--no-extra-components` break.
83
+ **WARNING — the lock migration is one-way:** writing `agents` drops the
84
+ legacy `hosts` key, so after any run of this version an older pinned CLI
85
+ (`npx …@0.1.6`) exits 2 in that repository with "no --host given, this
86
+ repository has no recorded install". Verified against the published 0.1.6
87
+ tarball.
88
+ - `install` invoked with a bad flag now reports `install`, not `apply`, in
89
+ its usage help.
90
+
91
+ ### Fixed
92
+
93
+ - `status` no longer labels a conflict as "edited since install". Its
94
+ `drift[]` entries now carry the action's `state`, and the human renderer
95
+ titles conflicts as conflicts.
96
+
10
97
  ## [0.1.6] - 2026-09-18
11
98
 
12
99
  ### Changed
package/CONTRIBUTING.md CHANGED
@@ -15,7 +15,7 @@ npm run gen:check # generated adapters match their sources
15
15
  node scripts/check-pack.mjs # the tarball matches the files allow-list
16
16
  ```
17
17
 
18
- If you edited an agent or a skill, regenerate the host adapters first and
18
+ If you edited an agent or a skill, regenerate the per-agent adapters first and
19
19
  commit the result:
20
20
 
21
21
  ```bash
@@ -29,14 +29,23 @@ npm run gen
29
29
  `scripts/gen-copilot-agents.mjs`. Never hand-edit them — run `npm run gen`
30
30
  and commit the output. `npm run gen:check` fails the build on drift.
31
31
  - **Every `SKILL.md` stays under 8192 bytes**, Codex's effective cap and the
32
- smallest of the four hosts'. A test enforces it. When a skill grows past the
33
- cap, move material into `reference/*.md` beside it — that is
32
+ smallest of the four coding agents'. A test enforces it. When a skill grows
33
+ past the cap, move material into `reference/*.md` beside it — that is
34
34
  **reorganisation, never compression**. Audit the split against the
35
35
  pre-split file line by line; do not drop meaning to make the number work.
36
- - **Skills stay host-neutral.** No `${CLAUDE_SKILL_DIR}`, no `$ARGUMENTS`, no
36
+ - **Skills stay agent-neutral.** No `${CLAUDE_SKILL_DIR}`, no `$ARGUMENTS`, no
37
37
  `SendMessage` or `subagent_type`, no literal `.claude/…` path. Any prose that
38
38
  asks the user a question names both Claude Code's and Codex's question
39
39
  tools, not just one.
40
+ - **The result object is the model; `lib/render.mjs` is only a view.** Every
41
+ command builds one body, `--json` prints it verbatim and the human summary
42
+ is rendered from that same body — never assembled beside it. The renderer is
43
+ pure `body -> string` with no I/O, so it is unit-tested in
44
+ `test/render.test.mjs` without a terminal. Human text goes to stdout (it is
45
+ the result); only the interactive picker and warnings go to stderr.
46
+ - **Test suites pass `--json`.** `test/helpers.mjs`'s `run()` appends it for
47
+ every call; only a suite that is about the human output opts out with
48
+ `{ json: false }`.
40
49
  - **The installer never prompts, never fetches, and writes atomically.**
41
50
  Every file is written to a temporary path and renamed. A change that breaks
42
51
  any of those three properties is a change to the contract this package
package/README.md CHANGED
@@ -43,34 +43,50 @@ identity, not an npm package name — and can be run standalone in any stdio MCP
43
43
  client without this harness.
44
44
 
45
45
  The two editors are **optional add-ons**, and each ships its own skill inside
46
- its package rather than here. `sw-setup` offers to install them; a host that
47
- declines is fully set up without them, and `--editor` on `sw-design-requirements`,
48
- `sw-design-solution` or `sw-discover-tender` then stops with one line saying so.
46
+ its package rather than here. They are not this CLI's business at all: it
47
+ neither detects nor installs them. `sw-setup` owns their whole lifecycle —
48
+ it offers them, and installs, updates and removes each one with that
49
+ package's own `install-skill`/`uninstall-skill --target <skills dir>`. A
50
+ project that declines is fully set up without them, and `--editor` on
51
+ `sw-design-requirements`, `sw-design-solution` or `sw-discover-tender` then
52
+ stops with one line saying so.
49
53
 
50
54
  ## Commands
51
55
 
52
56
  | Command | What it does |
53
57
  | --- | --- |
54
- | `install` | installs into the resolved host(s) (see Flags below); the same as `apply --yes` |
55
- | `status` | read-only; what is installed, what drifted, which optional extra components are present |
58
+ | `install` | installs into the resolved coding agent(s) (see Flags below); the same as `apply --yes` |
59
+ | `status` | read-only; what is installed, what drifted, and each agent's `skills_dir` |
56
60
  | `plan` | the exact changes, written as a diff; writes nothing |
57
61
  | `apply --yes` | performs them |
58
62
  | `uninstall --yes` | removes what the lock file records |
59
63
  | `guide` | the install protocol, the single source of truth |
60
64
 
61
- Flags: `--host claude-code|codex|copilot|cursor` (repeatable), `--scope
65
+ Flags: `--agent claude-code|codex|copilot|cursor` (repeatable), `--scope
62
66
  project|user` (default `project`), `--root <path>` (default the current
63
67
  directory), `--yes` (required by `apply` and `uninstall` — `install` implies
64
- it), and `--no-extra-components` (skip detection of the optional editor
65
- packages).
68
+ it), `--json` and `--verbose` (see Output below).
66
69
 
67
- `install`/`apply` resolve which host(s) to write into, in order: `--host` if
68
- given; else the hosts a lock file already records (a re-run needs no
69
- question); else, with a terminal attached, an interactive picker; else exit 2
70
- with the four `install --host <h>` commands as `help` — it never guesses and
71
- never hangs. `status` and `uninstall` are unaffected by this and keep
72
- covering every host by default; `plan` writes nothing, so with no `--host` and
73
- no lock it previews all four and says so.
70
+ `install`/`apply` resolve which coding agent(s) to write into, in order:
71
+ `--agent` if given; else the agents a lock file already records (a re-run
72
+ needs no question); else, with a terminal attached, an interactive picker;
73
+ else exit 2 with the four `install --agent <a>` commands as `help` — it never
74
+ guesses and never hangs. `status` and `uninstall` are unaffected by this and
75
+ keep covering every agent by default; `plan` writes nothing, so with no
76
+ `--agent` and no lock it previews all four and says so.
77
+
78
+ ### Output
79
+
80
+ `install`, `status`, `plan` and `uninstall` print a short human summary on
81
+ stdout — what changed, grouped by coding agent, and the restart each one
82
+ needs. When nothing changed, that is a single line. Conflicts, drift and
83
+ manual steps are always shown in full, with the file and the remedy, because
84
+ those are the only things you have to act on.
85
+
86
+ `--json` prints the result object instead: the same body, with the per-file
87
+ detail, a `next_step` on every success and a `help` array of runnable commands
88
+ on every error. **Anything parsing this output must pass `--json`.**
89
+ `--verbose` keeps the human summary but adds the per-file detail.
74
90
 
75
91
  ## Install
76
92
 
@@ -86,9 +102,9 @@ The command's output tells you which ones and how.
86
102
 
87
103
  `apply` refuses without `--yes`. Neither `apply` nor `install` prompts for
88
104
  consent — typing the verb, or passing `--yes`, is the consent — but with no
89
- `--host`, no existing lock and no terminal (Codex's question tool does not
105
+ `--agent`, no existing lock and no terminal (Codex's question tool does not
90
106
  block outside Plan mode, and CI has no terminal either), it exits 2 rather
91
- than guess. Add `--host claude-code` (repeatable) to install into one agent,
107
+ than guess. Add `--agent claude-code` (repeatable) to install into one agent,
92
108
  and `--scope user` to install into your home directory instead of this
93
109
  repository. The default scope is the project — nothing is written under `~`
94
110
  unless you ask.
@@ -105,6 +121,17 @@ unless you ask.
105
121
  `AGENTS.md` gets a managed block too — Codex, Copilot and Cursor read it, and
106
122
  Codex never reads `CLAUDE.md`.
107
123
 
124
+ The installer's own state — the lock file recording what it wrote — goes to
125
+ `var/sw-ai-sdk/harness.lock.json`. A Shopware project already ignores the whole
126
+ of `var/` through the `shopware/core` Flex recipe (`/var/*`) and already keeps
127
+ its machine-local state there, so the repository root stays clean and **no
128
+ `.gitignore` line is written at all**. A root with no `var/` — `--scope user`
129
+ under your home directory, or a checkout that is not a Shopware project —
130
+ falls back to `.sw-ai-sdk/` and gets the managed `.gitignore` line as before.
131
+ An install recorded at the old path is moved on the next `install`, which also
132
+ takes back the `.gitignore` line it no longer needs; nothing is reinstalled and
133
+ no declined rule is forgotten.
134
+
108
135
  ### What it will not do
109
136
 
110
137
  - **It never overwrites a file it did not install.** A file already at one of
@@ -124,15 +151,16 @@ Undo everything with:
124
151
  npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest uninstall --yes
125
152
  ```
126
153
 
127
- It removes exactly what the lock file at `.sw-ai-sdk/harness.lock.json` records,
154
+ It removes exactly what the lock file at `var/sw-ai-sdk/harness.lock.json` records,
128
155
  keeps anything you hand-edited, and tells you what it kept.
129
156
 
130
157
  ### From a skill
131
158
 
132
- `sw-setup` is a stub: it runs `status`, renders the table, asks once, and runs
133
- `apply --yes`. It deliberately restates none of the protocol, because an
134
- installed skill file goes stale and the CLI does not. Anything that needs the
135
- protocol runs:
159
+ `sw-setup` is a stub: it runs `status --json`, renders the table, asks once,
160
+ and runs `apply --yes --json`. A skill always passes `--json`; the bare
161
+ commands print the human summary. It deliberately restates none of the
162
+ protocol, because an installed skill file goes stale and the CLI does not.
163
+ Anything that needs the protocol runs:
136
164
 
137
165
  ```bash
138
166
  npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest guide
@@ -146,16 +174,16 @@ Three things update on different schedules.
146
174
  | --- | --- |
147
175
  | This package — skills, sub-agents, permission rules, MCP registrations | `npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest install` |
148
176
  | The MCP servers (`ShopwareDevKnowledgeBase`, `playwright`) | By themselves. They are registered as `@latest`, so your agent fetches the newest build the next time it starts one. Nothing to run. |
149
- | Specs Editor, Tender Discovery Tool | You update them. Each has its own line — see below. |
177
+ | Specs Editor, Tender Discovery Tool | `sw-setup` does, by re-running each package's own `install-skill` at `@latest` — see below. |
150
178
 
151
179
  ### The optional editors
152
180
 
153
- Install or update each at the exact version this release pins — the CLI
154
- probes for that version and skips the skill if it finds another:
181
+ They are installed, updated and removed by the `sw-setup` skill, not by this
182
+ CLI, and there is no version to match against this package:
155
183
 
156
184
  ```bash
157
- npm i -D @execuro-sw-ecosystem/sw-specs-editor@0.1.0
158
- npm i -D @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0
185
+ npx -y @execuro-sw-ecosystem/sw-specs-editor@latest install-skill --target <skills dir>
186
+ npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest install-skill --target <skills dir>
159
187
  ```
160
188
 
161
189
  - `sw-specs-editor` backs the `--editor` flag on `sw-design-requirements` and
@@ -163,22 +191,25 @@ npm i -D @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0
163
191
  - `sw-tender-discovery-tool` backs the `--editor` flag and the `.xlsx` import
164
192
  on `sw-discover-tender`.
165
193
 
166
- Re-run `install` afterwards so the new skill lands in each host. `status`'s
167
- `extra_components[]` array reports the pinned `version` and the exact `install`
168
- command for whichever one is missing.
194
+ `<skills dir>` is the `skills_dir` this CLI reports for that agent in
195
+ `status --json`. Re-running the same line is the update — `@latest` plus the
196
+ editor's own "already current" path makes it idempotent — and
197
+ `uninstall-skill` with the same `--target` removes it. Nothing needs to be
198
+ re-run here afterwards.
169
199
 
170
200
  Re-running `install` is safe at any time: it rewrites only what it owns,
171
201
  leaves anything you hand-edited alone (reported as drift), and records the new
172
- version in the lock file. Restart your coding agent afterwards — every host
173
- reads its configuration at startup.
202
+ version in the lock file. It prints one line when there was nothing to change.
203
+ Restart your coding agent afterwards — every host reads its configuration at
204
+ startup.
174
205
 
175
206
  `@latest` matters. Without it, `npx` can reuse a copy already in its cache or
176
207
  in this project's `node_modules`, so you would silently keep running the
177
208
  version you first installed.
178
209
 
179
210
  To look before you change anything: `... @latest status` reports
180
- `installed_version`, any drift, and which extra components are present. It
181
- writes nothing.
211
+ `installed_version`, any drift, and each agent's `skills_dir`. It writes
212
+ nothing.
182
213
 
183
214
  ## Prerequisites
184
215
 
@@ -334,7 +365,7 @@ repository is development-only.**
334
365
 
335
366
  ### Every `SKILL.md` is capped at 8 KB
336
367
 
337
- Codex's effective skill-body limit is the smallest of the four hosts', so it is
368
+ Codex's effective skill-body limit is the smallest of the four coding agents', so it is
338
369
  the budget every skill is written to. Overflow lives in `reference/*.md` beside
339
370
  each `SKILL.md`, loaded on demand. A test enforces the cap, so the gate is
340
371
  mechanical rather than a review habit.
@@ -343,7 +374,7 @@ mechanical rather than a review habit.
343
374
 
344
375
  | Symptom | What it means | What to do |
345
376
  | --- | --- | --- |
346
- | `state: "conflict"` | A file we did not install already sits at that path. It is never overwritten. | Move or delete the existing file, or `--host`-scope the run away from it, then re-run `apply`. |
377
+ | `state: "conflict"` | A file we did not install already sits at that path. It is never overwritten. | Move or delete the existing file, or `--agent`-scope the run away from it, then re-run `apply`. |
347
378
  | `state: "drift"` | You (or something else) edited a file this installer wrote. It is left alone on every later run. | Nothing to fix — this is by design. Re-run `status` to confirm it is the only thing reported. |
348
379
  | A manual step for `.vscode/mcp.json` | That file is JSONC (comments or trailing commas). Rewriting it would destroy your notes, so it is never touched automatically. | Add the printed snippet to `.vscode/mcp.json` yourself, under the `servers` key. |
349
380
  | `.codex/` reported read-only | Codex's default workspace-write sandbox makes `.codex/` and `.agents/` read-only from inside a Codex session. | Run the installer from a plain shell, not from inside Codex. |
package/SECURITY.md CHANGED
@@ -41,7 +41,7 @@ scripts** on install, which removes a large part of the usual npm attack
41
41
  surface.
42
42
 
43
43
  Out of scope: vulnerabilities in the coding agents themselves, in the
44
- separately published extra components (they have their own repositories
44
+ separately published visual editors (they have their own repositories
45
45
  and their own reporting), or in a third-party MCP server this package merely
46
46
  registers, such as Playwright's (report those upstream).
47
47
 
package/bin/cli.mjs CHANGED
@@ -28,32 +28,38 @@ const COMMANDS = {
28
28
 
29
29
  const USAGE = `usage: sw-ecosystem-agentic-harness <command> [options]
30
30
 
31
- install [--host <h>] [--scope project|user] [--root <path>] [--no-extra-components]
32
- status [--host <h>] [--scope project|user] [--root <path>]
33
- plan [--host <h>] [--scope project|user] [--root <path>] [--no-extra-components]
34
- apply --yes [--host <h>] [--scope project|user] [--root <path>] [--no-extra-components]
35
- uninstall --yes [--host <h>] [--scope project|user] [--root <path>]
31
+ install [--agent <a>] [--scope project|user] [--root <path>]
32
+ status [--agent <a>] [--scope project|user] [--root <path>]
33
+ plan [--agent <a>] [--scope project|user] [--root <path>]
34
+ apply --yes [--agent <a>] [--scope project|user] [--root <path>]
35
+ uninstall --yes [--agent <a>] [--scope project|user] [--root <path>]
36
36
  guide print the install protocol
37
37
 
38
38
  install is apply --yes under a friendlier name: the whole install in one
39
39
  command, no --yes needed — typing the verb is the consent for that write;
40
- it can still ask which host(s), see below.
40
+ it can still ask which coding agent(s), see below.
41
41
 
42
- <h> is one of: claude-code, codex, copilot, cursor. Repeat --host to select
43
- several. install/apply resolve which host(s) to use, in order: --host if
44
- given; else the hosts already recorded in the lock file, if one exists;
42
+ <a> is one of: claude-code, codex, copilot, cursor. Repeat --agent to select
43
+ several. install/apply resolve which agent(s) to use, in order: --agent if
44
+ given; else the agents already recorded in the lock file, if one exists;
45
45
  else, with a terminal attached, an interactive picker; else exit 2 with
46
- the four "... install --host <h>" commands as help. status and uninstall
47
- keep covering every host by default.
46
+ the four "... install --agent <a>" commands as help. status and uninstall
47
+ keep covering every agent by default.
48
48
 
49
49
  --scope defaults to project: nothing is written under your home directory
50
50
  unless you ask for it. --root defaults to the current directory.
51
51
 
52
- --no-extra-components skips the two optional extra-component skills (Specs
53
- Editor, Tender Discovery Tool) even when the package is present locally.
52
+ The two optional visual editors (Specs Editor, Tender Discovery Tool) are
53
+ not this CLI's business: each ships its own skill inside its own npm
54
+ package, and the sw-setup skill offers, installs, updates and removes
55
+ them.
54
56
 
55
- Every command prints one JSON object on stdout carrying a next_step. Run
56
- \`sw-ecosystem-agentic-harness guide\` first — it is the install protocol.`;
57
+ --json print the result object instead of the human summary
58
+ --verbose include the per-file detail --json carries
59
+
60
+ install, status, plan and uninstall print a short human summary on stdout.
61
+ Add --json for the machine-readable object, which always carries a next_step.
62
+ Run \`sw-ecosystem-agentic-harness guide\` first — it is the install protocol.`;
57
63
 
58
64
  const argv = process.argv.slice(2);
59
65
  const cmd = argv[0];
package/lib/actions.mjs CHANGED
@@ -20,13 +20,11 @@ import {
20
20
  import { PKG_ROOT } from './content.mjs';
21
21
  import { isDeclined } from './lock.mjs';
22
22
  import { readFileSync } from 'node:fs';
23
- import { EXTRA_COMPONENTS, probe } from './extra-components.mjs';
24
23
 
25
24
  /** Preview one action against the filesystem. Reads only. */
26
25
  export function preview(action, ctx) {
27
26
  switch (action.kind) {
28
27
  case 'file-copy': return previewFile(action, ctx);
29
- case 'skill-copy': return previewSkill(action, ctx);
30
28
  case 'json-merge': return previewJson(action, ctx);
31
29
  case 'toml-fence':
32
30
  case 'text-fence': return previewFence(action, ctx);
@@ -42,8 +40,7 @@ function previewFile(action, ctx) {
42
40
  return previewBytes(action, ctx, shipped);
43
41
  }
44
42
 
45
- /** The adopt/conflict/drift/update ladder, shared by `file-copy` and, with a
46
- * probed body instead of a shipped one, `skill-copy`. */
43
+ /** The adopt/conflict/drift/update ladder every byte-for-byte target walks. */
47
44
  function previewBytes(action, ctx, bytes) {
48
45
  const hash = sha256(bytes);
49
46
  const target = abs(ctx.root, action.target);
@@ -74,35 +71,6 @@ function previewBytes(action, ctx, bytes) {
74
71
  detail: 'shipped content changed' };
75
72
  }
76
73
 
77
- // ------------------------------------------------------------ skill-copy
78
-
79
- /** Strip the probed body (a Buffer) before it lands anywhere near the
80
- * action, which `commands.mjs` serialises straight to stdout. */
81
- function stripProbeBody({ body, ...rest }) {
82
- return rest;
83
- }
84
-
85
- function previewSkill(action, ctx) {
86
- const component = EXTRA_COMPONENTS.find((c) => c.id === action.component);
87
- const probed = probe(component, { platform: ctx.platform });
88
- const probeSummary = stripProbeBody(probed);
89
-
90
- if (!probed.available) {
91
- const remedy = probed.state === 'absent'
92
- ? `npm i -D ${probed.spec}`
93
- : 'check that npx works — probing needs network-free npx --no-install';
94
- return {
95
- ...action, state: 'skipped', available: false,
96
- probe: probeSummary, reason: probed.reason, remedy,
97
- };
98
- }
99
-
100
- return {
101
- ...previewBytes(action, ctx, probed.body),
102
- available: true, probe: probeSummary, body: probed.body,
103
- };
104
- }
105
-
106
74
  // ------------------------------------------------------------- json-merge
107
75
 
108
76
  function previewJson(action, ctx) {
@@ -275,18 +243,6 @@ export function execute(action, ctx) {
275
243
  return { kind: 'file-copy', host: action.host, target: action.target, source: action.source,
276
244
  hash: action.hash, bytes: action.bytes, created_file: action.created_file !== false, dirs };
277
245
  }
278
- case 'skill-copy': {
279
- // Collapses to a `file-copy` lock entry on purpose: `lock.record`,
280
- // `lock.entries`, `revert` and `rebuild` need no extra-component-specific
281
- // case, and `uninstall` needs no probe. `source` is provenance only —
282
- // `revert` never reads it.
283
- ensureDir(dirname(target));
284
- writeAtomic(target, action.body);
285
- const dirs = ancestorDirs(ctx.root, action.target);
286
- return { kind: 'file-copy', host: action.host, target: action.target,
287
- source: `npm:${action.package}#install-skill --print`,
288
- hash: action.hash, bytes: action.bytes, created_file: action.created_file !== false, dirs };
289
- }
290
246
  case 'json-merge': {
291
247
  // Recompute from what is on disk right now rather than writing the
292
248
  // snapshot `preview` took. Several actions can target one file — the two