@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.
- package/CHANGELOG.md +58 -0
- package/README.md +40 -17
- package/SECURITY.md +1 -1
- package/bin/cli.mjs +7 -5
- package/lib/actions.mjs +1 -45
- package/lib/commands.mjs +43 -45
- package/lib/content.mjs +31 -1
- package/lib/guide.mjs +9 -16
- package/lib/hosts.mjs +36 -34
- package/lib/lock.mjs +41 -9
- package/lib/render.mjs +10 -9
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/sw-design-requirements/SKILL.md +1 -1
- package/skills/sw-design-requirements/reference/editor-gate.md +1 -1
- package/skills/sw-design-requirements/reference/editor-mode.md +2 -2
- package/skills/sw-design-solution/SKILL.md +1 -1
- package/skills/sw-design-solution/reference/editor-mode.md +2 -2
- package/skills/sw-discover-tender/SKILL.md +2 -2
- package/skills/sw-discover-tender/reference/editor-session.md +3 -3
- package/skills/sw-discover-tender/reference/procedure.md +2 -2
- package/skills/sw-setup/SKILL.md +5 -5
- package/skills/sw-setup/reference/rows.md +105 -68
- package/lib/extra-components.mjs +0 -117
|
@@ -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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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-
|
|
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
|
-
|
|
89
|
-
skills directory,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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.
|
|
224
|
-
this list —
|
|
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
|
|
241
|
-
every host launch, so there is
|
|
242
|
-
|
|
243
|
-
|
|
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:**
|
|
248
|
-
timeout
|
|
249
|
-
|
|
250
|
-
`npm view
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
272
|
-
|
|
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.
|
package/lib/extra-components.mjs
DELETED
|
@@ -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
|
-
}
|