@peterxiaoyang/superspec 0.1.14 → 0.1.16-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 (131) hide show
  1. package/README.md +37 -36
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +301 -0
  4. package/dist/format.d.ts +29 -0
  5. package/dist/format.js +141 -0
  6. package/dist/install.d.ts +18 -0
  7. package/dist/install.js +161 -0
  8. package/dist/next.d.ts +3 -0
  9. package/dist/next.js +161 -0
  10. package/dist/openspec.d.ts +9 -0
  11. package/dist/openspec.js +41 -0
  12. package/dist/record.d.ts +20 -0
  13. package/dist/record.js +266 -0
  14. package/dist/skill_loop.d.ts +23 -0
  15. package/dist/skill_loop.js +58 -0
  16. package/dist/store.d.ts +31 -0
  17. package/dist/store.js +213 -0
  18. package/dist/sync.d.ts +3 -0
  19. package/dist/sync.js +135 -0
  20. package/dist/task.d.ts +7 -0
  21. package/dist/task.js +44 -0
  22. package/dist/transition.d.ts +34 -0
  23. package/dist/transition.js +400 -0
  24. package/dist/types.d.ts +141 -0
  25. package/dist/types.js +3 -0
  26. package/package.json +8 -53
  27. package/templates/workflow/agents/architect.toml +13 -0
  28. package/{adapters/codex → templates/workflow}/agents/code-reviewer.toml +2 -2
  29. package/templates/workflow/agents/critic.toml +13 -0
  30. package/{adapters/codex → templates/workflow}/agents/executor.toml +2 -2
  31. package/{adapters/codex → templates/workflow}/agents/explore.toml +3 -3
  32. package/templates/workflow/agents/final-audit.toml +13 -0
  33. package/templates/workflow/agents/proposal-auditor.toml +13 -0
  34. package/{adapters/codex → templates/workflow}/agents/test-engineer.toml +4 -4
  35. package/{adapters/codex → templates/workflow}/agents/test-runner.toml +2 -2
  36. package/{adapters/codex → templates/workflow}/agents/verifier.toml +2 -2
  37. package/templates/workflow/prompts/architect.md +16 -0
  38. package/templates/workflow/prompts/critic.md +16 -0
  39. package/templates/workflow/prompts/explore.md +1 -1
  40. package/templates/workflow/prompts/final-audit.md +32 -0
  41. package/templates/workflow/prompts/proposal-auditor.md +34 -0
  42. package/templates/workflow/prompts/test-engineer.md +16 -0
  43. package/templates/workflow/skills/superspec-apply/SKILL.md +39 -121
  44. package/templates/workflow/skills/superspec-archive/SKILL.md +17 -49
  45. package/templates/workflow/skills/superspec-explore/SKILL.md +34 -70
  46. package/templates/workflow/skills/superspec-propose/SKILL.md +57 -60
  47. package/templates/workflow/skills/superspec-review/SKILL.md +18 -85
  48. package/adapters/codex/agents/architect.toml +0 -13
  49. package/adapters/codex/agents/critic.toml +0 -13
  50. package/adapters/codex/install-map.json +0 -116
  51. package/bin/launch.js +0 -37
  52. package/bin/superspec-check.js +0 -4
  53. package/bin/superspec-hook.js +0 -4
  54. package/bin/superspec-init.js +0 -4
  55. package/bin/superspec.js +0 -4
  56. package/dist/src/apply_worker_chain.d.ts +0 -60
  57. package/dist/src/apply_worker_chain.js +0 -1283
  58. package/dist/src/apply_worker_chain_lifecycle.d.ts +0 -21
  59. package/dist/src/apply_worker_chain_lifecycle.js +0 -409
  60. package/dist/src/archive.d.ts +0 -23
  61. package/dist/src/archive.js +0 -430
  62. package/dist/src/cli.d.ts +0 -1
  63. package/dist/src/cli.js +0 -33
  64. package/dist/src/cli_args.d.ts +0 -32
  65. package/dist/src/cli_args.js +0 -454
  66. package/dist/src/core.d.ts +0 -20
  67. package/dist/src/core.js +0 -394
  68. package/dist/src/disclosure.d.ts +0 -35
  69. package/dist/src/disclosure.js +0 -671
  70. package/dist/src/doctor.d.ts +0 -44
  71. package/dist/src/doctor.js +0 -230
  72. package/dist/src/evidence.d.ts +0 -29
  73. package/dist/src/evidence.js +0 -1107
  74. package/dist/src/gates.d.ts +0 -19
  75. package/dist/src/gates.js +0 -1631
  76. package/dist/src/git.d.ts +0 -8
  77. package/dist/src/git.js +0 -112
  78. package/dist/src/hooks/adapter.d.ts +0 -5
  79. package/dist/src/hooks/adapter.js +0 -347
  80. package/dist/src/hooks/guard_api.d.ts +0 -12
  81. package/dist/src/hooks/guard_api.js +0 -797
  82. package/dist/src/hooks/health.d.ts +0 -4
  83. package/dist/src/hooks/health.js +0 -86
  84. package/dist/src/hooks/policy_event.d.ts +0 -41
  85. package/dist/src/hooks/policy_event.js +0 -2634
  86. package/dist/src/hooks/types.d.ts +0 -72
  87. package/dist/src/hooks/types.js +0 -1
  88. package/dist/src/hooks/validation.d.ts +0 -3
  89. package/dist/src/hooks/validation.js +0 -70
  90. package/dist/src/i18n.d.ts +0 -21
  91. package/dist/src/i18n.js +0 -720
  92. package/dist/src/init_cli.d.ts +0 -28
  93. package/dist/src/init_cli.js +0 -404
  94. package/dist/src/install_engine.d.ts +0 -71
  95. package/dist/src/install_engine.js +0 -538
  96. package/dist/src/invariants.d.ts +0 -16
  97. package/dist/src/invariants.js +0 -363
  98. package/dist/src/openspec.d.ts +0 -37
  99. package/dist/src/openspec.js +0 -274
  100. package/dist/src/packet_render.d.ts +0 -5
  101. package/dist/src/packet_render.js +0 -1767
  102. package/dist/src/packet_schema.d.ts +0 -59
  103. package/dist/src/packet_schema.js +0 -1
  104. package/dist/src/paths.d.ts +0 -22
  105. package/dist/src/paths.js +0 -203
  106. package/dist/src/project_init.d.ts +0 -33
  107. package/dist/src/project_init.js +0 -191
  108. package/dist/src/self_update.d.ts +0 -14
  109. package/dist/src/self_update.js +0 -56
  110. package/dist/src/state.d.ts +0 -37
  111. package/dist/src/state.js +0 -464
  112. package/dist/src/tasks.d.ts +0 -38
  113. package/dist/src/tasks.js +0 -373
  114. package/dist/src/util.d.ts +0 -163
  115. package/dist/src/util.js +0 -792
  116. package/dist/superspec.d.ts +0 -6
  117. package/dist/superspec.js +0 -97
  118. package/dist/superspec_guard.d.ts +0 -4
  119. package/dist/superspec_guard.js +0 -19
  120. package/dist/superspec_hook.d.ts +0 -4
  121. package/dist/superspec_hook.js +0 -35
  122. package/dist/superspec_init.d.ts +0 -2
  123. package/dist/superspec_init.js +0 -17
  124. package/schemas/hook-event.schema.json +0 -27
  125. package/schemas/install-manifest.schema.json +0 -97
  126. package/templates/hooks/codex-hooks.json +0 -35
  127. package/templates/sidecar/archive-preservation.json +0 -11
  128. package/templates/sidecar/business-invariants.md +0 -38
  129. package/templates/sidecar/config.yaml +0 -13
  130. package/templates/sidecar/discovery.md +0 -33
  131. package/templates/sidecar/test-contract.md +0 -27
@@ -1,430 +0,0 @@
1
- import { closeSync, copyFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
2
- import { dirname, join, relative } from "node:path";
3
- import { STATE_LOCK_FILENAME, allow, block, now, reason, renderList, repr, runtime, safe_within, sha256_file, sha256_text, toPosix, walkFiles, } from "./util.js";
4
- import { ensure_state_layout, sidecar_artifacts_dir, superspec_dir } from "./paths.js";
5
- export function archive_manifest_path(changeRoot) {
6
- return join(sidecar_artifacts_dir(changeRoot), "archive-preservation.json");
7
- }
8
- export function archive_preservation_dir(changeRoot) {
9
- return join(changeRoot, "superspec-preservation");
10
- }
11
- export function archive_preservation_manifest_path(changeRoot) {
12
- return join(archive_preservation_dir(changeRoot), "manifest.json");
13
- }
14
- function archive_staging_root(changeRoot, runId) {
15
- return join(changeRoot, ".superspec-staging", runId);
16
- }
17
- function fsync_dir_best_effort(dirPath) {
18
- let fd = null;
19
- try {
20
- fd = openSync(dirPath, "r");
21
- fsyncSync(fd);
22
- }
23
- catch {
24
- // Directory fsync is best-effort across platforms.
25
- }
26
- finally {
27
- if (fd !== null)
28
- closeSync(fd);
29
- }
30
- }
31
- function write_text(path, text) {
32
- mkdirSync(dirname(path), { recursive: true });
33
- writeFileSync(path, text, "utf8");
34
- }
35
- function excluded_manifest_entry(relPath) {
36
- if (relPath.endsWith(STATE_LOCK_FILENAME) || relPath.endsWith("superspec-state.tmp"))
37
- return true;
38
- if (relPath === ".superspec/hook-runtime" || relPath.startsWith(".superspec/hook-runtime/"))
39
- return true;
40
- if (relPath === ".superspec/artifacts/archive-preservation.json")
41
- return true;
42
- return false;
43
- }
44
- function manifest_entries(changeRoot, fileOverrides = {}) {
45
- const base = superspec_dir(changeRoot);
46
- const entries = [];
47
- const pendingOverrides = new Set(Object.keys(fileOverrides));
48
- if (existsSync(base) && statSync(base).isDirectory()) {
49
- for (const filePath of walkFiles(base).sort()) {
50
- const relPath = toPosix(relative(changeRoot, filePath));
51
- if (excluded_manifest_entry(relPath))
52
- continue;
53
- if (pendingOverrides.has(relPath)) {
54
- entries.push({ path: relPath, sha256: sha256_text(fileOverrides[relPath]) });
55
- pendingOverrides.delete(relPath);
56
- }
57
- else {
58
- entries.push({ path: relPath, sha256: sha256_file(filePath) });
59
- }
60
- }
61
- }
62
- for (const relPath of [...pendingOverrides].sort()) {
63
- if (excluded_manifest_entry(relPath))
64
- continue;
65
- entries.push({ path: relPath, sha256: sha256_text(fileOverrides[relPath]) });
66
- }
67
- return entries.sort((a, b) => String(a.path).localeCompare(String(b.path)));
68
- }
69
- export function sidecar_manifest_entries(changeRoot) {
70
- return manifest_entries(changeRoot);
71
- }
72
- function archive_manifest_data(change, changeRoot, fileOverrides = {}) {
73
- ensure_state_layout(changeRoot);
74
- return {
75
- schema_version: 1,
76
- change_id: change,
77
- created_at: now(),
78
- kind: "superspec_archive_preservation",
79
- entries: manifest_entries(changeRoot, fileOverrides),
80
- };
81
- }
82
- function write_manifest_file(filePath, manifest) {
83
- write_text(filePath, `${JSON.stringify(manifest, null, 2)}\n`);
84
- return filePath;
85
- }
86
- export function write_archive_manifest(change, changeRoot) {
87
- return write_manifest_file(archive_manifest_path(changeRoot), archive_manifest_data(change, changeRoot));
88
- }
89
- function stage_archive_bundle(change, changeRoot, runId, fileOverrides) {
90
- const stagingRoot = archive_staging_root(changeRoot, runId);
91
- const stagedManifestPath = join(stagingRoot, "next", "archive-preservation.json");
92
- const stagedBundleDir = join(stagingRoot, "next", "superspec-preservation");
93
- const stagedFilesRoot = join(stagedBundleDir, "files");
94
- const manifest = archive_manifest_data(change, changeRoot, fileOverrides);
95
- write_manifest_file(stagedManifestPath, manifest);
96
- for (const entry of manifest.entries ?? []) {
97
- const relPath = entry.path;
98
- if (typeof relPath !== "string")
99
- continue;
100
- const dst = join(stagedFilesRoot, relPath);
101
- if (relPath in fileOverrides) {
102
- write_text(dst, fileOverrides[relPath]);
103
- continue;
104
- }
105
- const src = join(changeRoot, relPath);
106
- if (!existsSync(src) || !statSync(src).isFile())
107
- continue;
108
- mkdirSync(dirname(dst), { recursive: true });
109
- copyFileSync(src, dst);
110
- }
111
- const bundleManifest = {
112
- ...manifest,
113
- kind: "superspec_archive_preservation_bundle",
114
- source_manifest: ".superspec/artifacts/archive-preservation.json",
115
- files_root: "files",
116
- };
117
- const stagedBundleManifestPath = join(stagedBundleDir, "manifest.json");
118
- write_text(stagedBundleManifestPath, `${JSON.stringify(bundleManifest, null, 2)}\n`);
119
- return { staged_manifest_path: stagedManifestPath, staged_bundle_dir: stagedBundleDir };
120
- }
121
- function restore_file_from_backup(finalPath, backupPath, hadFinal) {
122
- if (existsSync(backupPath)) {
123
- if (existsSync(finalPath))
124
- rmSync(finalPath, { force: true });
125
- mkdirSync(dirname(finalPath), { recursive: true });
126
- renameSync(backupPath, finalPath);
127
- }
128
- else if (!hadFinal) {
129
- if (existsSync(finalPath))
130
- rmSync(finalPath, { force: true });
131
- }
132
- else {
133
- throw new Error(`backup missing for ${finalPath}`);
134
- }
135
- }
136
- function restore_dir_from_backup(finalPath, backupPath, hadFinal) {
137
- if (existsSync(backupPath)) {
138
- if (existsSync(finalPath))
139
- rmSync(finalPath, { recursive: true, force: true });
140
- renameSync(backupPath, finalPath);
141
- }
142
- else if (!hadFinal) {
143
- if (existsSync(finalPath))
144
- rmSync(finalPath, { recursive: true, force: true });
145
- }
146
- else {
147
- throw new Error(`backup missing for ${finalPath}`);
148
- }
149
- }
150
- function restore_promoted_bundle(state) {
151
- restore_file_from_backup(state.final_manifest, state.backup_manifest, state.had_final_manifest);
152
- restore_dir_from_backup(state.final_bundle_dir, state.backup_bundle_dir, state.had_final_bundle);
153
- }
154
- function promote_archive_bundle(changeRoot, runId, stagedManifestPath, stagedBundleDir) {
155
- const finalManifest = archive_manifest_path(changeRoot);
156
- const finalBundleDir = archive_preservation_dir(changeRoot);
157
- const stagingRoot = archive_staging_root(changeRoot, runId);
158
- const backupRoot = join(stagingRoot, "backup");
159
- const backupManifest = join(backupRoot, "archive-preservation.json");
160
- const backupBundleDir = join(backupRoot, "superspec-preservation");
161
- const hadFinalManifest = existsSync(finalManifest);
162
- const hadFinalBundle = existsSync(finalBundleDir);
163
- const state = {
164
- staging_root: stagingRoot,
165
- final_manifest: finalManifest,
166
- final_bundle_dir: finalBundleDir,
167
- backup_manifest: backupManifest,
168
- backup_bundle_dir: backupBundleDir,
169
- had_final_manifest: hadFinalManifest,
170
- had_final_bundle: hadFinalBundle,
171
- };
172
- mkdirSync(backupRoot, { recursive: true });
173
- try {
174
- if (hadFinalBundle) {
175
- renameSync(finalBundleDir, backupBundleDir);
176
- fsync_dir_best_effort(changeRoot);
177
- }
178
- if (hadFinalManifest) {
179
- mkdirSync(dirname(backupManifest), { recursive: true });
180
- renameSync(finalManifest, backupManifest);
181
- fsync_dir_best_effort(dirname(finalManifest));
182
- }
183
- renameSync(stagedBundleDir, finalBundleDir);
184
- fsync_dir_best_effort(changeRoot);
185
- if (typeof runtime.after_archive_bundle_promote === "function") {
186
- runtime.after_archive_bundle_promote({
187
- change_root: changeRoot,
188
- final_bundle_dir: finalBundleDir,
189
- final_manifest: finalManifest,
190
- });
191
- }
192
- mkdirSync(dirname(finalManifest), { recursive: true });
193
- renameSync(stagedManifestPath, finalManifest);
194
- fsync_dir_best_effort(dirname(finalManifest));
195
- return state;
196
- }
197
- catch (err) {
198
- try {
199
- restore_promoted_bundle(state);
200
- rmSync(stagingRoot, { recursive: true, force: true });
201
- }
202
- catch (restoreErr) {
203
- throw new Error(`archive preservation promote failed: ${err.message}; rollback failed: ${restoreErr.message}`);
204
- }
205
- throw err;
206
- }
207
- }
208
- export function begin_archive_preservation_bundle(change, changeRoot, opts = {}) {
209
- const runId = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
210
- const staged = stage_archive_bundle(change, changeRoot, runId, opts.file_overrides ?? {});
211
- const promotion = promote_archive_bundle(changeRoot, runId, staged.staged_manifest_path, staged.staged_bundle_dir);
212
- let settled = false;
213
- return {
214
- manifest_path: archive_manifest_path(changeRoot),
215
- bundle_manifest_path: archive_preservation_manifest_path(changeRoot),
216
- commit: () => {
217
- if (settled)
218
- return;
219
- settled = true;
220
- try {
221
- rmSync(promotion.staging_root, { recursive: true, force: true });
222
- }
223
- catch {
224
- // Commit is already durable; staging cleanup is best-effort.
225
- }
226
- },
227
- rollback: () => {
228
- if (settled)
229
- return;
230
- restore_promoted_bundle(promotion);
231
- rmSync(promotion.staging_root, { recursive: true, force: true });
232
- settled = true;
233
- },
234
- };
235
- }
236
- export function write_archive_preservation_bundle(change, changeRoot, opts = {}) {
237
- const txn = begin_archive_preservation_bundle(change, changeRoot, opts);
238
- txn.commit();
239
- return txn.bundle_manifest_path;
240
- }
241
- export function find_archived_change(repoRoot, change) {
242
- const archiveRoot = join(repoRoot, "openspec", "changes", "archive");
243
- if (!existsSync(archiveRoot) || !lstatSync(archiveRoot).isDirectory())
244
- return null;
245
- const candidates = readdirSync(archiveRoot)
246
- .filter((name) => name === change || (/^\d{4}-\d{2}-\d{2}-.+/.test(name) && name.slice(11) === change))
247
- .map((name) => join(archiveRoot, name))
248
- .filter((item) => {
249
- const stat = lstatSync(item);
250
- return !stat.isSymbolicLink() && stat.isDirectory();
251
- })
252
- .sort();
253
- return candidates.at(-1) ?? null;
254
- }
255
- function manifest_change_id_reasons(change, manifest, label) {
256
- if (manifest.change_id !== change) {
257
- return [reason("archive_manifest_mismatch", `${label} manifest change_id=${repr(manifest.change_id)} does not match ${repr(change)}`)];
258
- }
259
- return [];
260
- }
261
- const PRIMARY_ARCHIVE_MANIFEST_KIND = "superspec_archive_preservation";
262
- const FALLBACK_ARCHIVE_MANIFEST_KIND = "superspec_archive_preservation_bundle";
263
- const REQUIRED_ARCHIVE_ENTRIES = [".superspec/ledger.jsonl", ".superspec/superspec-state.json"];
264
- function manifest_shape_reasons(change, manifest, label, expectedKind) {
265
- const reasons = manifest_change_id_reasons(change, manifest, label);
266
- if (manifest.kind !== expectedKind) {
267
- reasons.push(reason("archive_manifest_mismatch", `${label} manifest kind=${repr(manifest.kind)} does not match ${repr(expectedKind)}`));
268
- }
269
- if (!Array.isArray(manifest.entries) || manifest.entries.length === 0) {
270
- reasons.push(reason("archive_manifest_mismatch", `${label} manifest entries must be a non-empty list`));
271
- return reasons;
272
- }
273
- const paths = new Set();
274
- for (const entry of manifest.entries) {
275
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
276
- reasons.push(reason("archive_manifest_mismatch", `${label} manifest entries must be objects`));
277
- continue;
278
- }
279
- if (typeof entry.path === "string")
280
- paths.add(entry.path);
281
- }
282
- const missingRequired = REQUIRED_ARCHIVE_ENTRIES.filter((entry) => !paths.has(entry));
283
- if (missingRequired.length > 0) {
284
- reasons.push(reason("archive_manifest_mismatch", `${label} manifest missing required entries: ${renderList([...missingRequired])}`, [...missingRequired]));
285
- }
286
- return reasons;
287
- }
288
- function manifest_entry_target(baseRoot, relPath) {
289
- if (!relPath.startsWith(".superspec/"))
290
- return null;
291
- return safe_within(baseRoot, relPath);
292
- }
293
- function preserved_file_sha(filePath) {
294
- if (!existsSync(filePath))
295
- return null;
296
- const stat = lstatSync(filePath);
297
- if (stat.isSymbolicLink() || !stat.isFile() || stat.nlink > 1)
298
- return null;
299
- return sha256_file(filePath);
300
- }
301
- export function check_archived(change, repoRoot) {
302
- const archived = find_archived_change(repoRoot, change);
303
- if (archived === null)
304
- return block(change, "archived", [reason("archive_not_found", `archived change not found for ${change}`)]);
305
- const manifestPath = archive_manifest_path(archived);
306
- if (!existsSync(manifestPath) || !statSync(manifestPath).isFile()) {
307
- const fallbackManifest = archive_preservation_manifest_path(archived);
308
- if (!existsSync(fallbackManifest) || !statSync(fallbackManifest).isFile()) {
309
- return block(change, "archived", [reason("superspec_not_preserved", "archive preservation manifest missing")]);
310
- }
311
- return check_archived_preservation_bundle(change, archived, fallbackManifest);
312
- }
313
- let manifest;
314
- try {
315
- manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
316
- }
317
- catch {
318
- return block(change, "archived", [reason("superspec_not_preserved", "archive preservation manifest is invalid JSON")]);
319
- }
320
- const shapeReasons = manifest_shape_reasons(change, manifest, "archive preservation", PRIMARY_ARCHIVE_MANIFEST_KIND);
321
- if (shapeReasons.length > 0)
322
- return block(change, "archived", shapeReasons);
323
- const missing = [];
324
- const mismatched = [];
325
- const invalid = [];
326
- for (const entry of manifest.entries) {
327
- const relPath = entry.path;
328
- const expected = entry.sha256;
329
- if (typeof relPath !== "string" || typeof expected !== "string") {
330
- mismatched.push(String(relPath));
331
- continue;
332
- }
333
- const filePath = manifest_entry_target(archived, relPath);
334
- if (filePath === null) {
335
- invalid.push(relPath);
336
- continue;
337
- }
338
- const actual = preserved_file_sha(filePath);
339
- if (actual === null)
340
- missing.push(relPath);
341
- else if (actual !== expected)
342
- mismatched.push(relPath);
343
- }
344
- const reasons = [];
345
- if (invalid.length > 0)
346
- reasons.push(reason("archive_manifest_mismatch", `archived .superspec manifest paths are invalid: ${renderList(invalid.slice(0, 20))}`, invalid.slice(0, 20)));
347
- if (missing.length > 0)
348
- reasons.push(reason("superspec_not_preserved", `archived .superspec files missing: ${renderList(missing.slice(0, 20))}`));
349
- if (mismatched.length > 0)
350
- reasons.push(reason("archive_manifest_mismatch", `archived .superspec files changed: ${renderList(mismatched.slice(0, 20))}`));
351
- if (reasons.length > 0)
352
- return block(change, "archived", reasons);
353
- return allow(change, "archived", { gate_summary: { archive_root: archived, manifest_entries: (manifest.entries ?? []).length } });
354
- }
355
- export function check_archived_preservation_bundle(change, archived, manifestPath) {
356
- let manifest;
357
- try {
358
- manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
359
- }
360
- catch {
361
- return block(change, "archived", [reason("superspec_not_preserved", "fallback preservation manifest is invalid JSON")]);
362
- }
363
- const shapeReasons = manifest_shape_reasons(change, manifest, "fallback preservation", FALLBACK_ARCHIVE_MANIFEST_KIND);
364
- if (shapeReasons.length > 0)
365
- return block(change, "archived", shapeReasons);
366
- if (typeof manifest.files_root !== "string" || !manifest.files_root) {
367
- return block(change, "archived", [reason("archive_manifest_mismatch", "fallback preservation manifest requires files_root")]);
368
- }
369
- const filesRoot = safe_within(dirname(manifestPath), manifest.files_root);
370
- if (filesRoot === null || !existsSync(filesRoot) || !lstatSync(filesRoot).isDirectory()) {
371
- return block(change, "archived", [reason("archive_manifest_mismatch", `fallback preservation files_root is invalid: ${repr(manifest.files_root)}`)]);
372
- }
373
- const missing = [];
374
- const mismatched = [];
375
- const invalid = [];
376
- for (const entry of manifest.entries) {
377
- const relPath = entry.path;
378
- const expected = entry.sha256;
379
- if (typeof relPath !== "string" || typeof expected !== "string") {
380
- mismatched.push(String(relPath));
381
- continue;
382
- }
383
- const filePath = manifest_entry_target(filesRoot, relPath);
384
- if (filePath === null) {
385
- invalid.push(relPath);
386
- continue;
387
- }
388
- const actual = preserved_file_sha(filePath);
389
- if (actual === null)
390
- missing.push(relPath);
391
- else if (actual !== expected)
392
- mismatched.push(relPath);
393
- }
394
- const reasons = [];
395
- if (invalid.length > 0)
396
- reasons.push(reason("archive_manifest_mismatch", `fallback .superspec manifest paths are invalid: ${renderList(invalid.slice(0, 20))}`, invalid.slice(0, 20)));
397
- if (missing.length > 0)
398
- reasons.push(reason("superspec_not_preserved", `fallback .superspec files missing: ${renderList(missing.slice(0, 20))}`));
399
- if (mismatched.length > 0)
400
- reasons.push(reason("archive_manifest_mismatch", `fallback .superspec files changed: ${renderList(mismatched.slice(0, 20))}`));
401
- if (reasons.length > 0)
402
- return block(change, "archived", reasons);
403
- return allow(change, "archived", {
404
- gate_summary: {
405
- archive_root: archived,
406
- fallback_manifest: toPosix(relative(archived, manifestPath)),
407
- manifest_entries: (manifest.entries ?? []).length,
408
- },
409
- });
410
- }
411
- export function preset_upgrade_required(preset, changedPaths, flags = {}) {
412
- if (preset === "full")
413
- return false;
414
- if (preset === "hotfix")
415
- return changedPaths.length >= 3 || Boolean(flags.architecture) || Boolean(flags.schema) || Boolean(flags.public_api) || Boolean(flags.cross_module);
416
- if (preset === "tweak")
417
- return changedPaths.length >= 5 || Boolean(flags.cross_module) || Number(flags.new_tests ?? 0) >= 5 || Boolean(flags.config_key_add_remove);
418
- return true;
419
- }
420
- export function preset_upgrade_reasons(config, changedPaths, humanConfirmed = false, flags = {}) {
421
- const preset = String(config.preset ?? "full");
422
- if (!preset_upgrade_required(preset, changedPaths, flags))
423
- return [];
424
- if (humanConfirmed)
425
- return [];
426
- return [reason("preset_upgrade_requires_human_confirmation", `preset ${repr(preset)} must upgrade to full before proceeding`)];
427
- }
428
- export function preset_upgrade_required_from_context(config, changedPaths) {
429
- return preset_upgrade_required(String(config.preset ?? "full"), changedPaths);
430
- }
package/dist/src/cli.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function main(argv?: string[]): number;
package/dist/src/cli.js DELETED
@@ -1,33 +0,0 @@
1
- import { block, dispatch, GuardError, printDecision, reason } from "./core.js";
2
- import { emitArgparsePreamble, parse_argv } from "./cli_args.js";
3
- import { dispatch_packet, is_packet_command } from "./packet_render.js";
4
- import { printPacket, printPacketError } from "./util.js";
5
- export function main(argv = process.argv.slice(2)) {
6
- let args = null;
7
- const rawCommand = argv[0] ?? "";
8
- try {
9
- const argparseExit = emitArgparsePreamble(argv);
10
- if (argparseExit !== null)
11
- return argparseExit;
12
- args = parse_argv(argv);
13
- if (is_packet_command(args.command)) {
14
- const result = dispatch_packet(args);
15
- printPacket(result.payload, { format: result.output_format });
16
- return 0;
17
- }
18
- const [decision] = dispatch(args);
19
- printDecision(decision, { command: args.command, format: args.format });
20
- return decision.allowed ? 0 : 1;
21
- }
22
- catch (err) {
23
- if ((args && is_packet_command(args.command)) || is_packet_command(rawCommand)) {
24
- const errCode = err instanceof GuardError ? "guard_error" : "guard_internal_error";
25
- printPacketError(errCode, `${err.message}`);
26
- return 2;
27
- }
28
- const change = args?.change ?? "?";
29
- const errReason = err instanceof GuardError ? reason("guard_error", err.message) : reason("guard_internal_error", `${err.name}: ${err.message}`);
30
- printDecision(block(change, "guard_error", [errReason]), { command: args?.command, format: args?.format });
31
- return 2;
32
- }
33
- }
@@ -1,32 +0,0 @@
1
- import { type DecisionOutputFormat, type PacketOutputFormat } from "./util.ts";
2
- export type ParsedArgs = {
3
- command: string;
4
- change: string;
5
- format?: DecisionOutputFormat;
6
- packet_format?: PacketOutputFormat;
7
- artifact?: string;
8
- gate?: string;
9
- task_id?: string;
10
- test_id?: string;
11
- phase?: "red" | "characterization" | "green";
12
- event_ref?: string;
13
- workflow?: string;
14
- entrypoint_token?: string;
15
- end_reason?: string;
16
- lifecycle_token?: string;
17
- role?: string;
18
- evidence_kind?: string;
19
- round?: number;
20
- executor_report_refs?: string[];
21
- task_code_review_report_refs?: string[];
22
- apply_worker_chain_refs?: string[];
23
- green_test_run_evidence_refs?: string[];
24
- alternative_verification_evidence_refs?: string[];
25
- red_test_run_evidence_refs?: string[];
26
- characterization_test_run_evidence_refs?: string[];
27
- create?: boolean;
28
- force_unlock?: boolean;
29
- rebuild_corrupt?: boolean;
30
- };
31
- export declare function emitArgparsePreamble(argv: string[]): number | null;
32
- export declare function parse_argv(argv: string[]): ParsedArgs;