@rsaglobaltech/specgate 0.14.6 → 0.16.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/bin/specgate.ts +6 -1
  3. package/dist/bin/specgate.js +5 -1
  4. package/dist/bin/specgate.js.map +1 -1
  5. package/dist/packages/core/src/domain/DraftChecklist.js +334 -0
  6. package/dist/packages/core/src/domain/DraftChecklist.js.map +1 -0
  7. package/dist/packages/core/src/domain/ForeignSpec.js +55 -0
  8. package/dist/packages/core/src/domain/ForeignSpec.js.map +1 -0
  9. package/dist/packages/core/src/domain/OpenSpecReader.js +225 -0
  10. package/dist/packages/core/src/domain/OpenSpecReader.js.map +1 -0
  11. package/dist/packages/core/src/domain/VerifyClaims.js +113 -0
  12. package/dist/packages/core/src/domain/VerifyClaims.js.map +1 -0
  13. package/dist/packages/mcp-spec-driven/src/tools.js +14 -2
  14. package/dist/packages/mcp-spec-driven/src/tools.js.map +1 -1
  15. package/dist/scripts/agents/commands.js +4 -1
  16. package/dist/scripts/agents/commands.js.map +1 -1
  17. package/dist/scripts/agents/init.js +16 -1
  18. package/dist/scripts/agents/init.js.map +1 -1
  19. package/dist/scripts/cli/commands/quality/VerifyCommand.js +333 -0
  20. package/dist/scripts/cli/commands/quality/VerifyCommand.js.map +1 -0
  21. package/dist/scripts/cli/commands/spec/DraftCommand.js +215 -0
  22. package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -0
  23. package/dist/scripts/cli/commands/spec/StatusCommand.js +24 -5
  24. package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
  25. package/dist/scripts/draft.js +11 -0
  26. package/dist/scripts/draft.js.map +1 -0
  27. package/dist/scripts/gen_mcp_tools.js +8 -2
  28. package/dist/scripts/gen_mcp_tools.js.map +1 -1
  29. package/dist/scripts/lib/agent.js +5 -4
  30. package/dist/scripts/lib/agent.js.map +1 -1
  31. package/dist/scripts/lib/blocking-stdio.js +34 -0
  32. package/dist/scripts/lib/blocking-stdio.js.map +1 -0
  33. package/dist/scripts/lib/command.js +1 -0
  34. package/dist/scripts/lib/command.js.map +1 -1
  35. package/dist/scripts/lib/surface.js +21 -0
  36. package/dist/scripts/lib/surface.js.map +1 -1
  37. package/dist/scripts/verify.js +11 -0
  38. package/dist/scripts/verify.js.map +1 -0
  39. package/package.json +1 -1
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ /**
3
+ * `specgate verify` — what another tool calls done, gated on evidence
4
+ * (ADR-0030, docs/specs/verify-foreign-specs.md).
5
+ *
6
+ * Reads the other tool's files read-only, runs the rules in `VerifyClaims`,
7
+ * and writes nothing outside `.specgate/`. The facts the rules need and a
8
+ * pure module cannot gather — files, git history, the test run, the lock —
9
+ * are gathered here.
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.VerifyCommand = void 0;
46
+ exports.parseArgs = parseArgs;
47
+ exports.readSpec = readSpec;
48
+ exports.hashCriterion = hashCriterion;
49
+ const fs = __importStar(require("node:fs"));
50
+ const path = __importStar(require("node:path"));
51
+ const crypto = __importStar(require("node:crypto"));
52
+ const node_child_process_1 = require("node:child_process");
53
+ const command_1 = require("../../../lib/command");
54
+ const agent_1 = require("../../../lib/agent");
55
+ const diagnostics_1 = require("../../../lib/diagnostics");
56
+ const project_root_1 = require("../../../lib/project-root");
57
+ const DerivedMatrixSources_1 = require("../../../../packages/core/src/infrastructure/DerivedMatrixSources");
58
+ const OpenSpecReader_1 = require("../../../../packages/core/src/domain/OpenSpecReader");
59
+ const VerifyClaims_1 = require("../../../../packages/core/src/domain/VerifyClaims");
60
+ const LOCK = path.join(".specgate", "verify.lock");
61
+ const FORMATS = ["openspec"];
62
+ function usage() {
63
+ return ("Usage:\n" +
64
+ ' specgate verify [--from openspec] [--project-dir <dir>] [--run] [--test-cmd "<cmd>"]\n' +
65
+ " [--since <git-ref>] [--record] [--ids] [--json | --format github]\n\n" +
66
+ "Reads another tool's specification in place and fails while something it\n" +
67
+ "calls done has no test naming each criterion it covers (ADR-0030).\n\n" +
68
+ " --from <format> openspec. Detected when omitted.\n" +
69
+ " --run Run the test command too; a failing suite fails the check.\n" +
70
+ " --test-cmd <cmd> The suite to run (default: `npm test` when package.json has one).\n" +
71
+ " --since <ref> Gate only claims made after this git ref; older ones are reported.\n" +
72
+ " --record After a green run, record the verified criteria in .specgate/verify.lock.\n" +
73
+ " --ids Print every criterion id, to name in tests.\n" +
74
+ " --format github GitHub Actions annotations on the spec lines.\n");
75
+ }
76
+ function parseArgs(argv) {
77
+ const o = {
78
+ projectDir: ".",
79
+ from: "",
80
+ run: false,
81
+ testCmd: "",
82
+ since: "",
83
+ record: false,
84
+ ids: false,
85
+ json: (0, agent_1.wantsJson)(argv),
86
+ format: "text",
87
+ };
88
+ for (let i = 0; i < argv.length; i += 1) {
89
+ const a = argv[i];
90
+ const value = () => {
91
+ const v = argv[++i];
92
+ if (v === undefined)
93
+ throw new Error(`${a} needs a value`);
94
+ return v;
95
+ };
96
+ if (a === "--project-dir")
97
+ o.projectDir = value();
98
+ else if (a === "--from")
99
+ o.from = value();
100
+ else if (a === "--run")
101
+ o.run = true;
102
+ else if (a === "--test-cmd")
103
+ o.testCmd = value();
104
+ else if (a === "--since")
105
+ o.since = value();
106
+ else if (a === "--record")
107
+ o.record = true;
108
+ else if (a === "--ids")
109
+ o.ids = true;
110
+ else if (a === "--json")
111
+ o.format = "json";
112
+ else if (a === "--format") {
113
+ const f = value();
114
+ if (f !== "text" && f !== "github" && f !== "json")
115
+ throw new Error(`unknown --format ${f}`);
116
+ o.format = f;
117
+ }
118
+ else if (a === "--help" || a === "-h") {
119
+ process.stdout.write(usage());
120
+ process.exit(0);
121
+ }
122
+ else
123
+ throw new Error(`unknown argument ${a}`);
124
+ }
125
+ if (o.from && !FORMATS.includes(o.from)) {
126
+ throw new Error(`--from ${o.from}: supported formats are ${FORMATS.join(", ")}`);
127
+ }
128
+ return o;
129
+ }
130
+ function walk(root, rel, out) {
131
+ let entries;
132
+ try {
133
+ entries = fs.readdirSync(path.join(root, rel), { withFileTypes: true });
134
+ }
135
+ catch {
136
+ return;
137
+ }
138
+ for (const e of entries) {
139
+ const child = rel ? `${rel}/${e.name}` : e.name;
140
+ if (e.isDirectory())
141
+ walk(root, child, out);
142
+ else if (e.isFile() && e.name.endsWith(".md"))
143
+ out.push(child);
144
+ }
145
+ }
146
+ function readSpec(projectDir, from) {
147
+ const paths = [];
148
+ walk(projectDir, "openspec", paths);
149
+ if (from === "openspec" || (!from && (0, OpenSpecReader_1.isOpenSpecProject)(paths))) {
150
+ const files = paths.map((p) => ({
151
+ path: p,
152
+ source: fs.readFileSync(path.join(projectDir, p), "utf8"),
153
+ }));
154
+ return (0, OpenSpecReader_1.readOpenSpec)(files);
155
+ }
156
+ return null;
157
+ }
158
+ function git(projectDir, args) {
159
+ return (0, node_child_process_1.spawnSync)("git", args, { cwd: projectDir, encoding: "utf8" });
160
+ }
161
+ /** The claims whose dating path did not exist at `ref`. */
162
+ function freshClaims(projectDir, spec, ref) {
163
+ const ok = git(projectDir, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
164
+ if (ok.status !== 0)
165
+ throw new Error(`--since ${ref}: not a commit in this repository`);
166
+ const fresh = new Set();
167
+ for (const c of spec.claims) {
168
+ const tree = git(projectDir, ["ls-tree", ref, "--", c.datedBy]);
169
+ if ((tree.stdout || "").trim() === "")
170
+ fresh.add(c.datedBy);
171
+ }
172
+ return fresh;
173
+ }
174
+ function hashCriterion(text) {
175
+ const normal = text.replace(/\s+/g, " ").trim();
176
+ return crypto.createHash("sha256").update(normal).digest("hex").slice(0, 16);
177
+ }
178
+ function readLock(projectDir) {
179
+ try {
180
+ const doc = JSON.parse(fs.readFileSync(path.join(projectDir, LOCK), "utf8"));
181
+ return new Map(Object.entries(doc.criteria || {}).map(([k, v]) => [k, String(v.hash)]));
182
+ }
183
+ catch {
184
+ return new Map();
185
+ }
186
+ }
187
+ function writeLock(projectDir, spec, proved) {
188
+ const file = path.join(projectDir, LOCK);
189
+ let doc = { version: 1, criteria: {} };
190
+ try {
191
+ doc = JSON.parse(fs.readFileSync(file, "utf8"));
192
+ }
193
+ catch {
194
+ // a first record
195
+ }
196
+ const head = (git(projectDir, ["rev-parse", "HEAD"]).stdout || "").trim() || null;
197
+ const texts = new Map(spec.requirements.flatMap((r) => r.criteria.map((c) => [c.id, c.text])));
198
+ for (const id of [...proved].sort()) {
199
+ const text = texts.get(id);
200
+ if (text !== undefined)
201
+ doc.criteria[id] = { hash: hashCriterion(text), commit: head };
202
+ }
203
+ fs.mkdirSync(path.dirname(file), { recursive: true });
204
+ fs.writeFileSync(file, `${JSON.stringify(doc, null, 2)}\n`, "utf8");
205
+ }
206
+ function defaultTestCmd(projectDir) {
207
+ try {
208
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectDir, "package.json"), "utf8"));
209
+ if (pkg.scripts && pkg.scripts.test)
210
+ return "npm test";
211
+ }
212
+ catch {
213
+ // not a node project
214
+ }
215
+ return "";
216
+ }
217
+ function renderText(result) {
218
+ const gated = result.claims.filter((c) => c.gated);
219
+ const out = process.stdout;
220
+ out.write(`\n specgate verify — ${result.format}\n\n`);
221
+ out.write(` ${result.claims.length} claim(s) of done, ${gated.length} gated · ` +
222
+ `${result.coverage.named}/${result.coverage.total} criteria named by a test\n\n`);
223
+ for (const d of result.status) {
224
+ const mark = d.severity === "error" ? "✖" : d.severity === "warning" ? "▲" : "ℹ";
225
+ out.write(` ${mark} ${d.message}\n`);
226
+ if (d.fix && d.severity === "error")
227
+ out.write(` fix: ${d.fix}\n`);
228
+ }
229
+ const errors = result.status.filter((d) => d.severity === "error").length;
230
+ if (errors === 0 && gated.length === 0) {
231
+ out.write(`\n ✔ Nothing to gate: no finished claim of done${result.claims.length ? " is new" : ""}. ` +
232
+ `${result.claims.length - gated.length} older or unfinished claim(s) reported above.\n`);
233
+ return;
234
+ }
235
+ out.write(errors === 0
236
+ ? `\n ✔ Every gated claim of done is named by a test.\n` +
237
+ ` A test that names a criterion is evidence it ran, not proof it asserts the right thing.\n`
238
+ : `\n ✖ ${errors} problem(s) with what is called done.\n`);
239
+ }
240
+ function renderGithub(status) {
241
+ for (const d of status) {
242
+ if (d.severity === "info")
243
+ continue;
244
+ const level = d.severity === "error" ? "error" : "warning";
245
+ const where = d.file ? ` file=${d.file}${d.line ? `,line=${d.line}` : ""}` : "";
246
+ process.stdout.write(`::${level}${where},title=${d.code}::${d.message.replace(/\n/g, " ")}\n`);
247
+ }
248
+ }
249
+ class VerifyCommand extends command_1.BaseCommand {
250
+ execute() {
251
+ let o;
252
+ const io0 = (0, agent_1.agentIo)((0, agent_1.wantsJson)(this.args));
253
+ try {
254
+ o = parseArgs(this.args);
255
+ }
256
+ catch (err) {
257
+ io0.usage({ verify: null }, [
258
+ (0, diagnostics_1.error)("verify_usage", err.message, { fix: "specgate verify --help" }),
259
+ ]);
260
+ }
261
+ const io = (0, agent_1.agentIo)(o.format === "json" || o.json);
262
+ const opts = o;
263
+ const projectDir = (0, project_root_1.resolveProjectDir)(opts.projectDir);
264
+ const spec = readSpec(projectDir, opts.from);
265
+ if (!spec) {
266
+ io.fail({ verify: null }, [
267
+ (0, diagnostics_1.error)("verify_no_spec", `No OpenSpec specification found in ${projectDir}.`, {
268
+ fix: "Run it at the root of a project with an `openspec/` directory, or pass --project-dir.",
269
+ }),
270
+ ]);
271
+ }
272
+ if (opts.ids) {
273
+ if (io.json) {
274
+ io.emit({ verify: { ids: spec.requirements } });
275
+ return;
276
+ }
277
+ for (const r of spec.requirements) {
278
+ process.stdout.write(`${r.id} ${r.title}\n`);
279
+ for (const c of r.criteria)
280
+ process.stdout.write(` ${c.id} ${c.title}\n`);
281
+ }
282
+ return;
283
+ }
284
+ let fresh;
285
+ try {
286
+ fresh = opts.since ? freshClaims(projectDir, spec, opts.since) : undefined;
287
+ }
288
+ catch (err) {
289
+ io.usage({ verify: null }, [(0, diagnostics_1.error)("verify_since", err.message)]);
290
+ }
291
+ const tests = (0, DerivedMatrixSources_1.readDerivationSources)(projectDir).tests;
292
+ const result = (0, VerifyClaims_1.verifyClaims)({
293
+ spec: spec,
294
+ tests,
295
+ freshClaims: fresh,
296
+ lock: readLock(projectDir),
297
+ hash: hashCriterion,
298
+ });
299
+ if (opts.run) {
300
+ const cmd = opts.testCmd || defaultTestCmd(projectDir);
301
+ if (!cmd) {
302
+ result.status.push((0, diagnostics_1.error)("V2_failing_suite", "--run was given and no test command is known.", {
303
+ fix: 'Pass --test-cmd "<the command that runs the suite>".',
304
+ }));
305
+ }
306
+ else {
307
+ const r = (0, node_child_process_1.spawnSync)(cmd, {
308
+ cwd: projectDir,
309
+ shell: true,
310
+ stdio: io.json ? "pipe" : "inherit",
311
+ });
312
+ if (r.status !== 0) {
313
+ result.status.push((0, diagnostics_1.error)("V2_failing_suite", `\`${cmd}\` failed (exit ${r.status}); a red suite proves nothing done.`));
314
+ }
315
+ }
316
+ }
317
+ const failed = result.status.some((d) => d.severity === "error");
318
+ if (opts.record && !failed)
319
+ writeLock(projectDir, spec, result.proved);
320
+ if (opts.format === "github") {
321
+ renderGithub(result.status);
322
+ process.exitCode = failed ? 1 : 0;
323
+ return;
324
+ }
325
+ // Exit through exitCode, not process.exit: a large JSON document piped to
326
+ // another process must drain first (golden_app finding #33).
327
+ const { status, ...payload } = result;
328
+ io.emit({ verify: payload, status }, () => renderText(result));
329
+ process.exitCode = failed ? 1 : 0;
330
+ }
331
+ }
332
+ exports.VerifyCommand = VerifyCommand;
333
+ //# sourceMappingURL=VerifyCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VerifyCommand.js","sourceRoot":"","sources":["../../../../../scripts/cli/commands/quality/VerifyCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * `specgate draft --check <change-id>` — is a draft complete enough to
4
+ * review? (ADR-0029, docs/specs/draft-from-brief.md §4–5)
5
+ *
6
+ * Phase 1 of `draft`: the checklist, runnable on a change written by any
7
+ * agent or person. Drafting it with the project's agent comes later; this is
8
+ * what holds that draft — and any hand-written change — to the rules.
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || (function () {
27
+ var ownKeys = function(o) {
28
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29
+ var ar = [];
30
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
+ return ar;
32
+ };
33
+ return ownKeys(o);
34
+ };
35
+ return function (mod) {
36
+ if (mod && mod.__esModule) return mod;
37
+ var result = {};
38
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
+ __setModuleDefault(result, mod);
40
+ return result;
41
+ };
42
+ })();
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.DraftCommand = void 0;
45
+ exports.parseArgs = parseArgs;
46
+ const fs = __importStar(require("node:fs"));
47
+ const path = __importStar(require("node:path"));
48
+ const command_1 = require("../../../lib/command");
49
+ const agent_1 = require("../../../lib/agent");
50
+ const diagnostics_1 = require("../../../lib/diagnostics");
51
+ const project_root_1 = require("../../../lib/project-root");
52
+ const DraftChecklist_1 = require("../../../../packages/core/src/domain/DraftChecklist");
53
+ const CHANGES = path.join("docs", "specs", "changes");
54
+ function usage() {
55
+ return ("Usage:\n" +
56
+ " specgate draft --check <change-id> [--brief <file>] [--max-requirements <n>] [--project-dir <dir>] [--json]\n\n" +
57
+ "Checks a draft change against the checklist (ADR-0029):\n" +
58
+ " D1 every requirement has a scenario D5 a cited law or standard names its source\n" +
59
+ " D2 every requirement has a kind D6 a stated value is in the brief or an assumption\n" +
60
+ " D3 a scenario per surface each actor uses D7 an open question names what it blocks\n" +
61
+ " D4 a non-functional requirement is measured D8 the draft is small enough to review\n\n" +
62
+ " --brief <file> The brief the draft came from. Without it D3 and D6 cannot\n" +
63
+ " run, and the report says so. Also read from `brief:` in change.yaml.\n");
64
+ }
65
+ function parseArgs(argv) {
66
+ const o = {
67
+ check: "",
68
+ brief: "",
69
+ maxRequirements: 25,
70
+ projectDir: ".",
71
+ json: (0, agent_1.wantsJson)(argv),
72
+ };
73
+ for (let i = 0; i < argv.length; i += 1) {
74
+ const a = argv[i];
75
+ const value = () => {
76
+ const v = argv[++i];
77
+ if (v === undefined)
78
+ throw new Error(`${a} needs a value`);
79
+ return v;
80
+ };
81
+ if (a === "--check")
82
+ o.check = value();
83
+ else if (a === "--brief")
84
+ o.brief = value();
85
+ else if (a === "--max-requirements")
86
+ o.maxRequirements = Number(value());
87
+ else if (a === "--project-dir")
88
+ o.projectDir = value();
89
+ else if (a === "--json")
90
+ o.json = true;
91
+ else if (a === "--help" || a === "-h") {
92
+ process.stdout.write(usage());
93
+ process.exit(0);
94
+ }
95
+ else
96
+ throw new Error(`unknown argument ${a}`);
97
+ }
98
+ if (!o.check) {
99
+ throw new Error("--check <change-id> is required (drafting with an agent is not available yet)");
100
+ }
101
+ if (!Number.isInteger(o.maxRequirements) || o.maxRequirements < 1) {
102
+ throw new Error("--max-requirements needs a positive integer");
103
+ }
104
+ return o;
105
+ }
106
+ function specFiles(dir, rel = "") {
107
+ const out = [];
108
+ let entries = [];
109
+ try {
110
+ entries = fs.readdirSync(path.join(dir, rel), { withFileTypes: true });
111
+ }
112
+ catch {
113
+ return out;
114
+ }
115
+ for (const e of entries) {
116
+ const child = rel ? `${rel}/${e.name}` : e.name;
117
+ if (e.isDirectory())
118
+ out.push(...specFiles(dir, child));
119
+ else if (e.name === "spec.md")
120
+ out.push(child);
121
+ }
122
+ return out;
123
+ }
124
+ const readIf = (file) => (fs.existsSync(file) ? fs.readFileSync(file, "utf8") : undefined);
125
+ class DraftCommand extends command_1.BaseCommand {
126
+ execute() {
127
+ const io0 = (0, agent_1.agentIo)((0, agent_1.wantsJson)(this.args));
128
+ let o;
129
+ try {
130
+ o = parseArgs(this.args);
131
+ }
132
+ catch (err) {
133
+ io0.usage({ draft: null }, [
134
+ (0, diagnostics_1.error)("draft_usage", err.message, { fix: "specgate draft --help" }),
135
+ ]);
136
+ }
137
+ const opts = o;
138
+ const io = (0, agent_1.agentIo)(opts.json);
139
+ const projectDir = (0, project_root_1.resolveProjectDir)(opts.projectDir);
140
+ const changeDir = path.join(projectDir, CHANGES, opts.check);
141
+ if (!fs.existsSync(changeDir)) {
142
+ io.fail({ draft: null }, [
143
+ (0, diagnostics_1.error)("draft_no_change", `No change '${opts.check}' under ${CHANGES}/.`, {
144
+ fix: "specgate change list — or open one with `specgate change new <id>`.",
145
+ }),
146
+ ]);
147
+ }
148
+ const specs = path.join(changeDir, "specs");
149
+ const deltas = specFiles(specs).map((rel) => ({
150
+ path: path.join(CHANGES, opts.check, "specs", rel).split(path.sep).join("/"),
151
+ source: fs.readFileSync(path.join(specs, rel), "utf8"),
152
+ }));
153
+ if (deltas.length === 0) {
154
+ io.fail({ draft: null }, [
155
+ (0, diagnostics_1.error)("draft_no_specs", `Change '${opts.check}' has no specs/<capability>/spec.md to check.`),
156
+ ]);
157
+ }
158
+ // The brief: --brief, else `brief: <path>` in change.yaml.
159
+ let briefPath = opts.brief;
160
+ if (!briefPath) {
161
+ const yaml = readIf(path.join(changeDir, "change.yaml")) || "";
162
+ const m = /^brief:\s*["']?([^"'\n]+)["']?\s*$/m.exec(yaml);
163
+ if (m)
164
+ briefPath = m[1].trim();
165
+ }
166
+ let brief;
167
+ if (briefPath) {
168
+ brief = readIf(path.resolve(projectDir, briefPath));
169
+ if (brief === undefined) {
170
+ io.fail({ draft: null }, [
171
+ (0, diagnostics_1.error)("draft_no_brief", `The brief ${briefPath} does not exist.`),
172
+ ]);
173
+ }
174
+ }
175
+ const report = (0, DraftChecklist_1.checkDraft)({
176
+ deltas,
177
+ brief,
178
+ assumptions: readIf(path.join(changeDir, "assumptions.md")),
179
+ questions: readIf(path.join(changeDir, "questions.md")),
180
+ maxRequirements: opts.maxRequirements,
181
+ });
182
+ const status = [
183
+ ...report.status,
184
+ ...report.skipped.map((s) => (0, diagnostics_1.info)("draft_rule_skipped", `${s.rule} did not run: ${s.why}.`, {
185
+ fix: "Pass --brief <file>, with actors and their surfaces in its front matter for D3.",
186
+ })),
187
+ ];
188
+ const errors = report.status.length;
189
+ io.emit({
190
+ draft: {
191
+ change: opts.check,
192
+ requirements: report.requirements,
193
+ scenarios: report.scenarios,
194
+ skipped: report.skipped,
195
+ },
196
+ status,
197
+ }, () => {
198
+ const out = process.stdout;
199
+ out.write(`\n specgate draft --check ${opts.check}\n\n`);
200
+ out.write(` ${report.requirements} requirement(s), ${report.scenarios} scenario(s)\n\n`);
201
+ for (const d of status) {
202
+ out.write(` ${d.severity === "error" ? "✖" : "ℹ"} ${d.code} ${d.message}\n`);
203
+ if (d.fix && d.severity === "error")
204
+ out.write(` fix: ${d.fix}\n`);
205
+ }
206
+ const skipped = report.skipped.length;
207
+ out.write(errors === 0
208
+ ? `\n ✔ Ready to review${skipped ? ` (${skipped} rule(s) did not run — see above)` : ""}.\n`
209
+ : `\n ✖ ${errors} finding(s) to fix before review.\n`);
210
+ });
211
+ process.exitCode = errors === 0 ? 0 : 1;
212
+ }
213
+ }
214
+ exports.DraftCommand = DraftCommand;
215
+ //# sourceMappingURL=DraftCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DraftCommand.js","sourceRoot":"","sources":["../../../../../scripts/cli/commands/spec/DraftCommand.ts"],"names":[],"mappings":"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"}
@@ -46,6 +46,8 @@ const lock_1 = require("../../../specops/lock");
46
46
  const diagnostics_1 = require("../../../lib/diagnostics");
47
47
  const command_1 = require("../../../lib/command");
48
48
  const monorepo_fanout_1 = require("../../../lib/monorepo-fanout");
49
+ const DraftChecklist_1 = require("../../../../packages/core/src/domain/DraftChecklist");
50
+ const DerivedMatrixSources_1 = require("../../../../packages/core/src/infrastructure/DerivedMatrixSources");
49
51
  const MatrixCommand_1 = require("./MatrixCommand");
50
52
  const derived_writes_1 = require("../../../lib/derived-writes");
51
53
  const COLOR_ENABLED = process.stdout.isTTY && process.env.NO_COLOR === undefined && process.env.TERM !== "dumb";
@@ -197,7 +199,7 @@ function titleOf(item) {
197
199
  .trim();
198
200
  return t && t !== "-" ? t : "";
199
201
  }
200
- function emitText(projectDir, summary, lock) {
202
+ function emitText(projectDir, summary, lock, notes = []) {
201
203
  const { items, counts, pending, orphans } = summary;
202
204
  process.stdout.write(`\n ${c.bold}📊 Project status${c.reset} ${c.dim}${path.basename(path.resolve(projectDir))}${c.reset}\n\n`);
203
205
  process.stdout.write(` ${c.bold}Requirements${c.reset} ${c.dim}${counts.total} total · ${counts.DONE} done · ${pending} pending${c.reset}\n`);
@@ -217,6 +219,14 @@ function emitText(projectDir, summary, lock) {
217
219
  queue("To do", TODO_CATEGORIES, c.yellow);
218
220
  if (orphans.length > 0)
219
221
  process.stdout.write(`\n ${c.red}${orphans.length} orphan feature file(s)${c.reset} ${c.dim}— not in the matrix${c.reset}\n`);
222
+ if (notes.length > 0) {
223
+ process.stdout.write(`\n ${c.bold}Spec notes${c.reset} ${c.dim}(not failures — ADR-0029)${c.reset}\n`);
224
+ for (const n of notes.slice(0, 5)) {
225
+ process.stdout.write(` ${c.yellow}${n.code}${c.reset} ${n.message}\n`);
226
+ }
227
+ if (notes.length > 5)
228
+ process.stdout.write(` ${c.dim}… ${notes.length - 5} more in --json${c.reset}\n`);
229
+ }
220
230
  if (lock && lock.packs && lock.packs.length > 0) {
221
231
  process.stdout.write(`\n ${c.bold}Packs${c.reset} ${c.dim}(.specops.lock)${c.reset}\n`);
222
232
  for (const p of lock.packs) {
@@ -225,7 +235,7 @@ function emitText(projectDir, summary, lock) {
225
235
  }
226
236
  process.stdout.write(`\n ${c.bold}Next${c.reset} ${c.green}${nextCommandPlain(summary)}${c.reset} ${c.dim}— ${nextReason(summary)}${c.reset}\n\n`);
227
237
  }
228
- function emitJson(projectDir, summary, lock) {
238
+ function emitJson(projectDir, summary, lock, notes = []) {
229
239
  const { counts, pending, orphans } = summary;
230
240
  process.stdout.write(JSON.stringify({
231
241
  schemaVersion: 1,
@@ -242,7 +252,7 @@ function emitJson(projectDir, summary, lock) {
242
252
  needs: needsOf(it) || null,
243
253
  })),
244
254
  nextCommand: nextCommandPlain(summary),
245
- status: [],
255
+ status: notes,
246
256
  }, null, 2) + "\n");
247
257
  }
248
258
  class StatusCommand extends command_1.BaseCommand {
@@ -277,10 +287,19 @@ class StatusCommand extends command_1.BaseCommand {
277
287
  catch {
278
288
  lock = null;
279
289
  }
290
+ // D4 and D5 on the project's own specification: notes, never failures.
291
+ let notes = [];
292
+ try {
293
+ const sources = (0, DerivedMatrixSources_1.readDerivationSources)(projectDir);
294
+ notes = (0, DraftChecklist_1.specNotes)([{ path: "spec.md", source: sources.spec }, ...(sources.capabilities || [])], sources.features);
295
+ }
296
+ catch {
297
+ notes = [];
298
+ }
280
299
  if (opts.format === "json")
281
- emitJson(projectDir, summary, lock);
300
+ emitJson(projectDir, summary, lock, notes);
282
301
  else
283
- emitText(projectDir, summary, lock);
302
+ emitText(projectDir, summary, lock, notes);
284
303
  process.exit(0);
285
304
  }
286
305
  }