@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/lib/render.mjs ADDED
@@ -0,0 +1,365 @@
1
+ // The human view of a result body.
2
+ //
3
+ // Every command still builds exactly the same JSON object it always did — that
4
+ // object is the model. This module is the view: pure `body -> string`
5
+ // functions, no I/O, no process state, so the whole renderer is testable
6
+ // without a terminal and without running an install.
7
+ //
8
+ // Design rules, in the order they matter:
9
+ //
10
+ // 1. Nothing changed is ONE line. A file count is not news to a human, and
11
+ // "274 unchanged" reads like a failure to someone who typed `install`.
12
+ // 2. Something changed is reported per agent, in the user's vocabulary —
13
+ // skills and sub-agents by name, config files by path.
14
+ // 3. Conflicts, drift, manual steps and failures are never collapsed into a
15
+ // count: those are the only cases the user has to act on, so each one
16
+ // names its file and its remedy.
17
+ // 4. Never name an agent this project has not installed. A Claude Code user
18
+ // is not told about Codex, Cursor or Copilot.
19
+ //
20
+ // Zero dependencies: bare ANSI, and only when the caller says the stream is a
21
+ // terminal.
22
+
23
+ /** Human labels for the four supported coding agents. */
24
+ export const LABELS = {
25
+ 'claude-code': 'Claude Code',
26
+ codex: 'Codex',
27
+ copilot: 'GitHub Copilot',
28
+ cursor: 'Cursor',
29
+ };
30
+
31
+ /** What each agent needs before it reads the configuration we just wrote. */
32
+ export const RESTART = {
33
+ 'claude-code': 'Restart Claude Code, or run `/mcp` in the running session',
34
+ codex: 'Restart `codex` — .codex/config.toml is read once at startup',
35
+ copilot: 'Reload the VS Code window (Developer: Reload Window) for .vscode/mcp.json',
36
+ cursor: 'Restart Cursor so it re-reads .cursor/mcp.json',
37
+ };
38
+
39
+ function label(id) {
40
+ return LABELS[id] ?? id;
41
+ }
42
+
43
+ // ------------------------------------------------------------------ styling
44
+
45
+ const CODES = { bold: '1', dim: '2', red: '31', green: '32', yellow: '33' };
46
+
47
+ /** A theme whose functions are the identity when colour is off. */
48
+ function theme(color) {
49
+ const wrap = (code) => (color ? (s) => `\x1b[${code}m${s}\x1b[0m` : (s) => s);
50
+ const t = {};
51
+ for (const [name, code] of Object.entries(CODES)) t[name] = wrap(code);
52
+ return t;
53
+ }
54
+
55
+ // --------------------------------------------------------------- primitives
56
+
57
+ const MAX_NAMES = 6;
58
+
59
+ /** "a, b, c and 4 more" — a list a person reads, not a dump. */
60
+ function names(list) {
61
+ const max = MAX_NAMES;
62
+ const all = [...list];
63
+ if (all.length <= max) return all.join(', ');
64
+ return `${all.slice(0, max).join(', ')} and ${all.length - max} more`;
65
+ }
66
+
67
+ function plural(n, one, many = `${one}s`) {
68
+ return `${n} ${n === 1 ? one : many}`;
69
+ }
70
+
71
+ /**
72
+ * What a target is, in the words a user thinks in. A skill is one thing to
73
+ * them even though it is a directory of files; a config file is its path.
74
+ */
75
+ export function classify(target) {
76
+ const skill = /(?:^|\/)skills\/([^/]+)\//.exec(target);
77
+ if (skill) return { kind: 'skill', name: skill[1] };
78
+ const agent = /(?:^|\/)agents\/([^/]+)$/.exec(target);
79
+ if (agent) return { kind: 'agent', name: agent[1].replace(/(\.agent)?\.(md|toml)$/, '') };
80
+ return { kind: 'file', name: target };
81
+ }
82
+
83
+ const VERBS = {
84
+ create: 'added', created: 'added',
85
+ update: 'updated', updated: 'updated',
86
+ removed: 'removed', reverted: 'reverted',
87
+ };
88
+
89
+ const SHARED = '__shared__';
90
+
91
+ /**
92
+ * Group the actions in `states` by agent, then by verb, then by what kind of
93
+ * thing they are. Returns `[{ id, buckets: Map<verb, {skills, agents, files}> }]`
94
+ * in the order the agents first appear.
95
+ */
96
+ export function groupChanges(actions = [], states) {
97
+ const wanted = new Set(states);
98
+ const order = [];
99
+ const groups = new Map();
100
+ for (const action of actions) {
101
+ if (!wanted.has(action.state)) continue;
102
+ const id = !action.host || action.host === 'shared' ? SHARED : action.host;
103
+ if (!groups.has(id)) { groups.set(id, new Map()); order.push(id); }
104
+ const buckets = groups.get(id);
105
+ const verb = VERBS[action.state] ?? action.state;
106
+ if (!buckets.has(verb)) buckets.set(verb, { skill: new Set(), agent: new Set(), file: new Set() });
107
+ const bucket = buckets.get(verb);
108
+ const { kind, name } = classify(action.target);
109
+ // Several actions can target one config file (one per JSON pointer);
110
+ // the user changed one file, so it is named once.
111
+ bucket[kind].add(name);
112
+ (bucket.targets ??= []).push(action.target);
113
+ }
114
+ return order.map((id) => ({ id, buckets: groups.get(id) }));
115
+ }
116
+
117
+ function bucketLines(verb, bucket, { verbose }, t) {
118
+ const lines = [];
119
+ if (verbose) {
120
+ for (const target of bucket.targets ?? []) lines.push(` ${t.dim(verb)} ${target}`);
121
+ return lines;
122
+ }
123
+ if (bucket.skill.size) lines.push(` ${verb} ${plural(bucket.skill.size, 'skill')}: ${names(bucket.skill)}`);
124
+ if (bucket.agent.size) lines.push(` ${verb} ${plural(bucket.agent.size, 'sub-agent')}: ${names(bucket.agent)}`);
125
+ if (bucket.file.size) lines.push(` ${verb} ${names(bucket.file)}`);
126
+ return lines;
127
+ }
128
+
129
+ function groupLines(groups, opts, t) {
130
+ const lines = [];
131
+ for (const { id, buckets } of groups) {
132
+ lines.push(` ${t.bold(id === SHARED ? 'Project files' : label(id))}`);
133
+ for (const [verb, bucket] of buckets) lines.push(...bucketLines(verb, bucket, opts, t));
134
+ }
135
+ return lines;
136
+ }
137
+
138
+ // ------------------------------------------------------------------- issues
139
+
140
+ /** Everything the user has to act on, flattened into one shape. */
141
+ function issues(body) {
142
+ const found = [];
143
+ for (const a of body.actions ?? []) {
144
+ if (a.state === 'conflict' || a.state === 'drift' || a.state === 'failed') {
145
+ found.push({ kind: a.state, target: a.target, reason: a.reason, remedy: a.remedy });
146
+ }
147
+ }
148
+ for (const d of body.drift ?? []) {
149
+ found.push({ kind: d.state ?? 'drift', target: d.target, reason: d.reason, remedy: d.remedy });
150
+ }
151
+ for (const m of body.manual ?? []) {
152
+ found.push({ kind: 'manual', target: m.target ?? m.file, reason: m.reason, remedy: m.remedy });
153
+ }
154
+ for (const e of body.errors ?? []) {
155
+ found.push({ kind: 'failed', target: e.target ?? label(e.host), reason: e.error });
156
+ }
157
+ // The same file can reach us from both `actions` and `drift`; say it once.
158
+ const seen = new Set();
159
+ return found.filter((i) => {
160
+ const key = `${i.kind}:${i.target}`;
161
+ if (seen.has(key)) return false;
162
+ seen.add(key);
163
+ return true;
164
+ });
165
+ }
166
+
167
+ const ISSUE_TITLE = {
168
+ conflict: 'conflict', drift: 'edited since install',
169
+ manual: 'manual step', failed: 'failed',
170
+ };
171
+
172
+ function issueLines(list, t) {
173
+ if (!list.length) return [];
174
+ const paint = (kind) => (kind === 'drift' || kind === 'manual' ? t.yellow : t.red);
175
+ const lines = [` ${t.bold('Needs your attention')}`];
176
+ for (const i of list) {
177
+ lines.push(` ${paint(i.kind)(ISSUE_TITLE[i.kind] ?? i.kind)} ${i.target}`);
178
+ if (i.reason) lines.push(` ${i.reason}`);
179
+ if (i.remedy) lines.push(` ${t.dim('fix:')} ${i.remedy}`);
180
+ }
181
+ return lines;
182
+ }
183
+
184
+ // ------------------------------------------------------------------ restart
185
+
186
+ function restartLines(body, changedIds, t) {
187
+ const ids = changedIds.length
188
+ ? changedIds
189
+ : (body.agents ?? []).map((a) => a.id).filter((id) => RESTART[id]);
190
+ const uniq = [...new Set(ids)].filter((id) => RESTART[id]);
191
+ return uniq.map((id) => ` ${t.dim('→')} ${RESTART[id]}`);
192
+ }
193
+
194
+ // ------------------------------------------------------------ apply/install
195
+
196
+ function renderApply(body, opts, t) {
197
+ const s = body.summary ?? {};
198
+ const changed = (s.created ?? 0) + (s.updated ?? 0);
199
+ const problems = issues(body);
200
+ const migrated = body.migrated ?? [];
201
+
202
+ if (changed === 0 && problems.length === 0 && migrated.length === 0) {
203
+ // ONE line. Nothing changed means nothing to restart and nothing to read.
204
+ return `${t.green('✓')} Shopware agentic harness: already up to date — nothing to change.\n`;
205
+ }
206
+
207
+ const groups = groupChanges(body.actions, ['created', 'updated']);
208
+ const changedIds = groups.map((g) => g.id).filter((id) => id !== SHARED);
209
+ const verb = (s.updated ?? 0) === 0 ? 'Installed' : 'Updated';
210
+ const lines = [];
211
+ if (changed) lines.push(`${t.green('✓')} ${verb} the Shopware agentic harness.`);
212
+ else if (problems.length) lines.push(`${t.yellow('!')} Nothing was written — see below.`);
213
+ // Only tidy-up ran: the install itself was already current.
214
+ else lines.push(`${t.green('✓')} Shopware agentic harness: already up to date.`);
215
+ if (groups.length) {
216
+ lines.push('');
217
+ lines.push(...groupLines(groups, opts, t));
218
+ }
219
+ if (migrated.length) {
220
+ lines.push('');
221
+ for (const m of migrated) lines.push(` ${t.dim('·')} ${m.target}: ${m.detail}`);
222
+ }
223
+ if (problems.length) {
224
+ lines.push('');
225
+ lines.push(...issueLines(problems, t));
226
+ }
227
+ if (changed) {
228
+ lines.push('');
229
+ lines.push(...restartLines(body, changedIds, t));
230
+ }
231
+ return `${lines.join('\n')}\n`;
232
+ }
233
+
234
+ // -------------------------------------------------------------------- plan
235
+
236
+ function renderPlan(body, opts, t) {
237
+ const s = body.summary ?? {};
238
+ const changes = (s.create ?? 0) + (s.update ?? 0);
239
+ const problems = issues(body);
240
+ if (changes === 0 && problems.length === 0) {
241
+ return `${t.green('✓')} Nothing to do — every target is already up to date.\n`;
242
+ }
243
+ const lines = [];
244
+ // `plan` with nothing selected previews every supported agent. Say so, or
245
+ // the list silently names agents this project never installed.
246
+ if (/previews all four/i.test(body.next_step ?? '')) {
247
+ lines.push(t.dim('No agent selected and no recorded install — previewing every supported agent.'));
248
+ }
249
+ lines.push(`${plural(changes, 'change')} would be made. Nothing was written.`);
250
+ const groups = groupChanges(body.actions, ['create', 'update']);
251
+ if (groups.length) {
252
+ lines.push('');
253
+ lines.push(...groupLines(groups, opts, t));
254
+ }
255
+ if (problems.length) {
256
+ lines.push('');
257
+ lines.push(...issueLines(problems, t));
258
+ }
259
+ if (changes) {
260
+ lines.push('');
261
+ lines.push(` ${t.dim('→')} Run \`sw-ecosystem-agentic-harness apply --yes\` to perform them.`);
262
+ }
263
+ return `${lines.join('\n')}\n`;
264
+ }
265
+
266
+ // ------------------------------------------------------------------ status
267
+
268
+ /** An agent is only ours to talk about once it has actually been installed. */
269
+ function installedAgents(body) {
270
+ return (body.agents ?? []).filter((a) => ['ok', 'drift', 'conflict'].includes(a.state));
271
+ }
272
+
273
+ function renderStatus(body, opts, t) {
274
+ const mine = installedAgents(body);
275
+ const problems = issues(body);
276
+
277
+ if (!mine.length) {
278
+ return `${t.yellow('!')} No coding agent is set up in this project yet.\n`
279
+ + ` ${t.dim('→')} ${body.help?.[0] ?? 'sw-ecosystem-agentic-harness install'}\n`;
280
+ }
281
+
282
+ const worst = ['conflict', 'drift'].find((state) => mine.some((a) => a.state === state));
283
+ const lines = [];
284
+ lines.push(worst
285
+ ? `${t.yellow('!')} Shopware agentic harness ${body.installed_version ?? body.version} — ${plural(problems.length, 'item')} ${problems.length === 1 ? 'needs' : 'need'} attention.`
286
+ : `${t.green('✓')} Shopware agentic harness ${body.installed_version ?? body.version} — installed and up to date.`);
287
+
288
+ for (const a of mine) {
289
+ const counts = [];
290
+ if (a.installed?.skills) counts.push(plural(a.installed.skills, 'skill'));
291
+ if (a.installed?.agents) counts.push(plural(a.installed.agents, 'sub-agent'));
292
+ lines.push(` ${t.bold(label(a.id))}${counts.length ? `: ${counts.join(', ')}` : ''}`);
293
+ for (const note of a.notes ?? []) lines.push(` ${t.dim(note)}`);
294
+ }
295
+
296
+ if (problems.length) {
297
+ lines.push('');
298
+ lines.push(...issueLines(problems, t));
299
+ }
300
+
301
+ return `${lines.join('\n')}\n`;
302
+ }
303
+
304
+ // --------------------------------------------------------------- uninstall
305
+
306
+ function renderUninstall(body, opts, t) {
307
+ const s = body.summary ?? {};
308
+ const gone = (s.removed ?? 0) + (s.reverted ?? 0);
309
+ if (gone === 0 && !(body.kept ?? []).length) {
310
+ return `${t.green('✓')} Nothing to remove — this project has no recorded install.\n`;
311
+ }
312
+ const lines = [`${t.green('✓')} Removed the Shopware agentic harness — `
313
+ + `${plural(s.removed ?? 0, 'file')} removed, ${plural(s.reverted ?? 0, 'config block')} reverted.`];
314
+ if ((body.kept ?? []).length) {
315
+ lines.push('');
316
+ lines.push(` ${t.bold('Kept, because you edited them')}`);
317
+ for (const k of body.kept) lines.push(` ${k.target}`);
318
+ }
319
+ lines.push('');
320
+ lines.push(` ${t.dim('→')} Restart your coding agent(s) so they drop the removed configuration.`);
321
+ return `${lines.join('\n')}\n`;
322
+ }
323
+
324
+ // ------------------------------------------------------------------ errors
325
+
326
+ function renderProblem(body, opts, t) {
327
+ const lines = [`${t.red('✗')} ${body.error}`];
328
+ for (const e of body.errors ?? []) {
329
+ lines.push(` ${e.target ?? label(e.host)} — ${e.error}`);
330
+ }
331
+ const problems = issues({ ...body, errors: [] });
332
+ if (problems.length) {
333
+ lines.push('');
334
+ lines.push(...issueLines(problems, t));
335
+ }
336
+ if (body.help?.length) {
337
+ lines.push('');
338
+ lines.push(` ${t.bold('Try')}`);
339
+ for (const h of body.help) lines.push(` ${h}`);
340
+ }
341
+ return `${lines.join('\n')}\n`;
342
+ }
343
+
344
+ // ---------------------------------------------------------------- dispatch
345
+
346
+ const RENDERERS = {
347
+ install: renderApply,
348
+ apply: renderApply,
349
+ plan: renderPlan,
350
+ status: renderStatus,
351
+ uninstall: renderUninstall,
352
+ };
353
+
354
+ /**
355
+ * `body` is the exact object `--json` prints. `opts.verbose` prints the
356
+ * per-file detail the JSON carries; `opts.color` enables ANSI.
357
+ */
358
+ export function render(body, opts = {}) {
359
+ if (!body || typeof body !== 'object') return '';
360
+ const t = theme(opts.color === true);
361
+ if (body.ok === false) return renderProblem(body, opts, t);
362
+ const renderer = RENDERERS[body.command];
363
+ if (!renderer) return `${body.next_step ?? ''}\n`;
364
+ return renderer(body, opts, t);
365
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@execuro-sw-ecosystem/sw-ecosystem-agentic-harness",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Shopware 6 agentic harness: sw-* skills and sub-agents, plus an installer that writes them into Claude Code, Codex, GitHub Copilot and Cursor.",
5
5
  "license": "MIT",
6
6
  "author": "Execuro UG (haftungsbeschränkt)",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "sw-ecosystem-agentic-harness",
4
- "version": "0.1.6",
4
+ "version": "0.1.8",
5
5
  "description": "Shopware 6 agentic harness: sw-* skills and sub-agents for requirements, specs, implementation, verification and documentation, with an installer CLI that writes them into Claude Code, Codex, GitHub Copilot and Cursor. The knowledge-base MCP and the editor tools are separate npm packages.",
6
6
  "author": {
7
7
  "name": "Execuro UG (haftungsbeschränkt)",
@@ -3,7 +3,7 @@ name: sw-design-requirements
3
3
  description: Turn a briefing — chat text or a file, covering one or more features — into a lean, business-only PRD stored as specs/NNNN-slug.md. Runs an interactive clarification loop for the requirement gaps and inconsistencies that actually change the requirements, then scores a weighted confidence %. Use when asked to write, draft, refine, continue, or score a PRD / requirements doc / feature brief for this Shopware project. Never writes a tech spec or answers architecture questions — that's sw-design-solution.
4
4
  when_to_use: Trigger phrases — "write a PRD", "draft requirements", "turn this brief into a PRD", "continue PRD 0003", "is this PRD ready for specification", "raise the confidence on this PRD", "requirements for <feature>".
5
5
  argument-hint: '[file-path | briefing text | specs/NNNN-slug.md to continue] [--editor]'
6
- allowed-tools: Read Write Edit Glob Grep AskUserQuestion Agent Skill Bash(ls *) Bash(mkdir -p specs) Bash(npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 *) mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
6
+ allowed-tools: Read Write Edit Glob Grep AskUserQuestion Agent Skill Bash(ls *) Bash(mkdir -p specs) Bash(npx -y @execuro-sw-ecosystem/sw-specs-editor@latest *) mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
7
7
 
8
8
  ---
9
9
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Runs before the `--editor` hand-off (step 0). The Specs Editor is an **optional** add-on: it is not part of this plugin, and a host that never installed it is a supported, normal setup. `sw-setup` offers to install it.
4
4
 
5
- What is checked is the **skill**, `sw-specs-editor`, because that is what `sw-setup` installs and what the hand-off calls. The skill brings the CLI with it — it invokes `npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0`, which fetches the package on first use.
5
+ What is checked is the **skill**, `sw-specs-editor`, because that is what `sw-setup` installs and what the hand-off calls. The skill brings the CLI with it — it invokes `npx -y @execuro-sw-ecosystem/sw-specs-editor@latest`, which fetches the package on first use.
6
6
 
7
7
  Check: is the `sw-specs-editor` skill available in this session?
8
8
 
@@ -8,8 +8,8 @@ Invoked as `<path> --editor-session <url> --batch <batch.json>` — one note bat
8
8
  - **Full pass on request only.** A review request ("check the whole PRD", "reconcile") runs the full flow: step 2, §11 gap review, missing options/marks/notes filled. Otherwise touched questions get options.
9
9
  - **Scoped agent runs.** Spawn `sw-product-manager`/`sw-shopware-architect` only when a note touches feasibility, §10, or a §11 block changes (one brief per run); else edit, anchor, log alone.
10
10
  - **Preserve on every write:** status tags on item ids (`- **FR-3** [done] …`, also `AC-n`/`BR-n`), the `Diagram:` line, the §11 question blocks and ticks. Rewrite in place; never regenerate.
11
- - **Diagrams.** Domain diagram: `specs/NNNN-slug.domain.graph.json` (business concepts only). Write/update, run `npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 diagram specs/NNNN-slug.domain.graph.json specs/NNNN-slug.domain.excalidraw`, ensure §4 carries `Diagram: specs/NNNN-slug.domain.excalidraw`; never write `.excalidraw` directly, first request only.
12
- - **Progress.** Before each step, before/after each spawn: `npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 emit progress "<step>" --batch <id> --doc prd`.
11
+ - **Diagrams.** Domain diagram: `specs/NNNN-slug.domain.graph.json` (business concepts only). Write/update, run `npx -y @execuro-sw-ecosystem/sw-specs-editor@latest diagram specs/NNNN-slug.domain.graph.json specs/NNNN-slug.domain.excalidraw`, ensure §4 carries `Diagram: specs/NNNN-slug.domain.excalidraw`; never write `.excalidraw` directly, first request only.
12
+ - **Progress.** Before each step, before/after each spawn: `npx -y @execuro-sw-ecosystem/sw-specs-editor@latest emit progress "<step>" --batch <id> --doc prd`.
13
13
  - **Report:** changed blocks, answers (Q ids → anchor), top remaining gap or `none`, confidence %, status, `Agents: <list or none>`.
14
14
 
15
15
  Graph shape (`bin/cli.mjs diagram` input): `{ "title", "direction": "LR", "groups": [{id,label}], "nodes": [{id,label,type: entity|actor|service|external|event|store, group?, note?}], "edges": [{from,to,label?}] }`.
@@ -3,7 +3,7 @@ name: sw-design-solution
3
3
  description: Turn a PRD (specs/NNNN-slug.md) into a technical spec at specs/NNNN-slug-spec.md. Applies TDD — every acceptance criterion gets an implementation plan and e2e coverage, with Shopware toolchain (shopware-cli/PHPStan/ESLint/Stylelint) conventions baked into decisions up front. Runs a clarification loop for the gaps that change the implementation plan, and on the user's say-so extracts project-wide architecture/stack decisions into ADR files (specs/NNNN-slug-adr-<topic>.md) that gate readiness while proposed. Pre-checks vendor/ and the KB before it starts. Use when asked to write, draft, refine, or continue a tech spec / implementation plan. Never edits the source PRD or answers business/requirements questions — that's sw-design-requirements.
4
4
  when_to_use: Trigger phrases — "write the tech spec for PRD 0007", "create an implementation plan for this PRD", "draft the spec", "continue spec 0007", "is this spec ready for implementation".
5
5
  argument-hint: '[specs/NNNN-slug.md | specs/NNNN-slug-spec.md] [--editor]'
6
- allowed-tools: Read Write Edit Glob Grep AskUserQuestion Agent Skill Bash(ls *) Bash(npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 *) WebSearch WebFetch mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
6
+ allowed-tools: Read Write Edit Glob Grep AskUserQuestion Agent Skill Bash(ls *) Bash(npx -y @execuro-sw-ecosystem/sw-specs-editor@latest *) WebSearch WebFetch mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
7
7
  ---
8
8
 
9
9
  # sw-design-solution
@@ -9,8 +9,8 @@ Same procedure/boundary/verification/ADR rules, plus:
9
9
  - **Batch input.** Ticks first — a ticked question with no note is still an answer. `answer`/`[x]` tick → anchor, append Decision Log, delete block (`[adr]` sub-step 3, `[gate]` sub-step 5). `comment`/`free` → this run's briefing (block-bound `path`/`line`–`endLine`/`md`/`quote`/`hash`; verify `md` matches, fall back to `quote`; `selection` → rework only that text). `diagram` → update the graph file. *What*/*why* notes belong to the PRD. First write migrates a pre-template spec; blocks get missing options only when touched.
10
10
  - **Scoped runs.** Re-spawn architect only for an overturned/new decision, QA only for a changed test plan, `sw-product-manager` only for feasibility — together still one message; else edit/verify/anchor/log alone, name agents.
11
11
  - **Preserve:** status tags (`- **AC-2** [partly] (FR-3)`, `- **Decision:** [done] …`), `Diagram:` line, §6 blocks/ticks — rewrite in place, never regenerate.
12
- - **Diagrams.** `specs/NNNN-slug-spec.architecture.graph.json`; run `npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 diagram specs/NNNN-slug-spec.architecture.graph.json specs/NNNN-slug-spec.architecture.excalidraw`, keep §2's `Diagram:` line — never write it directly.
13
- - **Progress.** `npx -y @execuro-sw-ecosystem/sw-specs-editor@0.1.0 emit --since <step-0.5 start> progress "<step>" --batch <id> --doc spec` before/after each step/spawn; `--since` prefixes `+m:ss`.
12
+ - **Diagrams.** `specs/NNNN-slug-spec.architecture.graph.json`; run `npx -y @execuro-sw-ecosystem/sw-specs-editor@latest diagram specs/NNNN-slug-spec.architecture.graph.json specs/NNNN-slug-spec.architecture.excalidraw`, keep §2's `Diagram:` line — never write it directly.
13
+ - **Progress.** `npx -y @execuro-sw-ecosystem/sw-specs-editor@latest emit --since <step-0.5 start> progress "<step>" --batch <id> --doc spec` before/after each step/spawn; `--since` prefixes `+m:ss`.
14
14
  - **Report:** changed blocks; answers (Q ids → anchor); first unmet §7 criterion or `none`; status/confidence/`Open ADRs`; `Agents: <list or none>`; `Timing:`.
15
15
 
16
16
  Graph shape: `{ title, direction: "LR", groups: [{id,label}], nodes: [{id,label,type: entity|actor|service|external|event|store,group?,note?}], edges: [{from,to,label?}] }`.
@@ -3,7 +3,7 @@ name: sw-discover-tender
3
3
  description: Analyse a client tender (RFP, RFI or RFQ) for a Shopware 6 project into one markdown sidecar, <source basename>-analysis.md. Every requirement row gets a class against the installed Shopware version (stock / config / plugin / custom), a three-point person-day estimate, one line of mechanism and proposed scope-lock assumptions the partner accepts by ticking checkboxes — in the file or on the Tender Discovery Tool page (`--editor`); the next run reconciles the ticks, dissolves answered questions and re-estimates. At Ready to submit it exports one CSV per client table with compliance, comment and effort filled in the client's columns. Scope and PD only — never costs, prices, licence fees or budgets. Never designs the solution — that's sw-design-solution.
4
4
  when_to_use: Trigger phrases — "scope this RFP", "analyse the tender", "answer the RFI", "discover RFP 0001", "continue RFP 0001", "reconcile RFP 0001", "export the response for RFP 0001", "is RFP 0001 ready to submit", "open RFP 0001 in the browser", "open the tender tool", "sw-discover-tender specs/rfp-0001-x-analysis.md --editor".
5
5
  argument-hint: '[tender file or folder of exports (.xlsx|.md|.txt|.csv|.pdf) | specs/rfp-NNNN-slug-analysis.md to continue] [--editor] [--batch <n|all>] [--export]'
6
- allowed-tools: Read Write Edit Glob Grep Agent AskUserQuestion Bash(ls *) Bash(mkdir -p specs) Bash(mkdir -p specs/.rfp *) Bash(shasum -a 256 *) Bash(npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 *) Bash(open *) Bash(xdg-open *) Bash(tail *) Bash(grep *) Bash(printf *) mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
6
+ allowed-tools: Read Write Edit Glob Grep Agent AskUserQuestion Bash(ls *) Bash(mkdir -p specs) Bash(mkdir -p specs/.rfp *) Bash(shasum -a 256 *) Bash(npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest *) Bash(open *) Bash(xdg-open *) Bash(tail *) Bash(grep *) Bash(printf *) mcp__ShopwareDevKnowledgeBase__list_docs mcp__ShopwareDevKnowledgeBase__grep_docs mcp__ShopwareDevKnowledgeBase__read_doc mcp__ShopwareDevKnowledgeBase__kb_status
7
7
  ---
8
8
 
9
9
  # sw-discover-tender
@@ -24,7 +24,7 @@ One markdown sidecar per tender, `<source basename>-analysis.md`: class, three-p
24
24
  | Argument | Behaviour |
25
25
  | --- | --- |
26
26
  | `.md` / `.txt` / `.csv` / `.pdf`, or a folder of such exports | New tender: extract, analyse, write `<basename>-analysis.md` next to the source |
27
- | `.xlsx` | Import first, per `reference/procedure.md` step 1 ".xlsx import": `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 import` proposes a mapping (install gate: `reference/editor-session.md` §0), confirmed via `--editor` or a one-line yes/no, before the normalised source and the analysis are set. A refusal (encrypted, `.xls`, `.xlsb`) is relayed verbatim and the run stops |
27
+ | `.xlsx` | Import first, per `reference/procedure.md` step 1 ".xlsx import": `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest import` proposes a mapping (install gate: `reference/editor-session.md` §0), confirmed via `--editor` or a one-line yes/no, before the normalised source and the analysis are set. A refusal (encrypted, `.xls`, `.xlsb`) is relayed verbatim and the run stops |
28
28
  | `.docx` | Stop. One line: export every requirement table as CSV UTF-8 (or paste it as markdown tables, header row kept) and rerun with that file or folder |
29
29
  | `*-analysis.md` | Continue: reconcile, advance, rewrite in place |
30
30
  | `--export`, or "export the response for RFP NNNN" | Continue, then run step 9 if the gate holds |
@@ -5,7 +5,7 @@ The Tender Discovery Tool: a local live page for one analysis document. The skil
5
5
  **The protocol is not in this file.** Run
6
6
 
7
7
  ```
8
- npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 guide
8
+ npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest guide
9
9
  ```
10
10
 
11
11
  and follow it: it is the single source for the xlsx import, start, the batch kinds, poll, emit, redelivery and close, and every command ends with a `next_step:` line. An installed copy of any of that goes stale against a newer CLI. This file adds only what `guide` cannot know — the install gate, the row-batch setting, which opening batch to post, the subagent brief, the follow-up queueing grammar and the close report.
@@ -58,7 +58,7 @@ Invoke it with the Skill tool: skill "sw-discover-tender", args "<analysis path>
58
58
  Append the session's row-batch setting to the args when it is not the default: <--batch n | --batch all>.
59
59
  If the Skill tool is not available to you, read the SKILL.md of the `sw-discover-tender` skill and follow it exactly, including its "Editor mode" section.
60
60
  Rules: never ask the user a question with a structured question tool (Claude Code: `AskUserQuestion`; Codex: `request_user_input`); every gap becomes a §5 block with options; emit progress with
61
- npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 emit progress "<step>" --batch <id>
61
+ npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest emit progress "<step>" --batch <id>
62
62
  before each procedure step and before/after each agent wave; never change a [x] or [-] except by reconciling it; keep every [ ] line whose
63
63
  Evidence / risk or Risk to says "partner"; frozen accepted/rejected lines stay byte-identical; never edit the client's file.
64
64
  Context — last chat entries (newest last):
@@ -111,5 +111,5 @@ Invoked by the editor session (`reference/editor-session.md` in this skill's dir
111
111
  - **Notes.** `comment` notes carry `block`, `blockKind`, `path` (section breadcrumb), `line`–`endLine`, `md` (the block's source line), `quote`, `hash` and sometimes `selection` (the exact text the user highlighted). Open the file at that range under that path, confirm the text matches `md`, fall back to searching for `quote` when lines shifted. By `blockKind`: `req` → the note questions the class, mechanism or estimate: re-spawn the architect for that row only and rewrite the `req` line; `assume` / `global` → rewrite the statement as a new `[ ]` line (a frozen line is never edited; a proposed line may be replaced in place), or adjust `PD saved` when the note is about the figure; `clarify` → the decision text; `question` → reword or re-option the block (keep its id); `section` / `paragraph` / `row` → that text. `free` notes and `chat` are the briefing for the run. No PD figure ever comes from the page: a note asking for a different number is an architect question, not a hand edit.
112
112
  - **A note on a row still `queued` or `analysing`** is not an immediate re-spawn: carry it into that row's own estimate batch and answer it there.
113
113
  - **Preserve on every write.** Frozen `accepted <date>` / `rejected <date>` lines byte-identical; every `[x]` / `[-]` untouched except by reconciling it; partner-proposed `[ ]` lines; `X-n` exclusions the page added; §1.1, §1.2, §8, §9 and the nine section headings; the frontmatter block. Rewrite lines in place, never regenerate from the template. Every write must leave the document parseable — the page re-renders on each one.
114
- - **Progress.** `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 emit progress "<step>" --batch <id>` before each procedure step and before and after each spawn wave; the page shows it. Row status carries the rest: `queued` → `analysing` → `estimated`.
114
+ - **Progress.** `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest emit progress "<step>" --batch <id>` before each procedure step and before and after each spawn wave; the page shows it. Row status carries the rest: `queued` → `analysing` → `estimated`.
115
115
  - **Report.** The 8-line report of step 8 with its `next:` line (plus the 3 export lines); the editor posts it to the page. Never paste the document into the report.
@@ -14,7 +14,7 @@
14
14
 
15
15
  `ls specs`. Keep `rfp-NNNN-` from the input name; else `NNNN` = highest existing + 1, zero-padded, slug = kebab-case `<client>-<project>`. An xlsx is imported and its mapping confirmed first (below). `shasum -a 256` every source file into frontmatter `source`; for an xlsx, the workbook, `import-map.json` and every CSV. Continue mode: keep path, number and slug; never renumber, never a second file for the same tender.
16
16
 
17
- **.xlsx import.** Install gate first, per `reference/editor-session.md` §0: the `sw-tender-discovery-tool` skill must be installed; missing → stop, do not import. `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 import --source <file>` reads the workbook (hidden and `_` sheets never leave it) and proposes a mapping — which tabs are requirement tables, where each header sits, what each column means, which tokens the dropdowns allow. **With `--editor`** the user confirms it on the steering screen. **Without it**, print the proposed table the command listed, ask the user in one line whether it is right, and on a yes run `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 import --source <file> --map --accept-proposed`; if a tab or a column is wrong, say so and rerun with `--editor`. Either way the confirmed `import-map.json` and the normalised `<source dir>/<basename>/<pos>-<sheet-slug>.csv` are then the source, and the analysis lands next to the workbook. A refusal (encrypted, `.xls`, `.xlsb`) is relayed verbatim and the run stops.
17
+ **.xlsx import.** Install gate first, per `reference/editor-session.md` §0: the `sw-tender-discovery-tool` skill must be installed; missing → stop, do not import. `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest import --source <file>` reads the workbook (hidden and `_` sheets never leave it) and proposes a mapping — which tabs are requirement tables, where each header sits, what each column means, which tokens the dropdowns allow. **With `--editor`** the user confirms it on the steering screen. **Without it**, print the proposed table the command listed, ask the user in one line whether it is right, and on a yes run `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest import --source <file> --map --accept-proposed`; if a tab or a column is wrong, say so and rerun with `--editor`. Either way the confirmed `import-map.json` and the normalised `<source dir>/<basename>/<pos>-<sheet-slug>.csv` are then the source, and the analysis lands next to the workbook. A refusal (encrypted, `.xls`, `.xlsb`) is relayed verbatim and the run stops.
18
18
 
19
19
  ### 2. Reconcile — first step of every continue run, before any spawn
20
20
 
@@ -93,6 +93,6 @@ When the gate below holds, one more line: "Generate the response CSV?" Then end.
93
93
  - **Assemble and check, delegated**: one `sw-tender-editor` per client table, all in one message, cap 10, brief `§ASSEMBLE`. Each concatenates its cluster CSVs behind the client's header row into `<source basename>-response-<n>-<table-slug>.csv` (`<n>` and slug from the Source map) and runs the file checks: row count and id sequence equal the source table; header equals the client's; every compliance value in the allowed list; every effort cell a number, or empty with the blocked comment; no `A-`, `CQ-`, `Q-`, `RC-`, `.a`, `.c`, `PD saved`, `EUR`, `€`; no proposed or rejected assumption text; constant column count. Any failure → the agent deletes the file and returns the failing check. The orchestrator never reads the CSVs.
94
94
  - **Check the sums** itself, from the returned per-table effort sums: they must equal §2 per priority. Mismatch → delete the files, report the check.
95
95
  - **Write back.** Frontmatter `export: {date, files, source_sha256, stale: false}`; one `C-n`: `Response exported: <files> files, <rows> rows, Must <n> PD`.
96
- - **Workbook copy.** After every response CSV passes its checks, run `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@0.1.0 export --xlsx --source <file>`: it writes `<source basename>-response.xlsx`, a copy of the client's own workbook with compliance, comment and effort filled in from those CSVs, styles and dropdowns intact. The client's original is never written. Only for an xlsx tender with a confirmed mapping; a CSV/markdown tender stops at the CSVs.
96
+ - **Workbook copy.** After every response CSV passes its checks, run `npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest export --xlsx --source <file>`: it writes `<source basename>-response.xlsx`, a copy of the client's own workbook with compliance, comment and effort filled in from those CSVs, styles and dropdowns intact. The client's original is never written. Only for an xlsx tender with a confirmed mapping; a CSV/markdown tender stops at the CSVs.
97
97
  - **Report** three lines: files with row counts · Must / Should / Could as exported · checks passed or the failing check.
98
98
  - Same analysis and same source give byte-identical files.
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: sw-setup
3
- description: Print one environment-readiness table for the project's development/test setup — vendor/, Node, the editor CLIs, shopware-cli, the KB MCP, the acceptance-test project, Playwright browsers, its .env, per-plugin test scaffolding, the project wiki, `.gitignore` and whether the SW AH npm packages are current, plus the installer CLI's own configuration/drift status. Stops when every row is ticked. When rows are missing, asks one yes/no question and delegates the fix to the installer CLI. Use when asked to set up the project, check if the environment is ready, or bootstrap the tests. Never designs, implements or verifies a feature itself — that's sw-design-solution, sw-implement-feature and sw-verify-feature, which call this skill first. Never writes a host configuration file itself — that's the installer CLI.
3
+ description: Print one environment-readiness table for the project's development/test setup — vendor/, Node, the editor CLIs, shopware-cli, the KB MCP, the acceptance-test project, Playwright browsers, its .env, per-plugin test scaffolding, the project wiki, `.gitignore` and whether the SW AH npm packages are current, plus the installer CLI's own configuration/drift status. Stops when every row is ticked. When rows are missing, asks one yes/no question and delegates the fix to the installer CLI. Use when asked to set up the project, check if the environment is ready, or bootstrap the tests. Never designs, implements or verifies a feature itself — that's sw-design-solution, sw-implement-feature and sw-verify-feature, which call this skill first. Never writes a coding agent's configuration file itself — that's the installer CLI.
4
4
  when_to_use: Trigger phrases — "set up the project", "is the environment ready", "bootstrap the tests", "sw-setup".
5
- allowed-tools: Read Glob Grep AskUserQuestion Skill Bash mcp__ShopwareDevKnowledgeBase__kb_status Bash(npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest *)
5
+ allowed-tools: Read Glob Grep AskUserQuestion Skill Bash mcp__ShopwareDevKnowledgeBase__kb_status Bash(npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest *) Bash(npx -y @execuro-sw-ecosystem/sw-specs-editor@latest *) Bash(npx -y @execuro-sw-ecosystem/sw-tender-discovery-tool@latest *)
6
6
  ---
7
7
 
8
8
  # sw-setup
@@ -40,25 +40,27 @@ table from this run's output — it does not re-run `sw-setup`'s checks.
40
40
  Run:
41
41
 
42
42
  ```
43
- npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest status
43
+ npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest status --json
44
44
  ```
45
45
 
46
- It prints one JSON object (`ok`, `next_step`, `help`, and its own
47
- `hosts[]`/`drift[]` configuration state). Alongside it, run every
46
+ `--json` is mandatory for every call this skill makes: without it the CLI
47
+ prints a human summary, not the object below. It prints one JSON object
48
+ (`ok`, `next_step`, `help`, and its own `agents[]`/`drift[]` configuration
49
+ state). Alongside it, run every
48
50
  environment row's check from `reference/rows.md` in this skill's directory —
49
51
  read-only, seconds each: file/directory existence, one version command, one
50
- `kb_status` call, three `npm view` registry lookups (Package updates row) —
51
- the one part of step 1 that touches the network, so it is the slow part.
52
+ `kb_status` call, one `npm view` registry lookup (Package updates row) — the
53
+ one part of step 1 that touches the network, so it is the slow part.
52
54
  Never write, never install, never ask a question in this step.
53
55
 
54
56
  Print one checkbox list, one line per row — the environment rows first, then
55
- one line per configuration item the CLI's `hosts[]`/`drift[]` reports:
57
+ one line per configuration item the CLI's `agents[]`/`drift[]` reports:
56
58
 
57
59
  ```
58
60
  - [x] vendor/ — shopware/core 6.7.13.0
59
61
  - [ ] vendor/ — vendor/bin/phpunit missing (tree built --no-dev)
60
62
  - [ ] Node — 18.x (need >= 20)
61
- - [-] Visual editors (optional) — Specs Editor not installed, Tender tool not installed
63
+ - [-] Visual editors (optional) — Specs Editor installed, Tender tool declined
62
64
  - [x] shopware-cli — 0.16.10
63
65
  - [x] KB MCP — platform: implemented
64
66
  - [ ] Acceptance-test project — tests/acceptance/ missing
@@ -66,7 +68,7 @@ one line per configuration item the CLI's `hosts[]`/`drift[]` reports:
66
68
  - [ ] ATS env — tests/acceptance/.env missing
67
69
  - [x] Plugin tests — AhCheckout: phpunit + jest ok
68
70
  - [ ] Project wiki — docs/project-wiki/ missing
69
- - [ ] Package updates — harness 0.1.0 → 0.1.3, Specs Editor not installed
71
+ - [ ] Package updates — harness 0.1.0 → 0.1.3
70
72
  - [ ] Installer config — .mcp.json entry: drift (from CLI status)
71
73
  ```
72
74
 
@@ -88,7 +90,7 @@ For a missing/drifted configuration row, do not research or plan the fix
88
90
  yourself — the CLI's `plan` command already has it:
89
91
 
90
92
  ```
91
- npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest plan
93
+ npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest plan --json
92
94
  ```
93
95
 
94
96
  List the concrete steps in plain words: environment-row fixes in order
@@ -104,7 +106,7 @@ if you have one (Claude Code: `AskUserQuestion`; Codex: `request_user_input`,
104
106
  which is non-blocking outside Plan mode — so end the turn after asking).
105
107
  Options:
106
108
  - **Yes, run it** — run the environment-row fixes in order, then
107
- `npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest apply --yes`
109
+ `npx -y @execuro-sw-ecosystem/sw-ecosystem-agentic-harness@latest apply --yes --json`
108
110
  for the configuration changes, then re-run step 1 and print the final table.
109
111
  - **No, stop** — stop; the table from step 1 is already on screen.
110
112
 
@@ -124,11 +126,11 @@ Options:
124
126
  the corpus ships already built inside the
125
127
  `@execuro-sw-ecosystem/sw-dev-knowledge-base-mcp` package. If `platform` is
126
128
  not `implemented`, the fix is to check the registration (re-run the
127
- installer CLI's `apply --yes`) or update that package — never build a
129
+ installer CLI's `apply --yes --json`) or update that package — never build a
128
130
  corpus here. Neither is replicated in this skill.
129
- - This skill never writes a host configuration file itself (`.mcp.json`,
130
- permission grants, `.gitignore` lines). Every such write goes through the
131
- installer CLI's `apply --yes`, run only after the user's yes.
131
+ - This skill never writes a coding agent's configuration file itself
132
+ (`.mcp.json`, permission grants, `.gitignore` lines). Every such write goes
133
+ through the installer CLI's `apply --yes --json`, after the user's yes.
132
134
 
133
135
  ### 5. Report
134
136
 
@@ -144,6 +146,6 @@ line:
144
146
 
145
147
  `reference/rows.md` in this skill's directory — the twelve environment rows:
146
148
  check command(s), what "ticked" means, the fix steps verbatim from the
147
- guideline, and which skills the row blocks. Host configuration state (what
149
+ guideline, and which skills the row blocks. Agent configuration state (what
148
150
  gets installed into `.mcp.json`, permissions, `.gitignore`) is not in this
149
151
  file — it comes from the installer CLI's `status`/`plan`/`apply` output.