@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
package/README.md CHANGED
@@ -77,17 +77,16 @@ npm install -g @peterxiaoyang/superspec@latest
77
77
  进入你的项目根目录,然后运行:
78
78
 
79
79
  ```bash
80
- superspec init --scope project
80
+ superspec install
81
81
  ```
82
82
 
83
83
  这条命令的意思是:把 SuperSpec 当前可用的工作流入口安装到项目里。
84
-
85
- 初始化还会安装托管的 `.codex/hooks.json`。默认 manifest 只在子智能体启动和停止时调用 SuperSpec,记录 best-effort 审计信息;它不会拦截普通文件写入,也不会在测试命令后自动记录结果。
84
+ 当前 beta 会安装 `.superspec/` 引擎目录、`.codex/skills/superspec-*` 阶段入口、`.codex/prompts/*.md` 角色 prompt、`.codex/agents/*.toml` 子智能体配置,并补齐 `.codex/config.toml` 的多 agent 开关。`superspec init --scope project` 仍作为兼容别名可用。
86
85
 
87
86
  Windows PowerShell 如果拦截 npm 的 `.ps1` 脚本,请改用:
88
87
 
89
88
  ```powershell
90
- superspec.cmd init --scope project
89
+ superspec.cmd install
91
90
  ```
92
91
 
93
92
  ### 3. 按步骤使用
@@ -136,6 +135,8 @@ superspec.cmd init --scope project
136
135
 
137
136
  你日常主要记住这五个入口就够了。
138
137
 
138
+ CLI 不带 `--risk` 时默认是 `normal`;但内置的 `superspec-explore` 和 `superspec-propose` 技能默认用 `--risk strict` 驱动。探索阶段会创建 `critic` 工作项审查需求澄清记录;计划阶段会创建 `proposal-auditor`、`critic`、`architect` 和 `test-engineer` 工作项后再进入实现准备。
139
+
139
140
  ## 它会多保存哪些记录
140
141
 
141
142
  SuperSpec 会在每次变更下面保存一些辅助记录,方便后续追溯。
@@ -200,34 +201,24 @@ superspec --version
200
201
  安装到当前项目:
201
202
 
202
203
  ```bash
203
- superspec init --scope project
204
+ superspec install
204
205
  ```
205
206
 
206
- 更新当前项目里的 SuperSpec 入口:
207
+ `superspec init --scope project` 是兼容别名,也会执行同一套安装逻辑。
207
208
 
208
- ```bash
209
- superspec update --scope project
210
- ```
211
-
212
- 这条命令会先通过 npm 更新全局 `@peterxiaoyang/superspec`,再用新版本更新当前项目里的入口文件。只想使用当前已安装包更新项目文件时,可以运行:
209
+ 检查当前项目的 OpenSpec 探测结果:
213
210
 
214
211
  ```bash
215
- superspec update --scope project --local-only
212
+ superspec status
216
213
  ```
217
214
 
218
- 卸载当前项目里的 SuperSpec 入口:
215
+ 更新当前 beta CLI:
219
216
 
220
217
  ```bash
221
- superspec uninstall --scope project
218
+ superspec update
222
219
  ```
223
220
 
224
- 这些命令默认不会删除已经生成的 `.superspec/` 过程记录。
225
-
226
- 诊断全局安装、PATH、OpenSpec 依赖和 npm bin 指向问题:
227
-
228
- ```bash
229
- superspec doctor
230
- ```
221
+ 这条命令只检查当前 `.superspec/changes` 运行时是否已经是新引擎布局;真正升级全局 npm 包仍需使用 `npm install -g @peterxiaoyang/superspec@<version>`。
231
222
 
232
223
  ## 进阶信息
233
224
 
@@ -235,24 +226,35 @@ superspec doctor
235
226
 
236
227
  ```text
237
228
  .codex/
238
- hooks.json
239
229
  skills/superspec-explore/
240
230
  skills/superspec-propose/
241
231
  skills/superspec-apply/
242
232
  skills/superspec-review/
243
233
  skills/superspec-archive/
234
+ prompts/architect.md
235
+ prompts/code-reviewer.md
236
+ prompts/critic.md
237
+ prompts/executor.md
238
+ prompts/explore.md
239
+ prompts/final-audit.md
240
+ prompts/proposal-auditor.md
241
+ prompts/test-engineer.md
242
+ prompts/test-runner.md
243
+ prompts/verifier.md
244
+ agents/architect.toml
245
+ agents/code-reviewer.toml
246
+ agents/critic.toml
247
+ agents/executor.toml
248
+ agents/explore.toml
249
+ agents/final-audit.toml
250
+ agents/proposal-auditor.toml
251
+ agents/test-engineer.toml
252
+ agents/test-runner.toml
253
+ agents/verifier.toml
254
+ config.toml
244
255
  ```
245
256
 
246
- SuperSpec 内部还有一些检查命令,例如:
247
-
248
- ```bash
249
- superspec check check-init --change <变更ID>
250
- superspec check check-apply-ready --change <变更ID>
251
- superspec check check-review-ready --change <变更ID>
252
- superspec check check-archive-ready --change <变更ID>
253
- ```
254
-
255
- 普通使用者通常不需要手动运行这些命令;对应的阶段入口会在需要时使用它们。
257
+ 当前 beta 的阶段入口由 `superspec transition next --change <变更ID>` 驱动,不再提供旧版 `superspec check ...` surface。
256
258
 
257
259
  如果你要开发 SuperSpec 本身:
258
260
 
@@ -260,14 +262,13 @@ superspec check check-archive-ready --change <变更ID>
260
262
  npm run build
261
263
  npm run typecheck
262
264
  npm test
263
- npm run pack:dry-run
265
+ npm pack --dry-run
264
266
  ```
265
267
 
266
268
  更多细节见:
267
269
 
268
- - `docs/SPEC.md`:完整设计和规则
269
- - `docs/DISTRIBUTION.md`:安装、升级、卸载和分发说明
270
- - `.codex/skills/superspec-*/SKILL.md`:当前 Codex 适配器使用的阶段入口说明
270
+ - `docs/plans/SUPERSPEC_TRANSITION_ENGINE_SPEC_LITE.md`:transition engine 设计
271
+ - `templates/workflow/skills/superspec-*/SKILL.md`:当前 Codex 适配器使用的阶段入口说明
271
272
 
272
273
  ## 致谢与灵感来源
273
274
 
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env node
2
+ // SuperSpec 流程引擎 — CLI 入口
3
+ import { join } from "node:path";
4
+ import { installProject } from "./install.js";
5
+ import { writeSnapshot } from "./store.js";
6
+ import { rebuildSnapshot } from "./sync.js";
7
+ import { next as nextCmd } from "./next.js";
8
+ import { proposeReady, commitTransition, transitionInit, transitionExplore, startApply, taskStart, taskComplete, reviewReady, accept, archive } from "./transition.js";
9
+ import { recordJobSubmit, recordUserDecision, jobsList, jobsPacket } from "./record.js";
10
+ import { recordTestRun } from "./task.js";
11
+ import { probeOpenSpec, openspecStatus, changeRoot } from "./openspec.js";
12
+ // ===== 参数解析 =====
13
+ function parseArgs(argv) {
14
+ const [command, subcommand, ...rest] = argv;
15
+ const opts = {};
16
+ for (let i = 0; i < rest.length; i++) {
17
+ if (rest[i].startsWith("--")) {
18
+ const key = rest[i].slice(2);
19
+ const val = rest[i + 1] && !rest[i + 1].startsWith("--") ? rest[++i] : "true";
20
+ opts[key] = val;
21
+ }
22
+ }
23
+ // 如果 subcommand 以 -- 开头,说明没有 subcommand
24
+ if (subcommand && subcommand.startsWith("--")) {
25
+ Object.entries(parseFlags([subcommand, ...rest])).forEach(([k, v]) => { opts[k] = v; });
26
+ return { command, opts };
27
+ }
28
+ return { command, subcommand, opts };
29
+ }
30
+ function parseFlags(args) {
31
+ const opts = {};
32
+ for (let i = 0; i < args.length; i++) {
33
+ if (args[i].startsWith("--")) {
34
+ const key = args[i].slice(2);
35
+ const val = args[i + 1] && !args[i + 1].startsWith("--") ? args[++i] : "true";
36
+ opts[key] = val;
37
+ }
38
+ }
39
+ return opts;
40
+ }
41
+ // ===== 初始化 transition init =====
42
+ // ===== init/explore 现在在 transition.ts 中(走统一锁内路径)=====
43
+ // ===== 主分发 =====
44
+ async function main(argv) {
45
+ // --help / 无参数 → 打印用法
46
+ if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
47
+ console.log(`SuperSpec 流程引擎 0.1.16-alpha
48
+
49
+ 用法:superspec <命令> [选项]
50
+
51
+ 命令:
52
+ status --change <C> 查看状态
53
+ transition <子命令> --change <C> 状态流转(见下)
54
+ record <子命令> --change <C> 登记证据(见下)
55
+ jobs <子命令> --change <C> 工作项管理(见下)
56
+ install 安装项目工作流入口
57
+ init --scope project install 的兼容别名
58
+ update 更新 SuperSpec
59
+ version 版本号
60
+
61
+ transition 子命令:
62
+ init / explore / sync / next / propose-ready / start-apply
63
+ task-start --task <T> / task-complete --task <T>
64
+ review-ready / accept / archive
65
+
66
+ record 子命令:
67
+ job-submit --job <J> --report <F>
68
+ user-decision --input <F>
69
+ test-run --input <F>
70
+
71
+ jobs 子命令:
72
+ list / packet --job <J>
73
+ `);
74
+ return 0;
75
+ }
76
+ // version
77
+ if (argv[0] === "version" || argv[0] === "--version" || argv[0] === "-v") {
78
+ console.log("SuperSpec 0.1.16-alpha");
79
+ return 0;
80
+ }
81
+ const { command, subcommand, opts } = parseArgs(argv);
82
+ const projectRoot = process.cwd();
83
+ // install / init / update 不需要 --change
84
+ if (command === "install" || command === "init") {
85
+ if (command === "init" && opts.scope && opts.scope !== "project") {
86
+ console.log(JSON.stringify({
87
+ ok: false,
88
+ message: "当前 beta 只支持 init --scope project",
89
+ }));
90
+ return 1;
91
+ }
92
+ try {
93
+ console.log(JSON.stringify(installProject(projectRoot)));
94
+ return 0;
95
+ }
96
+ catch (err) {
97
+ console.log(JSON.stringify({
98
+ ok: false,
99
+ message: err.message,
100
+ }));
101
+ return 1;
102
+ }
103
+ }
104
+ if (command === "update") {
105
+ // 检测是否从老版 update 过来
106
+ const { existsSync } = await import("node:fs");
107
+ const isLegacyUpdate = !existsSync(join(projectRoot, ".superspec", "changes"));
108
+ if (isLegacyUpdate) {
109
+ console.log(JSON.stringify({
110
+ ok: false,
111
+ message: "SuperSpec 0.1.16-alpha 是全新引擎,不能从 0.x 直接 update。\n" +
112
+ "请用 npm install -g @peterxiaoyang/superspec@0.1.16-alpha 手动安装。\n" +
113
+ "现有 change 请先用 0.1.x 完成归档。",
114
+ }));
115
+ return 1;
116
+ }
117
+ console.log(JSON.stringify({ ok: true, message: "已是最新版本 0.1.16-alpha" }));
118
+ return 0;
119
+ }
120
+ const change = opts.change;
121
+ if (!change && command !== "status") {
122
+ console.error("错误:缺少 --change(用 --help 查看用法)");
123
+ return 1;
124
+ }
125
+ try {
126
+ switch (command) {
127
+ case "status": {
128
+ if (!change) {
129
+ // 全局 status
130
+ const probe = probeOpenSpec(projectRoot);
131
+ console.log(JSON.stringify({ openspec: probe }, null, 2));
132
+ return 0;
133
+ }
134
+ const cr = changeRoot(projectRoot, change);
135
+ const snapshot = rebuildSnapshot(projectRoot, change, cr);
136
+ const jobs = jobsList(projectRoot, change);
137
+ console.log(JSON.stringify({
138
+ change,
139
+ state: snapshot.state,
140
+ open_jobs: jobs.open.length,
141
+ accepted_jobs: jobs.accepted.length,
142
+ rejected_jobs: jobs.rejected.length,
143
+ document_digests: snapshot.document_digests,
144
+ last_transition: snapshot.last_transition,
145
+ }, null, 2));
146
+ return 0;
147
+ }
148
+ case "transition": {
149
+ const cr = changeRoot(projectRoot, change);
150
+ switch (subcommand) {
151
+ case "init":
152
+ console.log(JSON.stringify(transitionInit(projectRoot, change, cr), null, 2));
153
+ return 0;
154
+ case "explore":
155
+ {
156
+ const risk = opts.risk ?? "normal";
157
+ console.log(JSON.stringify(transitionExplore(projectRoot, change, cr, risk), null, 2));
158
+ }
159
+ return 0;
160
+ case "sync": {
161
+ const snapshot = rebuildSnapshot(projectRoot, change, cr, openspecStatus(projectRoot, change));
162
+ writeSnapshot(projectRoot, change, snapshot);
163
+ console.log(JSON.stringify({
164
+ ok: true,
165
+ state: snapshot.state,
166
+ message: "snapshot 已重建",
167
+ stale_accepted_removed: 0, // sync 不报告具体移除(轻量)
168
+ }, null, 2));
169
+ return 0;
170
+ }
171
+ case "next": {
172
+ const risk = opts.risk ?? "normal";
173
+ const result = nextCmd(projectRoot, change, cr, risk);
174
+ console.log(JSON.stringify(result, null, 2));
175
+ return 0;
176
+ }
177
+ case "propose-ready": {
178
+ const risk = opts.risk ?? "normal";
179
+ const result = proposeReady(projectRoot, change, cr, risk);
180
+ console.log(JSON.stringify(result, null, 2));
181
+ return result.events_written === 0 && result.message.includes("不能") ? 1 : 0;
182
+ }
183
+ case "start-apply": {
184
+ const result = startApply(projectRoot, change, cr);
185
+ console.log(JSON.stringify(result, null, 2));
186
+ return result.events_written === 0 ? 1 : 0;
187
+ }
188
+ case "task-start": {
189
+ const taskId = opts.task;
190
+ if (!taskId) {
191
+ console.error("task-start 需要 --task");
192
+ return 1;
193
+ }
194
+ const result = taskStart(projectRoot, change, cr, taskId);
195
+ console.log(JSON.stringify(result, null, 2));
196
+ return result.events_written === 0 ? 1 : 0;
197
+ }
198
+ case "task-complete": {
199
+ const taskId = opts.task;
200
+ if (!taskId) {
201
+ console.error("task-complete 需要 --task");
202
+ return 1;
203
+ }
204
+ const result = taskComplete(projectRoot, change, cr, taskId);
205
+ console.log(JSON.stringify(result, null, 2));
206
+ return result.events_written === 0 ? 1 : 0;
207
+ }
208
+ case "review-ready": {
209
+ const risk = opts.risk ?? "normal";
210
+ const result = reviewReady(projectRoot, change, cr, risk);
211
+ console.log(JSON.stringify(result, null, 2));
212
+ return result.events_written === 0 ? 1 : 0;
213
+ }
214
+ case "accept": {
215
+ const result = accept(projectRoot, change, cr);
216
+ console.log(JSON.stringify(result, null, 2));
217
+ return result.events_written === 0 ? 1 : 0;
218
+ }
219
+ case "archive": {
220
+ const result = archive(projectRoot, change, cr);
221
+ console.log(JSON.stringify(result, null, 2));
222
+ return result.events_written === 0 ? 1 : 0;
223
+ }
224
+ default:
225
+ console.error(`未知的 transition 子命令:${subcommand}`);
226
+ return 1;
227
+ }
228
+ }
229
+ case "record": {
230
+ const cr = changeRoot(projectRoot, change);
231
+ switch (subcommand) {
232
+ case "job-submit": {
233
+ const jobId = opts.job;
234
+ const report = opts.report;
235
+ if (!jobId || !report) {
236
+ console.error("record job-submit 需要 --job 和 --report");
237
+ return 1;
238
+ }
239
+ const result = recordJobSubmit(projectRoot, change, cr, jobId, report);
240
+ console.log(JSON.stringify(result, null, 2));
241
+ return result.accepted ? 0 : 1;
242
+ }
243
+ case "user-decision": {
244
+ const inputFile = opts.input;
245
+ if (!inputFile) {
246
+ console.error("record user-decision 需要 --input");
247
+ return 1;
248
+ }
249
+ const result = recordUserDecision(projectRoot, change, inputFile);
250
+ console.log(JSON.stringify(result, null, 2));
251
+ return result.accepted ? 0 : 1;
252
+ }
253
+ case "test-run": {
254
+ const inputFile = opts.input;
255
+ if (!inputFile) {
256
+ console.error("record test-run 需要 --input");
257
+ return 1;
258
+ }
259
+ const result = recordTestRun(projectRoot, change, inputFile);
260
+ console.log(JSON.stringify(result, null, 2));
261
+ return result.accepted ? 0 : 1;
262
+ }
263
+ default:
264
+ console.error(`未知的 record 子命令:${subcommand}`);
265
+ return 1;
266
+ }
267
+ }
268
+ case "jobs": {
269
+ switch (subcommand) {
270
+ case "list": {
271
+ const result = jobsList(projectRoot, change);
272
+ console.log(JSON.stringify(result, null, 2));
273
+ return 0;
274
+ }
275
+ case "packet": {
276
+ const jobId = opts.job;
277
+ if (!jobId) {
278
+ console.error("jobs packet 需要 --job");
279
+ return 1;
280
+ }
281
+ const result = jobsPacket(projectRoot, change, jobId);
282
+ console.log(JSON.stringify(result, null, 2));
283
+ return result.found ? 0 : 1;
284
+ }
285
+ default:
286
+ console.error(`未知的 jobs 子命令:${subcommand}`);
287
+ return 1;
288
+ }
289
+ }
290
+ default:
291
+ console.error(`未知命令:${command}。可用:status, transition, record, jobs, install, init, update, version`);
292
+ return 1;
293
+ }
294
+ }
295
+ catch (err) {
296
+ console.error(`错误:${err.message}`);
297
+ return 2;
298
+ }
299
+ }
300
+ // 入口
301
+ main(process.argv.slice(2)).then(exitCode => process.exit(exitCode));
@@ -0,0 +1,29 @@
1
+ /** 从 discovery.md 提取"待确认问题"段内的未确认项数量 */
2
+ export declare function countDiscoveryOpenQuestions(content: string): number;
3
+ /** 完整校验 discovery.md:存在 + 非空 + 无未确认问题 */
4
+ export declare function validateDiscovery(changeRoot: string): {
5
+ ok: boolean;
6
+ message: string;
7
+ openCount: number;
8
+ };
9
+ export interface ParsedTask {
10
+ taskId: string;
11
+ lineIdx: number;
12
+ done: boolean;
13
+ tddRequired: boolean;
14
+ noTddReason: string | null;
15
+ }
16
+ /** 解析 tasks.md 的全部任务行 */
17
+ export declare function parseTasksMd(content: string): ParsedTask[];
18
+ /** 在 tasks.md 中按 taskId 精确查找任务(词边界,不误判子串) */
19
+ export declare function findTaskInLines(lines: string[], taskId: string): number;
20
+ /** tasks.md 结构指纹(复选框归一化) */
21
+ export declare function tasksStructureDigest(content: string, sha256Text: (s: string) => string): string;
22
+ export declare function validateTestRunInput(tr: Record<string, unknown>): {
23
+ ok: boolean;
24
+ message: string;
25
+ };
26
+ export declare function validateUserDecision(d: Record<string, unknown>): {
27
+ ok: boolean;
28
+ message: string;
29
+ };
package/dist/format.js ADDED
@@ -0,0 +1,141 @@
1
+ // SuperSpec 流程引擎 — format.ts:文档格式解析的唯一权威源
2
+ //
3
+ // 所有文档的格式定义和解析逻辑都在这里。skills 文案引用这里的格式。
4
+ // 修改格式 = 修改这里 + 对应 skill。禁止在其它地方重复解析。
5
+ import { readFileSync, existsSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ // ===== discovery.md =====
8
+ //
9
+ // 格式(explore skill 定义):
10
+ // ## 待确认问题
11
+ // - [ ] 问题1的描述
12
+ // - [ ] 问题2的描述
13
+ //
14
+ // 引擎只解析"待确认问题"段内的 `- [ ]`,不误判正常 checklist。
15
+ /** 从 discovery.md 提取"待确认问题"段内的未确认项数量 */
16
+ export function countDiscoveryOpenQuestions(content) {
17
+ // 找"待确认问题"标题(中英文兼容)
18
+ const sectionMatch = content.match(/^#{1,6}\s*(待确认问题|Open Questions|Pending Questions)\s*$/im);
19
+ if (!sectionMatch)
20
+ return 0;
21
+ const sectionStart = sectionMatch.index + sectionMatch[0].length;
22
+ // 截取到下一个标题或文件末尾
23
+ const restContent = content.slice(sectionStart);
24
+ const nextHeadingMatch = restContent.match(/^#{1,6}\s+/m);
25
+ const sectionBody = nextHeadingMatch ? restContent.slice(0, nextHeadingMatch.index) : restContent;
26
+ // 数未确认项
27
+ const matches = sectionBody.match(/- \[ \]/g);
28
+ return matches ? matches.length : 0;
29
+ }
30
+ /** 完整校验 discovery.md:存在 + 非空 + 无未确认问题 */
31
+ export function validateDiscovery(changeRoot) {
32
+ const path = join(changeRoot, ".superspec", "artifacts", "discovery.md");
33
+ if (!existsSync(path))
34
+ return { ok: false, message: "discovery.md 不存在", openCount: -1 };
35
+ const content = readFileSync(path, "utf8");
36
+ if (!content.trim())
37
+ return { ok: false, message: "discovery.md 为空", openCount: -1 };
38
+ const openCount = countDiscoveryOpenQuestions(content);
39
+ if (openCount > 0)
40
+ return { ok: false, message: `discovery.md 有 ${openCount} 个未确认问题`, openCount };
41
+ return { ok: true, message: "discovery.md 就绪", openCount: 0 };
42
+ }
43
+ const TASK_LINE_RE = /^(- \[([ xX])\])\s+(\S+)/;
44
+ /** 解析 tasks.md 的全部任务行 */
45
+ export function parseTasksMd(content) {
46
+ const lines = content.split("\n");
47
+ const tasks = [];
48
+ for (let i = 0; i < lines.length; i++) {
49
+ const m = lines[i].match(TASK_LINE_RE);
50
+ if (!m)
51
+ continue;
52
+ const taskId = m[3];
53
+ const done = m[2].toLowerCase() === "x";
54
+ // 用正则锚定字段边界,不依赖 includes()
55
+ const tddMatch = lines[i].match(/\btdd_required:(true|false)\b/);
56
+ const reasonMatch = lines[i].match(/\bno_tdd_reason:(\S+)\b/);
57
+ tasks.push({
58
+ taskId,
59
+ lineIdx: i,
60
+ done,
61
+ tddRequired: tddMatch ? tddMatch[1] === "true" : true, // 默认 true
62
+ noTddReason: reasonMatch ? reasonMatch[1] : null,
63
+ });
64
+ }
65
+ return tasks;
66
+ }
67
+ /** 在 tasks.md 中按 taskId 精确查找任务(词边界,不误判子串) */
68
+ export function findTaskInLines(lines, taskId) {
69
+ for (let i = 0; i < lines.length; i++) {
70
+ // 精确匹配行内的 taskId token
71
+ const m = lines[i].match(TASK_LINE_RE);
72
+ if (m && m[3] === taskId)
73
+ return i;
74
+ // 回退:用转义正则匹配(兼容 taskId 后跟标点的情况)
75
+ const escaped = taskId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
76
+ if (new RegExp("(?:^|\\s)" + escaped + "(?:\\s|$|[.,:;!?)\\]])").test(lines[i]))
77
+ return i;
78
+ }
79
+ return -1;
80
+ }
81
+ /** tasks.md 结构指纹(复选框归一化) */
82
+ export function tasksStructureDigest(content, sha256Text) {
83
+ return sha256Text(content.replace(/- \[[xX]\]/g, "- [ ]"));
84
+ }
85
+ // ===== test-run JSON =====
86
+ //
87
+ // 格式(apply skill 定义):
88
+ // {
89
+ // "test_id": "TEST-XXX",
90
+ // "attempt_id": "ATT-TASK-XXX-...",
91
+ // "task_structure_digest": "sha256:...",
92
+ // "command": "npm test",
93
+ // "cwd": "/path",
94
+ // "exit_code": 1,
95
+ // "semantic_status": "expected_failure",
96
+ // "target_fingerprint": "sha256:..."
97
+ // }
98
+ //
99
+ // 引擎校验:test_id + task_structure_digest 必填,其余可选
100
+ export function validateTestRunInput(tr) {
101
+ if (!tr.test_id)
102
+ return { ok: false, message: "缺少 test_id" };
103
+ if (!tr.task_structure_digest)
104
+ return { ok: false, message: "缺少 task_structure_digest" };
105
+ return { ok: true, message: "" };
106
+ }
107
+ // ===== user-decision JSON =====
108
+ //
109
+ // 格式(explore skill 定义):
110
+ // {
111
+ // "scope": "enter_propose",
112
+ // "question": "是否进入计划阶段?",
113
+ // "answer": "yes"
114
+ // }
115
+ //
116
+ // 引擎校验:scope + answer 必填
117
+ export function validateUserDecision(d) {
118
+ if (!d.scope)
119
+ return { ok: false, message: "决策文件缺少 scope" };
120
+ if (!d.answer)
121
+ return { ok: false, message: "决策文件缺少 answer" };
122
+ return { ok: true, message: "" };
123
+ }
124
+ // ===== business-invariants.md =====
125
+ //
126
+ // 格式(propose skill 定义):
127
+ // # Business Invariants
128
+ // - INV-001 用户密码必须加密存储
129
+ //
130
+ // 引擎行为:Phase 1-5 只校验文件存在性(轻量)。
131
+ // 内部结构(INV-XXX 编号)是 agent 指引,引擎不逐行解析。
132
+ // ===== test-contract.md =====
133
+ //
134
+ // 格式(propose skill 定义):
135
+ // # Test Contract
136
+ // | test_id | invariant | scenario |
137
+ // |---|---|---|
138
+ // | TEST-001 | INV-001 | 注册时密码被加密 |
139
+ //
140
+ // 引擎行为:Phase 1-5 只校验文件存在性(轻量)。
141
+ // 表格结构是 agent 指引,引擎不逐行解析。
@@ -0,0 +1,18 @@
1
+ export declare const WORKFLOW_SKILLS: readonly ["superspec-explore", "superspec-propose", "superspec-apply", "superspec-review", "superspec-archive"];
2
+ export declare const WORKFLOW_PROMPTS: readonly ["architect.md", "code-reviewer.md", "critic.md", "executor.md", "explore.md", "final-audit.md", "proposal-auditor.md", "test-engineer.md", "test-runner.md", "verifier.md"];
3
+ export declare const WORKFLOW_AGENTS: readonly ["architect.toml", "code-reviewer.toml", "critic.toml", "executor.toml", "explore.toml", "final-audit.toml", "proposal-auditor.toml", "test-engineer.toml", "test-runner.toml", "verifier.toml"];
4
+ export interface InstallResult {
5
+ ok: boolean;
6
+ message: string;
7
+ installed: {
8
+ engine_dir: string;
9
+ skills: string[];
10
+ prompts: string[];
11
+ agents: string[];
12
+ config: string;
13
+ };
14
+ }
15
+ export interface InstallOptions {
16
+ templateRoot?: string;
17
+ }
18
+ export declare function installProject(projectRoot: string, options?: InstallOptions): InstallResult;