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.
- package/.claude-plugin/plugin.json +1 -2
- package/.codex-plugin/plugin.json +1 -2
- package/CHANGELOG.md +320 -0
- package/agents/sdd-scanner.md +1 -1
- package/package.json +11 -12
- package/plugin.json +55 -0
- package/skills/align-spec/SKILL.md +1 -1
- package/skills/align-spec/scripts/align-spec.mjs +6755 -12
- package/skills/blast-estimate/README.md +3 -3
- package/skills/blast-estimate/scripts/blast-estimate.mjs +601 -12
- package/skills/check-field-mandates/scripts/check-field-mandates.mjs +253 -12
- package/skills/check-partition-quality/scripts/check-partition-quality.mjs +235 -12
- package/skills/check-plan-safety/SKILL.md +2 -3
- package/skills/check-plan-safety/scripts/check-plan-safety.mjs +109 -12
- package/skills/check-plugin-manifests/scripts/check-plugin-manifests.mjs +250 -12
- package/skills/check-project-specs/SKILL.md +1 -1
- package/skills/check-project-specs/scripts/check-project-specs.mjs +593 -12
- package/skills/check-retired-terms/SKILL.md +2 -3
- package/skills/check-retired-terms/scripts/check-retired-terms.mjs +186 -12
- package/skills/check-scenario-overlap/SKILL.md +1 -2
- package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mjs +177 -12
- package/skills/check-spec-references/SKILL.md +2 -2
- package/skills/check-spec-references/scripts/check-spec-references.mjs +287 -12
- package/skills/check-spec-structure/SKILL.md +1 -2
- package/skills/check-spec-structure/scripts/check-spec-structure.mjs +243 -12
- package/skills/collision-ladder/README.md +2 -2
- package/skills/collision-ladder/scripts/collision-ladder.mjs +7047 -12
- package/skills/combat-log-governance/SKILL.md +1 -1
- package/skills/concept-index/SKILL.md +1 -1
- package/skills/concept-index/scripts/concept-index.mjs +183 -12
- package/skills/discover-plans/README.md +3 -3
- package/skills/discover-plans/SKILL.md +1 -1
- package/skills/discover-plans/scripts/discover-plans.mjs +137 -12
- package/skills/discover-specs/README.md +3 -3
- package/skills/discover-specs/SKILL.md +1 -1
- package/skills/discover-specs/scripts/discover-specs.mjs +321 -12
- package/skills/doctrine-loop/SKILL.md +1 -1
- package/skills/gate-validation-governance/SKILL.md +1 -1
- package/skills/init/README.md +2 -2
- package/skills/init/scripts/wire-statusline.mjs +168 -12
- package/skills/manage-ignore/README.md +3 -3
- package/skills/manage-ignore/SKILL.md +1 -2
- package/skills/manage-ignore/scripts/manage-ignore.mjs +285 -12
- 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.mjs +239 -12
- package/skills/manage-spec-anchors/README.md +3 -3
- package/skills/manage-spec-anchors/SKILL.md +1 -1
- package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mjs +310 -12
- package/skills/mission-graph/README.md +2 -2
- package/skills/mission-graph/SKILL.md +1 -1
- package/skills/mission-graph/scripts/mission-graph.mjs +1040 -12
- package/skills/pause-mission/SKILL.md +1 -1
- package/skills/place-node/SKILL.md +2 -2
- package/skills/place-node/scripts/place-node.mjs +117 -12
- package/skills/plan-retirement/README.md +2 -2
- package/skills/plan-retirement/scripts/retire-plans.mjs +123 -12
- package/skills/resolve-governances/README.md +3 -3
- package/skills/resolve-governances/SKILL.md +1 -1
- package/skills/resolve-governances/scripts/resolve-governances.mjs +352 -12
- package/skills/resolve-tracking/SKILL.md +1 -1
- package/skills/resolve-tracking/scripts/resolve-tracking.mjs +152 -12
- package/skills/scaffold-project-spec/SKILL.md +1 -1
- package/skills/spec-gate/README.md +12 -9
- package/skills/spec-gate/SKILL.md +2 -2
- package/skills/spec-gate/scripts/check-spec-state.mjs +422 -12
- package/skills/spec-gate/scripts/check-suite.mjs +6500 -12
- package/skills/spec-gate/scripts/classify-edit-class.mjs +6579 -12
- package/skills/spec-producer-governance/SKILL.md +2 -2
- package/skills/start-mission/SKILL.md +1 -1
- package/skills/suite-format-governance/README.md +1 -1
- package/skills/suite-format-governance/SKILL.md +1 -1
- package/skills/touch-set-correction/README.md +5 -5
- package/skills/touch-set-correction/SKILL.md +1 -1
- package/skills/touch-set-correction/scripts/touch-set-correction.mjs +6663 -12
- package/skills/verify-scenarios/README.md +6 -6
- package/skills/verify-scenarios/scripts/verify-scenarios.mjs +6539 -12
- package/.plugin/pins.json +0 -3
- package/.plugin/plugin.json +0 -19
- package/dist/align-spec/scripts/align-spec.js +0 -102
- package/dist/check-project-specs/scripts/check-project-specs.js +0 -312
- package/dist/check-scenario-overlap/scripts/check-scenario-overlap.js +0 -175
- package/dist/check-spec-references/scripts/check-spec-references.js +0 -285
- package/dist/check-spec-structure/scripts/check-spec-structure.js +0 -241
- package/dist/concept-index/scripts/concept-index.js +0 -181
- package/dist/discover-specs/scripts/discover-specs.js +0 -318
- package/dist/spec-gate/scripts/check-spec-state.js +0 -420
- package/dist/spec-gate/scripts/check-suite.js +0 -317
- package/dist/spec-gate/scripts/classify-edit-class.js +0 -263
- package/dist/spec-gate/vendor/gherkin-cli.js +0 -6369
- package/skills/align-spec/scripts/align-spec.bundle.mjs +0 -6753
- package/skills/align-spec/scripts/align-spec.mts +0 -188
- package/skills/blast-estimate/scripts/blast-estimate.bundle.mjs +0 -593
- package/skills/blast-estimate/scripts/blast-estimate.mts +0 -586
- package/skills/check-field-mandates/scripts/check-field-mandates.bundle.mjs +0 -251
- package/skills/check-field-mandates/scripts/check-field-mandates.mts +0 -337
- package/skills/check-partition-quality/scripts/check-partition-quality.bundle.mjs +0 -233
- package/skills/check-partition-quality/scripts/check-partition-quality.mts +0 -338
- package/skills/check-plan-safety/scripts/check-plan-safety.bundle.mjs +0 -107
- package/skills/check-plan-safety/scripts/check-plan-safety.mts +0 -148
- package/skills/check-plugin-manifests/scripts/check-plugin-manifests.bundle.mjs +0 -248
- package/skills/check-plugin-manifests/scripts/check-plugin-manifests.mts +0 -303
- package/skills/check-project-specs/scripts/check-project-specs.bundle.mjs +0 -584
- package/skills/check-project-specs/scripts/check-project-specs.mts +0 -370
- package/skills/check-retired-terms/scripts/check-retired-terms.bundle.mjs +0 -184
- package/skills/check-retired-terms/scripts/check-retired-terms.mts +0 -293
- package/skills/check-scenario-overlap/scripts/check-scenario-overlap.bundle.mjs +0 -175
- package/skills/check-scenario-overlap/scripts/check-scenario-overlap.mts +0 -250
- package/skills/check-spec-references/scripts/check-spec-references.bundle.mjs +0 -285
- package/skills/check-spec-references/scripts/check-spec-references.mts +0 -422
- package/skills/check-spec-structure/scripts/check-spec-structure.bundle.mjs +0 -241
- package/skills/check-spec-structure/scripts/check-spec-structure.mts +0 -347
- package/skills/collision-ladder/scripts/collision-ladder.bundle.mjs +0 -7041
- package/skills/collision-ladder/scripts/collision-ladder.mts +0 -662
- package/skills/concept-index/scripts/concept-index.bundle.mjs +0 -181
- package/skills/concept-index/scripts/concept-index.mts +0 -246
- package/skills/discover-plans/scripts/discover-plans.bundle.mjs +0 -135
- package/skills/discover-plans/scripts/discover-plans.mts +0 -215
- package/skills/discover-specs/scripts/discover-specs.bundle.mjs +0 -319
- package/skills/discover-specs/scripts/discover-specs.mts +0 -420
- package/skills/init/scripts/wire-statusline.bundle.mjs +0 -166
- package/skills/init/scripts/wire-statusline.mts +0 -279
- package/skills/manage-ignore/scripts/manage-ignore.bundle.mjs +0 -244
- package/skills/manage-ignore/scripts/manage-ignore.mts +0 -297
- package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.bundle.mjs +0 -237
- package/skills/manage-scenario-bridge/scripts/manage-scenario-bridge.mts +0 -159
- package/skills/manage-spec-anchors/scripts/manage-spec-anchors.bundle.mjs +0 -308
- package/skills/manage-spec-anchors/scripts/manage-spec-anchors.mts +0 -331
- package/skills/mission-graph/scripts/mission-graph.bundle.mjs +0 -1038
- package/skills/mission-graph/scripts/mission-graph.mts +0 -1333
- package/skills/place-node/scripts/place-node.bundle.mjs +0 -115
- package/skills/place-node/scripts/place-node.mts +0 -158
- package/skills/plan-retirement/scripts/retire-plans.bundle.mjs +0 -121
- package/skills/plan-retirement/scripts/retire-plans.mts +0 -205
- package/skills/resolve-governances/scripts/resolve-governances.bundle.mjs +0 -350
- package/skills/resolve-governances/scripts/resolve-governances.mts +0 -518
- package/skills/resolve-tracking/scripts/resolve-tracking.bundle.mjs +0 -150
- package/skills/resolve-tracking/scripts/resolve-tracking.mts +0 -214
- package/skills/spec-gate/scripts/check-spec-state.bundle.mjs +0 -420
- package/skills/spec-gate/scripts/check-spec-state.mts +0 -637
- package/skills/spec-gate/scripts/check-suite.bundle.mjs +0 -6498
- package/skills/spec-gate/scripts/check-suite.mts +0 -538
- package/skills/spec-gate/scripts/classify-edit-class.bundle.mjs +0 -6577
- package/skills/spec-gate/scripts/classify-edit-class.mts +0 -414
- package/skills/spec-gate/vendor/gherkin-cli.d.mts +0 -2
- package/skills/spec-gate/vendor/gherkin-cli.mjs +0 -6545
- package/skills/touch-set-correction/scripts/touch-set-correction.bundle.mjs +0 -6655
- package/skills/touch-set-correction/scripts/touch-set-correction.mts +0 -429
- package/skills/verify-scenarios/scripts/verify-scenarios.bundle.mjs +0 -6537
- package/skills/verify-scenarios/scripts/verify-scenarios.mts +0 -470
|
@@ -71,7 +71,7 @@ procedure above, plus one gate before declaring the plan retirement-ready:
|
|
|
71
71
|
escape hatch — no suite-relevant behavior, no CR opened, no gate invoked) needs none; mark it
|
|
72
72
|
complete on its own merits.
|
|
73
73
|
- **Run the gate floor.** Run `checkGateFloor` (`plugins/sdd/skills/spec-gate/scripts/
|
|
74
|
-
check-spec-state.
|
|
74
|
+
check-spec-state.mjs`, wired into `pnpm verify:specs`) before marking the plan
|
|
75
75
|
retirement-ready. A clean floor → mark it. A violation (the status is approved/implemented but
|
|
76
76
|
the ledger has no matching gate approve line) → do **not** mark the plan retirement-ready on
|
|
77
77
|
git evidence alone; record the violation explicitly in `## NEXT` so a human resolves it (either
|
|
@@ -11,8 +11,8 @@ metadata:
|
|
|
11
11
|
The concrete engine for the **place-node** step. Given a new
|
|
12
12
|
node's `concept` (and optional name), it suggests a **provisional** capability home and catches possible
|
|
13
13
|
duplicates, so explore places a node without holding the whole tree in its head (it scans the project-spec's
|
|
14
|
-
`concept:` frontmatter and ranks the capability folders those facets already sit in). Self-contained `.
|
|
15
|
-
(
|
|
14
|
+
`concept:` frontmatter and ranks the capability folders those facets already sit in). Self-contained `.mjs`
|
|
15
|
+
(compiled from `src/`; no runtime deps, Node ≥22.11).
|
|
16
16
|
|
|
17
17
|
## Run it
|
|
18
18
|
|
|
@@ -1,12 +1,117 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Compiled by `universal-plugin plugin build` from src/place-node/place-node.mts. Edit the source, not this file.
|
|
3
|
+
globalThis.__SKILL_SCRIPT__ = {"package":null,"bin":null,"version":"0.7.2","entry":"skills/place-node/scripts/place-node.mjs","commands":{}};
|
|
4
|
+
import { readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
//#region src/place-node/place-node.mts
|
|
8
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
9
|
+
"node_modules",
|
|
10
|
+
".git",
|
|
11
|
+
"dist",
|
|
12
|
+
".turbo",
|
|
13
|
+
".next",
|
|
14
|
+
"coverage"
|
|
15
|
+
]);
|
|
16
|
+
function parseConcepts(text) {
|
|
17
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/.exec(text);
|
|
18
|
+
if (!m) return [];
|
|
19
|
+
const lines = m[1].split("\n").map((l) => l.replace(/\r$/, ""));
|
|
20
|
+
for (let i = 0; i < lines.length; i++) {
|
|
21
|
+
const line = lines[i];
|
|
22
|
+
if (line.length - line.trimStart().length !== 0) continue;
|
|
23
|
+
const [key, ...rest] = line.trim().split(":");
|
|
24
|
+
if (key !== "concept") continue;
|
|
25
|
+
const value = rest.join(":").trim();
|
|
26
|
+
if (value.startsWith("[") && value.endsWith("]")) return value.slice(1, -1).split(",").map((s) => unquote(s.trim())).filter((s) => s.length > 0);
|
|
27
|
+
if (value !== "") return [unquote(value)];
|
|
28
|
+
const out = [];
|
|
29
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
30
|
+
const item = lines[j];
|
|
31
|
+
if (item.trim() === "") continue;
|
|
32
|
+
if (item.length - item.trimStart().length === 0) break;
|
|
33
|
+
const dash = /^\s*-\s+(.*)$/.exec(item);
|
|
34
|
+
if (dash) out.push(unquote(dash[1].trim()));
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
function unquote(v) {
|
|
41
|
+
return v.replace(/^["']|["']$/g, "");
|
|
42
|
+
}
|
|
43
|
+
function displayPath(relPath) {
|
|
44
|
+
const p = relPath.replace(/\\/g, "/");
|
|
45
|
+
return p.endsWith("/README.md") ? p.slice(0, -9) : p;
|
|
46
|
+
}
|
|
47
|
+
function scanProjectSpec(specDir) {
|
|
48
|
+
const records = [];
|
|
49
|
+
walk(specDir, specDir, records);
|
|
50
|
+
return records;
|
|
51
|
+
}
|
|
52
|
+
function walk(dir, specDir, out) {
|
|
53
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
54
|
+
if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue;
|
|
55
|
+
const full = join(dir, entry.name);
|
|
56
|
+
if (entry.isDirectory()) walk(full, specDir, out);
|
|
57
|
+
else if (entry.name.endsWith(".md")) {
|
|
58
|
+
const concepts = parseConcepts(readFileSync(full, "utf8"));
|
|
59
|
+
if (concepts.length === 0) continue;
|
|
60
|
+
const relPath = full.slice(specDir.length + 1).replace(/\\/g, "/");
|
|
61
|
+
out.push({
|
|
62
|
+
relPath,
|
|
63
|
+
capability: relPath.split("/")[0],
|
|
64
|
+
display: displayPath(relPath),
|
|
65
|
+
concepts
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function suggestHomes(records, concept) {
|
|
71
|
+
const counts = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const rec of records) {
|
|
73
|
+
if (!rec.concepts.includes(concept)) continue;
|
|
74
|
+
counts.set(rec.capability, (counts.get(rec.capability) ?? 0) + 1);
|
|
75
|
+
}
|
|
76
|
+
return [...counts.entries()].map(([capability, count]) => ({
|
|
77
|
+
capability,
|
|
78
|
+
count
|
|
79
|
+
})).sort((a, b) => b.count - a.count || a.capability.localeCompare(b.capability));
|
|
80
|
+
}
|
|
81
|
+
function findNear(records, name) {
|
|
82
|
+
const needle = name.trim().toLowerCase();
|
|
83
|
+
if (needle === "") return [];
|
|
84
|
+
return records.filter((rec) => rec.relPath.toLowerCase().includes(needle)).sort((a, b) => a.display.localeCompare(b.display));
|
|
85
|
+
}
|
|
86
|
+
function render(homes, near, concept, name) {
|
|
87
|
+
const lines = [`place-node: concept=${concept || "(none)"} name=${name || "(none)"}`];
|
|
88
|
+
if (homes.length > 0) {
|
|
89
|
+
lines.push(`homes[${homes.length}]{capability,facets}:`);
|
|
90
|
+
for (const h of homes) lines.push(` ${h.capability},${h.count}`);
|
|
91
|
+
} else lines.push("homes[0]: (new concept — pick any plausible capability; finalized at handoff)");
|
|
92
|
+
if (near.length > 0) {
|
|
93
|
+
lines.push(`near[${near.length}]:`);
|
|
94
|
+
for (const n of near) lines.push(` ${n.display}`);
|
|
95
|
+
} else lines.push("near[0]: (no name overlap)");
|
|
96
|
+
lines.push("note: placement is provisional — finalized at handoff");
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
function main(argv) {
|
|
100
|
+
let specDir = ".";
|
|
101
|
+
let concept = "";
|
|
102
|
+
let name = "";
|
|
103
|
+
for (let i = 0; i < argv.length; i++) {
|
|
104
|
+
const a = argv[i];
|
|
105
|
+
if (a === "--spec-dir") specDir = argv[++i] ?? ".";
|
|
106
|
+
else if (a === "--concept") concept = argv[++i] ?? "";
|
|
107
|
+
else if (a === "--name") name = argv[++i] ?? "";
|
|
108
|
+
}
|
|
109
|
+
const records = scanProjectSpec(specDir);
|
|
110
|
+
const homes = concept ? suggestHomes(records, concept) : [];
|
|
111
|
+
const near = name ? findNear(records, name) : [];
|
|
112
|
+
process.stdout.write(`${render(homes, near, concept, name)}\n`);
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
|
|
116
|
+
//#endregion
|
|
117
|
+
export { findNear, main, parseConcepts, scanProjectSpec, suggestHomes };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Internal, non-user-invocable SDD skill carrying the Doctrine loop's **last retro step** — the
|
|
4
4
|
gated, idempotent **tracked deletion** of a retired mission plan. It holds a self-contained
|
|
5
|
-
`scripts/retire-plans.
|
|
5
|
+
`scripts/retire-plans.mjs` (node ≥22.11, no deps; an agent fallback when `node` is absent).
|
|
6
6
|
|
|
7
7
|
**Distill and delete are decoupled.** The Scanner distills the combat log into ledger `strategy`
|
|
8
8
|
early (at `→ implemented`); this sweep deletes the plan **later**, gated on source = `done`/merged
|
|
@@ -32,4 +32,4 @@ combat log's presence only — a brief owes no distillation, so a cr-ref with br
|
|
|
32
32
|
alone does — a brief without a `plan.md` is untouched). Each brief is deleted only if present; an
|
|
33
33
|
absent one is a no-op, same as the missing log half.
|
|
34
34
|
|
|
35
|
-
Tests (`
|
|
35
|
+
Tests (`src/plan-retirement/retire-plans.test.mts`) run under `pnpm verify:specs`.
|
|
@@ -1,12 +1,123 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Compiled by `universal-plugin plugin build` from src/plan-retirement/retire-plans.mts. Edit the source, not this file.
|
|
3
|
+
globalThis.__SKILL_SCRIPT__ = {"package":null,"bin":null,"version":"0.7.2","entry":"skills/plan-retirement/scripts/retire-plans.mjs","commands":{}};
|
|
4
|
+
import { existsSync, readFileSync, readdirSync, realpathSync, unlinkSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
//#region src/plan-retirement/retire-plans.mts
|
|
8
|
+
const PLAN_SUFFIX = ".plan.md";
|
|
9
|
+
const LOG_SUFFIX = ".log.jsonl";
|
|
10
|
+
const DESIGN_SUFFIX = ".design.md";
|
|
11
|
+
const OPERATIONS_SUFFIX = ".operations.md";
|
|
12
|
+
const EVIDENCE_SUFFIX = ".evidence.md";
|
|
13
|
+
function transientArtifactFiles(crRef) {
|
|
14
|
+
return [
|
|
15
|
+
`${crRef}${PLAN_SUFFIX}`,
|
|
16
|
+
`${crRef}${LOG_SUFFIX}`,
|
|
17
|
+
`${crRef}${DESIGN_SUFFIX}`,
|
|
18
|
+
`${crRef}${OPERATIONS_SUFFIX}`,
|
|
19
|
+
`${crRef}${EVIDENCE_SUFFIX}`
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
function parseCleared(value) {
|
|
23
|
+
if (!value) return [];
|
|
24
|
+
const seen = /* @__PURE__ */ new Set();
|
|
25
|
+
for (const raw of value.split(",")) {
|
|
26
|
+
const ref = raw.trim();
|
|
27
|
+
if (ref) seen.add(ref);
|
|
28
|
+
}
|
|
29
|
+
return [...seen];
|
|
30
|
+
}
|
|
31
|
+
function discoverPlans(root) {
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = readdirSync(root);
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
return entries.filter((f) => f.endsWith(PLAN_SUFFIX)).map((f) => f.slice(0, -8));
|
|
39
|
+
}
|
|
40
|
+
function discoverLogs(root) {
|
|
41
|
+
let entries;
|
|
42
|
+
try {
|
|
43
|
+
entries = readdirSync(root);
|
|
44
|
+
} catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
return entries.filter((f) => f.endsWith(LOG_SUFFIX)).map((f) => f.slice(0, -10));
|
|
48
|
+
}
|
|
49
|
+
function distilledCrRefs(ledgerDir) {
|
|
50
|
+
const distilled = /* @__PURE__ */ new Set();
|
|
51
|
+
let entries;
|
|
52
|
+
try {
|
|
53
|
+
entries = readdirSync(ledgerDir);
|
|
54
|
+
} catch {
|
|
55
|
+
return distilled;
|
|
56
|
+
}
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
59
|
+
let text;
|
|
60
|
+
try {
|
|
61
|
+
text = readFileSync(join(ledgerDir, entry), "utf8");
|
|
62
|
+
} catch {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
for (const line of text.split("\n")) {
|
|
66
|
+
const trimmed = line.trim();
|
|
67
|
+
if (!trimmed) continue;
|
|
68
|
+
let record;
|
|
69
|
+
try {
|
|
70
|
+
record = JSON.parse(trimmed);
|
|
71
|
+
} catch {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (record === null || typeof record !== "object") continue;
|
|
75
|
+
const { kind, distills } = record;
|
|
76
|
+
if (kind === "strategy" && typeof distills === "string" && distills.length > 0) distilled.add(distills);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return distilled;
|
|
80
|
+
}
|
|
81
|
+
function decideRetirements(cleared, existing, distilled, logPresent) {
|
|
82
|
+
const present = new Set(existing);
|
|
83
|
+
const seen = /* @__PURE__ */ new Set();
|
|
84
|
+
const out = [];
|
|
85
|
+
for (const ref of cleared) if (present.has(ref) && (distilled.has(ref) || !logPresent.has(ref)) && !seen.has(ref)) {
|
|
86
|
+
seen.add(ref);
|
|
87
|
+
out.push(ref);
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
function main(argv) {
|
|
92
|
+
const root = argv.includes("--root") ? argv[argv.indexOf("--root") + 1] : ".agents/plans";
|
|
93
|
+
const ledgerArg = argv.includes("--ledger") ? argv[argv.indexOf("--ledger") + 1] : void 0;
|
|
94
|
+
const cleared = parseCleared(argv.includes("--retire") ? argv[argv.indexOf("--retire") + 1] : void 0);
|
|
95
|
+
const dryRun = argv.includes("--dry-run");
|
|
96
|
+
if (argv.includes("--distilled")) {
|
|
97
|
+
for (const ref of distilledCrRefs(argv[argv.indexOf("--distilled") + 1] ?? "")) process.stdout.write(`${ref}\n`);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
let retiring;
|
|
101
|
+
if (!ledgerArg || !existsSync(ledgerArg)) {
|
|
102
|
+
process.stdout.write(`no verifiable ledger (${ledgerArg ? `--ledger ${ledgerArg} unreadable` : "--ledger not given"}): distillation cannot be checked, so retirement is skipped for all cr-refs\n`);
|
|
103
|
+
retiring = [];
|
|
104
|
+
} else {
|
|
105
|
+
const distilled = distilledCrRefs(ledgerArg);
|
|
106
|
+
const logPresent = new Set(discoverLogs(root));
|
|
107
|
+
retiring = decideRetirements(cleared, discoverPlans(root), distilled, logPresent);
|
|
108
|
+
}
|
|
109
|
+
const deleted = [];
|
|
110
|
+
for (const ref of retiring) for (const file of transientArtifactFiles(ref)) {
|
|
111
|
+
const path = join(root, file);
|
|
112
|
+
if (!existsSync(path)) continue;
|
|
113
|
+
if (!dryRun) unlinkSync(path);
|
|
114
|
+
deleted.push(path);
|
|
115
|
+
}
|
|
116
|
+
const verb = dryRun ? "would delete" : "deleted";
|
|
117
|
+
for (const path of deleted) process.stdout.write(`${verb} ${path}\n`);
|
|
118
|
+
process.stdout.write(`${dryRun ? "dry-run: " : ""}retired ${retiring.length} plan(s), ${deleted.length} file(s)\n`);
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) process.exit(main(process.argv.slice(2)));
|
|
122
|
+
//#endregion
|
|
123
|
+
export { decideRetirements, discoverLogs, discoverPlans, distilledCrRefs, main, parseCleared, transientArtifactFiles };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# resolve-governances
|
|
2
2
|
|
|
3
3
|
The concrete engine for **SDD governance resolution**.
|
|
4
|
-
A non-user-invocable skill carrying a self-contained `.
|
|
4
|
+
A non-user-invocable skill carrying a self-contained `.mjs` script that, for a touched file's
|
|
5
5
|
artifact-type, resolves each production-chain role to its agent plus the resolved-actor bars it loads
|
|
6
6
|
— matching candidates across the project's `.agents/governances/` anchors, the matched plugin squad,
|
|
7
7
|
and the sdd defaults.
|
|
8
8
|
|
|
9
9
|
- **Skill contract:** [`SKILL.md`](./SKILL.md)
|
|
10
|
-
- **Script:** [`scripts/resolve-governances.
|
|
11
|
-
- **Tests:** [`
|
|
10
|
+
- **Script:** [`scripts/resolve-governances.mjs`](./scripts/resolve-governances.mjs)
|
|
11
|
+
- **Tests:** [`src/resolve-governances/resolve-governances.test.mts`](../../src/resolve-governances/resolve-governances.test.mts) (`node:test`)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
node scripts/resolve-governances.mjs --root . --artifact-type skill
|
|
@@ -15,7 +15,7 @@ project anchors, the matched plugin squad (from the project registry
|
|
|
15
15
|
`.agents/universal-plugin.json`), and the sdd defaults. It is a **dumb matcher**: it returns each
|
|
16
16
|
bar's candidates **bucketed by tier** and does **not** order by precedence or apply `compose` — the
|
|
17
17
|
consuming agent composes. The conductor and the cold judges run it so they **never hand-enumerate**
|
|
18
|
-
the bars. It carries a self-contained `.
|
|
18
|
+
the bars. It carries a self-contained `.mjs` script (compiled from `src/`; no runtime deps, Node ≥22.11).
|
|
19
19
|
|
|
20
20
|
## Run the resolution
|
|
21
21
|
|