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
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// align-spec — project-spec/align-spec's concrete engine. Detects prose↔suite drift across the
|
|
3
|
-
// project spec's nodes and, on request, applies the mechanical write primitives a judge-directed
|
|
4
|
-
// reconcile step uses (see this skill's README.md / SKILL.md).
|
|
5
|
-
//
|
|
6
|
-
// The 12 frozen scenarios split two ways (align-spec.feature):
|
|
7
|
-
// - Mechanical (this engine ships code + a test for each):
|
|
8
|
-
// * a scenario-diff flags a narrowing of the frozen suite → Clearance
|
|
9
|
-
// * check mode exits non-zero on drift and writes nothing
|
|
10
|
-
// * check mode exits zero when there is no drift
|
|
11
|
-
// * detect runs over every node of the project spec (a chosen set)
|
|
12
|
-
// * reconcile never writes lifecycle state (writes only prose or scenarios)
|
|
13
|
-
// - Judge-orchestrated (SKILL.md documents the procedure; no engine code):
|
|
14
|
-
// coverage-gap detection, prose/scenario contradiction detection, the aligned-report-no-
|
|
15
|
-
// drift aggregate, and every reconcile *decision* (add a scenario / trim prose / align the
|
|
16
|
-
// losing side / escalate a Clearance) — there are no scenario IDs in prose, so prose↔suite
|
|
17
|
-
// alignment is judge-only. This engine feeds that judge the mechanical scan (node
|
|
18
|
-
// iteration + scenario-diff); it never itself judges coverage or contradiction.
|
|
19
|
-
//
|
|
20
|
-
// Node iteration and the scenario-diff reuse the existing engines rather than re-implementing
|
|
21
|
-
// them: check-spec-structure's scanProjectSpec (node discovery) and spec-gate's classify-edit-
|
|
22
|
-
// class (the gherkin-cli-backed structural diff against a frozen baseline).
|
|
23
|
-
//
|
|
24
|
-
// No dependencies (the repo's node-≥23.6 / no-deps convention). Pure functions are exported for
|
|
25
|
-
// node:test; running the file directly drives the CLI.
|
|
26
|
-
|
|
27
|
-
import { existsSync, readdirSync, realpathSync } from 'node:fs'
|
|
28
|
-
import { isAbsolute, join, relative } from 'node:path'
|
|
29
|
-
import { pathToFileURL } from 'node:url'
|
|
30
|
-
import { type NodeRecord, scanProjectSpec } from '../../check-spec-structure/scripts/check-spec-structure.mts'
|
|
31
|
-
import { classifyFile } from '../../spec-gate/scripts/classify-edit-class.mts'
|
|
32
|
-
|
|
33
|
-
export const DEFAULT_BASE = 'HEAD'
|
|
34
|
-
|
|
35
|
-
export type DriftKind = 'narrowing'
|
|
36
|
-
export type DriftSeverity = 'clearance'
|
|
37
|
-
|
|
38
|
-
export interface DriftFinding {
|
|
39
|
-
kind: DriftKind
|
|
40
|
-
severity: DriftSeverity
|
|
41
|
-
/** The node's display path (a folder for a README-rooted node). */
|
|
42
|
-
node: string
|
|
43
|
-
detail: string
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ── Node selection — the "chosen set" a detect run scopes to ──
|
|
47
|
-
// No `--nodes` arg selects every node scanProjectSpec finds; an explicit list scopes the sweep
|
|
48
|
-
// to exactly those nodes (matched by display path or the README's relative path).
|
|
49
|
-
export function selectNodes(records: NodeRecord[], only?: string[]): NodeRecord[] {
|
|
50
|
-
if (!only || only.length === 0) return records
|
|
51
|
-
const wanted = new Set(only.map(normalizeNodeRef))
|
|
52
|
-
return records.filter((r) => wanted.has(normalizeNodeRef(r.display)) || wanted.has(normalizeNodeRef(r.relPath)))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function normalizeNodeRef(ref: string): string {
|
|
56
|
-
return ref
|
|
57
|
-
.replace(/\\/g, '/')
|
|
58
|
-
.replace(/\/README\.md$/, '')
|
|
59
|
-
.replace(/\/+$/, '')
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ── Locate a node's sibling `.feature` file (same convention check-spec-structure scans by) ──
|
|
63
|
-
export function findFeaturePath(specDir: string, node: NodeRecord): string | null {
|
|
64
|
-
const nodeDir = join(specDir, node.relPath.replace(/README\.md$/, ''))
|
|
65
|
-
if (!existsSync(nodeDir)) return null
|
|
66
|
-
const entries = readdirSync(nodeDir, { withFileTypes: true })
|
|
67
|
-
const feature = entries.find((e) => e.isFile() && e.name.endsWith('.feature'))
|
|
68
|
-
return feature ? join(nodeDir, feature.name) : null
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ── Mechanical scenario-diff: a modified/removed baseline scenario is a narrowing → Clearance ──
|
|
72
|
-
// Reuses spec-gate's classify-edit-class rather than hand-rolling a line-diff (a line-diff is
|
|
73
|
-
// fooled by a step reassigned off a frozen scenario onto a newly-added adjacent one).
|
|
74
|
-
export function detectNarrowing(node: NodeRecord, specDir: string, base: string, cwd = '.'): DriftFinding[] {
|
|
75
|
-
const featurePath = findFeaturePath(specDir, node)
|
|
76
|
-
if (!featurePath) return []
|
|
77
|
-
// classifyFile (and the `git show <base>:<path>` it drives) needs a path relative to cwd
|
|
78
|
-
// (the git repo root) — resolve it, since specDir/featurePath may already be absolute.
|
|
79
|
-
const relFeaturePath = isAbsolute(featurePath) ? relative(cwd, featurePath) : featurePath
|
|
80
|
-
const result = classifyFile(relFeaturePath, base, cwd)
|
|
81
|
-
if (result.classification !== 'narrowing' && result.classification !== 'mixed') return []
|
|
82
|
-
const narrowed = result.scenarios.filter((s) => s.change === 'modified' || s.change === 'removed')
|
|
83
|
-
return [
|
|
84
|
-
{
|
|
85
|
-
kind: 'narrowing',
|
|
86
|
-
severity: 'clearance',
|
|
87
|
-
node: node.display,
|
|
88
|
-
detail: `scenario-diff vs ${base} narrows: ${narrowed.map((s) => s.name).join(', ')} — escalate a Clearance CR, do not silently rewrite`,
|
|
89
|
-
},
|
|
90
|
-
]
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Runs the mechanical scan over exactly the chosen node set — reports drift per node.
|
|
94
|
-
export function detect(records: NodeRecord[], specDir: string, base: string, cwd = '.'): DriftFinding[] {
|
|
95
|
-
return records.flatMap((node) => detectNarrowing(node, specDir, base, cwd))
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function hasDrift(findings: DriftFinding[]): boolean {
|
|
99
|
-
return findings.length > 0
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ── The write boundary ──
|
|
103
|
-
// Reconcile decisions (add/trim/align/escalate) are judge-orchestrated (SKILL.md), but the
|
|
104
|
-
// mechanical write primitives the judge's verdict drives are engine code, and they are built to
|
|
105
|
-
// make writing lifecycle state structurally impossible: a README write splits frontmatter from
|
|
106
|
-
// body and only ever touches the body; a .feature write only ever appends a whole scenario block.
|
|
107
|
-
export interface SplitDocument {
|
|
108
|
-
frontmatter: string
|
|
109
|
-
body: string
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function splitFrontmatter(text: string): SplitDocument {
|
|
113
|
-
const m = /^(---\r?\n[\s\S]*?\r?\n---\s*(?:\r?\n|$))([\s\S]*)$/.exec(text)
|
|
114
|
-
if (!m) return { frontmatter: '', body: text }
|
|
115
|
-
return { frontmatter: m[1], body: m[2] }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Trims prose out of a node's README body — the frontmatter (and any status/approval/freeze
|
|
119
|
-
// field it carries) passes through byte-for-byte untouched.
|
|
120
|
-
export function trimProse(readmeText: string, proseToRemove: string): string {
|
|
121
|
-
const { frontmatter, body } = splitFrontmatter(readmeText)
|
|
122
|
-
return frontmatter + body.split(proseToRemove).join('')
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Appends a whole scenario block to a `.feature` file. `.feature` files carry no frontmatter /
|
|
126
|
-
// lifecycle fields to begin with — this only ever appends, never rewrites an existing scenario
|
|
127
|
-
// (a rewrite of an existing frozen scenario is the narrowing path above, which escalates instead).
|
|
128
|
-
export function appendScenario(featureText: string, scenarioBlock: string): string {
|
|
129
|
-
const trimmed = featureText.replace(/\s+$/, '')
|
|
130
|
-
return `${trimmed}\n\n${scenarioBlock.trim()}\n`
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ── Render ──
|
|
134
|
-
export function renderFindings(findings: DriftFinding[], specDir: string): string {
|
|
135
|
-
const lines: string[] = [`align-spec: spec-dir=${specDir}`, `drift[${findings.length}]:`]
|
|
136
|
-
for (const f of findings) lines.push(` ${f.node} — ${f.kind} (${f.severity}): ${f.detail}`)
|
|
137
|
-
if (findings.length === 0) lines.push(' (none — mechanical scenario-diff found no narrowing)')
|
|
138
|
-
lines.push(
|
|
139
|
-
'note: coverage gaps and prose/scenario contradictions are judge-only (no scenario IDs in prose) — this engine reports only the mechanical scenario-diff',
|
|
140
|
-
)
|
|
141
|
-
return lines.join('\n')
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ── CLI ──
|
|
145
|
-
function parseNodesArg(value: string | undefined): string[] | undefined {
|
|
146
|
-
if (!value) return undefined
|
|
147
|
-
const parts = value
|
|
148
|
-
.split(',')
|
|
149
|
-
.map((s) => s.trim())
|
|
150
|
-
.filter(Boolean)
|
|
151
|
-
return parts.length > 0 ? parts : undefined
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function main(argv: string[]): number {
|
|
155
|
-
let specDir = '.'
|
|
156
|
-
let base = DEFAULT_BASE
|
|
157
|
-
let mode: 'detect' | 'check' = 'detect'
|
|
158
|
-
let format: 'toon' | 'json' = 'toon'
|
|
159
|
-
let only: string[] | undefined
|
|
160
|
-
for (let i = 0; i < argv.length; i++) {
|
|
161
|
-
const a = argv[i]
|
|
162
|
-
if (a === '--spec-dir') specDir = argv[++i] ?? '.'
|
|
163
|
-
else if (a === '--check') mode = 'check'
|
|
164
|
-
else if (a === '--base') base = argv[++i] ?? DEFAULT_BASE
|
|
165
|
-
else if (a === '--format') format = (argv[++i] as 'toon' | 'json') ?? 'toon'
|
|
166
|
-
else if (a === '--nodes') only = parseNodesArg(argv[++i])
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const records = selectNodes(scanProjectSpec(specDir), only)
|
|
170
|
-
const findings = detect(records, specDir, base)
|
|
171
|
-
|
|
172
|
-
if (mode === 'check') {
|
|
173
|
-
if (hasDrift(findings)) {
|
|
174
|
-
process.stderr.write(`align-spec: ${findings.length} drift finding(s) (mechanical scenario-diff)\n`)
|
|
175
|
-
return 1
|
|
176
|
-
}
|
|
177
|
-
process.stdout.write('align-spec: no mechanical drift\n')
|
|
178
|
-
return 0
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (format === 'json') process.stdout.write(`${JSON.stringify(findings)}\n`)
|
|
182
|
-
else process.stdout.write(`${renderFindings(findings, specDir)}\n`)
|
|
183
|
-
return 0
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {
|
|
187
|
-
process.exit(main(process.argv.slice(2)))
|
|
188
|
-
}
|