cyber-sdd 0.7.0 → 0.7.2

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.
Files changed (150) hide show
  1. package/.claude-plugin/plugin.json +1 -2
  2. package/.codex-plugin/plugin.json +1 -2
  3. package/CHANGELOG.md +320 -0
  4. package/agents/sdd-scanner.md +1 -1
  5. package/package.json +11 -12
  6. package/plugin.json +55 -0
  7. package/skills/align-spec/SKILL.md +1 -1
  8. package/skills/align-spec/scripts/align-spec.mjs +6755 -12
  9. package/skills/blast-estimate/README.md +3 -3
  10. package/skills/blast-estimate/scripts/blast-estimate.mjs +601 -12
  11. package/skills/check-field-mandates/scripts/check-field-mandates.mjs +253 -12
  12. package/skills/check-partition-quality/scripts/check-partition-quality.mjs +235 -12
  13. package/skills/check-plan-safety/SKILL.md +2 -3
  14. package/skills/check-plan-safety/scripts/check-plan-safety.mjs +109 -12
  15. package/skills/check-plugin-manifests/scripts/check-plugin-manifests.mjs +250 -12
  16. package/skills/check-project-specs/SKILL.md +1 -1
  17. package/skills/check-project-specs/scripts/check-project-specs.mjs +593 -12
  18. package/skills/check-retired-terms/SKILL.md +2 -3
  19. package/skills/check-retired-terms/scripts/check-retired-terms.mjs +186 -12
  20. package/skills/check-scenario-overlap/SKILL.md +1 -2
  21. package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mjs +177 -12
  22. package/skills/check-spec-references/SKILL.md +2 -2
  23. package/skills/check-spec-references/scripts/check-spec-references.mjs +287 -12
  24. package/skills/check-spec-structure/SKILL.md +1 -2
  25. package/skills/check-spec-structure/scripts/check-spec-structure.mjs +243 -12
  26. package/skills/collision-ladder/README.md +2 -2
  27. package/skills/collision-ladder/scripts/collision-ladder.mjs +7047 -12
  28. package/skills/combat-log-governance/SKILL.md +1 -1
  29. package/skills/concept-index/SKILL.md +1 -1
  30. package/skills/concept-index/scripts/concept-index.mjs +183 -12
  31. package/skills/discover-plans/README.md +3 -3
  32. package/skills/discover-plans/SKILL.md +1 -1
  33. package/skills/discover-plans/scripts/discover-plans.mjs +137 -12
  34. package/skills/discover-specs/README.md +3 -3
  35. package/skills/discover-specs/SKILL.md +1 -1
  36. package/skills/discover-specs/scripts/discover-specs.mjs +321 -12
  37. package/skills/doctrine-loop/SKILL.md +1 -1
  38. package/skills/gate-validation-governance/SKILL.md +1 -1
  39. package/skills/init/README.md +2 -2
  40. package/skills/init/scripts/wire-statusline.mjs +168 -12
  41. package/skills/manage-ignore/README.md +3 -3
  42. package/skills/manage-ignore/SKILL.md +1 -2
  43. package/skills/manage-ignore/scripts/manage-ignore.mjs +285 -12
  44. package/skills/manage-scenario-bridge/README.md +3 -3
  45. package/skills/manage-scenario-bridge/SKILL.md +1 -1
  46. package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mjs +239 -12
  47. package/skills/manage-spec-anchors/README.md +3 -3
  48. package/skills/manage-spec-anchors/SKILL.md +1 -1
  49. package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mjs +310 -12
  50. package/skills/mission-graph/README.md +2 -2
  51. package/skills/mission-graph/SKILL.md +1 -1
  52. package/skills/mission-graph/scripts/mission-graph.mjs +1040 -12
  53. package/skills/pause-mission/SKILL.md +1 -1
  54. package/skills/place-node/SKILL.md +2 -2
  55. package/skills/place-node/scripts/place-node.mjs +117 -12
  56. package/skills/plan-retirement/README.md +2 -2
  57. package/skills/plan-retirement/scripts/retire-plans.mjs +123 -12
  58. package/skills/resolve-governances/README.md +3 -3
  59. package/skills/resolve-governances/SKILL.md +1 -1
  60. package/skills/resolve-governances/scripts/resolve-governances.mjs +352 -12
  61. package/skills/resolve-tracking/SKILL.md +1 -1
  62. package/skills/resolve-tracking/scripts/resolve-tracking.mjs +152 -12
  63. package/skills/scaffold-project-spec/SKILL.md +1 -1
  64. package/skills/spec-gate/README.md +12 -9
  65. package/skills/spec-gate/SKILL.md +2 -2
  66. package/skills/spec-gate/scripts/check-spec-state.mjs +422 -12
  67. package/skills/spec-gate/scripts/check-suite.mjs +6500 -12
  68. package/skills/spec-gate/scripts/classify-edit-class.mjs +6579 -12
  69. package/skills/spec-producer-governance/SKILL.md +2 -2
  70. package/skills/start-mission/SKILL.md +1 -1
  71. package/skills/suite-format-governance/README.md +1 -1
  72. package/skills/suite-format-governance/SKILL.md +1 -1
  73. package/skills/touch-set-correction/README.md +5 -5
  74. package/skills/touch-set-correction/SKILL.md +1 -1
  75. package/skills/touch-set-correction/scripts/touch-set-correction.mjs +6663 -12
  76. package/skills/verify-scenarios/README.md +6 -6
  77. package/skills/verify-scenarios/scripts/verify-scenarios.mjs +6539 -12
  78. package/.plugin/pins.json +0 -3
  79. package/.plugin/plugin.json +0 -19
  80. package/dist/align-spec/scripts/align-spec.js +0 -102
  81. package/dist/check-project-specs/scripts/check-project-specs.js +0 -312
  82. package/dist/check-scenario-overlap/scripts/check-scenario-overlap.js +0 -175
  83. package/dist/check-spec-references/scripts/check-spec-references.js +0 -285
  84. package/dist/check-spec-structure/scripts/check-spec-structure.js +0 -241
  85. package/dist/concept-index/scripts/concept-index.js +0 -181
  86. package/dist/discover-specs/scripts/discover-specs.js +0 -318
  87. package/dist/spec-gate/scripts/check-spec-state.js +0 -420
  88. package/dist/spec-gate/scripts/check-suite.js +0 -317
  89. package/dist/spec-gate/scripts/classify-edit-class.js +0 -263
  90. package/dist/spec-gate/vendor/gherkin-cli.js +0 -6369
  91. package/skills/align-spec/scripts/align-spec.bundle.mjs +0 -6753
  92. package/skills/align-spec/scripts/align-spec.mts +0 -188
  93. package/skills/blast-estimate/scripts/blast-estimate.bundle.mjs +0 -593
  94. package/skills/blast-estimate/scripts/blast-estimate.mts +0 -586
  95. package/skills/check-field-mandates/scripts/check-field-mandates.bundle.mjs +0 -251
  96. package/skills/check-field-mandates/scripts/check-field-mandates.mts +0 -337
  97. package/skills/check-partition-quality/scripts/check-partition-quality.bundle.mjs +0 -233
  98. package/skills/check-partition-quality/scripts/check-partition-quality.mts +0 -338
  99. package/skills/check-plan-safety/scripts/check-plan-safety.bundle.mjs +0 -107
  100. package/skills/check-plan-safety/scripts/check-plan-safety.mts +0 -148
  101. package/skills/check-plugin-manifests/scripts/check-plugin-manifests.bundle.mjs +0 -248
  102. package/skills/check-plugin-manifests/scripts/check-plugin-manifests.mts +0 -303
  103. package/skills/check-project-specs/scripts/check-project-specs.bundle.mjs +0 -584
  104. package/skills/check-project-specs/scripts/check-project-specs.mts +0 -370
  105. package/skills/check-retired-terms/scripts/check-retired-terms.bundle.mjs +0 -184
  106. package/skills/check-retired-terms/scripts/check-retired-terms.mts +0 -293
  107. package/skills/check-scenario-overlap/scripts/check-scenario-overlap.bundle.mjs +0 -175
  108. package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mts +0 -250
  109. package/skills/check-spec-references/scripts/check-spec-references.bundle.mjs +0 -285
  110. package/skills/check-spec-references/scripts/check-spec-references.mts +0 -422
  111. package/skills/check-spec-structure/scripts/check-spec-structure.bundle.mjs +0 -241
  112. package/skills/check-spec-structure/scripts/check-spec-structure.mts +0 -347
  113. package/skills/collision-ladder/scripts/collision-ladder.bundle.mjs +0 -7041
  114. package/skills/collision-ladder/scripts/collision-ladder.mts +0 -662
  115. package/skills/concept-index/scripts/concept-index.bundle.mjs +0 -181
  116. package/skills/concept-index/scripts/concept-index.mts +0 -246
  117. package/skills/discover-plans/scripts/discover-plans.bundle.mjs +0 -135
  118. package/skills/discover-plans/scripts/discover-plans.mts +0 -215
  119. package/skills/discover-specs/scripts/discover-specs.bundle.mjs +0 -319
  120. package/skills/discover-specs/scripts/discover-specs.mts +0 -420
  121. package/skills/init/scripts/wire-statusline.bundle.mjs +0 -166
  122. package/skills/init/scripts/wire-statusline.mts +0 -279
  123. package/skills/manage-ignore/scripts/manage-ignore.bundle.mjs +0 -244
  124. package/skills/manage-ignore/scripts/manage-ignore.mts +0 -297
  125. package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.bundle.mjs +0 -237
  126. package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mts +0 -159
  127. package/skills/manage-spec-anchors/scripts/manage-spec-anchors.bundle.mjs +0 -308
  128. package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mts +0 -331
  129. package/skills/mission-graph/scripts/mission-graph.bundle.mjs +0 -1038
  130. package/skills/mission-graph/scripts/mission-graph.mts +0 -1333
  131. package/skills/place-node/scripts/place-node.bundle.mjs +0 -115
  132. package/skills/place-node/scripts/place-node.mts +0 -158
  133. package/skills/plan-retirement/scripts/retire-plans.bundle.mjs +0 -121
  134. package/skills/plan-retirement/scripts/retire-plans.mts +0 -205
  135. package/skills/resolve-governances/scripts/resolve-governances.bundle.mjs +0 -350
  136. package/skills/resolve-governances/scripts/resolve-governances.mts +0 -518
  137. package/skills/resolve-tracking/scripts/resolve-tracking.bundle.mjs +0 -150
  138. package/skills/resolve-tracking/scripts/resolve-tracking.mts +0 -214
  139. package/skills/spec-gate/scripts/check-spec-state.bundle.mjs +0 -420
  140. package/skills/spec-gate/scripts/check-spec-state.mts +0 -637
  141. package/skills/spec-gate/scripts/check-suite.bundle.mjs +0 -6498
  142. package/skills/spec-gate/scripts/check-suite.mts +0 -538
  143. package/skills/spec-gate/scripts/classify-edit-class.bundle.mjs +0 -6577
  144. package/skills/spec-gate/scripts/classify-edit-class.mts +0 -414
  145. package/skills/spec-gate/vendor/gherkin-cli.d.mts +0 -2
  146. package/skills/spec-gate/vendor/gherkin-cli.mjs +0 -6545
  147. package/skills/touch-set-correction/scripts/touch-set-correction.bundle.mjs +0 -6655
  148. package/skills/touch-set-correction/scripts/touch-set-correction.mts +0 -429
  149. package/skills/verify-scenarios/scripts/verify-scenarios.bundle.mjs +0 -6537
  150. package/skills/verify-scenarios/scripts/verify-scenarios.mts +0 -470
@@ -1,12 +1,285 @@
1
- // Launcher for the engine of the same name. Run it as `node <skill>/scripts/<engine>.mjs`.
2
- // A checkout runs the .mts source. An npm install keeps the skill under node_modules, where Node
3
- // will not strip types, so it runs the self-contained bundle built for the package.
4
- import { spawnSync } from 'node:child_process'
5
- import { fileURLToPath } from 'node:url'
6
-
7
- const self = fileURLToPath(import.meta.url)
8
- const installed = /[\\/]node_modules[\\/]/.test(self)
9
- const target = self.replace(/\.mjs$/, installed ? '.bundle.mjs' : '.mts')
10
- const run = spawnSync(process.execPath, [...process.execArgv, target, ...process.argv.slice(2)], { stdio: 'inherit' })
11
- if (run.error) throw run.error
12
- process.exitCode = run.status ?? 1
1
+ #!/usr/bin/env node
2
+ // Compiled by `universal-plugin plugin build` from src/manage-ignore/manage-ignore.mts. Edit the source, not this file.
3
+ globalThis.__SKILL_SCRIPT__ = {"package":null,"bin":null,"version":"0.7.2","entry":"skills/manage-ignore/scripts/manage-ignore.mjs","commands":{}};
4
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
5
+ import { dirname, join } from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ //#region src/manage-ignore/manage-ignore.mts
8
+ const IGNORE_FILE = ".agents/sdd/.sddignore";
9
+ const SKIP_DIRS = /* @__PURE__ */ new Set([
10
+ "node_modules",
11
+ ".git",
12
+ "dist",
13
+ ".turbo",
14
+ ".next",
15
+ "coverage"
16
+ ]);
17
+ function splitLines(text) {
18
+ const lines = text.split("\n");
19
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
20
+ return lines;
21
+ }
22
+ function readIgnoreLines(root) {
23
+ const file = join(root, IGNORE_FILE);
24
+ if (!existsSync(file)) return [];
25
+ try {
26
+ return splitLines(readFileSync(file, "utf8"));
27
+ } catch {
28
+ return [];
29
+ }
30
+ }
31
+ function writeIgnoreLines(root, lines) {
32
+ const file = join(root, IGNORE_FILE);
33
+ mkdirSync(dirname(file), { recursive: true });
34
+ writeFileSync(file, lines.length === 0 ? "" : `${lines.join("\n")}\n`);
35
+ }
36
+ function isRuleLine(line) {
37
+ const t = line.trim();
38
+ return t !== "" && !t.startsWith("#");
39
+ }
40
+ function listRules(root) {
41
+ return readIgnoreLines(root).filter(isRuleLine).map((l) => l.trim());
42
+ }
43
+ function hasUnclosedBracket(s) {
44
+ let i = 0;
45
+ while (i < s.length) {
46
+ if (s[i] === "\\") {
47
+ i += 2;
48
+ continue;
49
+ }
50
+ if (s[i] === "[") {
51
+ const close = s.indexOf("]", i + 1);
52
+ if (close === -1) return true;
53
+ i = close + 1;
54
+ continue;
55
+ }
56
+ i++;
57
+ }
58
+ return false;
59
+ }
60
+ function isValidPattern(pattern) {
61
+ let s = pattern;
62
+ if (s.startsWith("!")) s = s.slice(1);
63
+ s = s.replace(/^\s+|\s+$/g, "");
64
+ if (s === "" || s.startsWith("#")) return false;
65
+ if (hasUnclosedBracket(s)) return false;
66
+ return true;
67
+ }
68
+ function addRule(root, pattern) {
69
+ const p = pattern.trim();
70
+ if (!isValidPattern(p)) return {
71
+ ok: false,
72
+ reason: "malformed gitignore pattern"
73
+ };
74
+ const lines = readIgnoreLines(root);
75
+ if (lines.some((l) => l.trim() === p)) return {
76
+ ok: true,
77
+ changed: false,
78
+ rules: listRules(root),
79
+ message: "already present"
80
+ };
81
+ const next = [...lines, p];
82
+ writeIgnoreLines(root, next);
83
+ return {
84
+ ok: true,
85
+ changed: true,
86
+ rules: next.filter(isRuleLine).map((l) => l.trim()),
87
+ message: `added ${p}`
88
+ };
89
+ }
90
+ function removeRule(root, pattern) {
91
+ const p = pattern.trim();
92
+ const lines = readIgnoreLines(root);
93
+ const next = lines.filter((l) => l.trim() !== p);
94
+ if (next.length === lines.length) return {
95
+ ok: true,
96
+ changed: false,
97
+ rules: listRules(root),
98
+ message: "nothing was removed"
99
+ };
100
+ writeIgnoreLines(root, next);
101
+ return {
102
+ ok: true,
103
+ changed: true,
104
+ rules: next.filter(isRuleLine).map((l) => l.trim()),
105
+ message: `removed ${p}`
106
+ };
107
+ }
108
+ function inducePatterns(_root, samplePath) {
109
+ const normalized = samplePath.trim().replace(/\\/g, "/");
110
+ if (normalized.startsWith("/")) return {
111
+ ok: false,
112
+ reason: "path is not repo-relative (absolute)"
113
+ };
114
+ const rel = normalized.replace(/\/+$/g, "");
115
+ if (rel === "" || /(^|\/)\.\.(\/|$)/.test(rel)) return {
116
+ ok: false,
117
+ reason: "path is not repo-relative"
118
+ };
119
+ const generalized = `**/${rel.split("/").pop() ?? rel}`;
120
+ return {
121
+ ok: true,
122
+ candidates: generalized === rel ? [rel] : [rel, generalized]
123
+ };
124
+ }
125
+ function tokenize(pat) {
126
+ const tokens = [];
127
+ for (let i = 0; i < pat.length; i++) {
128
+ const c = pat[i];
129
+ if (c === "*") {
130
+ if (pat[i + 1] === "*") {
131
+ i++;
132
+ if (pat[i + 1] === "/") {
133
+ i++;
134
+ tokens.push({ kind: "deepdir" });
135
+ } else tokens.push({ kind: "deep" });
136
+ } else tokens.push({ kind: "star" });
137
+ } else if (c === "?") tokens.push({ kind: "one" });
138
+ else if (c === "[") {
139
+ let j = i + 1;
140
+ const negated = pat[j] === "!";
141
+ if (negated) j++;
142
+ let chars = "";
143
+ while (j < pat.length && pat[j] !== "]") chars += pat[j++];
144
+ tokens.push({
145
+ kind: "class",
146
+ negated,
147
+ chars
148
+ });
149
+ i = j;
150
+ } else tokens.push({
151
+ kind: "lit",
152
+ ch: c
153
+ });
154
+ }
155
+ return tokens;
156
+ }
157
+ function classHas(chars, ch) {
158
+ for (let k = 0; k < chars.length; k++) if (chars[k + 1] === "-" && k + 2 < chars.length) {
159
+ if (ch >= chars[k] && ch <= chars[k + 2]) return true;
160
+ k += 2;
161
+ } else if (chars[k] === ch) return true;
162
+ return false;
163
+ }
164
+ function matchTokens(tokens, path, start) {
165
+ const seen = /* @__PURE__ */ new Set();
166
+ const walk = (ti, pi) => {
167
+ const key = ti * (path.length + 1) + pi;
168
+ if (seen.has(key)) return false;
169
+ seen.add(key);
170
+ if (ti === tokens.length) return pi === path.length || path[pi] === "/";
171
+ const t = tokens[ti];
172
+ switch (t.kind) {
173
+ case "lit": return path[pi] === t.ch && walk(ti + 1, pi + 1);
174
+ case "one": return pi < path.length && path[pi] !== "/" && walk(ti + 1, pi + 1);
175
+ case "class": return pi < path.length && classHas(t.chars, path[pi]) !== t.negated && walk(ti + 1, pi + 1);
176
+ case "star": for (let k = pi;; k++) {
177
+ if (walk(ti + 1, k)) return true;
178
+ if (k >= path.length || path[k] === "/") return false;
179
+ }
180
+ case "deep":
181
+ for (let k = pi; k <= path.length; k++) if (walk(ti + 1, k)) return true;
182
+ return false;
183
+ case "deepdir":
184
+ if (walk(ti + 1, pi)) return true;
185
+ for (let k = pi; k < path.length; k++) if (path[k] === "/" && walk(ti + 1, k + 1)) return true;
186
+ return false;
187
+ }
188
+ };
189
+ return walk(0, start);
190
+ }
191
+ function matchesPattern(pattern, path) {
192
+ let pat = pattern.startsWith("!") ? pattern.slice(1) : pattern;
193
+ if (pat.endsWith("/")) pat = pat.slice(0, -1);
194
+ let anchored = pat.startsWith("/");
195
+ if (anchored) pat = pat.slice(1);
196
+ if (pat.includes("/")) anchored = true;
197
+ const tokens = tokenize(pat);
198
+ if (matchTokens(tokens, path, 0)) return true;
199
+ if (anchored) return false;
200
+ for (let k = 0; k < path.length; k++) if (path[k] === "/" && matchTokens(tokens, path, k + 1)) return true;
201
+ return false;
202
+ }
203
+ function walkTree(root) {
204
+ const out = [];
205
+ const walk = (rel) => {
206
+ let entries;
207
+ try {
208
+ entries = readdirSync(join(root, rel), { withFileTypes: true });
209
+ } catch {
210
+ return;
211
+ }
212
+ for (const e of entries) {
213
+ if (SKIP_DIRS.has(e.name)) continue;
214
+ const child = rel ? `${rel}/${e.name}` : e.name;
215
+ out.push(child);
216
+ if (e.isDirectory()) walk(child);
217
+ }
218
+ };
219
+ walk("");
220
+ return out.sort();
221
+ }
222
+ function previewPattern(root, pattern) {
223
+ const p = pattern.trim();
224
+ if (!isValidPattern(p)) return {
225
+ ok: false,
226
+ reason: "malformed gitignore pattern"
227
+ };
228
+ return {
229
+ ok: true,
230
+ negated: p.startsWith("!"),
231
+ matches: walkTree(root).filter((path) => matchesPattern(p, path))
232
+ };
233
+ }
234
+ function flag(argv, name) {
235
+ const i = argv.indexOf(name);
236
+ return i === -1 ? void 0 : argv[i + 1];
237
+ }
238
+ function main(argv) {
239
+ const root = flag(argv, "--root") ?? ".";
240
+ const w = (s) => process.stdout.write(`${s}\n`);
241
+ if (argv.includes("--list")) {
242
+ for (const rule of listRules(root)) w(rule);
243
+ return 0;
244
+ }
245
+ if (argv.includes("--add")) {
246
+ const r = addRule(root, flag(argv, "--add") ?? "");
247
+ w(r.ok ? r.message : `refused: ${r.reason}`);
248
+ return r.ok ? 0 : 1;
249
+ }
250
+ if (argv.includes("--remove")) {
251
+ const r = removeRule(root, flag(argv, "--remove") ?? "");
252
+ w(r.ok ? r.message : `refused: ${r.reason}`);
253
+ return r.ok ? 0 : 1;
254
+ }
255
+ if (argv.includes("--induce")) {
256
+ const r = inducePatterns(root, flag(argv, "--induce") ?? "");
257
+ if (!r.ok) {
258
+ w(`unusable: ${r.reason}`);
259
+ return 1;
260
+ }
261
+ w("Candidate ignore patterns:");
262
+ for (const c of r.candidates) w(` ${c}`);
263
+ return 0;
264
+ }
265
+ if (argv.includes("--preview")) {
266
+ const r = previewPattern(root, flag(argv, "--preview") ?? "");
267
+ if (!r.ok) {
268
+ w(`invalid: ${r.reason}`);
269
+ return 1;
270
+ }
271
+ const verb = r.negated ? "re-track" : "ignore";
272
+ if (r.matches.length === 0) {
273
+ w(`This pattern would ${verb} no path.`);
274
+ return 0;
275
+ }
276
+ w(`This pattern would ${verb}:`);
277
+ for (const m of r.matches) w(` ${m}`);
278
+ return 0;
279
+ }
280
+ w("usage: manage-ignore --list | --add <p> | --remove <p> | --induce <path> | --preview <p>");
281
+ return 0;
282
+ }
283
+ if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
284
+ //#endregion
285
+ export { addRule, inducePatterns, isRuleLine, isValidPattern, listRules, main, matchesPattern, previewPattern, readIgnoreLines, removeRule, splitLines };
@@ -3,12 +3,12 @@
3
3
  The concrete engine for `<project-path>/.agents/sdd/scenario-bridge.toml` — the one-time
4
4
  per-project wiring the `verify-scenarios` bridge and the impl-judge step-0 consumption both read. A
5
5
  non-user-invocable skill, loaded in-session by the `manage` gateway (Setup & discovery), carrying a
6
- self-contained `.mts` script that lists / scaffolds / adds sources so users never hand-author the
6
+ self-contained `.mjs` script that lists / scaffolds / adds sources so users never hand-author the
7
7
  config.
8
8
 
9
9
  - **Skill contract:** [`SKILL.md`](./SKILL.md)
10
- - **Script:** [`scripts/manage-scenario-bridge.mts`](./scripts/manage-scenario-bridge.mts)
11
- - **Tests:** [`scripts/manage-scenario-bridge.test.mts`](./scripts/manage-scenario-bridge.test.mts) (`node:test`)
10
+ - **Script:** [`scripts/manage-scenario-bridge.mjs`](./scripts/manage-scenario-bridge.mjs)
11
+ - **Tests:** [`src/manage-scenario-bridge/manage-scenario-bridge.test.mts`](../../src/manage-scenario-bridge/manage-scenario-bridge.test.mts) (`node:test`)
12
12
 
13
13
  ```bash
14
14
  node scripts/manage-scenario-bridge.mjs --project-path packages/cyberlegion --list
@@ -13,7 +13,7 @@ per-project wiring the [`verify-scenarios`](../verify-scenarios/) bridge and the
13
13
  step-0 consumption both read. It is the **write** side of that config (`verify-scenarios` is the
14
14
  read side). It exists so a user wires a project's scenario bridge through a clean interface instead
15
15
  of hand-authoring the TOML. Loaded **in-session** by the `manage` gateway (Setup & discovery group);
16
- it carries a self-contained `.mts` script (the repo's node-≥23.6 / no-deps convention).
16
+ it carries a self-contained `.mjs` script (compiled from `src/`; no runtime deps, Node ≥22.11).
17
17
 
18
18
  ## The file it curates
19
19
 
@@ -1,12 +1,239 @@
1
- // Launcher for the engine of the same name. Run it as `node <skill>/scripts/<engine>.mjs`.
2
- // A checkout runs the .mts source. An npm install keeps the skill under node_modules, where Node
3
- // will not strip types, so it runs the self-contained bundle built for the package.
4
- import { spawnSync } from 'node:child_process'
5
- import { fileURLToPath } from 'node:url'
6
-
7
- const self = fileURLToPath(import.meta.url)
8
- const installed = /[\\/]node_modules[\\/]/.test(self)
9
- const target = self.replace(/\.mjs$/, installed ? '.bundle.mjs' : '.mts')
10
- const run = spawnSync(process.execPath, [...process.execArgv, target, ...process.argv.slice(2)], { stdio: 'inherit' })
11
- if (run.error) throw run.error
12
- process.exitCode = run.status ?? 1
1
+ #!/usr/bin/env node
2
+ // Compiled by `universal-plugin plugin build` from src/manage-scenario-bridge/manage-scenario-bridge.mts. Edit the source, not this file.
3
+ globalThis.__SKILL_SCRIPT__ = {"package":null,"bin":null,"version":"0.7.2","entry":"skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mjs","commands":{}};
4
+ import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
5
+ import { dirname, join } from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ //#region src/vendor/gherkin-cli.mjs
8
+ var TokenType;
9
+ (function(TokenType) {
10
+ TokenType[TokenType["None"] = 0] = "None";
11
+ TokenType[TokenType["EOF"] = 1] = "EOF";
12
+ TokenType[TokenType["Empty"] = 2] = "Empty";
13
+ TokenType[TokenType["Comment"] = 3] = "Comment";
14
+ TokenType[TokenType["TagLine"] = 4] = "TagLine";
15
+ TokenType[TokenType["FeatureLine"] = 5] = "FeatureLine";
16
+ TokenType[TokenType["RuleLine"] = 6] = "RuleLine";
17
+ TokenType[TokenType["BackgroundLine"] = 7] = "BackgroundLine";
18
+ TokenType[TokenType["ScenarioLine"] = 8] = "ScenarioLine";
19
+ TokenType[TokenType["ExamplesLine"] = 9] = "ExamplesLine";
20
+ TokenType[TokenType["StepLine"] = 10] = "StepLine";
21
+ TokenType[TokenType["DocStringSeparator"] = 11] = "DocStringSeparator";
22
+ TokenType[TokenType["TableRow"] = 12] = "TableRow";
23
+ TokenType[TokenType["Language"] = 13] = "Language";
24
+ TokenType[TokenType["Other"] = 14] = "Other";
25
+ })(TokenType || (TokenType = {}));
26
+ var RuleType;
27
+ (function(RuleType) {
28
+ RuleType[RuleType["None"] = 0] = "None";
29
+ RuleType[RuleType["_EOF"] = 1] = "_EOF";
30
+ RuleType[RuleType["_Empty"] = 2] = "_Empty";
31
+ RuleType[RuleType["_Comment"] = 3] = "_Comment";
32
+ RuleType[RuleType["_TagLine"] = 4] = "_TagLine";
33
+ RuleType[RuleType["_FeatureLine"] = 5] = "_FeatureLine";
34
+ RuleType[RuleType["_RuleLine"] = 6] = "_RuleLine";
35
+ RuleType[RuleType["_BackgroundLine"] = 7] = "_BackgroundLine";
36
+ RuleType[RuleType["_ScenarioLine"] = 8] = "_ScenarioLine";
37
+ RuleType[RuleType["_ExamplesLine"] = 9] = "_ExamplesLine";
38
+ RuleType[RuleType["_StepLine"] = 10] = "_StepLine";
39
+ RuleType[RuleType["_DocStringSeparator"] = 11] = "_DocStringSeparator";
40
+ RuleType[RuleType["_TableRow"] = 12] = "_TableRow";
41
+ RuleType[RuleType["_Language"] = 13] = "_Language";
42
+ RuleType[RuleType["_Other"] = 14] = "_Other";
43
+ RuleType[RuleType["GherkinDocument"] = 15] = "GherkinDocument";
44
+ RuleType[RuleType["Feature"] = 16] = "Feature";
45
+ RuleType[RuleType["FeatureHeader"] = 17] = "FeatureHeader";
46
+ RuleType[RuleType["Rule"] = 18] = "Rule";
47
+ RuleType[RuleType["RuleHeader"] = 19] = "RuleHeader";
48
+ RuleType[RuleType["Background"] = 20] = "Background";
49
+ RuleType[RuleType["ScenarioDefinition"] = 21] = "ScenarioDefinition";
50
+ RuleType[RuleType["Scenario"] = 22] = "Scenario";
51
+ RuleType[RuleType["ExamplesDefinition"] = 23] = "ExamplesDefinition";
52
+ RuleType[RuleType["Examples"] = 24] = "Examples";
53
+ RuleType[RuleType["ExamplesTable"] = 25] = "ExamplesTable";
54
+ RuleType[RuleType["Step"] = 26] = "Step";
55
+ RuleType[RuleType["StepArg"] = 27] = "StepArg";
56
+ RuleType[RuleType["DataTable"] = 28] = "DataTable";
57
+ RuleType[RuleType["DocString"] = 29] = "DocString";
58
+ RuleType[RuleType["Tags"] = 30] = "Tags";
59
+ RuleType[RuleType["DescriptionHelper"] = 31] = "DescriptionHelper";
60
+ RuleType[RuleType["Description"] = 32] = "Description";
61
+ })(RuleType || (RuleType = {}));
62
+ var AttachmentContentEncoding;
63
+ (function(AttachmentContentEncoding) {
64
+ AttachmentContentEncoding["IDENTITY"] = "IDENTITY";
65
+ AttachmentContentEncoding["BASE64"] = "BASE64";
66
+ })(AttachmentContentEncoding || (AttachmentContentEncoding = {}));
67
+ var HookType;
68
+ (function(HookType) {
69
+ HookType["BEFORE_TEST_RUN"] = "BEFORE_TEST_RUN";
70
+ HookType["AFTER_TEST_RUN"] = "AFTER_TEST_RUN";
71
+ HookType["BEFORE_TEST_CASE"] = "BEFORE_TEST_CASE";
72
+ HookType["AFTER_TEST_CASE"] = "AFTER_TEST_CASE";
73
+ HookType["BEFORE_TEST_STEP"] = "BEFORE_TEST_STEP";
74
+ HookType["AFTER_TEST_STEP"] = "AFTER_TEST_STEP";
75
+ })(HookType || (HookType = {}));
76
+ var PickleStepType;
77
+ (function(PickleStepType) {
78
+ PickleStepType["UNKNOWN"] = "Unknown";
79
+ PickleStepType["CONTEXT"] = "Context";
80
+ PickleStepType["ACTION"] = "Action";
81
+ PickleStepType["OUTCOME"] = "Outcome";
82
+ })(PickleStepType || (PickleStepType = {}));
83
+ var SourceMediaType;
84
+ (function(SourceMediaType) {
85
+ SourceMediaType["TEXT_X_CUCUMBER_GHERKIN_PLAIN"] = "text/x.cucumber.gherkin+plain";
86
+ SourceMediaType["TEXT_X_CUCUMBER_GHERKIN_MARKDOWN"] = "text/x.cucumber.gherkin+markdown";
87
+ })(SourceMediaType || (SourceMediaType = {}));
88
+ var StepDefinitionPatternType;
89
+ (function(StepDefinitionPatternType) {
90
+ StepDefinitionPatternType["CUCUMBER_EXPRESSION"] = "CUCUMBER_EXPRESSION";
91
+ StepDefinitionPatternType["REGULAR_EXPRESSION"] = "REGULAR_EXPRESSION";
92
+ })(StepDefinitionPatternType || (StepDefinitionPatternType = {}));
93
+ var StepKeywordType;
94
+ (function(StepKeywordType) {
95
+ StepKeywordType["UNKNOWN"] = "Unknown";
96
+ StepKeywordType["CONTEXT"] = "Context";
97
+ StepKeywordType["ACTION"] = "Action";
98
+ StepKeywordType["OUTCOME"] = "Outcome";
99
+ StepKeywordType["CONJUNCTION"] = "Conjunction";
100
+ })(StepKeywordType || (StepKeywordType = {}));
101
+ var TestStepResultStatus;
102
+ (function(TestStepResultStatus) {
103
+ TestStepResultStatus["UNKNOWN"] = "UNKNOWN";
104
+ TestStepResultStatus["PASSED"] = "PASSED";
105
+ TestStepResultStatus["SKIPPED"] = "SKIPPED";
106
+ TestStepResultStatus["PENDING"] = "PENDING";
107
+ TestStepResultStatus["UNDEFINED"] = "UNDEFINED";
108
+ TestStepResultStatus["AMBIGUOUS"] = "AMBIGUOUS";
109
+ TestStepResultStatus["FAILED"] = "FAILED";
110
+ })(TestStepResultStatus || (TestStepResultStatus = {}));
111
+ var KeywordPrefix;
112
+ (function(KeywordPrefix) {
113
+ KeywordPrefix["BULLET"] = "^(\\s*[*+-]\\s*)";
114
+ KeywordPrefix["HEADER"] = "^(#{1,6}\\s)";
115
+ })(KeywordPrefix || (KeywordPrefix = {}));
116
+ StepKeywordType.UNKNOWN, PickleStepType.UNKNOWN, StepKeywordType.CONTEXT, PickleStepType.CONTEXT, StepKeywordType.ACTION, PickleStepType.ACTION, StepKeywordType.OUTCOME, PickleStepType.OUTCOME, StepKeywordType.CONJUNCTION;
117
+ //#endregion
118
+ //#region src/verify-scenarios/verify-scenarios.mts
119
+ function parseSourcesToml(text) {
120
+ const out = [];
121
+ const blocks = text.split(/(?=^\s*\[\[source\]\]\s*$)/m).filter((b) => /^\s*\[\[source\]\]\s*$/m.test(b));
122
+ for (const block of blocks) {
123
+ const body = block.replace(/^\s*\[\[source\]\]\s*$/m, "");
124
+ const fields = {};
125
+ for (const m of body.matchAll(/^\s*([A-Za-z_][\w-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')\s*$/gm)) fields[m[1]] = m[2] ?? m[3] ?? "";
126
+ if (!fields.adapter || !fields.reportPath) continue;
127
+ out.push({
128
+ adapter: fields.adapter,
129
+ command: fields.command,
130
+ reportPath: fields.reportPath
131
+ });
132
+ }
133
+ return out;
134
+ }
135
+ if (process.argv[1] && false);
136
+ //#endregion
137
+ //#region src/manage-scenario-bridge/manage-scenario-bridge.mts
138
+ const CONFIG_REL_PATH = ".agents/sdd/scenario-bridge.toml";
139
+ function configPath(projectPath) {
140
+ return join(projectPath, CONFIG_REL_PATH);
141
+ }
142
+ function listSources(projectPath) {
143
+ const file = configPath(projectPath);
144
+ if (!existsSync(file)) return [];
145
+ try {
146
+ return parseSourcesToml(readFileSync(file, "utf8"));
147
+ } catch {
148
+ return [];
149
+ }
150
+ }
151
+ function renderBlock(source) {
152
+ return [
153
+ "[[source]]",
154
+ `adapter = "${source.adapter}"`,
155
+ ...source.command !== void 0 ? [`command = "${source.command}"`] : [],
156
+ `reportPath = "${source.reportPath}"`
157
+ ].join("\n");
158
+ }
159
+ function validateInput(input) {
160
+ if (!input.adapter || !input.reportPath) return {
161
+ ok: false,
162
+ reason: "a source needs both adapter and reportPath"
163
+ };
164
+ return {
165
+ ok: true,
166
+ adapter: input.adapter,
167
+ command: input.command,
168
+ reportPath: input.reportPath
169
+ };
170
+ }
171
+ function scaffoldSource(projectPath, input) {
172
+ const valid = validateInput(input);
173
+ if (!valid.ok) return valid;
174
+ const file = configPath(projectPath);
175
+ if (existsSync(file)) return {
176
+ ok: false,
177
+ reason: "scenario-bridge.toml already exists; use add to append a source"
178
+ };
179
+ mkdirSync(dirname(file), { recursive: true });
180
+ writeFileSync(file, `${renderBlock(valid)}\n`);
181
+ const sources = listSources(projectPath);
182
+ return {
183
+ ok: true,
184
+ message: `scaffolded ${file}`,
185
+ sources
186
+ };
187
+ }
188
+ function addSource(projectPath, input) {
189
+ const valid = validateInput(input);
190
+ if (!valid.ok) return valid;
191
+ const file = configPath(projectPath);
192
+ if (!existsSync(file)) return {
193
+ ok: false,
194
+ reason: "scenario-bridge.toml does not exist yet; use scaffold to create it first"
195
+ };
196
+ const existing = readFileSync(file, "utf8");
197
+ const sep = existing.endsWith("\n") ? "" : "\n";
198
+ writeFileSync(file, `${existing}${sep}\n${renderBlock(valid)}\n`);
199
+ const sources = listSources(projectPath);
200
+ return {
201
+ ok: true,
202
+ message: `added a source to ${file}`,
203
+ sources
204
+ };
205
+ }
206
+ function flag(argv, name) {
207
+ const i = argv.indexOf(name);
208
+ return i === -1 ? void 0 : argv[i + 1];
209
+ }
210
+ function inputFromArgv(argv) {
211
+ return {
212
+ adapter: flag(argv, "--adapter"),
213
+ command: flag(argv, "--command"),
214
+ reportPath: flag(argv, "--report-path")
215
+ };
216
+ }
217
+ function main(argv) {
218
+ const projectPath = flag(argv, "--project-path") ?? ".";
219
+ const w = (s) => process.stdout.write(`${s}\n`);
220
+ if (argv.includes("--list")) {
221
+ for (const s of listSources(projectPath)) w(`${s.adapter}${s.command ? ` (${s.command})` : ""} -> ${s.reportPath}`);
222
+ return 0;
223
+ }
224
+ if (argv.includes("--scaffold")) {
225
+ const r = scaffoldSource(projectPath, inputFromArgv(argv));
226
+ w(r.ok ? r.message : `refused: ${r.reason}`);
227
+ return r.ok ? 0 : 1;
228
+ }
229
+ if (argv.includes("--add")) {
230
+ const r = addSource(projectPath, inputFromArgv(argv));
231
+ w(r.ok ? r.message : `refused: ${r.reason}`);
232
+ return r.ok ? 0 : 1;
233
+ }
234
+ w("usage: manage-scenario-bridge --project-path <dir> --list | --scaffold --adapter <a> [--command <c>] --report-path <p> | --add --adapter <a> [--command <c>] --report-path <p>");
235
+ return 0;
236
+ }
237
+ if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
238
+ //#endregion
239
+ export { addSource, configPath, listSources, main, scaffoldSource };
@@ -2,13 +2,13 @@
2
2
 
3
3
  The concrete engine for the SDD **spec-anchors** config — the opt-in registry of extra spec anchors
4
4
  `discover-specs` scans on top of the three fixed conventions (ADR-0019). A non-user-invocable skill,
5
- loaded in-session by the `manage` gateway (Housekeeping), carrying a self-contained `.mts` script
5
+ loaded in-session by the `manage` gateway (Housekeeping), carrying a self-contained `.mjs` script
6
6
  that lists / CRUDs / induces / previews the anchors so users never hand-edit
7
7
  `.agents/sdd/spec-anchors.toml`.
8
8
 
9
9
  - **Skill contract:** [`SKILL.md`](./SKILL.md)
10
- - **Script:** [`scripts/manage-spec-anchors.mts`](./scripts/manage-spec-anchors.mts)
11
- - **Tests:** [`scripts/manage-spec-anchors.test.mts`](./scripts/manage-spec-anchors.test.mts) (`node:test`)
10
+ - **Script:** [`scripts/manage-spec-anchors.mjs`](./scripts/manage-spec-anchors.mjs)
11
+ - **Tests:** [`src/manage-spec-anchors/manage-spec-anchors.test.mts`](../../src/manage-spec-anchors/manage-spec-anchors.test.mts) (`node:test`)
12
12
 
13
13
  ```bash
14
14
  node scripts/manage-spec-anchors.mjs --list
@@ -12,7 +12,7 @@ The concrete engine for the SDD **spec-anchors** config — the opt-in registry
12
12
  anchors that `discover-specs` scans on top of the three fixed conventions (ADR-0019). It exists so a
13
13
  user curates those anchors through a clean interface instead of hand-editing
14
14
  `.agents/sdd/spec-anchors.toml`. Loaded **in-session** by the `manage` gateway (Housekeeping group);
15
- it carries a self-contained `.mts` script (the repo's node-≥23.6 / no-deps convention).
15
+ it carries a self-contained `.mjs` script (compiled from `src/`; no runtime deps, Node ≥22.11).
16
16
 
17
17
  ## The config it curates
18
18