cyber-sdd 0.6.0 → 0.7.0
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.plugin/plugin.json +1 -1
- package/agents/sdd-automaton.md +2 -3
- package/agents/sdd-impl-judge.md +5 -4
- package/agents/sdd-scanner.md +1 -1
- package/agents/sdd-spec-judge.md +3 -3
- package/agents/sdd-warden.md +8 -0
- package/dist/check-project-specs/scripts/check-project-specs.js +1 -0
- package/package.json +2 -2
- package/skills/align-spec/README.md +3 -3
- package/skills/align-spec/SKILL.md +1 -1
- package/skills/align-spec/scripts/align-spec.bundle.mjs +6753 -0
- package/skills/align-spec/scripts/align-spec.mjs +12 -0
- package/skills/architect-impl-governance/SKILL.md +3 -1
- package/skills/architect-spec-governance/SKILL.md +5 -1
- package/skills/blast-estimate/README.md +1 -1
- package/skills/blast-estimate/SKILL.md +1 -1
- package/skills/blast-estimate/scripts/blast-estimate.bundle.mjs +593 -0
- package/skills/blast-estimate/scripts/blast-estimate.mjs +12 -0
- package/skills/check-field-mandates/SKILL.md +1 -1
- package/skills/check-field-mandates/scripts/check-field-mandates.bundle.mjs +251 -0
- package/skills/check-field-mandates/scripts/check-field-mandates.mjs +12 -0
- package/skills/check-partition-quality/SKILL.md +1 -1
- package/skills/check-partition-quality/scripts/check-partition-quality.bundle.mjs +233 -0
- package/skills/check-partition-quality/scripts/check-partition-quality.mjs +12 -0
- package/skills/check-plan-safety/README.md +3 -3
- package/skills/check-plan-safety/SKILL.md +1 -1
- package/skills/check-plan-safety/scripts/check-plan-safety.bundle.mjs +107 -0
- package/skills/check-plan-safety/scripts/check-plan-safety.mjs +12 -0
- package/skills/check-plugin-manifests/SKILL.md +1 -1
- package/skills/check-plugin-manifests/scripts/check-plugin-manifests.bundle.mjs +248 -0
- package/skills/check-plugin-manifests/scripts/check-plugin-manifests.mjs +12 -0
- package/skills/check-project-specs/README.md +3 -3
- package/skills/check-project-specs/SKILL.md +2 -2
- package/skills/check-project-specs/scripts/check-project-specs.bundle.mjs +584 -0
- package/skills/check-project-specs/scripts/check-project-specs.mjs +12 -0
- package/skills/check-project-specs/scripts/check-project-specs.mts +1 -0
- package/skills/check-retired-terms/README.md +2 -2
- package/skills/check-retired-terms/SKILL.md +2 -2
- package/skills/check-retired-terms/scripts/check-retired-terms.bundle.mjs +184 -0
- package/skills/check-retired-terms/scripts/check-retired-terms.mjs +12 -0
- package/skills/check-scenario-overlap/README.md +2 -2
- package/skills/check-scenario-overlap/SKILL.md +2 -3
- package/skills/check-scenario-overlap/scripts/check-scenario-overlap.bundle.mjs +175 -0
- package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mjs +12 -0
- package/skills/check-spec-references/README.md +1 -1
- package/skills/check-spec-references/SKILL.md +1 -1
- package/skills/check-spec-references/scripts/check-spec-references.bundle.mjs +285 -0
- package/skills/check-spec-references/scripts/check-spec-references.mjs +12 -0
- package/skills/check-spec-structure/README.md +2 -2
- package/skills/check-spec-structure/SKILL.md +1 -1
- package/skills/check-spec-structure/scripts/check-spec-structure.bundle.mjs +241 -0
- package/skills/check-spec-structure/scripts/check-spec-structure.mjs +12 -0
- package/skills/collision-ladder/SKILL.md +3 -3
- package/skills/collision-ladder/scripts/collision-ladder.bundle.mjs +7041 -0
- package/skills/collision-ladder/scripts/collision-ladder.mjs +12 -0
- package/skills/collision-ladder/scripts/collision-ladder.mts +4 -2
- package/skills/combat-log-governance/SKILL.md +1 -1
- package/skills/concept-index/README.md +2 -2
- package/skills/concept-index/SKILL.md +1 -1
- package/skills/concept-index/scripts/concept-index.bundle.mjs +181 -0
- package/skills/concept-index/scripts/concept-index.mjs +12 -0
- package/skills/discover-plans/README.md +2 -2
- package/skills/discover-plans/SKILL.md +1 -1
- package/skills/discover-plans/scripts/discover-plans.bundle.mjs +135 -0
- package/skills/discover-plans/scripts/discover-plans.mjs +12 -0
- package/skills/discover-specs/README.md +1 -1
- package/skills/discover-specs/SKILL.md +1 -1
- package/skills/discover-specs/scripts/discover-specs.bundle.mjs +319 -0
- package/skills/discover-specs/scripts/discover-specs.mjs +12 -0
- package/skills/doctrine-loop/SKILL.md +2 -2
- package/skills/formation-loop/SKILL.md +11 -4
- package/skills/gate-validation-governance/SKILL.md +1 -1
- package/skills/init/README.md +3 -3
- package/skills/init/SKILL.md +3 -3
- package/skills/init/scripts/wire-statusline.bundle.mjs +166 -0
- package/skills/init/scripts/wire-statusline.mjs +12 -0
- package/skills/manage-ignore/README.md +5 -5
- package/skills/manage-ignore/SKILL.md +1 -1
- package/skills/manage-ignore/scripts/manage-ignore.bundle.mjs +244 -0
- package/skills/manage-ignore/scripts/manage-ignore.mjs +12 -0
- package/skills/manage-scenario-bridge/README.md +3 -3
- package/skills/manage-scenario-bridge/SKILL.md +1 -1
- package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.bundle.mjs +237 -0
- package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mjs +12 -0
- package/skills/manage-spec-anchors/README.md +4 -4
- package/skills/manage-spec-anchors/SKILL.md +1 -1
- package/skills/manage-spec-anchors/scripts/manage-spec-anchors.bundle.mjs +308 -0
- package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mjs +12 -0
- package/skills/mission-graph/SKILL.md +9 -9
- package/skills/mission-graph/scripts/mission-graph.bundle.mjs +1038 -0
- package/skills/mission-graph/scripts/mission-graph.mjs +12 -0
- package/skills/pause-mission/SKILL.md +1 -1
- package/skills/place-node/README.md +1 -1
- package/skills/place-node/SKILL.md +1 -1
- package/skills/place-node/scripts/place-node.bundle.mjs +115 -0
- package/skills/place-node/scripts/place-node.mjs +12 -0
- package/skills/plan-retirement/SKILL.md +1 -1
- package/skills/plan-retirement/scripts/retire-plans.bundle.mjs +121 -0
- package/skills/plan-retirement/scripts/retire-plans.mjs +12 -0
- package/skills/plan-retirement/scripts/retire-plans.mts +6 -0
- package/skills/plugin-contract-governance/SKILL.md +5 -12
- package/skills/resolve-governances/README.md +1 -1
- package/skills/resolve-governances/SKILL.md +1 -1
- package/skills/resolve-governances/scripts/resolve-governances.bundle.mjs +350 -0
- package/skills/resolve-governances/scripts/resolve-governances.mjs +12 -0
- package/skills/resolve-governances/scripts/resolve-governances.mts +1 -1
- package/skills/resolve-tracking/SKILL.md +1 -1
- package/skills/resolve-tracking/scripts/resolve-tracking.bundle.mjs +150 -0
- package/skills/resolve-tracking/scripts/resolve-tracking.mjs +12 -0
- package/skills/scaffold-project-spec/SKILL.md +2 -2
- package/skills/sdd/SKILL.md +1 -1
- package/skills/solution-producer-governance/README.md +1 -1
- package/skills/solution-producer-governance/SKILL.md +1 -1
- package/skills/spec-gate/SKILL.md +5 -5
- package/skills/spec-gate/scripts/check-spec-state.bundle.mjs +420 -0
- package/skills/spec-gate/scripts/check-spec-state.mjs +12 -0
- package/skills/spec-gate/scripts/check-suite.bundle.mjs +6498 -0
- package/skills/spec-gate/scripts/check-suite.mjs +12 -0
- package/skills/spec-gate/scripts/classify-edit-class.bundle.mjs +6577 -0
- package/skills/spec-gate/scripts/classify-edit-class.mjs +12 -0
- package/skills/spec-producer-governance/README.md +1 -1
- package/skills/spec-producer-governance/SKILL.md +3 -3
- package/skills/spec-structure-governance/README.md +4 -2
- package/skills/spec-structure-governance/SKILL.md +42 -7
- package/skills/start-mission/README.md +1 -1
- package/skills/start-mission/SKILL.md +6 -6
- package/skills/suite-format-governance/references/rubric.md +1 -1
- package/skills/touch-set-correction/SKILL.md +2 -2
- package/skills/touch-set-correction/scripts/touch-set-correction.bundle.mjs +6655 -0
- package/skills/touch-set-correction/scripts/touch-set-correction.mjs +12 -0
- package/skills/touch-set-correction/scripts/touch-set-correction.mts +12 -3
- package/skills/verify-scenarios/README.md +3 -3
- package/skills/verify-scenarios/SKILL.md +3 -3
- package/skills/verify-scenarios/scripts/verify-scenarios.bundle.mjs +6537 -0
- package/skills/verify-scenarios/scripts/verify-scenarios.mjs +12 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
//#region skills/manage-ignore/scripts/manage-ignore.mts
|
|
6
|
+
const IGNORE_FILE = ".agents/sdd/.sddignore";
|
|
7
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
8
|
+
"node_modules",
|
|
9
|
+
".git",
|
|
10
|
+
"dist",
|
|
11
|
+
".turbo",
|
|
12
|
+
".next",
|
|
13
|
+
"coverage"
|
|
14
|
+
]);
|
|
15
|
+
function splitLines(text) {
|
|
16
|
+
const lines = text.split("\n");
|
|
17
|
+
if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
18
|
+
return lines;
|
|
19
|
+
}
|
|
20
|
+
function readIgnoreLines(root) {
|
|
21
|
+
const file = join(root, IGNORE_FILE);
|
|
22
|
+
if (!existsSync(file)) return [];
|
|
23
|
+
try {
|
|
24
|
+
return splitLines(readFileSync(file, "utf8"));
|
|
25
|
+
} catch {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeIgnoreLines(root, lines) {
|
|
30
|
+
const file = join(root, IGNORE_FILE);
|
|
31
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
32
|
+
writeFileSync(file, lines.length === 0 ? "" : `${lines.join("\n")}\n`);
|
|
33
|
+
}
|
|
34
|
+
function isRuleLine(line) {
|
|
35
|
+
const t = line.trim();
|
|
36
|
+
return t !== "" && !t.startsWith("#");
|
|
37
|
+
}
|
|
38
|
+
function listRules(root) {
|
|
39
|
+
return readIgnoreLines(root).filter(isRuleLine).map((l) => l.trim());
|
|
40
|
+
}
|
|
41
|
+
function hasUnclosedBracket(s) {
|
|
42
|
+
let i = 0;
|
|
43
|
+
while (i < s.length) {
|
|
44
|
+
if (s[i] === "\\") {
|
|
45
|
+
i += 2;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (s[i] === "[") {
|
|
49
|
+
const close = s.indexOf("]", i + 1);
|
|
50
|
+
if (close === -1) return true;
|
|
51
|
+
i = close + 1;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
function isValidPattern(pattern) {
|
|
59
|
+
let s = pattern;
|
|
60
|
+
if (s.startsWith("!")) s = s.slice(1);
|
|
61
|
+
s = s.replace(/^\s+|\s+$/g, "");
|
|
62
|
+
if (s === "" || s.startsWith("#")) return false;
|
|
63
|
+
if (hasUnclosedBracket(s)) return false;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
function addRule(root, pattern) {
|
|
67
|
+
const p = pattern.trim();
|
|
68
|
+
if (!isValidPattern(p)) return {
|
|
69
|
+
ok: false,
|
|
70
|
+
reason: "malformed gitignore pattern"
|
|
71
|
+
};
|
|
72
|
+
const lines = readIgnoreLines(root);
|
|
73
|
+
if (lines.some((l) => l.trim() === p)) return {
|
|
74
|
+
ok: true,
|
|
75
|
+
changed: false,
|
|
76
|
+
rules: listRules(root),
|
|
77
|
+
message: "already present"
|
|
78
|
+
};
|
|
79
|
+
const next = [...lines, p];
|
|
80
|
+
writeIgnoreLines(root, next);
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
changed: true,
|
|
84
|
+
rules: next.filter(isRuleLine).map((l) => l.trim()),
|
|
85
|
+
message: `added ${p}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function removeRule(root, pattern) {
|
|
89
|
+
const p = pattern.trim();
|
|
90
|
+
const lines = readIgnoreLines(root);
|
|
91
|
+
const next = lines.filter((l) => l.trim() !== p);
|
|
92
|
+
if (next.length === lines.length) return {
|
|
93
|
+
ok: true,
|
|
94
|
+
changed: false,
|
|
95
|
+
rules: listRules(root),
|
|
96
|
+
message: "nothing was removed"
|
|
97
|
+
};
|
|
98
|
+
writeIgnoreLines(root, next);
|
|
99
|
+
return {
|
|
100
|
+
ok: true,
|
|
101
|
+
changed: true,
|
|
102
|
+
rules: next.filter(isRuleLine).map((l) => l.trim()),
|
|
103
|
+
message: `removed ${p}`
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function inducePatterns(_root, samplePath) {
|
|
107
|
+
const normalized = samplePath.trim().replace(/\\/g, "/");
|
|
108
|
+
if (normalized.startsWith("/")) return {
|
|
109
|
+
ok: false,
|
|
110
|
+
reason: "path is not repo-relative (absolute)"
|
|
111
|
+
};
|
|
112
|
+
const rel = normalized.replace(/\/+$/g, "");
|
|
113
|
+
if (rel === "" || /(^|\/)\.\.(\/|$)/.test(rel)) return {
|
|
114
|
+
ok: false,
|
|
115
|
+
reason: "path is not repo-relative"
|
|
116
|
+
};
|
|
117
|
+
const generalized = `**/${rel.split("/").pop() ?? rel}`;
|
|
118
|
+
return {
|
|
119
|
+
ok: true,
|
|
120
|
+
candidates: generalized === rel ? [rel] : [rel, generalized]
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function gitignoreToRegExp(pattern) {
|
|
124
|
+
let pat = pattern;
|
|
125
|
+
if (pat.endsWith("/")) pat = pat.slice(0, -1);
|
|
126
|
+
let anchored = pat.startsWith("/");
|
|
127
|
+
if (anchored) pat = pat.slice(1);
|
|
128
|
+
if (pat.includes("/")) anchored = true;
|
|
129
|
+
let body = "";
|
|
130
|
+
for (let i = 0; i < pat.length; i++) {
|
|
131
|
+
const c = pat[i];
|
|
132
|
+
if (c === "*") {
|
|
133
|
+
if (pat[i + 1] === "*") {
|
|
134
|
+
i++;
|
|
135
|
+
if (pat[i + 1] === "/") {
|
|
136
|
+
i++;
|
|
137
|
+
body += "(?:.*/)?";
|
|
138
|
+
} else body += ".*";
|
|
139
|
+
} else body += "[^/]*";
|
|
140
|
+
} else if (c === "?") body += "[^/]";
|
|
141
|
+
else if (c === "[") {
|
|
142
|
+
let j = i + 1;
|
|
143
|
+
let cls = "[";
|
|
144
|
+
if (pat[j] === "!") {
|
|
145
|
+
cls += "^";
|
|
146
|
+
j++;
|
|
147
|
+
}
|
|
148
|
+
while (j < pat.length && pat[j] !== "]") {
|
|
149
|
+
cls += /[\\^\]]/.test(pat[j]) ? `\\${pat[j]}` : pat[j];
|
|
150
|
+
j++;
|
|
151
|
+
}
|
|
152
|
+
cls += "]";
|
|
153
|
+
body += cls;
|
|
154
|
+
i = j;
|
|
155
|
+
} else body += c.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
156
|
+
}
|
|
157
|
+
return new RegExp(`${anchored ? "^" : "^(?:.*/)?"}${body}(?:/.*)?$`);
|
|
158
|
+
}
|
|
159
|
+
function matchesPattern(pattern, path) {
|
|
160
|
+
return gitignoreToRegExp(pattern.startsWith("!") ? pattern.slice(1) : pattern).test(path);
|
|
161
|
+
}
|
|
162
|
+
function walkTree(root) {
|
|
163
|
+
const out = [];
|
|
164
|
+
const walk = (rel) => {
|
|
165
|
+
let entries;
|
|
166
|
+
try {
|
|
167
|
+
entries = readdirSync(join(root, rel), { withFileTypes: true });
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const e of entries) {
|
|
172
|
+
if (SKIP_DIRS.has(e.name)) continue;
|
|
173
|
+
const child = rel ? `${rel}/${e.name}` : e.name;
|
|
174
|
+
out.push(child);
|
|
175
|
+
if (e.isDirectory()) walk(child);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
walk("");
|
|
179
|
+
return out.sort();
|
|
180
|
+
}
|
|
181
|
+
function previewPattern(root, pattern) {
|
|
182
|
+
const p = pattern.trim();
|
|
183
|
+
if (!isValidPattern(p)) return {
|
|
184
|
+
ok: false,
|
|
185
|
+
reason: "malformed gitignore pattern"
|
|
186
|
+
};
|
|
187
|
+
return {
|
|
188
|
+
ok: true,
|
|
189
|
+
negated: p.startsWith("!"),
|
|
190
|
+
matches: walkTree(root).filter((path) => matchesPattern(p, path))
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function flag(argv, name) {
|
|
194
|
+
const i = argv.indexOf(name);
|
|
195
|
+
return i === -1 ? void 0 : argv[i + 1];
|
|
196
|
+
}
|
|
197
|
+
function main(argv) {
|
|
198
|
+
const root = flag(argv, "--root") ?? ".";
|
|
199
|
+
const w = (s) => process.stdout.write(`${s}\n`);
|
|
200
|
+
if (argv.includes("--list")) {
|
|
201
|
+
for (const rule of listRules(root)) w(rule);
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
if (argv.includes("--add")) {
|
|
205
|
+
const r = addRule(root, flag(argv, "--add") ?? "");
|
|
206
|
+
w(r.ok ? r.message : `refused: ${r.reason}`);
|
|
207
|
+
return r.ok ? 0 : 1;
|
|
208
|
+
}
|
|
209
|
+
if (argv.includes("--remove")) {
|
|
210
|
+
const r = removeRule(root, flag(argv, "--remove") ?? "");
|
|
211
|
+
w(r.ok ? r.message : `refused: ${r.reason}`);
|
|
212
|
+
return r.ok ? 0 : 1;
|
|
213
|
+
}
|
|
214
|
+
if (argv.includes("--induce")) {
|
|
215
|
+
const r = inducePatterns(root, flag(argv, "--induce") ?? "");
|
|
216
|
+
if (!r.ok) {
|
|
217
|
+
w(`unusable: ${r.reason}`);
|
|
218
|
+
return 1;
|
|
219
|
+
}
|
|
220
|
+
w("Candidate ignore patterns:");
|
|
221
|
+
for (const c of r.candidates) w(` ${c}`);
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
if (argv.includes("--preview")) {
|
|
225
|
+
const r = previewPattern(root, flag(argv, "--preview") ?? "");
|
|
226
|
+
if (!r.ok) {
|
|
227
|
+
w(`invalid: ${r.reason}`);
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
const verb = r.negated ? "re-track" : "ignore";
|
|
231
|
+
if (r.matches.length === 0) {
|
|
232
|
+
w(`This pattern would ${verb} no path.`);
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
w(`This pattern would ${verb}:`);
|
|
236
|
+
for (const m of r.matches) w(` ${m}`);
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
w("usage: manage-ignore --list | --add <p> | --remove <p> | --induce <path> | --preview <p>");
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
242
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
|
|
243
|
+
//#endregion
|
|
244
|
+
export { addRule, gitignoreToRegExp, inducePatterns, isRuleLine, isValidPattern, listRules, main, matchesPattern, previewPattern, readIgnoreLines, removeRule, splitLines };
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
|
@@ -11,10 +11,10 @@ config.
|
|
|
11
11
|
- **Tests:** [`scripts/manage-scenario-bridge.test.mts`](./scripts/manage-scenario-bridge.test.mts) (`node:test`)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
node scripts/manage-scenario-bridge.
|
|
15
|
-
node scripts/manage-scenario-bridge.
|
|
14
|
+
node scripts/manage-scenario-bridge.mjs --project-path packages/cyberlegion --list
|
|
15
|
+
node scripts/manage-scenario-bridge.mjs --project-path packages/cyberlegion --scaffold \
|
|
16
16
|
--adapter junit --command "vitest run --reporter=junit --outputFile=.agents/.scenario-report.xml" \
|
|
17
17
|
--report-path .agents/.scenario-report.xml
|
|
18
|
-
node scripts/manage-scenario-bridge.
|
|
18
|
+
node scripts/manage-scenario-bridge.mjs --project-path packages/cyberlegion --add \
|
|
19
19
|
--adapter junit --report-path .agents/.other-report.xml
|
|
20
20
|
```
|
|
@@ -35,7 +35,7 @@ reports it covers.
|
|
|
35
35
|
## Run an operation
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
node "<skill>/scripts/manage-scenario-bridge.
|
|
38
|
+
node "<skill>/scripts/manage-scenario-bridge.mjs" --project-path <dir> <operation>
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
| Operation | Effect |
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
//#region skills/spec-gate/vendor/gherkin-cli.mjs
|
|
6
|
+
var TokenType;
|
|
7
|
+
(function(TokenType) {
|
|
8
|
+
TokenType[TokenType["None"] = 0] = "None";
|
|
9
|
+
TokenType[TokenType["EOF"] = 1] = "EOF";
|
|
10
|
+
TokenType[TokenType["Empty"] = 2] = "Empty";
|
|
11
|
+
TokenType[TokenType["Comment"] = 3] = "Comment";
|
|
12
|
+
TokenType[TokenType["TagLine"] = 4] = "TagLine";
|
|
13
|
+
TokenType[TokenType["FeatureLine"] = 5] = "FeatureLine";
|
|
14
|
+
TokenType[TokenType["RuleLine"] = 6] = "RuleLine";
|
|
15
|
+
TokenType[TokenType["BackgroundLine"] = 7] = "BackgroundLine";
|
|
16
|
+
TokenType[TokenType["ScenarioLine"] = 8] = "ScenarioLine";
|
|
17
|
+
TokenType[TokenType["ExamplesLine"] = 9] = "ExamplesLine";
|
|
18
|
+
TokenType[TokenType["StepLine"] = 10] = "StepLine";
|
|
19
|
+
TokenType[TokenType["DocStringSeparator"] = 11] = "DocStringSeparator";
|
|
20
|
+
TokenType[TokenType["TableRow"] = 12] = "TableRow";
|
|
21
|
+
TokenType[TokenType["Language"] = 13] = "Language";
|
|
22
|
+
TokenType[TokenType["Other"] = 14] = "Other";
|
|
23
|
+
})(TokenType || (TokenType = {}));
|
|
24
|
+
var RuleType;
|
|
25
|
+
(function(RuleType) {
|
|
26
|
+
RuleType[RuleType["None"] = 0] = "None";
|
|
27
|
+
RuleType[RuleType["_EOF"] = 1] = "_EOF";
|
|
28
|
+
RuleType[RuleType["_Empty"] = 2] = "_Empty";
|
|
29
|
+
RuleType[RuleType["_Comment"] = 3] = "_Comment";
|
|
30
|
+
RuleType[RuleType["_TagLine"] = 4] = "_TagLine";
|
|
31
|
+
RuleType[RuleType["_FeatureLine"] = 5] = "_FeatureLine";
|
|
32
|
+
RuleType[RuleType["_RuleLine"] = 6] = "_RuleLine";
|
|
33
|
+
RuleType[RuleType["_BackgroundLine"] = 7] = "_BackgroundLine";
|
|
34
|
+
RuleType[RuleType["_ScenarioLine"] = 8] = "_ScenarioLine";
|
|
35
|
+
RuleType[RuleType["_ExamplesLine"] = 9] = "_ExamplesLine";
|
|
36
|
+
RuleType[RuleType["_StepLine"] = 10] = "_StepLine";
|
|
37
|
+
RuleType[RuleType["_DocStringSeparator"] = 11] = "_DocStringSeparator";
|
|
38
|
+
RuleType[RuleType["_TableRow"] = 12] = "_TableRow";
|
|
39
|
+
RuleType[RuleType["_Language"] = 13] = "_Language";
|
|
40
|
+
RuleType[RuleType["_Other"] = 14] = "_Other";
|
|
41
|
+
RuleType[RuleType["GherkinDocument"] = 15] = "GherkinDocument";
|
|
42
|
+
RuleType[RuleType["Feature"] = 16] = "Feature";
|
|
43
|
+
RuleType[RuleType["FeatureHeader"] = 17] = "FeatureHeader";
|
|
44
|
+
RuleType[RuleType["Rule"] = 18] = "Rule";
|
|
45
|
+
RuleType[RuleType["RuleHeader"] = 19] = "RuleHeader";
|
|
46
|
+
RuleType[RuleType["Background"] = 20] = "Background";
|
|
47
|
+
RuleType[RuleType["ScenarioDefinition"] = 21] = "ScenarioDefinition";
|
|
48
|
+
RuleType[RuleType["Scenario"] = 22] = "Scenario";
|
|
49
|
+
RuleType[RuleType["ExamplesDefinition"] = 23] = "ExamplesDefinition";
|
|
50
|
+
RuleType[RuleType["Examples"] = 24] = "Examples";
|
|
51
|
+
RuleType[RuleType["ExamplesTable"] = 25] = "ExamplesTable";
|
|
52
|
+
RuleType[RuleType["Step"] = 26] = "Step";
|
|
53
|
+
RuleType[RuleType["StepArg"] = 27] = "StepArg";
|
|
54
|
+
RuleType[RuleType["DataTable"] = 28] = "DataTable";
|
|
55
|
+
RuleType[RuleType["DocString"] = 29] = "DocString";
|
|
56
|
+
RuleType[RuleType["Tags"] = 30] = "Tags";
|
|
57
|
+
RuleType[RuleType["DescriptionHelper"] = 31] = "DescriptionHelper";
|
|
58
|
+
RuleType[RuleType["Description"] = 32] = "Description";
|
|
59
|
+
})(RuleType || (RuleType = {}));
|
|
60
|
+
var AttachmentContentEncoding;
|
|
61
|
+
(function(AttachmentContentEncoding) {
|
|
62
|
+
AttachmentContentEncoding["IDENTITY"] = "IDENTITY";
|
|
63
|
+
AttachmentContentEncoding["BASE64"] = "BASE64";
|
|
64
|
+
})(AttachmentContentEncoding || (AttachmentContentEncoding = {}));
|
|
65
|
+
var HookType;
|
|
66
|
+
(function(HookType) {
|
|
67
|
+
HookType["BEFORE_TEST_RUN"] = "BEFORE_TEST_RUN";
|
|
68
|
+
HookType["AFTER_TEST_RUN"] = "AFTER_TEST_RUN";
|
|
69
|
+
HookType["BEFORE_TEST_CASE"] = "BEFORE_TEST_CASE";
|
|
70
|
+
HookType["AFTER_TEST_CASE"] = "AFTER_TEST_CASE";
|
|
71
|
+
HookType["BEFORE_TEST_STEP"] = "BEFORE_TEST_STEP";
|
|
72
|
+
HookType["AFTER_TEST_STEP"] = "AFTER_TEST_STEP";
|
|
73
|
+
})(HookType || (HookType = {}));
|
|
74
|
+
var PickleStepType;
|
|
75
|
+
(function(PickleStepType) {
|
|
76
|
+
PickleStepType["UNKNOWN"] = "Unknown";
|
|
77
|
+
PickleStepType["CONTEXT"] = "Context";
|
|
78
|
+
PickleStepType["ACTION"] = "Action";
|
|
79
|
+
PickleStepType["OUTCOME"] = "Outcome";
|
|
80
|
+
})(PickleStepType || (PickleStepType = {}));
|
|
81
|
+
var SourceMediaType;
|
|
82
|
+
(function(SourceMediaType) {
|
|
83
|
+
SourceMediaType["TEXT_X_CUCUMBER_GHERKIN_PLAIN"] = "text/x.cucumber.gherkin+plain";
|
|
84
|
+
SourceMediaType["TEXT_X_CUCUMBER_GHERKIN_MARKDOWN"] = "text/x.cucumber.gherkin+markdown";
|
|
85
|
+
})(SourceMediaType || (SourceMediaType = {}));
|
|
86
|
+
var StepDefinitionPatternType;
|
|
87
|
+
(function(StepDefinitionPatternType) {
|
|
88
|
+
StepDefinitionPatternType["CUCUMBER_EXPRESSION"] = "CUCUMBER_EXPRESSION";
|
|
89
|
+
StepDefinitionPatternType["REGULAR_EXPRESSION"] = "REGULAR_EXPRESSION";
|
|
90
|
+
})(StepDefinitionPatternType || (StepDefinitionPatternType = {}));
|
|
91
|
+
var StepKeywordType;
|
|
92
|
+
(function(StepKeywordType) {
|
|
93
|
+
StepKeywordType["UNKNOWN"] = "Unknown";
|
|
94
|
+
StepKeywordType["CONTEXT"] = "Context";
|
|
95
|
+
StepKeywordType["ACTION"] = "Action";
|
|
96
|
+
StepKeywordType["OUTCOME"] = "Outcome";
|
|
97
|
+
StepKeywordType["CONJUNCTION"] = "Conjunction";
|
|
98
|
+
})(StepKeywordType || (StepKeywordType = {}));
|
|
99
|
+
var TestStepResultStatus;
|
|
100
|
+
(function(TestStepResultStatus) {
|
|
101
|
+
TestStepResultStatus["UNKNOWN"] = "UNKNOWN";
|
|
102
|
+
TestStepResultStatus["PASSED"] = "PASSED";
|
|
103
|
+
TestStepResultStatus["SKIPPED"] = "SKIPPED";
|
|
104
|
+
TestStepResultStatus["PENDING"] = "PENDING";
|
|
105
|
+
TestStepResultStatus["UNDEFINED"] = "UNDEFINED";
|
|
106
|
+
TestStepResultStatus["AMBIGUOUS"] = "AMBIGUOUS";
|
|
107
|
+
TestStepResultStatus["FAILED"] = "FAILED";
|
|
108
|
+
})(TestStepResultStatus || (TestStepResultStatus = {}));
|
|
109
|
+
var KeywordPrefix;
|
|
110
|
+
(function(KeywordPrefix) {
|
|
111
|
+
KeywordPrefix["BULLET"] = "^(\\s*[*+-]\\s*)";
|
|
112
|
+
KeywordPrefix["HEADER"] = "^(#{1,6}\\s)";
|
|
113
|
+
})(KeywordPrefix || (KeywordPrefix = {}));
|
|
114
|
+
StepKeywordType.UNKNOWN, PickleStepType.UNKNOWN, StepKeywordType.CONTEXT, PickleStepType.CONTEXT, StepKeywordType.ACTION, PickleStepType.ACTION, StepKeywordType.OUTCOME, PickleStepType.OUTCOME, StepKeywordType.CONJUNCTION;
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region skills/verify-scenarios/scripts/verify-scenarios.mts
|
|
117
|
+
function parseSourcesToml(text) {
|
|
118
|
+
const out = [];
|
|
119
|
+
const blocks = text.split(/(?=^\s*\[\[source\]\]\s*$)/m).filter((b) => /^\s*\[\[source\]\]\s*$/m.test(b));
|
|
120
|
+
for (const block of blocks) {
|
|
121
|
+
const body = block.replace(/^\s*\[\[source\]\]\s*$/m, "");
|
|
122
|
+
const fields = {};
|
|
123
|
+
for (const m of body.matchAll(/^\s*([A-Za-z_][\w-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')\s*$/gm)) fields[m[1]] = m[2] ?? m[3] ?? "";
|
|
124
|
+
if (!fields.adapter || !fields.reportPath) continue;
|
|
125
|
+
out.push({
|
|
126
|
+
adapter: fields.adapter,
|
|
127
|
+
command: fields.command,
|
|
128
|
+
reportPath: fields.reportPath
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
if (process.argv[1] && false);
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mts
|
|
136
|
+
const CONFIG_REL_PATH = ".agents/sdd/scenario-bridge.toml";
|
|
137
|
+
function configPath(projectPath) {
|
|
138
|
+
return join(projectPath, CONFIG_REL_PATH);
|
|
139
|
+
}
|
|
140
|
+
function listSources(projectPath) {
|
|
141
|
+
const file = configPath(projectPath);
|
|
142
|
+
if (!existsSync(file)) return [];
|
|
143
|
+
try {
|
|
144
|
+
return parseSourcesToml(readFileSync(file, "utf8"));
|
|
145
|
+
} catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function renderBlock(source) {
|
|
150
|
+
return [
|
|
151
|
+
"[[source]]",
|
|
152
|
+
`adapter = "${source.adapter}"`,
|
|
153
|
+
...source.command !== void 0 ? [`command = "${source.command}"`] : [],
|
|
154
|
+
`reportPath = "${source.reportPath}"`
|
|
155
|
+
].join("\n");
|
|
156
|
+
}
|
|
157
|
+
function validateInput(input) {
|
|
158
|
+
if (!input.adapter || !input.reportPath) return {
|
|
159
|
+
ok: false,
|
|
160
|
+
reason: "a source needs both adapter and reportPath"
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
ok: true,
|
|
164
|
+
adapter: input.adapter,
|
|
165
|
+
command: input.command,
|
|
166
|
+
reportPath: input.reportPath
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function scaffoldSource(projectPath, input) {
|
|
170
|
+
const valid = validateInput(input);
|
|
171
|
+
if (!valid.ok) return valid;
|
|
172
|
+
const file = configPath(projectPath);
|
|
173
|
+
if (existsSync(file)) return {
|
|
174
|
+
ok: false,
|
|
175
|
+
reason: "scenario-bridge.toml already exists; use add to append a source"
|
|
176
|
+
};
|
|
177
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
178
|
+
writeFileSync(file, `${renderBlock(valid)}\n`);
|
|
179
|
+
const sources = listSources(projectPath);
|
|
180
|
+
return {
|
|
181
|
+
ok: true,
|
|
182
|
+
message: `scaffolded ${file}`,
|
|
183
|
+
sources
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function addSource(projectPath, input) {
|
|
187
|
+
const valid = validateInput(input);
|
|
188
|
+
if (!valid.ok) return valid;
|
|
189
|
+
const file = configPath(projectPath);
|
|
190
|
+
if (!existsSync(file)) return {
|
|
191
|
+
ok: false,
|
|
192
|
+
reason: "scenario-bridge.toml does not exist yet; use scaffold to create it first"
|
|
193
|
+
};
|
|
194
|
+
const existing = readFileSync(file, "utf8");
|
|
195
|
+
const sep = existing.endsWith("\n") ? "" : "\n";
|
|
196
|
+
writeFileSync(file, `${existing}${sep}\n${renderBlock(valid)}\n`);
|
|
197
|
+
const sources = listSources(projectPath);
|
|
198
|
+
return {
|
|
199
|
+
ok: true,
|
|
200
|
+
message: `added a source to ${file}`,
|
|
201
|
+
sources
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function flag(argv, name) {
|
|
205
|
+
const i = argv.indexOf(name);
|
|
206
|
+
return i === -1 ? void 0 : argv[i + 1];
|
|
207
|
+
}
|
|
208
|
+
function inputFromArgv(argv) {
|
|
209
|
+
return {
|
|
210
|
+
adapter: flag(argv, "--adapter"),
|
|
211
|
+
command: flag(argv, "--command"),
|
|
212
|
+
reportPath: flag(argv, "--report-path")
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function main(argv) {
|
|
216
|
+
const projectPath = flag(argv, "--project-path") ?? ".";
|
|
217
|
+
const w = (s) => process.stdout.write(`${s}\n`);
|
|
218
|
+
if (argv.includes("--list")) {
|
|
219
|
+
for (const s of listSources(projectPath)) w(`${s.adapter}${s.command ? ` (${s.command})` : ""} -> ${s.reportPath}`);
|
|
220
|
+
return 0;
|
|
221
|
+
}
|
|
222
|
+
if (argv.includes("--scaffold")) {
|
|
223
|
+
const r = scaffoldSource(projectPath, inputFromArgv(argv));
|
|
224
|
+
w(r.ok ? r.message : `refused: ${r.reason}`);
|
|
225
|
+
return r.ok ? 0 : 1;
|
|
226
|
+
}
|
|
227
|
+
if (argv.includes("--add")) {
|
|
228
|
+
const r = addSource(projectPath, inputFromArgv(argv));
|
|
229
|
+
w(r.ok ? r.message : `refused: ${r.reason}`);
|
|
230
|
+
return r.ok ? 0 : 1;
|
|
231
|
+
}
|
|
232
|
+
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>");
|
|
233
|
+
return 0;
|
|
234
|
+
}
|
|
235
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
|
|
236
|
+
//#endregion
|
|
237
|
+
export { addSource, configPath, listSources, main, scaffoldSource };
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
|
@@ -11,8 +11,8 @@ that lists / CRUDs / induces / previews the anchors so users never hand-edit
|
|
|
11
11
|
- **Tests:** [`scripts/manage-spec-anchors.test.mts`](./scripts/manage-spec-anchors.test.mts) (`node:test`)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
node scripts/manage-spec-anchors.
|
|
15
|
-
node scripts/manage-spec-anchors.
|
|
16
|
-
node scripts/manage-spec-anchors.
|
|
17
|
-
node scripts/manage-spec-anchors.
|
|
14
|
+
node scripts/manage-spec-anchors.mjs --list
|
|
15
|
+
node scripts/manage-spec-anchors.mjs --induce curriculum/web/react/s-01
|
|
16
|
+
node scripts/manage-spec-anchors.mjs --preview 'curriculum/*/*/<project>'
|
|
17
|
+
node scripts/manage-spec-anchors.mjs --add 'curriculum/*/*/<project>'
|
|
18
18
|
```
|