sillyspec 3.27.1 → 3.27.5

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 (224) hide show
  1. package/.claude/skills/sillyspec-execute/SKILL.md +8 -0
  2. package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
  3. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  4. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  5. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  6. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  7. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  8. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  9. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  10. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  11. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
  12. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
  13. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  14. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  15. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  16. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  17. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  18. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
  19. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
  20. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  21. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  22. package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
  23. package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
  24. package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
  25. package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
  26. package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
  27. package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
  28. package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
  29. package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
  30. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  31. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  32. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
  33. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
  34. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
  35. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
  36. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
  37. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
  38. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
  39. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
  40. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
  41. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
  42. package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
  43. package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
  44. package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
  45. package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
  46. package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
  47. package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
  48. package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
  49. package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
  50. package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
  51. package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
  52. package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
  53. package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
  54. package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
  55. package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
  56. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
  57. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
  58. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
  59. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
  60. package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
  61. package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
  62. package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
  63. package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
  64. package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
  65. package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
  66. package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
  67. package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
  68. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
  69. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
  70. package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
  71. package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
  72. package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
  73. package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
  74. package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
  75. package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
  76. package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
  77. package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
  78. package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
  79. package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
  80. package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
  81. package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
  82. package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
  83. package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
  84. package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
  85. package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
  86. package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
  87. package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
  88. package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
  89. package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
  90. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
  91. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
  92. package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
  93. package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
  94. package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
  95. package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
  96. package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
  97. package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
  98. package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
  99. package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
  100. package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
  101. package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
  102. package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
  103. package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
  104. package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
  105. package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
  106. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
  107. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
  108. package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
  109. package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
  110. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
  111. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
  112. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
  113. package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
  114. package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
  115. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
  116. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
  117. package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
  118. package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
  119. package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
  120. package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
  121. package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
  122. package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
  123. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
  124. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
  125. package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
  126. package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
  127. package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
  128. package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
  129. package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
  130. package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
  131. package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
  132. package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
  133. package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
  134. package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
  135. package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
  136. package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
  137. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
  138. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
  139. package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
  140. package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
  141. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
  142. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
  143. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
  144. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
  145. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
  146. package/README.md +1 -1
  147. package/eval/README.md +86 -0
  148. package/eval/eval.config.json +28 -0
  149. package/eval/lib/adapters/cli.mjs +63 -0
  150. package/eval/lib/adapters/dryrun.mjs +27 -0
  151. package/eval/lib/config.mjs +82 -0
  152. package/eval/lib/db.mjs +76 -0
  153. package/eval/lib/report.mjs +120 -0
  154. package/eval/lib/runner.mjs +157 -0
  155. package/eval/lib/tasks.mjs +73 -0
  156. package/eval/lib/util.mjs +107 -0
  157. package/eval/lib/workdir.mjs +30 -0
  158. package/eval/run.mjs +83 -0
  159. package/eval/tasks/001-slugify/files/package.json +6 -0
  160. package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  161. package/eval/tasks/001-slugify/task.json +6 -0
  162. package/eval/tasks/001-slugify/verify.mjs +28 -0
  163. package/eval/tasks/002-each-day/files/package.json +6 -0
  164. package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  165. package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  166. package/eval/tasks/002-each-day/task.json +6 -0
  167. package/eval/tasks/002-each-day/verify.mjs +31 -0
  168. package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  169. package/eval/tasks/003-word-report/files/package.json +6 -0
  170. package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  171. package/eval/tasks/003-word-report/task.json +6 -0
  172. package/eval/tasks/003-word-report/verify.mjs +38 -0
  173. package/package.json +4 -2
  174. package/src/agent-session-log.js +803 -0
  175. package/src/change-list.js +22 -2
  176. package/src/change-risk-profile.js +83 -14
  177. package/src/config-schema.js +18 -3
  178. package/src/contract-matrix.js +153 -8
  179. package/src/datetime.js +20 -0
  180. package/src/decision-distill.js +517 -0
  181. package/src/dispatch/backends/local-agent.js +4 -4
  182. package/src/docs-check.js +227 -0
  183. package/src/docs-debt.js +187 -24
  184. package/src/doctor-diagnostics.js +102 -2
  185. package/src/foreign-declared.js +78 -0
  186. package/src/index.js +99 -10
  187. package/src/init.js +9 -7
  188. package/src/knowledge-match.js +107 -6
  189. package/src/local-register.js +7 -1
  190. package/src/module-resolve.js +12 -1
  191. package/src/modules.js +2 -1
  192. package/src/plan-adopt-waves.js +126 -0
  193. package/src/quicklog.js +61 -7
  194. package/src/run/command.js +139 -20
  195. package/src/run/complete-handlers.js +48 -19
  196. package/src/run/complete.js +43 -3
  197. package/src/run/gates.js +87 -22
  198. package/src/run/prompt.js +84 -42
  199. package/src/run/quick-audit.js +28 -0
  200. package/src/run/shared.js +176 -11
  201. package/src/run/stage.js +23 -0
  202. package/src/run.js +2 -2
  203. package/src/scan-postcheck.js +30 -17
  204. package/src/stage-contract-spec.js +2 -1
  205. package/src/stage-contract.js +68 -4
  206. package/src/stages/archive.js +53 -12
  207. package/src/stages/brainstorm-auto.js +7 -0
  208. package/src/stages/brainstorm.js +11 -0
  209. package/src/stages/doctor.js +157 -1
  210. package/src/stages/execute.js +33 -6
  211. package/src/stages/plan-postcheck.js +79 -18
  212. package/src/stages/plan.js +4 -0
  213. package/src/stages/quick.js +6 -1
  214. package/src/stages/verify.js +31 -14
  215. package/src/sync.js +94 -2
  216. package/src/task-review.js +2 -2
  217. package/src/taskcard-placeholders.js +21 -0
  218. package/src/taskcard.js +10 -1
  219. package/src/verify-postcheck.js +315 -13
  220. package/src/verify-probes.js +46 -4
  221. package/src/worktree-apply.js +184 -7
  222. package/src/worktree-deps.js +69 -0
  223. package/src/worktree.js +201 -58
  224. package/templates/prompts/taskcard-rules.md +1 -0
@@ -0,0 +1,23 @@
1
+ # Claude Code 指引
2
+
3
+ ## 项目说明
4
+ 本项目使用 **SillySpec** 管理变更,采用文档驱动开发。SillySpec 是给 Agent 调用的 CLI 流程控制器,不是给人类直接使用的产品,也不是处理业务逻辑的工具——你(Agent)通过 CLI 告诉它"我在哪",它告诉你"下一步做什么";你执行步骤,它校验产出、推进状态,人类只在关键决策点介入审批。要考虑多 agent 同时操作代码,代码随时可能变化。所有变更以稳定、可用、可维护为目标,按生产级标准处理。
5
+
6
+ ## 核心规则
7
+ 1. **禁止绕过本文件规则和 SillySpec 流程**。所有变更走 sillyspec 流程,不裸改裸提交。
8
+ 2. **改代码前必须先说明依据**——依据的文档路径(design.md / 模块文档 / file-lifecycle.md)或现有代码依据,无依据不改。
9
+ 3. **新功能 / 大改动走完整流程**:`brainstorm → plan → execute → verify → archive`。
10
+ 4. **小修复 / 小调整走 quick**:`sillyspec run quick`。
11
+ 5. **执行顺序**:文档 → 读代码 → 写测试 → 写实现 → 跑测试 → 验收 → 更新文档。
12
+ 6. **判规模选档**:≤3 文件、范围明确走 `quick`;多阶段 / 架构级走完整流程。
13
+ 7. **代码先行不补流程(倒推 B 模式)**:代码若已先写好,**不回头补 brainstorm/plan 装样子**——用 `quick --done` 收尾 + 补 quicklog 条目,把已落盘改动如实登记进进度库。
14
+ 8. **实证核验再 `--done`**:`quick --done` 前,触及 `src`/`test` 的改动先 `npm test` + `npm run lint`;纯 doc/配置改动可跳过(lint 不扫 docs/,空转无信息),以落盘文件与测试结果为准,不信口头"已完成"。
15
+ 9. **中途停下不靠额外命令存进度**——进度已由上一次 `--done` 自动落盘;恢复时用 `sillyspec progress show` 查看进度,再用 `sillyspec run <stage>` 续跑,不直接 commit 半成品。
16
+ 10. **实现完成后对照文档验收**(design.md / 模块文档),并检查是否影响已有测试。
17
+ 11. **非测试逻辑本身有误时,禁止改测试来"通过"**——修逻辑,不修测试。
18
+ 12. **hook 拦截提交时禁止跳过**(`.husky/pre-push`),修复问题后再提交。
19
+ 13. **代码必须兼容 Windows / Linux / macOS**(路径 / 换行 / 并发都要顾)。
20
+ 14. **任务记录隔离**:永不重置 / reset / 清零已存在的 change;多个活跃 change 各自 `--change <名>` 隔离不重叠;quick 同一 QUICKLOG 按 ql-ID 条目追加,不冲突。
21
+ 15. **quicklog 结构化落盘**:末步 `--done` 用四参数 `--req/--cause/--solution/--result`(CLI 合成结构化 output 并自动提取标题/四段分行);文件括注用 `--file-notes "path::注 || path2"`。骨架由 CLI 接管,`--done` 后按需核对即可,勿手拼模板。
22
+ 16. **代码可能随时在修改**(多 agent 并行),Edit 前重跑 + 查最新态;破坏性 git op 前先备份。
23
+ 17. **不奉承用户**,禁止"你说得对"类话术,直接给结论、依据、方案。
@@ -0,0 +1,28 @@
1
+ TaskCard 格式规则(必须严格遵守):
2
+ - 总长度 20~40 行,不要写成长文档
3
+ - frontmatter 只含必要字段,不加 estimated_hours
4
+ - title 用英文短语(kebab 风格动词短语,如 "Add readonly auxiliary constant"),title_zh 用对应中文标题——两字段是同一任务的双语表示,非不同信息;归档产物与 sillyhub 平台解析各取所需(title_zh 为中文展示首选)
5
+ - goal: 一句话,用 > 多行字符串
6
+ - implementation: 列表,每条一个具体步骤
7
+ - acceptance: 列表,每条可独立验证(不是表格)
8
+ - verify: 列表,实际可执行的命令
9
+ - constraints: 列表,明确边界(含 brownfield 兼容、异常处理)
10
+ - 不需要:修改文件章节、覆盖来源章节、接口定义章节、TDD 步骤章节、参考章节
11
+ - frontmatter 必须以三减号结尾闭合(开头和结尾各一行 ---)。缺结尾会让 postcheck 提取不到 frontmatter,误报「字段缺失 / allowed_paths 为空」
12
+ - allowed_paths 用块式写法(键名换行后每项一行「 - 路径」),不要用流式方括号 [path]——块式与所有校验器一致最稳
13
+ - implementation / acceptance / constraints / verify 的每条列表项是 YAML plain scalar,避免以下特殊字符触发 ScannerError:
14
+ - 冒号+空格(如代码签名 provider_id:str、queryUsage(id:string))会被当映射键报 mapping values are not allowed here——去掉冒号后空格或改成中文描述
15
+ - 花括号且内部含冒号或引号(如 JS 对象、JS 模板字面量)会报 expected block end——改用不含这些字符的中文描述
16
+ - 引号不成对会报扫描错误
17
+ - 注:goal 用 > 折叠标量可容忍花括号,goal 里写占位符不炸;只有上述 plain scalar 列表项需注意
18
+ - provides / expects_from 是可选字段:仅当跨 task 契约(一个 task 的接口/DTO/响应被另一个 task 消费)时才填,单 task 或无对外接口场景留空即可
19
+ - 填写后 plan-postcheck 会做硬对账:consumer 的每个 expects_from[provider].needs 字段必须在对应 provider 的 provides.fields 里,否则 plan 阶段阻断(不进入 execute)
20
+ - 不要把内部实现字段塞进 provides;只暴露给其他 task 的对外契约形状
21
+ - related_tests 是可选字段:当本 task 改动会导致既有测试断言失效时填(判据 = 是否有既有测试因本次改动而失败,而非源文件是否共享——覆盖改共享/被多 task 依赖源文件、改被测试精确匹配的值如 UI 文案/按钮文本/错误信息/常量/枚举字面量、改函数签名或返回结构等单文件场景),列出失效测试文件 + 为何失效。关键:这些测试路径必须同时写进本 task 的 allowed_paths(否则子代理被 allowed_paths 铁律锁死、改不了测试 → 退化成主代理事后兜底);若测试由独立的测试 task 负责,则在该测试 task 的 allowed_paths 覆盖、本字段留空
22
+ - 如果存在 decisions.md,无法覆盖的 D-xxx@vN 在 constraints 中标注
23
+ - **保存前格式自检**(plan-postcheck 会硬校验,不通过到 Step 4 会批量报错,先在这里逐条自查):
24
+ - **硬校验字段**(缺失 plan-postcheck 直接报错阻断,必须齐全):id、title、title_zh、allowed_paths、goal、implementation、acceptance、verify、constraints
25
+ - **规范约定字段**(应填但不硬校验,缺失不阻断完成、只影响规范性):author、created_at、priority、depends_on、blocks
26
+ - allowed_paths 非空(至少一个真实源文件路径;回归类 task 无源码改动时填被验证的关键入口文件)
27
+ - acceptance 与 verify 都在 frontmatter 内(漏写会被 plan-postcheck 报「缺少验收标准」/「缺少验证步骤」)
28
+ - **生成方式**:用 `sillyspec taskcard <change-name> --task task-NN [--all]` 生成安全骨架(LF 行尾 + frontmatter 必闭合 + 九个硬校验字段齐全 + author/created_at 自动填),再往骨架里填语义内容——**勿用 Write tool 整文件手写**(CRLF / 漏闭合 `---` / 漏字段的根源,postcheck 报错大多由此来);已存在的卡命令会跳过不覆盖,局部修改用 Edit 定点改
@@ -0,0 +1,12 @@
1
+ ### 测试用例设计(写测试时按此检查)
2
+
3
+ 写测试是为了拦住回归,不是"有测试文件"。
4
+ **基础习惯照做、不展开**:FIRST(快/独立/可重复/自校验/及时)、金字塔分层(单元为主/集成少量/E2E 只冒烟)、AAA 结构、测试名描述场景、测试数据轻量构造(Object Mother/Builder)、覆盖率不追数字。
5
+
6
+ 逐条对照检查:
7
+ 1. **覆盖**:正常路径 + 边界 + 异常/非法输入,不只写业务正例;单测全绿 ≠ 集成正确。
8
+ 2. **断言**:断言真实输出/副作用,禁止只"不抛错"的空断言;不 mock 被测方法自身。
9
+ 3. **行为 vs 实现**:走公开 API 测行为;重构后功能不变,测试不应失败。
10
+ 4. **契约与回归**:覆盖本次改动会破坏的既有行为与相邻模块接口;改公共签名/文案/常量时同步修复受影响既有测试并跑全量,禁止删断言凑绿。
11
+ 5. **时间敏感分支**:超时/重试/并发分支别真等——超时参数做成可注入,测试传毫秒级极小值或注入可控时钟推进,再断言超时后的行为(走哪个分支/返回什么/资源是否回收)。
12
+ 6. **隔离确定性**:独立 fixture、可重复跑,不依赖共享状态/执行顺序。
@@ -0,0 +1,32 @@
1
+ ### 自动探针(必须先执行)
2
+
3
+ > 🔧 **先跑 CLI 机械探针(一条命令)**:`sillyspec verify-probes --change <change-name> [--init]`
4
+ > 输出已包含四个纯机械探针的结果(可直接进验证报告):**探针 1** 未实现标记扫描(design 清单文件逐行 TODO/FIXME 命中 + 行号)、**探针 3** 测试文件递归查找(含 co-located tests/,逐 task 覆盖)、**探针 5** API 契约对账表(endpoints.json × 前端调用 diff)、**探针 6** 删除对账三态(git 事实 × design 声明)。`--init` 顺带生成 verify-result.md 九章节骨架(探针结果已预填,`<!--TODO-->` 占位替换即可)。
5
+ >
6
+ > 下列条目中,只有**半语义部分**需要你执行:探针 2(关键词提取)、探针 3.4 集成盲区标注、探针 3.5 断言有效性抽查、探针 4(决策追踪闭环判定)。CLI 已跑的部分勿重复手跑——对 CLI 输出的 warning 项做语义复核即可。
7
+
8
+ **探针 2:设计关键词覆盖探针(你执行——关键词提取是语义)**
9
+ 1. 读取 design.md,从中提取所有能力关键词(如"登录"、"导出"、"批量"、"删除"、"搜索"等动作词)
10
+ 2. 对每个关键词,在源码目录中 grep 确认是否有对应的实现代码:
11
+ ```bash
12
+ grep -rl "<关键词>" <源码目录>/ --include="*.java" --include="*.js" --include="*.ts" --include="*.jsx" --include="*.tsx" --include="*.py"
13
+ ```
14
+ 3. 如果某个关键词在源码中完全没有匹配,标记为 ⚠️ 可能未实现
15
+
16
+ **探针 3 补充(CLI 已查存在性,你补语义)**
17
+ - **集成盲区提示**:测试文件存在 ≠ 集成正确——路由/layout 守卫重定向、跨模块装配这类集成 bug 组件单测覆盖不到,只有集成/冒烟/E2E 才暴露。对路由/layout/跨进程装配敏感的 task,额外检查是否有集成冒烟覆盖;无则标 ⚠️ 集成层未验证(需人工或部署确认)
18
+ - **断言有效性抽查(与 execute「测试用例设计」闭环)**:测试文件存在 ≠ 测试有效。对最能代表本次变更行为的 2-3 个核心测试做抽查:① 断言验证真实输出/副作用,不是只"不抛错"的空断言、只测 getter/setter;② 覆盖边界/异常分支,不只业务正例;③ 走公开 API 测行为,不测实现细节(重构后功能不变测试不应失败)。不达标标 ⚠️ 断言薄弱或无效(advisory:CLI 不阻断,是否 FAIL 由你诚实判定;execute 已按「测试用例设计」写的,这里只抽查核验,不重审全量)
19
+
20
+ **探针 4:决策追踪覆盖探针(如存在 decisions.md——闭环图机械,证据真伪是语义)**
21
+ 1. 从 decisions.md 提取所有当前版本 D-xxx@vN
22
+ 2. 检查 requirements.md 是否引用每个 D-xxx@vN,并映射到 FR-xxx
23
+ 3. 检查 plan.md 或 tasks/task-NN.md 是否引用每个 FR-xxx/D-xxx@vN
24
+ 4. 检查本步骤收集的实现证据是否能回指到对应 D-xxx@vN/FR-xxx
25
+ 5. 任意 D-xxx@vN 无下游覆盖时标记为 ⚠️ 决策未闭环
26
+ 6. 任意 P0/P1 unresolved/blocking 决策标记为 FAIL blocker
27
+
28
+ **探针 5 补充(CLI 已出对账表,你做诚实判定)**
29
+ CLI 的 missing backend endpoint 是 advisory(不硬阻断归档)——但 contract gap 是真实集成缺陷,应诚实标 FAIL 并回 execute 补端点,勿因 CLI 不拦而放行。后端 router 的端点清单可用 `sillyspec endpoints extract --change <变更名> --task <task-NN>` 重新静态提取(勿手扫装饰器)。
30
+
31
+ **探针 6 补充(CLI 已出三态判定,你做终审)**
32
+ 以 git 事实为准(真实 > 声明);CLI 的三态(合规/高风险/未声明)是机械判定,是否构成 FAIL blocker 由你诚实判定,务必如实记录——静默删除代码是 verify 的最大盲区。
@@ -0,0 +1,79 @@
1
+ name: archive-impact
2
+ description: 分析变更影响的模块并同步模块文档
3
+ spec_version: 1
4
+
5
+ roles:
6
+ - id: impact-analyzer
7
+ name: "影响分析"
8
+ task: "分析 git diff,提取变更影响模块"
9
+ inputs:
10
+ paths: [".sillyspec/changes/", ".sillyspec/docs/*/modules/"]
11
+ hints:
12
+ grep_patterns: ["_module-map", "module-impact", "git diff"]
13
+ outputs:
14
+ - path: ".sillyspec/changes/<change-name>/module-impact.md"
15
+ required: true
16
+ checks:
17
+ - type: file_exists
18
+ - type: min_lines
19
+ min: 20
20
+ - type: contains_sections
21
+ sections: ["模块影响矩阵", "未匹配文件"]
22
+ constraints:
23
+ - "以 git diff 为准(真实 > 声明)"
24
+ - "影响类型:逻辑变更/数据结构变更/接口变更/调用关系变更/配置变更/新增"
25
+ - "需要 review 标记不确定的影响"
26
+
27
+ - id: doc-syncer
28
+ name: "文档同步"
29
+ task: "根据 module-impact.md 同步更新模块索引和卡片"
30
+ depends_on:
31
+ - impact-analyzer
32
+ inputs:
33
+ from_role: impact-analyzer
34
+ output: module-impact
35
+ output_description: "变更影响分析结果,包含模块影响矩阵"
36
+ paths: [".sillyspec/docs/*/modules/"]
37
+ hints:
38
+ grep_patterns: ["_module-map", "module-impact"]
39
+ outputs:
40
+ - path: ".sillyspec/docs/sillyspec/modules/_module-map.yaml"
41
+ required: false
42
+ checks:
43
+ - type: file_exists
44
+ - path: ".sillyspec/docs/sillyspec/modules/<module-id>.md"
45
+ required: false
46
+ # checks 跳过:路径含动态 <module-id> 占位符,不适合静态检查
47
+ constraints:
48
+ - "结构化事实改 _module-map.yaml,语义解释改模块卡片"
49
+ - "人工备注区域永远保护,不覆盖"
50
+ - "更新前展示 diff 摘要,请用户确认"
51
+
52
+ orchestration:
53
+ mode: sequential
54
+ timeout_per_role: 180
55
+
56
+ checks:
57
+ role_level:
58
+ - type: file_exists
59
+ - type: min_lines
60
+ min: 10
61
+ workflow_level:
62
+ - type: file_exists
63
+ path: ".sillyspec/changes/<change-name>/module-impact.md"
64
+
65
+ retry:
66
+ max_attempts: 1
67
+ include_failure_context: true
68
+ retry_scope: failed_role_only
69
+
70
+ on_check_failure: prompt_retry
71
+
72
+ permissions:
73
+ write_mode: patch_only
74
+ write_scope:
75
+ - ".sillyspec/docs/"
76
+ - ".sillyspec/changes/<change-name>/"
77
+ allow_shell: true
78
+ allow_network: false
79
+ allow_git: true
@@ -0,0 +1,132 @@
1
+ name: scan-docs
2
+ description: 并行生成项目的扫描文档(7份)
3
+ spec_version: 1
4
+
5
+ roles:
6
+ - id: arch
7
+ name: "技术架构"
8
+ task: "生成 ARCHITECTURE.md"
9
+ inputs:
10
+ paths:
11
+ - "src/*.js"
12
+ - "package.json"
13
+ hints:
14
+ grep_patterns: ["class ", "export ", "import ", "schema", "CREATE TABLE"]
15
+ outputs:
16
+ - path: "{SPEC_ROOT}/docs/<project>/scan/ARCHITECTURE.md"
17
+ required: true
18
+ checks:
19
+ - type: file_exists
20
+ - type: min_lines
21
+ min: 20
22
+ - type: contains_sections
23
+ sections: ["技术栈", "架构概览"]
24
+ constraints:
25
+ - "禁止读源码全文,只用 grep/rg 搜索"
26
+ - "Schema 只记表名+说明+字段数"
27
+
28
+ - id: conventions
29
+ name: "代码约定"
30
+ task: "生成 CONVENTIONS.md"
31
+ inputs:
32
+ paths: ["src/"]
33
+ hints:
34
+ grep_patterns: ["function ", "const ", "async ", "try ", "catch "]
35
+ outputs:
36
+ - path: "{SPEC_ROOT}/docs/<project>/scan/CONVENTIONS.md"
37
+ required: true
38
+ checks:
39
+ - type: file_exists
40
+ - type: min_lines
41
+ min: 15
42
+ - type: contains_sections
43
+ sections: ["框架隐形规则", "代码风格"]
44
+ constraints:
45
+ - "禁止读源码全文"
46
+ - "提取 3-5 个典型模式"
47
+
48
+ - id: structure
49
+ name: "目录结构+外部集成"
50
+ task: "生成 STRUCTURE.md 和 INTEGRATIONS.md"
51
+ inputs:
52
+ paths: ["./"]
53
+ hints:
54
+ grep_patterns: ["fetch", "http", "WebSocket", "ws", "chokidar"]
55
+ outputs:
56
+ - path: "{SPEC_ROOT}/docs/<project>/scan/STRUCTURE.md"
57
+ required: true
58
+ checks:
59
+ - type: file_exists
60
+ - type: min_lines
61
+ min: 15
62
+ - path: "{SPEC_ROOT}/docs/<project>/scan/INTEGRATIONS.md"
63
+ required: true
64
+ checks:
65
+ - type: file_exists
66
+ - type: min_lines
67
+ min: 15
68
+ constraints:
69
+ - "STRUCTURE: 目录树+模块说明"
70
+ - "INTEGRATIONS: 按类型分组外部依赖"
71
+
72
+ - id: quality
73
+ name: "测试+债务+概览"
74
+ task: "生成 TESTING.md、CONCERNS.md、PROJECT.md"
75
+ inputs:
76
+ paths: ["src/", "packages/"]
77
+ hints:
78
+ grep_patterns: ["TODO", "FIXME", "deprecated", "test", "describe"]
79
+ outputs:
80
+ - path: "{SPEC_ROOT}/docs/<project>/scan/TESTING.md"
81
+ required: true
82
+ checks:
83
+ - type: file_exists
84
+ - type: min_lines
85
+ min: 10
86
+ - type: no_placeholder
87
+ - path: "{SPEC_ROOT}/docs/<project>/scan/CONCERNS.md"
88
+ required: true
89
+ checks:
90
+ - type: file_exists
91
+ - type: min_lines
92
+ min: 10
93
+ - type: contains_sections
94
+ sections: ["代码质量", "依赖风险"]
95
+ - path: "{SPEC_ROOT}/docs/<project>/scan/PROJECT.md"
96
+ required: true
97
+ checks:
98
+ - type: file_exists
99
+ - type: min_lines
100
+ min: 15
101
+ - type: contains_sections
102
+ sections: ["项目简介", "技术栈"]
103
+ constraints:
104
+ - "CONCERNS 按严重程度分组(🔴/🟡/🟢)"
105
+ - "不编造不存在的测试"
106
+
107
+ orchestration:
108
+ mode: parallel
109
+ max_concurrent: 4
110
+ timeout_per_role: 120
111
+
112
+ checks:
113
+ workflow_level:
114
+ - type: file_count
115
+ path: "scan/"
116
+ min: 7
117
+ - type: no_empty_files
118
+
119
+ retry:
120
+ max_attempts: 1
121
+ include_failure_context: true
122
+ retry_scope: failed_role_only
123
+
124
+ on_check_failure: prompt_retry
125
+
126
+ permissions:
127
+ write_mode: direct
128
+ write_scope:
129
+ - "{SPEC_ROOT}/docs/<project>/scan/"
130
+ allow_shell: true
131
+ allow_network: false
132
+ allow_git: false
package/README.md CHANGED
@@ -141,7 +141,7 @@ sillyspec doctor 全量自检 + 修复进度
141
141
  - **进度持久化** — SQLite(node:sqlite)持久化,支持断点恢复
142
142
  - **模块文档** — 模块级知识库,AI 执行时按需加载相关上下文
143
143
  - **浏览器自动化** — 可选 MCP(Playwright / Chrome DevTools),供集成/E2E 冒烟验证
144
- - **平台同步** — 可选对接 SillyHub,文档同步 + 团队审批
144
+ - **平台同步** — 可选对接 SillyHub,文档同步 + 团队审批 + 本地 agent 会话日志路径主动上报(平台会话展示本地 agent 完整日志;支持 Claude Code / Codex / ZCode 自动探测,其他 CLI 用 `SILLYSPEC_AGENT_LOG` 显式指定)
145
145
 
146
146
  ## 可靠性保障
147
147
 
package/eval/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # SillySpec A/B 评测
2
+
3
+ 客观量化回答一个问题:**同一个 agent,走 SillySpec 流程(B 臂)比裸跑(A 臂)到底好多少?**
4
+
5
+ - 同任务、同模型、同判分脚本(每任务一个 `verify.mjs`,退出码 0 = 通过),唯一变量是「有没有 SillySpec」。
6
+ - 产出:分臂通过率 + Wilson 95% 置信区间、Δ(B−A) 区间、flaky 剔除、token/费用/耗时、基线回归对比。
7
+ - 所有结果落 SQLite(`eval/results/eval.db`),可审计、可复跑。
8
+
9
+ ## 快速开始
10
+
11
+ ```bash
12
+ node eval/run.mjs --dry-run # ① 零 token:假 agent 验证整条管道(先跑这个)
13
+ node eval/run.mjs --preflight # ② 零 token:检查 Node 版本与 agent CLI 可用
14
+ node eval/run.mjs --pilot # ③ 真跑:前 20 个任务 × 双臂(从这里开始烧 token)
15
+ node eval/run.mjs --report # 查看报告
16
+ node eval/run.mjs --set-baseline # 成绩满意后固化为回归基线(发版前对比)
17
+ ```
18
+
19
+ npm 快捷方式:`npm run eval:dry`、`npm run eval:pilot`。
20
+
21
+ ## 认证与 apikey(重要)
22
+
23
+ **不需要把 apikey 配置在本评测的任何脚本或配置文件里。**
24
+
25
+ CLI 适配器只是以子进程方式调起你本机的 headless agent CLI(默认 `claude -p`,可换 zcode / codex 等),认证完全沿用该 CLI 自己的登录态或它读取的环境变量——你之前怎么用它,评测就怎么用。评测脚本不接管、不存储、不转发任何密钥,`eval.config.json` 可以安全提交。
26
+
27
+ 前置条件只有一条:目标 agent CLI 已安装、已登录、终端里能跑通。拿不准就先 `node eval/run.mjs --preflight`。
28
+
29
+ 未来若要接裸 API(如 GLM 的 OpenAI 兼容端点)跑自研 agent 循环,那才需要环境变量方式的 key(同样是环境变量,不进脚本)——届时新增一个 adapter 即可。
30
+
31
+ ## 命令一览
32
+
33
+ | 命令 | 用途 | token 消耗 |
34
+ |---|---|---|
35
+ | `--dry-run[=mixed\|pass\|fail]` | 假 agent 跑管道(mixed 会确定性制造两臂差异) | 0 |
36
+ | `--preflight` | Node 版本 + agent CLI 探活 | 0 |
37
+ | `--pilot` | 前 20 任务双臂真跑 | 真实消耗 |
38
+ | `--task <id>` / `--arm A\|B` / `--sample N` | 收窄范围 | 按范围 |
39
+ | `--rerun-failed` | 只重跑上轮 fail/timeout/error | 定向,省钱 |
40
+ | `--force` | 忽略缓存强制重跑 | 按范围 |
41
+ | `--report [--dry-run]` | 报告(CI / Δ / flaky / 基线) | 0 |
42
+ | `--set-baseline` | 固化当前成绩为回归基线 | 0 |
43
+
44
+ ## 省 token 机制(内建)
45
+
46
+ 1. **缓存**:同 `(config_hash, task, arm)` 已有 pass/fail 终态自动跳过;改了提示词/流程/任务内容会换 hash,只重跑受影响部分。
47
+ 2. **定向重跑**:`--rerun-failed` 不碰已通过的任务。
48
+ 3. **双重熔断**:单任务 agent 超时(`adapter.timeoutMs`)+ 判分超时(`verifyTimeoutMs`),死循环烧不穿。
49
+ 4. **dry-run / preflight 全零 token**,烧钱的大跑之前管道一定先验通。
50
+
51
+ ## 任务格式
52
+
53
+ 每个任务一个目录,四件套:
54
+
55
+ ```
56
+ eval/tasks/001-slugify/
57
+ ├── task.json # id / instruction(两臂收到同一份需求文本)
58
+ ├── verify.mjs # 判分:以被测工作目录为 cwd 执行,退出码 0 = 通过
59
+ ├── files/ # 工作副本脚手架(复制后交给 agent;棕地任务在这里放待改代码)
60
+ └── solution/ # 参考解(仅 dry-run 假 agent 使用,不参与指纹)
61
+ ```
62
+
63
+ 写任务的要点:instruction 必须无歧义(判分才有唯一正确解);verify 只看行为不看出身。当前 3 个种子任务偏小(用于验管道),正式 pilot 前应扩充到 20+,并逐步引入更贴近 SillySpec 甜区的中等规模功能任务。后续如需对接 Terminal-Bench 2.0 等外部任务源,写一个「外部任务 → 本格式」的导入器即可,编排与报告层不用动。
64
+
65
+ ## 配置(eval.config.json)
66
+
67
+ - `arms.A / arms.B`:两臂的 `setup`(agent 进场前执行的命令,B 臂默认 `npx sillyspec init`;dry-run 跳过)与 `promptTemplate`(`{instruction}` 占位)。
68
+ - `adapter`:`command` 数组 + `stdin: "prompt"`(prompt 走 stdin,规避跨平台引号问题;也可在 command 里用 `{prompt}` 占位改为参数注入);`{workdir}` / `{maxTurns}` 占位可用;`parseStdoutJson: true` 时尽力从 stdout JSON 提取 token/费用(提不到记 null,不瞎填)。
69
+ - 换被测 agent:改 `adapter.tool` + `adapter.command`(如 zcode / codex 的 headless 形式),两臂 prompt 模板不用动。
70
+
71
+ ## 目录
72
+
73
+ ```
74
+ eval/
75
+ ├── run.mjs # 入口
76
+ ├── eval.config.json # 配置(无密钥,可提交)
77
+ ├── lib/ # 编排/报告/适配器/DB
78
+ ├── tasks/ # 任务集
79
+ └── results/ # 运行产物(eval.db / 工作副本 / 日志 / baseline.json)——已 gitignore
80
+ ```
81
+
82
+ ## 已知边界
83
+
84
+ - 通过率只统计 pass/fail;timeout / error(agent 崩溃、臂 setup 失败)单列不计入分母,避免把管道故障算成 agent 失败。
85
+ - 同任务同臂多次运行结果摇摆会被标记 flaky 并从通过率剔除——放量前建议每任务跑 2 次,flaky 高说明任务本身不稳定,先修任务。
86
+ - 单臂 n < 30 时报告会提示区间仅供方向参考。
@@ -0,0 +1,28 @@
1
+ {
2
+ "tasksDir": "./tasks",
3
+ "resultsDir": "./results",
4
+ "defaultSample": 20,
5
+ "verifyTimeoutMs": 120000,
6
+ "regressionThresholdPp": 5,
7
+ "arms": {
8
+ "A": {
9
+ "label": "裸agent",
10
+ "setup": [],
11
+ "promptTemplate": "你在当前目录工作,直接完成以下需求(不要提问,直接实现,确保代码可运行):\n\n{instruction}"
12
+ },
13
+ "B": {
14
+ "label": "SillySpec",
15
+ "setup": ["npx sillyspec init --dir {workdir} --tool {tool}"],
16
+ "promptTemplate": "当前项目已安装 SillySpec 工作流。请按 SillySpec 流程完成以下需求(小任务走 quick 模式),完成后确保代码可运行:\n\n{instruction}"
17
+ }
18
+ },
19
+ "adapter": {
20
+ "type": "cli",
21
+ "tool": "claude",
22
+ "command": ["claude", "-p", "--output-format", "json", "--max-turns", "{maxTurns}"],
23
+ "stdin": "prompt",
24
+ "timeoutMs": 900000,
25
+ "maxTurns": 60,
26
+ "parseStdoutJson": true
27
+ }
28
+ }
@@ -0,0 +1,63 @@
1
+ // CLI 适配器:以子进程调起本机 headless agent CLI(claude -p / zcode / codex 等,见 eval.config.json)。
2
+ // 认证沿用该 CLI 自身的登录态或其读取的环境变量——本评测不接管、不存储任何密钥。
3
+ // prompt 默认经 stdin 注入({prompt} 占位符是备选),规避跨平台引号转义。
4
+ import { mkdirSync, writeFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { spawnCapture } from '../util.mjs';
7
+
8
+ export async function run({ adapter, prompt, workdir, logDir }) {
9
+ const timeoutMs = adapter.timeoutMs ?? 900_000;
10
+ const replacements = {
11
+ '{workdir}': workdir,
12
+ '{maxTurns}': String(adapter.maxTurns ?? 0),
13
+ '{tool}': adapter.tool ?? '',
14
+ };
15
+ let args = adapter.command.map((a) => {
16
+ let s = String(a);
17
+ for (const [k, v] of Object.entries(replacements)) s = s.replaceAll(k, v);
18
+ return s;
19
+ });
20
+ const viaStdin = (adapter.stdin ?? 'prompt') === 'prompt' && !args.some((a) => a.includes('{prompt}'));
21
+ args = args.map((a) => a.replaceAll('{prompt}', prompt));
22
+
23
+ mkdirSync(logDir, { recursive: true });
24
+ writeFileSync(join(logDir, 'prompt.txt'), prompt, 'utf8');
25
+ const res = await spawnCapture({ args, cwd: workdir, timeoutMs, input: viaStdin ? prompt : null });
26
+ try {
27
+ writeFileSync(join(logDir, 'stdout.txt'), res.stdout, 'utf8');
28
+ writeFileSync(join(logDir, 'stderr.txt'), res.stderr, 'utf8');
29
+ } catch { /* 日志落盘失败不影响评测本身 */ }
30
+
31
+ const usage = adapter.parseStdoutJson ? extractUsage(res.stdout) : {};
32
+ return {
33
+ code: res.code,
34
+ timedOut: res.timedOut,
35
+ stdout: res.stdout,
36
+ stderr: res.stderr,
37
+ tokensIn: usage.tokensIn ?? null,
38
+ tokensOut: usage.tokensOut ?? null,
39
+ costUsd: usage.costUsd ?? null,
40
+ logDir,
41
+ };
42
+ }
43
+
44
+ // 宽松提取 token/费用字段:兼容 claude -p --output-format json 等常见 stdout 形状,
45
+ // 提不到就留空(null),报告里显示为缺测而非 0。
46
+ function extractUsage(stdout) {
47
+ const trimmed = (stdout ?? '').trim();
48
+ if (!trimmed.startsWith('{')) return {};
49
+ let obj = null;
50
+ for (const candidate of [trimmed, trimmed.split('\n').pop()]) {
51
+ try { obj = JSON.parse(candidate); break; } catch { /* 试下一候选 */ }
52
+ }
53
+ if (!obj || typeof obj !== 'object') return {};
54
+ const out = {};
55
+ const scan = (o) => {
56
+ if (!o || typeof o !== 'object') return;
57
+ if (typeof o.input_tokens === 'number') out.tokensIn ??= o.input_tokens;
58
+ if (typeof o.output_tokens === 'number') out.tokensOut ??= o.output_tokens;
59
+ if (typeof o.total_cost_usd === 'number') out.costUsd ??= o.total_cost_usd;
60
+ };
61
+ scan(obj); scan(obj.usage); scan(obj.cost); scan(obj.message?.usage);
62
+ return out;
63
+ }
@@ -0,0 +1,27 @@
1
+ // dry-run 假 agent:零 token 验证管道(工作副本、verify、落库、报告整条链路)。
2
+ // mixed 模式确定性制造两臂差异:A 臂全过,B 臂按任务号奇偶过——报告能展示通过率/Δ/置信区间的完整形态。
3
+ import { writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { copyInto } from '../workdir.mjs';
6
+
7
+ export function run({ task, arm, workdir, solutionDir, mode = 'mixed' }) {
8
+ const numeric = Number.parseInt(String(task.id).split('-')[0], 10);
9
+ let pass;
10
+ if (mode === 'pass') pass = true;
11
+ else if (mode === 'fail') pass = false;
12
+ else pass = arm === 'A' ? true : Number.isInteger(numeric) && numeric % 2 === 1;
13
+
14
+ if (pass) copyInto(workdir, solutionDir);
15
+ else writeFileSync(join(workdir, 'DRY_RUN_WRONG_ANSWER.mjs'), '// dry-run 失败路径占位产物\n');
16
+
17
+ return {
18
+ code: 0,
19
+ timedOut: false,
20
+ stdout: `[dry-run mode=${mode}] pass=${pass}`,
21
+ stderr: '',
22
+ tokensIn: 0,
23
+ tokensOut: 0,
24
+ costUsd: 0,
25
+ logDir: null,
26
+ };
27
+ }
@@ -0,0 +1,82 @@
1
+ // eval 配置加载 + 实验指纹(config hash):改动任务内容/臂定义/适配器/版本都会换新分组,
2
+ // 旧缓存不再命中,报告也不会把两轮不同实验混在一起。
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { sha256, stableStringify } from './util.mjs';
7
+
8
+ export const EVAL_ROOT = dirname(dirname(fileURLToPath(import.meta.url))); // eval/
9
+ export const EVAL_SCHEMA_VERSION = 1;
10
+
11
+ // 与 eval/eval.config.json 保持同构;文件缺失/部分字段缺失时以此兜底
12
+ const DEFAULTS = {
13
+ tasksDir: './tasks',
14
+ resultsDir: './results',
15
+ defaultSample: 20,
16
+ verifyTimeoutMs: 120_000,
17
+ regressionThresholdPp: 5,
18
+ arms: {
19
+ A: {
20
+ label: '裸agent',
21
+ setup: [],
22
+ promptTemplate: '你在当前目录工作,直接完成以下需求(不要提问,直接实现,确保代码可运行):\n\n{instruction}',
23
+ },
24
+ B: {
25
+ label: 'SillySpec',
26
+ setup: ['npx sillyspec init --dir {workdir} --tool {tool}'],
27
+ promptTemplate: '当前项目已安装 SillySpec 工作流。请按 SillySpec 流程完成以下需求(小任务走 quick 模式),完成后确保代码可运行:\n\n{instruction}',
28
+ },
29
+ },
30
+ adapter: {
31
+ type: 'cli',
32
+ tool: 'claude',
33
+ command: ['claude', '-p', '--output-format', 'json', '--max-turns', '{maxTurns}'],
34
+ stdin: 'prompt',
35
+ timeoutMs: 900_000,
36
+ maxTurns: 60,
37
+ parseStdoutJson: true,
38
+ },
39
+ };
40
+
41
+ function deepMerge(target, src) {
42
+ for (const key of Object.keys(src)) {
43
+ const sv = src[key];
44
+ if (sv && typeof sv === 'object' && !Array.isArray(sv) && target[key] && typeof target[key] === 'object' && !Array.isArray(target[key])) {
45
+ deepMerge(target[key], sv);
46
+ } else {
47
+ target[key] = sv;
48
+ }
49
+ }
50
+ return target;
51
+ }
52
+
53
+ export function loadConfig(configPath = resolve(EVAL_ROOT, 'eval.config.json')) {
54
+ let file = {};
55
+ if (existsSync(configPath)) file = JSON.parse(readFileSync(configPath, 'utf8'));
56
+ const config = deepMerge(structuredClone(DEFAULTS), file);
57
+ config.tasksDir = resolve(EVAL_ROOT, config.tasksDir);
58
+ config.resultsDir = resolve(EVAL_ROOT, config.resultsDir);
59
+ config._path = configPath;
60
+ return config;
61
+ }
62
+
63
+ export function sillyspecVersion() {
64
+ const pkg = JSON.parse(readFileSync(resolve(EVAL_ROOT, '..', 'package.json'), 'utf8'));
65
+ return pkg.version;
66
+ }
67
+
68
+ /**
69
+ * 实验分组哈希:臂定义(prompt/setup)+ 适配器 + 任务指纹 + SillySpec 版本 + schema 版本。
70
+ * 注意 tasksDir/resultsDir 不参与——目录挪位置不该让实验换组。
71
+ */
72
+ export function computeConfigHash(config, adapterType, tasksFingerprint) {
73
+ const payload = {
74
+ schema: EVAL_SCHEMA_VERSION,
75
+ adapterType,
76
+ arms: config.arms,
77
+ adapter: config.adapter,
78
+ tasksFingerprint,
79
+ sillyspecVersion: sillyspecVersion(),
80
+ };
81
+ return sha256(stableStringify(payload)).slice(0, 12);
82
+ }