@execuro-sw-ecosystem/sw-ecosystem-agentic-harness 0.1.7 → 0.1.9

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.
@@ -59,45 +59,88 @@ directly again. Expect `agents[]` in every output this skill reads.
59
59
 
60
60
  ## 3. Visual editors (optional)
61
61
 
62
- The Specs Editor and the Tender Discovery Tool are **optional add-ons**, not
63
- part of this plugin. The installer CLI installs them itself, per host — this
64
- row never runs an extra component's own install command.
65
-
66
- So this row never blocks readiness. It asks.
67
-
68
- - **Check:** read `extra_components[]` from the `status` output the skill already
69
- ran in step 1 — each entry's `available`, `installed_for` (the coding agents
70
- it is placed in), and `install` (the npm command, when missing). Never probe a
71
- path and never run an extra component by hand; the CLI owns both.
72
- - **Ticked:** `[x]` when an extra component's `available` is true and
73
- `installed_for` includes this agent; `[-]` when the user has declined it.
74
- Only an unanswered offer shows `[ ]`, and even then it does not hold the
75
- table open — report it as optional and move on.
76
- - **Fix:** offer each missing extra component inside step 3's single question,
77
- naming what it buys, not how it works: "Specs Editor — review a PRD or
78
- tech spec on a live page, with notes, question answers and diagrams.
79
- Install?" — and "Tender Discovery Tool — read a client tender workbook,
80
- confirm its column mapping and review the analysis on a live page.
81
- Install?" On yes, for each accepted one: `npm i -D <package>@0.1.0` (the
82
- `package` field from `extra_components[]`), then re-run
62
+ The Specs Editor and the Tender Discovery Tool are **optional add-ons** in
63
+ their own npm packages. Each ships its own skill and installs it itself. The
64
+ installer CLI has nothing to do with them: it does not detect them, does not
65
+ report them, and never fetches them — this skill owns their whole lifecycle,
66
+ and this row is the only place that lifecycle lives.
67
+
68
+ So this row never blocks readiness, and it never probes. It asks.
69
+
70
+ - **Check:** read `agents[]` from the `status --json` output step 1 already
71
+ ran. Each entry carries `id` and `skills_dir` — the directory that agent
72
+ actually reads skills from. For each agent whose `state` is not `absent`,
73
+ list `<skills_dir>/sw-specs-editor/` and
74
+ `<skills_dir>/sw-tender-discovery-tool/`: a `SKILL.md` there means that
75
+ editor is installed for that agent. That directory read is the whole check —
76
+ never run an editor's CLI to find out, never `npm view`, never `npx
77
+ --no-install`. All three reach the network, and a missing editor is a normal
78
+ state, not something to go looking for. Also read
79
+ `sw-setup-editors.json` from the installer's own state directory if it
80
+ exists — this skill's note of what the user has already declined
81
+ (`{"sw-specs-editor": "declined"}`). That directory is whatever `lock_file`
82
+ in the step-1 `status --json` output names, minus the file name — normally
83
+ `var/sw-ai-sdk/`, which a Shopware project already ignores. Read the path;
84
+ never hard-code it.
85
+ - **Ticked:** `[x]` when the editor's `SKILL.md` is present in every
86
+ non-`absent` agent's `skills_dir`; `[-]` when the note records a decline, or
87
+ when it is installed for some agents but not all (say which). `[ ]` only for
88
+ an editor that is neither installed nor declined — and even then it does not
89
+ hold the table open: report it as optional and move on.
90
+ - **Fix:** offer both inside step 3's single question, naming what each buys,
91
+ not how it works:
92
+ - "**Specs Editor** — review a PRD or tech spec on a live page, with notes,
93
+ answered questions and Excalidraw diagrams. It is what backs `--editor` on
94
+ `sw-design-requirements` and `sw-design-solution`. Install?"
95
+ - "**Tender Discovery Tool** — read a client tender workbook, confirm its
96
+ column mapping and review the analysis on a live page. It is what backs
97
+ `--editor` and the `.xlsx` import on `sw-discover-tender`. Install?"
98
+
99
+ On yes, for each accepted editor, run its own installer once per
100
+ non-`absent` agent, passing that agent's `skills_dir` from `status --json`:
83
101
 
84
102
  ```
85
- npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest apply --yes --json
103
+ npx -y @execuro-sw-ecosystem/sw-specs-editor@latest install-skill --target <skills_dir>
104
+ npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest install-skill --target <skills_dir>
86
105
  ```
87
106
 
88
- which places one `SKILL.md` per extra component into each selected agent's own
89
- skills directory, records it, and removes it again on uninstall. **Never
90
- run the extra component's own `install-skill`** — with no `--target` it
91
- defaults to Claude Code's own skills directory, wrong for a Codex, Copilot
92
- or Cursor install. Needs the Node row ticked.
93
- - **On no:** record the decline and do not re-ask on the next run. `apply`
94
- keeps reporting that skill as `skipped` — the intended steady state, not a
95
- fault. `--editor` on `sw-design-requirements` / `sw-design-solution` /
96
- `sw-discover-tender` then stops with one line naming this skill.
97
- - **Blocks:** Specs Editor missing → `sw-design-requirements --editor`,
98
- `sw-design-solution --editor`, the `sw-specs-editor` skill. Tender
99
- Discovery Tool missing → `sw-discover-tender --editor` and its `.xlsx`
100
- import, plus the `sw-tender-discovery-tool` skill.
107
+ Never omit `--target`: with no target these default to Claude Code's own
108
+ skills directory, which is wrong for a Codex, Copilot or Cursor install.
109
+ Never pass a hard-coded path either — `skills_dir` is what that agent reads,
110
+ and for Cursor it is deliberately Claude's tree when one exists. Needs the
111
+ Node row ticked. Report each command's own output; a failure is that
112
+ editor's failure, never an unticked environment.
113
+ - **Updating:** re-run exactly the same `install-skill` line. `@latest`
114
+ fetches the newest package and the editor's own installer recognises a copy
115
+ that is already current and says so, so re-running is idempotent and is the
116
+ one command that updates an editor. There is nothing else to run and nothing
117
+ to un-install first.
118
+ - **Removal:** the same shape with `uninstall-skill`:
119
+
120
+ ```
121
+ npx -y @execuro-sw-ecosystem/sw-specs-editor@latest uninstall-skill --target <skills_dir>
122
+ ```
123
+
124
+ `uninstall-skill` is newer than `install-skill`. An editor package that
125
+ predates it answers with "unknown command", "unknown subcommand" or a usage
126
+ dump, and `npx` may exit non-zero. That is not a failure of this row and not
127
+ a reason to delete anything by hand: report it in one line — "this version
128
+ of the Specs Editor cannot remove its own skill; update it with `npx -y
129
+ @execuro-sw-ecosystem/sw-specs-editor@latest install-skill --target
130
+ <skills_dir>` and re-run the removal" — and carry on with the other agents
131
+ and the other editor.
132
+ - **On no:** write the decline to `sw-setup-editors.json` in the directory
133
+ `lock_file` names (create the file, and that directory, if absent; it is
134
+ never tracked) and do not
135
+ offer that editor again on any later run. The user asking for it by name is
136
+ the only thing that re-opens it — then delete its key and install. `--editor`
137
+ on `sw-design-requirements` / `sw-design-solution` / `sw-discover-tender`
138
+ stops with one line naming this skill, which is the intended steady state,
139
+ not a fault.
140
+ - **Blocks:** nothing. Specs Editor missing → `sw-design-requirements
141
+ --editor`, `sw-design-solution --editor` and the `sw-specs-editor` skill are
142
+ unavailable. Tender Discovery Tool missing → `sw-discover-tender --editor`
143
+ and its `.xlsx` import, plus the `sw-tender-discovery-tool` skill.
101
144
 
102
145
  ## 4. shopware-cli
103
146
 
@@ -220,8 +263,9 @@ So this row never blocks readiness. It asks.
220
263
  var/verification-screenshots/
221
264
  ```
222
265
  (`/specs/.editor/` and `/specs/.rfp/` are already present in this project's
223
- `.gitignore`; check the other four independently. `.sw-ai-sdk/` is not on
224
- this list — the installer CLI adds that one itself.)
266
+ `.gitignore`; check the other four independently. The installer's own state
267
+ is not on this list — it lives in `var/sw-ai-sdk/`, which the
268
+ `###> shopware/core ###` recipe block already ignores through `/var/*`.)
225
269
 
226
270
  Do **not** add `specs/<rfp-basename>/`. The tender tool's normalised source
227
271
  export and its `import-map.json` live there and are committed on purpose —
@@ -237,39 +281,32 @@ So this row never blocks readiness. It asks.
237
281
 
238
282
  ## 12. Package updates (optional)
239
283
 
240
- The KB MCP is excluded — it is registered as `@latest` and re-resolves on
241
- every host launch, so there is nothing to update (see row 5). This row covers
242
- only the three versioned packages: the harness itself, the Specs Editor and
243
- the Tender Discovery Tool.
284
+ This row covers **the harness package only**. The KB MCP is excluded — it is
285
+ registered as `@latest` and re-resolves on every host launch, so there is
286
+ nothing to update (see row 5). The two visual editors are excluded too: they
287
+ are no longer version-matched against a harness pin, they are invoked as
288
+ `@latest` everywhere, and row 3's `install-skill` line both installs and
289
+ updates them. Never report an editor version here.
244
290
 
245
291
  This row never blocks readiness. It folds into step 3's single question.
246
292
 
247
- - **Check:** three `npm view <pkg> version` calls, each with a 10-second
248
- timeout — `npm view @execuro-sw-ecosystem/sw-ecosystem-agentic-harness
249
- version`, `npm view @execuro-sw-ecosystem/sw-specs-editor version`,
250
- `npm view @execuro-sw-ecosystem/sw-tender-discovery-tool version`. Installed
251
- versions come from three different places: the harness's from
252
- `installed_version` in the `status` JSON the skill already ran in step 1
253
- (from the lock file); the Specs Editor's from `version` in
254
- `node_modules/@execuro-sw-ecosystem/sw-specs-editor/package.json`; the
255
- Tender Discovery Tool's the same way, in its own `node_modules` path. A
256
- failed or timed-out `npm view` call reports "could not check" for that
257
- package only — never an unticked row, never an error, never a blocked run.
258
- No network is a normal condition, not a fault.
259
- - **Ticked:** all three packages at their target version — the harness at
260
- npm's latest, each editor at the pin its own `status` output names
261
- (`extra_components[].version`), not at npm's latest.
262
- - **Unticked:** one line per stale package, `installed → available` — e.g.
263
- `harness 0.1.1 → 0.1.3`, `Specs Editor 0.1.0 → 0.1.0 (pinned)` when current.
264
- An editor whose npm latest is ahead of the pin is a harness-release lag,
265
- not a missing update: report it, but do not offer to install that newer
266
- version — only a newer harness can raise the pin.
267
- - **Fix:** update the harness first — a newer harness may carry newer pins:
268
- `npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest install`.
293
+ - **Check:** one `npm view @execuro-sw-ecosystem/sw-ecosystem-agentic-harness
294
+ version` call with a 10-second timeout. The installed version is
295
+ `installed_version` in the `status --json` output step 1 already ran (it
296
+ comes from the lock file). A failed or timed-out `npm view` reports "could
297
+ not check" and nothing else — never an unticked row, never an error, never a
298
+ blocked run. No network is a normal condition, not a fault.
299
+ - **Ticked:** the installed harness version equals npm's latest.
300
+ - **Unticked:** one line, `installed → available` — e.g. `harness 0.1.1 →
301
+ 0.1.8`.
302
+ - **Fix:**
303
+
304
+ ```
305
+ npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest install
306
+ ```
307
+
269
308
  That command rewrites the installed `sw-setup` skill itself, so the newer
270
- skill takes effect on the next run — which step 3 already causes by
271
- re-running step 1. Re-read the new `status` output, then for each stale
272
- editor run the same `npm i -D <package>@<version>` shape row 3's Fix uses,
273
- with `<package>` and `<version>` taken from that editor's own
274
- `extra_components[]` entry in the re-read `status`.
309
+ skill takes effect on the next run — which step 3 already causes by re-running
310
+ step 1. For the editors, see row 3: re-running their `install-skill` line is
311
+ their update.
275
312
  - **Blocks:** nothing. Out of date is not broken.
@@ -1,117 +0,0 @@
1
- // The two optional extra components, probed rather than installed by us.
2
- //
3
- // Read-then-copy, not `install-skill --target`: the engine's whole safety
4
- // story is "hash what we intend to write, compare, record". A foreign binary
5
- // that writes on its own cannot be previewed, so `plan` would lie and
6
- // `uninstall` would have to guess. Reading the body with `--print` and
7
- // copying it ourselves through `writeAtomic` keeps every extra-component
8
- // skill on the same adopt/conflict/drift/update ladder as everything else
9
- // this CLI writes, and makes `uninstall` exact even after the user has
10
- // removed the extra component — the common case, since it is optional.
11
- //
12
- // `--no-install` plus `npm_config_yes=false` are two independent guards that
13
- // this can never reach the network: the first tells npx not to fetch a
14
- // missing package, the second refuses the prompt that would offer to.
15
-
16
- import { spawnSync } from 'node:child_process';
17
- import { sha256 } from './fsx.mjs';
18
- import { wrapCommand } from './content.mjs';
19
-
20
- export const EXTRA_COMPONENTS = [
21
- {
22
- id: 'sw-specs-editor', pkg: '@execuro-sw-ecosystem/sw-specs-editor', version: '0.1.0',
23
- label: 'Specs Editor',
24
- },
25
- {
26
- id: 'sw-tender-discovery-tool', pkg: '@execuro-sw-ecosystem/sw-tender-discovery-tool', version: '0.1.0',
27
- label: 'Tender Discovery Tool',
28
- },
29
- ];
30
-
31
- /** The argv `probe` would spawn, without spawning it — for tests. */
32
- export function probeArgs(component, platform) {
33
- const spec = `${component.pkg}@${component.version}`;
34
- const wrapped = wrapCommand(
35
- { command: 'npx', args: ['--no-install', spec, 'install-skill', '--print'] },
36
- platform,
37
- );
38
- return [wrapped.command, ...wrapped.args];
39
- }
40
-
41
- // One probe per `<pkg>@<version>` per process. `status`/`plan`/`apply` each
42
- // ask this question once per host, and the answer never changes mid-run.
43
- const cache = new Map();
44
-
45
- export function resetProbeCache() {
46
- cache.clear();
47
- }
48
-
49
- function lastLine(text) {
50
- const lines = text.trim().split('\n').filter(Boolean);
51
- return lines.length ? lines[lines.length - 1] : '';
52
- }
53
-
54
- function doProbe(component, platform) {
55
- const spec = `${component.pkg}@${component.version}`;
56
- const base = { id: component.id, pkg: component.pkg, version: component.version, spec, label: component.label };
57
- const wrapped = wrapCommand(
58
- { command: 'npx', args: ['--no-install', spec, 'install-skill', '--print'] },
59
- platform,
60
- );
61
-
62
- const res = spawnSync(wrapped.command, wrapped.args, {
63
- stdio: ['ignore', 'pipe', 'pipe'],
64
- timeout: 20000,
65
- windowsHide: true,
66
- env: { ...process.env, npm_config_yes: 'false', npm_config_audit: 'false' },
67
- });
68
-
69
- if (res.error) {
70
- if (res.error.code === 'ENOENT') {
71
- return { ...base, available: false, state: 'probe-failed', reason: 'npx was not found on PATH' };
72
- }
73
- return {
74
- ...base, available: false, state: 'probe-failed',
75
- reason: `probing ${spec} failed: ${res.error.message}`,
76
- };
77
- }
78
- if (res.signal) {
79
- return {
80
- ...base, available: false, state: 'probe-failed',
81
- reason: `probing ${spec} was killed (${res.signal}), possibly a timeout`,
82
- };
83
- }
84
- if (res.status !== 0) {
85
- return {
86
- ...base, available: false, state: 'absent', reason: `${spec} is not installed locally`,
87
- detail: lastLine((res.stderr ?? Buffer.alloc(0)).toString('utf8')),
88
- };
89
- }
90
- const stdout = res.stdout ?? Buffer.alloc(0);
91
- if (stdout.length === 0) {
92
- return {
93
- ...base, available: false, state: 'probe-failed',
94
- reason: `${spec} install-skill --print returned nothing`,
95
- };
96
- }
97
- if (!stdout.toString('utf8').startsWith('---')) {
98
- return {
99
- ...base, available: false, state: 'probe-failed',
100
- reason: `${spec} install-skill --print did not return a skill document`,
101
- };
102
- }
103
- return { ...base, available: true, state: 'available', body: stdout, hash: sha256(stdout), bytes: stdout.length };
104
- }
105
-
106
- /** Probe one extra component. Never throws. */
107
- export function probe(component, { platform = process.platform } = {}) {
108
- const key = `${component.pkg}@${component.version}`;
109
- if (cache.has(key)) return cache.get(key);
110
- const result = doProbe(component, platform);
111
- cache.set(key, result);
112
- return result;
113
- }
114
-
115
- export function probeAll(opts) {
116
- return EXTRA_COMPONENTS.map((c) => probe(c, opts));
117
- }