@peterxiaoyang/superspec 0.1.13 → 0.1.15-alpha

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 (126) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +302 -0
  3. package/dist/format.d.ts +29 -0
  4. package/dist/format.js +141 -0
  5. package/dist/next.d.ts +3 -0
  6. package/dist/next.js +161 -0
  7. package/dist/openspec.d.ts +9 -0
  8. package/dist/openspec.js +41 -0
  9. package/dist/record.d.ts +20 -0
  10. package/dist/record.js +211 -0
  11. package/dist/skill_loop.d.ts +23 -0
  12. package/dist/skill_loop.js +58 -0
  13. package/dist/store.d.ts +31 -0
  14. package/dist/store.js +213 -0
  15. package/dist/sync.d.ts +3 -0
  16. package/dist/sync.js +135 -0
  17. package/dist/task.d.ts +7 -0
  18. package/dist/task.js +44 -0
  19. package/dist/transition.d.ts +34 -0
  20. package/dist/transition.js +400 -0
  21. package/dist/types.d.ts +138 -0
  22. package/dist/types.js +3 -0
  23. package/package.json +8 -53
  24. package/templates/workflow/skills/superspec-apply/SKILL.md +46 -118
  25. package/templates/workflow/skills/superspec-archive/SKILL.md +22 -47
  26. package/templates/workflow/skills/superspec-explore/SKILL.md +38 -69
  27. package/templates/workflow/skills/superspec-propose/SKILL.md +58 -57
  28. package/templates/workflow/skills/superspec-review/SKILL.md +36 -81
  29. package/adapters/codex/agents/architect.toml +0 -13
  30. package/adapters/codex/agents/code-reviewer.toml +0 -13
  31. package/adapters/codex/agents/critic.toml +0 -13
  32. package/adapters/codex/agents/executor.toml +0 -13
  33. package/adapters/codex/agents/explore.toml +0 -13
  34. package/adapters/codex/agents/test-engineer.toml +0 -13
  35. package/adapters/codex/agents/test-runner.toml +0 -13
  36. package/adapters/codex/agents/verifier.toml +0 -13
  37. package/adapters/codex/install-map.json +0 -116
  38. package/bin/launch.js +0 -37
  39. package/bin/superspec-check.js +0 -4
  40. package/bin/superspec-hook.js +0 -4
  41. package/bin/superspec-init.js +0 -4
  42. package/bin/superspec.js +0 -4
  43. package/dist/src/apply_worker_chain.d.ts +0 -60
  44. package/dist/src/apply_worker_chain.js +0 -1283
  45. package/dist/src/apply_worker_chain_lifecycle.d.ts +0 -21
  46. package/dist/src/apply_worker_chain_lifecycle.js +0 -409
  47. package/dist/src/archive.d.ts +0 -23
  48. package/dist/src/archive.js +0 -430
  49. package/dist/src/cli.d.ts +0 -1
  50. package/dist/src/cli.js +0 -33
  51. package/dist/src/cli_args.d.ts +0 -32
  52. package/dist/src/cli_args.js +0 -454
  53. package/dist/src/core.d.ts +0 -20
  54. package/dist/src/core.js +0 -394
  55. package/dist/src/disclosure.d.ts +0 -35
  56. package/dist/src/disclosure.js +0 -671
  57. package/dist/src/doctor.d.ts +0 -44
  58. package/dist/src/doctor.js +0 -230
  59. package/dist/src/evidence.d.ts +0 -29
  60. package/dist/src/evidence.js +0 -1107
  61. package/dist/src/gates.d.ts +0 -19
  62. package/dist/src/gates.js +0 -1631
  63. package/dist/src/git.d.ts +0 -8
  64. package/dist/src/git.js +0 -112
  65. package/dist/src/hooks/adapter.d.ts +0 -5
  66. package/dist/src/hooks/adapter.js +0 -347
  67. package/dist/src/hooks/guard_api.d.ts +0 -12
  68. package/dist/src/hooks/guard_api.js +0 -797
  69. package/dist/src/hooks/health.d.ts +0 -4
  70. package/dist/src/hooks/health.js +0 -86
  71. package/dist/src/hooks/policy_event.d.ts +0 -41
  72. package/dist/src/hooks/policy_event.js +0 -2634
  73. package/dist/src/hooks/types.d.ts +0 -72
  74. package/dist/src/hooks/types.js +0 -1
  75. package/dist/src/hooks/validation.d.ts +0 -3
  76. package/dist/src/hooks/validation.js +0 -70
  77. package/dist/src/i18n.d.ts +0 -21
  78. package/dist/src/i18n.js +0 -720
  79. package/dist/src/init_cli.d.ts +0 -28
  80. package/dist/src/init_cli.js +0 -399
  81. package/dist/src/install_engine.d.ts +0 -71
  82. package/dist/src/install_engine.js +0 -538
  83. package/dist/src/invariants.d.ts +0 -16
  84. package/dist/src/invariants.js +0 -363
  85. package/dist/src/openspec.d.ts +0 -37
  86. package/dist/src/openspec.js +0 -274
  87. package/dist/src/packet_render.d.ts +0 -5
  88. package/dist/src/packet_render.js +0 -1759
  89. package/dist/src/packet_schema.d.ts +0 -58
  90. package/dist/src/packet_schema.js +0 -1
  91. package/dist/src/paths.d.ts +0 -22
  92. package/dist/src/paths.js +0 -203
  93. package/dist/src/project_init.d.ts +0 -31
  94. package/dist/src/project_init.js +0 -167
  95. package/dist/src/self_update.d.ts +0 -14
  96. package/dist/src/self_update.js +0 -56
  97. package/dist/src/state.d.ts +0 -37
  98. package/dist/src/state.js +0 -464
  99. package/dist/src/tasks.d.ts +0 -38
  100. package/dist/src/tasks.js +0 -373
  101. package/dist/src/util.d.ts +0 -163
  102. package/dist/src/util.js +0 -792
  103. package/dist/superspec.d.ts +0 -6
  104. package/dist/superspec.js +0 -97
  105. package/dist/superspec_guard.d.ts +0 -4
  106. package/dist/superspec_guard.js +0 -19
  107. package/dist/superspec_hook.d.ts +0 -4
  108. package/dist/superspec_hook.js +0 -35
  109. package/dist/superspec_init.d.ts +0 -2
  110. package/dist/superspec_init.js +0 -17
  111. package/schemas/hook-event.schema.json +0 -27
  112. package/schemas/install-manifest.schema.json +0 -97
  113. package/templates/hooks/codex-hooks.json +0 -35
  114. package/templates/sidecar/archive-preservation.json +0 -11
  115. package/templates/sidecar/business-invariants.md +0 -38
  116. package/templates/sidecar/config.yaml +0 -13
  117. package/templates/sidecar/discovery.md +0 -33
  118. package/templates/sidecar/test-contract.md +0 -27
  119. package/templates/workflow/prompts/architect.md +0 -27
  120. package/templates/workflow/prompts/code-reviewer.md +0 -34
  121. package/templates/workflow/prompts/critic.md +0 -30
  122. package/templates/workflow/prompts/executor.md +0 -32
  123. package/templates/workflow/prompts/explore.md +0 -27
  124. package/templates/workflow/prompts/test-engineer.md +0 -28
  125. package/templates/workflow/prompts/test-runner.md +0 -35
  126. package/templates/workflow/prompts/verifier.md +0 -35
package/dist/src/tasks.js DELETED
@@ -1,373 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { existsSync, readFileSync, statSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { reason, renderList, walkFiles } from "./util.js";
5
- import { sidecar_test_contract_path } from "./paths.js";
6
- import { live_pass } from "./evidence.js";
7
- const TASK_LINE = /^- \[( |x|X)\]\s+(\S+)\s*(.*)$/;
8
- const ATTR_LINE = /^\s+- (\w+):\s*(.*)$/;
9
- const TEST_ID_RE = /\bTEST-\d+[A-Za-z0-9_-]*\b/g;
10
- const SCENARIO_RE = /^####\s+Scenario:?\s*(.+?)\s*$/;
11
- export function parse_tasks(changeRoot) {
12
- const tasksMd = join(changeRoot, "tasks.md");
13
- if (!existsSync(tasksMd) || !statSync(tasksMd).isFile())
14
- return {};
15
- const tasks = {};
16
- let current = null;
17
- for (const raw of readFileSync(tasksMd, "utf8").split(/\r?\n/)) {
18
- const match = raw.match(TASK_LINE);
19
- if (match) {
20
- const checked = match[1].toLowerCase() === "x";
21
- const taskId = match[2].trim();
22
- current = { task_id: taskId, checked, desc: match[3].trim(), attrs: {} };
23
- tasks[taskId] = current;
24
- continue;
25
- }
26
- const attr = raw.match(ATTR_LINE);
27
- if (attr && current) {
28
- current.attrs[attr[1]] = attr[2].trim();
29
- }
30
- else if (raw && !raw.startsWith(" ") && !raw.startsWith("\t")) {
31
- current = null;
32
- }
33
- }
34
- return tasks;
35
- }
36
- // FIX-8 (audit A-5): checkbox-state-insensitive fingerprint of tasks.md. Checking a box is
37
- // normal apply progress; any other edit (new task, attrs, descriptions) changes the hash and
38
- // therefore invalidates the user's apply-scope approval.
39
- export function tasks_structure_hash(changeRoot) {
40
- const tasksMd = join(changeRoot, "tasks.md");
41
- if (!existsSync(tasksMd) || !statSync(tasksMd).isFile())
42
- return null;
43
- const normalized = readFileSync(tasksMd, "utf8").replace(/^(\s*[-*]\s*)\[[xX]\]/gm, "$1[ ]");
44
- return `sha256:${createHash("sha256").update(normalized, "utf8").digest("hex")}`;
45
- }
46
- export function splitList(value) {
47
- const stripped = value.trim().replace(/^\[/, "").replace(/\]$/, "");
48
- if (!stripped)
49
- return [];
50
- return stripped.split(/[,\s]+/).map((item) => item.trim()).filter(Boolean);
51
- }
52
- function parseMarkdownRow(line) {
53
- return line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((cell) => cell.trim());
54
- }
55
- function isSeparatorRow(cells) {
56
- return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
57
- }
58
- function normalizeHeader(header) {
59
- return header.trim().toLowerCase().replace(/\s+/g, "_");
60
- }
61
- function tableLinesAfterHeading(text, headings) {
62
- const lines = text.split(/\r?\n/);
63
- const start = lines.findIndex((line) => headings.some((heading) => heading.test(line.trim())));
64
- if (start < 0)
65
- return [];
66
- const table = [];
67
- let started = false;
68
- for (const line of lines.slice(start + 1)) {
69
- const trimmed = line.trim();
70
- if (!trimmed && !started)
71
- continue;
72
- if (!trimmed.startsWith("|")) {
73
- if (started)
74
- break;
75
- continue;
76
- }
77
- started = true;
78
- table.push(line);
79
- }
80
- return table;
81
- }
82
- function columnIndex(headers, predicate) {
83
- return headers.findIndex(predicate);
84
- }
85
- export function parse_test_contract_records(changeRoot) {
86
- const text = test_contract_text(changeRoot);
87
- const table = tableLinesAfterHeading(text, [/^##\s+测试覆盖矩阵\s*$/i, /^##\s+test coverage matrix\s*$/i]);
88
- if (table.length < 3)
89
- return [];
90
- const headers = parseMarkdownRow(table[0]).map(normalizeHeader);
91
- const testIdx = columnIndex(headers, (header) => header === "test-id" || header === "test_id" || header === "testid");
92
- const scenarioIdx = columnIndex(headers, (header) => header.includes("scenario") || header.includes("req") || header.includes("需求") || header.includes("关联"));
93
- const invIdx = columnIndex(headers, (header) => header.includes("inv"));
94
- if (testIdx < 0)
95
- return [];
96
- const records = [];
97
- for (const line of table.slice(1)) {
98
- const cells = parseMarkdownRow(line);
99
- if (isSeparatorRow(cells))
100
- continue;
101
- const testId = cells[testIdx] ?? "";
102
- if (!TEST_ID_RE.test(testId))
103
- continue;
104
- TEST_ID_RE.lastIndex = 0;
105
- records.push({
106
- row: records.length + 1,
107
- test_id: testId.match(TEST_ID_RE)?.[0] ?? "",
108
- scenario_ref: scenarioIdx >= 0 ? cells[scenarioIdx] ?? "" : "",
109
- invariant_refs: invIdx >= 0 ? splitList(cells[invIdx] ?? "").filter((item) => item.startsWith("INV-")) : [],
110
- });
111
- }
112
- return records;
113
- }
114
- export function parse_test_contract_ids(changeRoot) {
115
- return new Set(parse_test_contract_records(changeRoot).map((record) => record.test_id).filter(Boolean));
116
- }
117
- export function test_contract_text(changeRoot) {
118
- const filePath = sidecar_test_contract_path(changeRoot);
119
- if (!existsSync(filePath) || !statSync(filePath).isFile())
120
- return "";
121
- return readFileSync(filePath, "utf8");
122
- }
123
- function test_contract_section_lines(changeRoot, testId) {
124
- const lines = test_contract_text(changeRoot).split(/\r?\n/);
125
- const start = lines.findIndex((line) => {
126
- const match = line.trim().match(/^###\s+(\S+)\s*$/);
127
- return match?.[1] === testId;
128
- });
129
- if (start < 0)
130
- return [];
131
- const out = [];
132
- for (const line of lines.slice(start + 1)) {
133
- if (/^###\s+\S+/.test(line.trim()) || /^##\s+/.test(line.trim()))
134
- break;
135
- out.push(line);
136
- }
137
- return out;
138
- }
139
- function contractField(line) {
140
- const match = line.match(/^\s*-\s+`?([A-Za-z0-9_-]+)`?\s*:\s*(.*)$/);
141
- if (!match)
142
- return null;
143
- return { key: match[1], value: match[2].trim() };
144
- }
145
- export function resolve_test_contract_command(changeRoot, testId, config = {}) {
146
- const blockers = [];
147
- const lines = test_contract_section_lines(changeRoot, testId);
148
- if (lines.length === 0) {
149
- return { test_id: testId, command: null, source: null, blockers: [reason("missing_test_contract_section", `test contract missing ### ${testId} section`)] };
150
- }
151
- const fields = new Map();
152
- for (const line of lines) {
153
- const field = contractField(line);
154
- if (!field)
155
- continue;
156
- const values = fields.get(field.key) ?? [];
157
- values.push(field.value);
158
- fields.set(field.key, values);
159
- }
160
- const commands = fields.get("test_command") ?? [];
161
- const refs = fields.get("test_command_ref") ?? [];
162
- if (commands.length === 0 && refs.length === 0)
163
- blockers.push(reason("missing_test_command", `test contract ${testId} requires exactly one test_command or test_command_ref`));
164
- if (commands.length > 1 || refs.length > 1)
165
- blockers.push(reason("duplicate_test_command", `test contract ${testId} has duplicate test command fields`));
166
- if (commands.length > 0 && refs.length > 0)
167
- blockers.push(reason("ambiguous_test_command", `test contract ${testId} must not mix test_command and test_command_ref`));
168
- const expected_failure_signature = (fields.get("expected_failure_signature") ?? [])[0];
169
- const expected_failure_classifier = (fields.get("expected_failure_classifier") ?? [])[0];
170
- if (commands.length === 1 && refs.length === 0) {
171
- const command = commands[0];
172
- if (!command)
173
- blockers.push(reason("missing_test_command", `test contract ${testId} has empty test_command`));
174
- return {
175
- test_id: testId,
176
- command: command || null,
177
- source: command ? "test_command" : null,
178
- expected_failure_signature,
179
- expected_failure_classifier,
180
- blockers,
181
- };
182
- }
183
- if (refs.length === 1 && commands.length === 0) {
184
- const refValue = refs[0];
185
- const match = refValue.match(/^config\.commands\.([A-Za-z0-9_.-]+)$/);
186
- if (!match) {
187
- blockers.push(reason("untrusted_test_command_ref", `test contract ${testId} test_command_ref must be config.commands.<id>`));
188
- return { test_id: testId, command: null, source: null, command_ref: refValue, expected_failure_signature, expected_failure_classifier, blockers };
189
- }
190
- const commandId = match[1];
191
- const commandsConfig = config.commands;
192
- const command = commandsConfig && typeof commandsConfig === "object" ? commandsConfig[commandId] : undefined;
193
- if (typeof command !== "string" || !command.trim()) {
194
- blockers.push(reason("untrusted_test_command_ref", `test contract ${testId} test_command_ref ${refValue} does not resolve to config.commands.${commandId}`));
195
- return { test_id: testId, command: null, source: null, command_ref: refValue, expected_failure_signature, expected_failure_classifier, blockers };
196
- }
197
- return {
198
- test_id: testId,
199
- command,
200
- source: "test_command_ref",
201
- command_ref: refValue,
202
- expected_failure_signature,
203
- expected_failure_classifier,
204
- blockers,
205
- };
206
- }
207
- return { test_id: testId, command: null, source: null, expected_failure_signature, expected_failure_classifier, blockers };
208
- }
209
- export function parse_spec_scenarios(changeRoot) {
210
- const specs = join(changeRoot, "specs");
211
- const scenarios = [];
212
- if (!existsSync(specs) || !statSync(specs).isDirectory())
213
- return scenarios;
214
- for (const filePath of walkFiles(specs).sort()) {
215
- if (!filePath.endsWith(".md"))
216
- continue;
217
- for (const line of readFileSync(filePath, "utf8").split(/\r?\n/)) {
218
- const match = line.match(SCENARIO_RE);
219
- if (match)
220
- scenarios.push(match[1].trim());
221
- }
222
- }
223
- return scenarios;
224
- }
225
- export function test_contract_covers_scenario(changeRoot, scenario) {
226
- return parse_test_contract_records(changeRoot).some((record) => record.scenario_ref.includes(scenario));
227
- }
228
- export function test_contract_invariant_refs_by_test(changeRoot) {
229
- const out = new Map();
230
- for (const record of parse_test_contract_records(changeRoot)) {
231
- const refs = out.get(record.test_id) ?? new Set();
232
- for (const ref of record.invariant_refs)
233
- refs.add(ref);
234
- out.set(record.test_id, refs);
235
- }
236
- return out;
237
- }
238
- export function task_test_refs(tasks) {
239
- const refs = new Set();
240
- for (const task of Object.values(tasks)) {
241
- for (const ref of splitList(task.attrs.test_refs ?? ""))
242
- refs.add(ref);
243
- }
244
- return refs;
245
- }
246
- export const APPLY_EXECUTION_SURFACES = new Set(["implementation", "runtime_config", "docs_generated", "no_code"]);
247
- function cleanWriteScope(scope) {
248
- return scope.trim().replace(/\\/g, "/");
249
- }
250
- function unsafeWriteScope(scope) {
251
- const parts = scope.split("/");
252
- return scope === "" || scope === "." || scope.startsWith("/") || parts.some((part) => part === "" || part === "." || part === "..");
253
- }
254
- function rootMarkdown(scope) {
255
- return !scope.includes("/") && /\.(?:md|mdx|rst|adoc)$/iu.test(scope);
256
- }
257
- function rootReadmeOrChangelog(scope) {
258
- if (scope.includes("/"))
259
- return false;
260
- return /^(?:README|CHANGELOG)(?:\.(?:md|mdx|rst|adoc))?$/iu.test(scope);
261
- }
262
- function docsGeneratedScopeAllowed(scope) {
263
- if (unsafeWriteScope(scope))
264
- return false;
265
- if (scope.startsWith("docs/") || scope.startsWith("doc/"))
266
- return true;
267
- if (rootMarkdown(scope) || rootReadmeOrChangelog(scope))
268
- return true;
269
- return scope.startsWith("templates/") && scope.endsWith(".md");
270
- }
271
- export function docs_generated_write_scope_reasons(writeScope, taskId = "") {
272
- const invalid = writeScope
273
- .map(cleanWriteScope)
274
- .filter((scope) => !docsGeneratedScopeAllowed(scope))
275
- .sort();
276
- if (invalid.length === 0)
277
- return [];
278
- const prefix = taskId ? `task ${taskId} ` : "";
279
- return [reason("invalid_docs_generated_write_scope", `${prefix}apply_execution_surface=docs_generated only allows docs/**, doc/**, root README/CHANGELOG/markdown, and templates/**/*.md write_scope entries: ${renderList(invalid)}`, invalid)];
280
- }
281
- export function task_apply_execution_surface(task) {
282
- const explicit = task.attrs.apply_execution_surface?.trim();
283
- if (explicit)
284
- return explicit;
285
- return splitList(task.attrs.write_scope ?? "").length > 0 ? "implementation" : "no_code";
286
- }
287
- export function task_apply_execution_surface_reasons(taskId, task) {
288
- const surface = task_apply_execution_surface(task);
289
- const writeScope = splitList(task.attrs.write_scope ?? "");
290
- if (!APPLY_EXECUTION_SURFACES.has(surface)) {
291
- return [reason("invalid_apply_execution_surface", `task ${taskId}: apply_execution_surface=${surface}`)];
292
- }
293
- if (surface === "implementation" || surface === "runtime_config") {
294
- return writeScope.length === 0
295
- ? [reason("missing_write_scope", `task ${taskId} apply_execution_surface=${surface} requires non-empty write_scope`)]
296
- : [];
297
- }
298
- if (surface === "no_code") {
299
- return writeScope.length === 0
300
- ? []
301
- : [reason("invalid_apply_execution_surface_write_scope", `task ${taskId} apply_execution_surface=no_code requires empty write_scope`, writeScope)];
302
- }
303
- if (writeScope.length === 0) {
304
- return [reason("missing_write_scope", `task ${taskId} apply_execution_surface=docs_generated requires non-empty write_scope`)];
305
- }
306
- return docs_generated_write_scope_reasons(writeScope, taskId);
307
- }
308
- export function write_scope_conflict_reasons(tasks) {
309
- const byGroup = {};
310
- for (const [taskId, task] of Object.entries(tasks)) {
311
- const group = task.attrs.parallel_group;
312
- if (!group)
313
- continue;
314
- for (const scope of splitList(task.attrs.write_scope ?? "")) {
315
- byGroup[group] ??= {};
316
- byGroup[group][scope] ??= [];
317
- byGroup[group][scope].push(taskId);
318
- }
319
- }
320
- const problems = [];
321
- for (const [group, scopes] of Object.entries(byGroup)) {
322
- for (const [scope, taskIds] of Object.entries(scopes)) {
323
- if (taskIds.length > 1)
324
- problems.push(reason("write_scope_conflict", `parallel_group ${group} has overlapping write_scope ${scope}: ${renderList(taskIds)}`));
325
- }
326
- }
327
- return problems;
328
- }
329
- export function red_green_test_ids(evidences) {
330
- const ids = new Set();
331
- for (const ev of live_pass(evidences, { kind: "test_run" })) {
332
- if (typeof ev.test_id === "string" && ev.test_id)
333
- ids.add(ev.test_id);
334
- }
335
- return ids;
336
- }
337
- export function task_test_evidence(evidences, taskId, semanticStatus, gate = null) {
338
- return live_pass(evidences, { gate, kind: "test_run", task_id: taskId }).filter((ev) => ev.semantic_status === semanticStatus);
339
- }
340
- export function task_alternative_verification(evidences, taskId) {
341
- return [
342
- ...live_pass(evidences, { kind: "alternative_verification", task_id: taskId }),
343
- ...live_pass(evidences, { kind: "manual_verification", task_id: taskId }),
344
- ];
345
- }
346
- export function evidence_test_id_reasons(evidences, taskId, declared, contractIds, semanticStatus) {
347
- const problems = [];
348
- for (const ev of evidences) {
349
- const tid = ev.test_id;
350
- if (typeof tid !== "string" || !tid) {
351
- problems.push(reason("missing_test_id", `task ${taskId} ${semanticStatus} evidence requires test_id`));
352
- continue;
353
- }
354
- if (declared.size > 0 && !declared.has(tid)) {
355
- problems.push(reason("test_contract_not_honored", `task ${taskId} ${semanticStatus} test_id ${tid} not in declared test_refs ${renderList([...declared].sort())}`));
356
- }
357
- if (contractIds.size > 0 && !contractIds.has(tid)) {
358
- problems.push(reason("test_contract_not_honored", `task ${taskId} ${semanticStatus} test_id ${tid} not in test-contract ids ${renderList([...contractIds].sort())}`));
359
- }
360
- }
361
- return problems;
362
- }
363
- export function declared_test_evidence_reasons(evidences, taskId, declared, semanticStatus) {
364
- if (declared.size === 0)
365
- return [];
366
- const covered = new Set(evidences
367
- .map((ev) => typeof ev.test_id === "string" ? ev.test_id : "")
368
- .filter((testId) => declared.has(testId)));
369
- const missing = [...declared].filter((testId) => !covered.has(testId)).sort();
370
- if (missing.length === 0)
371
- return [];
372
- return [reason("missing_declared_test_evidence", `task ${taskId} ${semanticStatus} evidence missing declared test_refs: ${renderList(missing)}`, missing)];
373
- }
@@ -1,163 +0,0 @@
1
- import { type WorkflowTermHint } from "./i18n.ts";
2
- export declare const SCHEMA_VERSION = 1;
3
- export declare const GUARD_VERSION = "superspec-guard@1";
4
- export declare const CONFIG_FILENAME = "config.yaml";
5
- export declare const STATE_FILENAME = "superspec-state.json";
6
- export declare const STATE_LOCK_FILENAME = "superspec-state.lock";
7
- export declare const PROJECT_CONFIG_ALIASES: readonly [".superspec.yaml", ".superspec.yml", "superspec.yaml", "superspec.yml", "superspec.json", ".superspecrc", ".superspec/config.json"];
8
- export declare const CHANGE_CONFIG_ALIASES: readonly [".superspec.yaml", ".superspec.yml", "superspec.yaml", "superspec.yml", "superspec.json", ".superspecrc", ".superspec/config.json"];
9
- export declare const STATE_ALIASES: readonly [".superspec/state.json", ".superspec/state.lock", ".superspec/superspec_state.json", ".superspec/superspec-state.yaml"];
10
- export declare const REQUIRED_SIDECAR_DIRS: readonly ["artifacts", "evidence/discovery", "evidence/design", "evidence/invariants", "evidence/test-contract", "evidence/tasks", "evidence/red", "evidence/green", "evidence/reviews", "evidence/verification", "evidence/archive", "handoffs", "reports", "raw"];
11
- export type JsonMap = Record<string, any>;
12
- export type Reason = {
13
- code: string;
14
- message: string;
15
- refs: string[];
16
- label_zh?: string;
17
- hint_zh?: string;
18
- message_zh?: string;
19
- };
20
- export type Decision = {
21
- allowed: boolean;
22
- decision: "allow" | "block" | "status";
23
- change_id: string;
24
- gate: string;
25
- task_id: string | null;
26
- openspec_status_summary: Record<string, string>;
27
- superspec_gate_summary: Record<string, any>;
28
- block_reasons: Reason[];
29
- next_allowed_actions: string[];
30
- trust_warnings: string[];
31
- actions?: JsonMap[];
32
- decision_zh?: string;
33
- gate_label_zh?: string;
34
- gate_hint_zh?: string;
35
- command?: string;
36
- command_label_zh?: string;
37
- command_hint_zh?: string;
38
- next_allowed_actions_zh?: string[];
39
- trust_warnings_zh?: string[];
40
- workflow_terms_zh?: WorkflowTermHint[];
41
- };
42
- export type DecisionOutputFormat = "json" | "agent" | "user";
43
- export type PacketOutputFormat = "agent" | "prompt";
44
- export type AgentWorkflowAction = "continue" | "fix_artifacts" | "ask_user_confirmation" | "collect_review_evidence" | "collect_test_evidence" | "repair_evidence" | "rerun_check" | "inspect_diagnostics";
45
- export type TaskInfo = {
46
- task_id: string;
47
- checked: boolean;
48
- desc: string;
49
- attrs: Record<string, string>;
50
- };
51
- export declare const BUILTIN_CONFIG: JsonMap;
52
- export declare const ALLOWED_CONFIG_KEYS: Set<string>;
53
- export declare const EVIDENCE_STATUSES: Set<string>;
54
- export declare const EVIDENCE_KINDS: Set<string>;
55
- export declare const HUMAN_CONFIRMATION_GATES: Set<string>;
56
- export declare const PENDING_CONFIRMATION_RE: RegExp;
57
- export declare const UNCHECKED_CHECKBOX_RE: RegExp;
58
- export declare const CHECKED_CHECKBOX_RE: RegExp;
59
- export declare function confirmation_text_has_pending_wording(text: string): boolean;
60
- export declare const NO_TDD_REASONS: Set<string>;
61
- export declare const TDD_MODES: Set<string>;
62
- export declare const ROLE_EVIDENCE_FIELDS: readonly ["agent_role", "agent_id", "prompt_ref", "output_ref", "source_anchors", "target_refs"];
63
- export declare const SELF_REVIEW_MARKERS: Set<string>;
64
- export declare const REVIEW_EVIDENCE_REQUIRED_FIELDS: readonly ["base_ref", "head_ref", "reviewed_files"];
65
- export declare const VERIFY_EVIDENCE_REQUIRED_FIELDS: readonly ["openspec_validate_ref", "task_matrix_ref", "invariant_matrix_ref", "scope_drift_ref", "test_evidence_refs"];
66
- export declare const REVIEW_GUIDANCE_ROLES: readonly ["code-reviewer", "architect", "critic"];
67
- export declare const FINAL_VERIFICATION_ROLES: readonly ["verifier", "critic"];
68
- export declare const SOURCE_GUIDANCE_REQUIRED_FIELDS: readonly ["source_refs", "required_load_refs", "required_claim_ids"];
69
- export declare const MAIN_ADJUDICATION_REQUIRED_FIELDS: readonly ["output_ref", "source_evidence_refs", "verification_evidence_refs", "loaded_refs", "claim_adjudications", "finding_adjudications"];
70
- export declare const MAIN_ADJUDICATION_DECISIONS: readonly ["allow", "request_changes"];
71
- export declare const REQUEST_CHANGES_ROUTES: readonly ["reopen_tasks", "change_update"];
72
- export declare const CLAIM_ADJUDICATION_DECISIONS: readonly ["accept", "reject", "needs_fix"];
73
- export declare const FINDING_ADJUDICATION_DECISIONS: readonly ["dismissed", "accepted_fixed", "accepted_deviation", "needs_fix"];
74
- export declare const FINAL_TEST_REQUIRED_FIELDS: readonly ["test_command", "output_ref"];
75
- export declare const TASK_REOPEN_REQUIRED_FIELDS: readonly ["task_id", "reopen_id", "source_adjudication_evidence_id", "source_guidance_evidence_id", "violated_test_ids", "violated_requirement_refs", "invalidated_completion_evidence_ids", "required_supersede_evidence_ids", "completion_invalidity_class", "scope_expansion", "why_completion_invalid", "required_fix", "before_tasks_sha256", "after_tasks_sha256"];
76
- export declare const TASK_REOPEN_RESOLVED_REQUIRED_FIELDS: readonly ["reopen_evidence_id", "reopen_id", "task_id", "successor_completion_evidence_ids", "after_tasks_sha256"];
77
- export declare const TASK_REOPEN_INVALIDITY_CLASSES: readonly ["insufficient_completion_evidence"];
78
- export declare const FORBIDDEN_FIELDS: Set<string>;
79
- export declare const OPENSPEC_ARTIFACTS: Set<string>;
80
- export declare const REQUIRED_OPENSPEC_CODEX_SKILLS: readonly [];
81
- export declare const REQUIRED_SUPERSPEC_WORKFLOW_SKILLS: readonly ["superspec-explore", "superspec-propose", "superspec-apply", "superspec-review", "superspec-archive"];
82
- export declare const REQUIRED_SUPERSPEC_AGENT_ROLES: readonly ["architect", "critic", "executor", "test-runner", "test-engineer", "code-reviewer", "verifier"];
83
- export declare const REQUIRED_OPENSPEC_CLI_SURFACES: readonly [readonly ["list", "--help"], readonly ["instructions", "--help"], readonly ["archive", "--help"], readonly ["validate", "--help"], readonly ["status", "--help"]];
84
- export declare const ARTIFACT_ENTER_GATE: Record<string, string>;
85
- export declare const ROUTE_ORDER: Record<string, number>;
86
- export declare const ROUTE_ALIASES: Record<string, string>;
87
- export declare const GATE_ALIASES: Record<string, string>;
88
- export declare const GATE_ROUTE: Record<string, string>;
89
- export declare class GuardError extends Error {
90
- }
91
- export declare const runtime: JsonMap;
92
- export declare function parseDecisionOutputFormat(raw: string): DecisionOutputFormat;
93
- export declare function parsePacketOutputFormat(raw: string, opts?: {
94
- allowPrompt?: boolean;
95
- }): PacketOutputFormat;
96
- export declare function reason(code: string, message: string, refs?: string[] | null): Reason;
97
- export declare function pinned_ref_key(item: JsonMap): string;
98
- export declare function trustWarnings(): string[];
99
- export declare function allow(change: string, gate: string, opts?: {
100
- task_id?: string | null;
101
- openspec_summary?: Record<string, string>;
102
- gate_summary?: Record<string, any>;
103
- }): Decision;
104
- export declare function block(change: string, gate: string, reasons: Reason[], opts?: {
105
- task_id?: string | null;
106
- openspec_summary?: Record<string, string>;
107
- gate_summary?: Record<string, any>;
108
- next_actions?: string[];
109
- }): Decision;
110
- export declare function decorateDecision(decision: JsonMap, opts?: {
111
- command?: string;
112
- }): JsonMap;
113
- export declare function workflowActionForReasonCodes(reasonCodes: string[], allowed?: boolean): AgentWorkflowAction;
114
- export declare function renderAgentDecision(decision: JsonMap, opts?: {
115
- command?: string;
116
- }): JsonMap;
117
- export declare function renderUserFacingDecision(decision: JsonMap, opts?: {
118
- command?: string;
119
- }): string;
120
- export declare function printDecision(decision: JsonMap, opts?: {
121
- command?: string;
122
- format?: DecisionOutputFormat;
123
- }): void;
124
- export declare function printPacket(payload: JsonMap | string, opts: {
125
- format: PacketOutputFormat;
126
- }): void;
127
- export declare function printPacketError(code: string, message: string): void;
128
- export declare function runCommand(cmd: string, args: string[], opts?: {
129
- cwd?: string;
130
- timeout?: number;
131
- platform?: NodeJS.Platform;
132
- }): {
133
- status: number | null;
134
- stdout: string;
135
- stderr: string;
136
- error?: Error;
137
- };
138
- export declare function sha256_text(text: string): string;
139
- export declare function sha256_file(filePath: string): string | null;
140
- export declare function fingerprint_obj(obj: any): string;
141
- export declare function safe_within(base: string, candidate: string): string | null;
142
- export declare function now(): string;
143
- export declare function isObject(value: any): value is JsonMap;
144
- export declare function repr(value: any): string;
145
- export declare function renderList(items: any[]): string;
146
- export declare function walkFiles(root: string): string[];
147
- export declare function toPosix(pathValue: string): string;
148
- export declare function commandLookupInvocation(cmd: string, platform?: NodeJS.Platform): {
149
- cmd: string;
150
- args: string[];
151
- shell: boolean;
152
- };
153
- export declare function selectWindowsCommandCandidate(cmd: string, whereStdout: string): string;
154
- export declare function windowsShellEscapeArg(arg: string): string;
155
- export declare function windowsCmdShimInvocation(cmdPath: string, args: string[], comspec?: string): {
156
- cmd: string;
157
- args: string[];
158
- };
159
- export declare function commandExists(cmd: string, opts?: {
160
- cwd?: string;
161
- platform?: NodeJS.Platform;
162
- }): boolean;
163
- export declare function deepEqual(a: any, b: any): boolean;