sillyspec 3.27.2 → 3.27.6

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 (398) 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/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  147. package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  148. package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  149. package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  150. package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  151. package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  152. package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  153. package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  154. package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
  155. package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
  156. package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  157. package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  158. package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
  159. package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  160. package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  161. package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  162. package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
  163. package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
  164. package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  165. package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  166. package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
  167. package/.worktrees/8d2d0392/.gitattributes +2 -0
  168. package/.worktrees/8d2d0392/.husky/pre-push +20 -0
  169. package/.worktrees/8d2d0392/README.md +203 -0
  170. package/.worktrees/8d2d0392/SKILL.md +91 -0
  171. package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
  172. package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
  173. package/.worktrees/8d2d0392/eval/README.md +86 -0
  174. package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
  175. package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
  176. package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
  177. package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
  178. package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
  179. package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
  180. package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
  181. package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
  182. package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
  183. package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
  184. package/.worktrees/8d2d0392/eval/run.mjs +83 -0
  185. package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
  186. package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  187. package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
  188. package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
  189. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
  190. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  191. package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  192. package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
  193. package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
  194. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  195. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
  196. package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  197. package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
  198. package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
  199. package/.worktrees/8d2d0392/logo.jpg +0 -0
  200. package/.worktrees/8d2d0392/package-lock.json +977 -0
  201. package/.worktrees/8d2d0392/package.json +41 -0
  202. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  203. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  204. package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
  205. package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
  206. package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
  207. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
  208. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
  209. package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
  210. package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
  211. package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
  212. package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
  213. package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
  214. package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
  215. package/.worktrees/8d2d0392/src/change-list.js +290 -0
  216. package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
  217. package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
  218. package/.worktrees/8d2d0392/src/classify-change.js +109 -0
  219. package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
  220. package/.worktrees/8d2d0392/src/config-cat.js +88 -0
  221. package/.worktrees/8d2d0392/src/config-schema.js +328 -0
  222. package/.worktrees/8d2d0392/src/constants.js +97 -0
  223. package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
  224. package/.worktrees/8d2d0392/src/datetime.js +20 -0
  225. package/.worktrees/8d2d0392/src/db-engine.js +55 -0
  226. package/.worktrees/8d2d0392/src/db.js +381 -0
  227. package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
  228. package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
  229. package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
  230. package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
  231. package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
  232. package/.worktrees/8d2d0392/src/docs-check.js +825 -0
  233. package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
  234. package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
  235. package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
  236. package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
  237. package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
  238. package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
  239. package/.worktrees/8d2d0392/src/git-helper.js +150 -0
  240. package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
  241. package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
  242. package/.worktrees/8d2d0392/src/index.js +2854 -0
  243. package/.worktrees/8d2d0392/src/init.js +626 -0
  244. package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
  245. package/.worktrees/8d2d0392/src/local-detect.js +128 -0
  246. package/.worktrees/8d2d0392/src/local-register.js +104 -0
  247. package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
  248. package/.worktrees/8d2d0392/src/migrate.js +127 -0
  249. package/.worktrees/8d2d0392/src/module-impact.js +166 -0
  250. package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
  251. package/.worktrees/8d2d0392/src/modules.js +580 -0
  252. package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
  253. package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
  254. package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
  255. package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
  256. package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
  257. package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
  258. package/.worktrees/8d2d0392/src/progress.js +1304 -0
  259. package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
  260. package/.worktrees/8d2d0392/src/quicklog.js +883 -0
  261. package/.worktrees/8d2d0392/src/review-tier.js +77 -0
  262. package/.worktrees/8d2d0392/src/run/command.js +1641 -0
  263. package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
  264. package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
  265. package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
  266. package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
  267. package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
  268. package/.worktrees/8d2d0392/src/run/next.js +128 -0
  269. package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
  270. package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
  271. package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
  272. package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
  273. package/.worktrees/8d2d0392/src/run/stage.js +587 -0
  274. package/.worktrees/8d2d0392/src/run.js +23 -0
  275. package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
  276. package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
  277. package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
  278. package/.worktrees/8d2d0392/src/setup.js +414 -0
  279. package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
  280. package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
  281. package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
  282. package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
  283. package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
  284. package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
  285. package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
  286. package/.worktrees/8d2d0392/src/stage-review.js +597 -0
  287. package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
  288. package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
  289. package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
  290. package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
  291. package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
  292. package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
  293. package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
  294. package/.worktrees/8d2d0392/src/stages/index.js +29 -0
  295. package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
  296. package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
  297. package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
  298. package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
  299. package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
  300. package/.worktrees/8d2d0392/src/stages/status.js +64 -0
  301. package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
  302. package/.worktrees/8d2d0392/src/sync.js +1470 -0
  303. package/.worktrees/8d2d0392/src/task-review.js +1498 -0
  304. package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
  305. package/.worktrees/8d2d0392/src/taskcard.js +217 -0
  306. package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
  307. package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
  308. package/.worktrees/8d2d0392/src/version.js +19 -0
  309. package/.worktrees/8d2d0392/src/workflow.js +600 -0
  310. package/.worktrees/8d2d0392/src/workspace.js +125 -0
  311. package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
  312. package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
  313. package/.worktrees/8d2d0392/src/worktree.js +1838 -0
  314. package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
  315. package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
  316. package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
  317. package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
  318. package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
  319. package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
  320. package/architecture-analysis.md +448 -0
  321. package/eval/README.md +86 -0
  322. package/eval/eval.config.json +28 -0
  323. package/eval/lib/adapters/cli.mjs +63 -0
  324. package/eval/lib/adapters/dryrun.mjs +27 -0
  325. package/eval/lib/config.mjs +82 -0
  326. package/eval/lib/db.mjs +76 -0
  327. package/eval/lib/report.mjs +120 -0
  328. package/eval/lib/runner.mjs +157 -0
  329. package/eval/lib/tasks.mjs +73 -0
  330. package/eval/lib/util.mjs +107 -0
  331. package/eval/lib/workdir.mjs +30 -0
  332. package/eval/run.mjs +83 -0
  333. package/eval/tasks/001-slugify/files/package.json +6 -0
  334. package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  335. package/eval/tasks/001-slugify/task.json +6 -0
  336. package/eval/tasks/001-slugify/verify.mjs +28 -0
  337. package/eval/tasks/002-each-day/files/package.json +6 -0
  338. package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  339. package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  340. package/eval/tasks/002-each-day/task.json +6 -0
  341. package/eval/tasks/002-each-day/verify.mjs +31 -0
  342. package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  343. package/eval/tasks/003-word-report/files/package.json +6 -0
  344. package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  345. package/eval/tasks/003-word-report/task.json +6 -0
  346. package/eval/tasks/003-word-report/verify.mjs +38 -0
  347. package/package.json +4 -2
  348. package/src/agent-session-log.js +45 -5
  349. package/src/change-risk-profile.js +83 -14
  350. package/src/config-schema.js +18 -3
  351. package/src/contract-matrix.js +90 -29
  352. package/src/datetime.js +20 -0
  353. package/src/decision-distill.js +517 -0
  354. package/src/dispatch/backends/local-agent.js +4 -4
  355. package/src/docs-check.js +227 -0
  356. package/src/docs-debt.js +187 -24
  357. package/src/doctor-diagnostics.js +102 -2
  358. package/src/endpoint-extractor.js +41 -52
  359. package/src/foreign-declared.js +155 -0
  360. package/src/index.js +95 -13
  361. package/src/init.js +9 -7
  362. package/src/knowledge-match.js +107 -6
  363. package/src/local-register.js +7 -1
  364. package/src/module-resolve.js +12 -1
  365. package/src/modules.js +2 -1
  366. package/src/plan-adopt-waves.js +126 -0
  367. package/src/quicklog.js +50 -4
  368. package/src/run/command.js +124 -44
  369. package/src/run/complete-handlers.js +48 -19
  370. package/src/run/complete.js +5 -2
  371. package/src/run/gates.js +104 -22
  372. package/src/run/prompt.js +84 -42
  373. package/src/run/quick-audit.js +11 -0
  374. package/src/run/shared.js +152 -10
  375. package/src/run/stage.js +8 -5
  376. package/src/run.js +2 -2
  377. package/src/scan-postcheck.js +30 -17
  378. package/src/stage-contract-spec.js +3 -2
  379. package/src/stage-contract.js +68 -4
  380. package/src/stages/archive.js +53 -12
  381. package/src/stages/brainstorm-auto.js +50 -1
  382. package/src/stages/brainstorm.js +13 -0
  383. package/src/stages/doctor.js +157 -1
  384. package/src/stages/execute.js +32 -6
  385. package/src/stages/plan-postcheck.js +76 -17
  386. package/src/stages/plan.js +9 -4
  387. package/src/stages/quick.js +6 -1
  388. package/src/stages/verify.js +32 -15
  389. package/src/sync.js +41 -3
  390. package/src/task-review.js +2 -2
  391. package/src/taskcard-placeholders.js +21 -0
  392. package/src/taskcard.js +43 -1
  393. package/src/verify-postcheck.js +315 -13
  394. package/src/verify-probes.js +73 -10
  395. package/src/worktree-apply.js +569 -227
  396. package/src/worktree-deps.js +150 -1
  397. package/src/worktree.js +285 -77
  398. package/templates/prompts/taskcard-rules.md +2 -1
@@ -0,0 +1,543 @@
1
+ /**
2
+ * Machine Interface v1 — 机器接口层(SillyHub driver 模式地基)
3
+ *
4
+ * 把 SillySpec 既有的门控与事实核验从「埋在 run <stage> --done 人类可读输出流里」
5
+ * 抽象成可被程序化消费的统一 JSON envelope + 退出码契约。
6
+ *
7
+ * 设计原则(见 change 2026-07-09-machine-interface-v1 design.md §2/§3):
8
+ * - 方案 B:独立模块单点封装,不污染既有 run/progress 输出
9
+ * - 只聚合不新增校验:复用 stage-contract / task-review / verify-postcheck 既有策略引擎
10
+ * - 只读语义边界(D-002@v1):只调 ProgressManager 读路径,不写 sillyspec.db
11
+ * - stdout 纯 JSON(D-005@v1):--json 模式下由 CLI 层(src/index.js 的 withJsonOutput)
12
+ * 在调用 runGate/runDerive 期间劫持 console.log 到 stderr,防被调模块污染机器输出
13
+ * - 退出码 0/1/2 三段语义(D-004@v1):0=通过,1=事实阻断,2=无法核验
14
+ *
15
+ * 仅依赖 Node 18+ 原生 API,零新增外部依赖。
16
+ */
17
+
18
+ import { existsSync, readFileSync } from 'fs';
19
+ import { join } from 'path';
20
+ import { ProgressManager, resolveSpecDir } from './progress.js';
21
+ import { resolveRuntimeRoot } from './run/shared.js';
22
+ import { runValidators, checkTransition, checkExecuteCodeEvidence } from './stage-contract.js';
23
+ import { validateTaskReviews, resolveLatestExecuteRunId } from './task-review.js';
24
+ import { runVerifyTestCheck } from './verify-postcheck.js';
25
+
26
+ // ============ 退出码常量(D-004@v1)============
27
+
28
+ export const EXIT_OK = 0; // 核验通过(可含 warnings)
29
+ export const EXIT_BLOCKED = 1; // 事实性阻断(JSON 含 errors)
30
+ export const EXIT_UNKNOWN = 2; // 无法核验(用法错/变更不存在/环境错/内部异常)
31
+
32
+ // ============ envelope schema 版本(D-005@v1)============
33
+
34
+ export const SCHEMA_VERSION = 1;
35
+
36
+ // ============ envelope 组装 ============
37
+
38
+ /**
39
+ * 组装统一的 JSON envelope。
40
+ *
41
+ * 顶层固定字段:schema_version / command / change / ok / errors / warnings / generated_at。
42
+ * stage / facet / checks / data 仅在显式传参(!== undefined)时出现——保持 envelope 紧凑,
43
+ * daemon 可只看顶层 ok/errors/warnings。
44
+ *
45
+ * @param {object} fields
46
+ * @param {string|undefined} [fields.command]
47
+ * @param {string|undefined} [fields.stage]
48
+ * @param {string|undefined} [fields.facet]
49
+ * @param {string|undefined} [fields.change]
50
+ * @param {boolean} fields.ok
51
+ * @param {string[]} [fields.errors=[]]
52
+ * @param {string[]} [fields.warnings=[]]
53
+ * @param {Array<object>|undefined} [fields.checks]
54
+ * @param {object|undefined} [fields.data]
55
+ * @returns {object} 可直接 JSON.stringify 的 envelope 对象
56
+ */
57
+ export function buildEnvelope({
58
+ command,
59
+ stage,
60
+ facet,
61
+ change,
62
+ ok,
63
+ errors = [],
64
+ warnings = [],
65
+ checks,
66
+ data,
67
+ }) {
68
+ const envelope = {
69
+ schema_version: SCHEMA_VERSION,
70
+ command,
71
+ change,
72
+ ok,
73
+ errors,
74
+ warnings,
75
+ generated_at: new Date().toISOString(),
76
+ };
77
+
78
+ // 按需字段:仅当显式传参时挂上,避免空 null 污染
79
+ if (stage !== undefined) envelope.stage = stage;
80
+ if (facet !== undefined) envelope.facet = facet;
81
+ if (checks !== undefined) envelope.checks = checks;
82
+ if (data !== undefined) envelope.data = data;
83
+
84
+ return envelope;
85
+ }
86
+
87
+ // ============ 输出纪律(design §8)============
88
+ // --json 模式的 stdout 劫持(console.log/info → stderr)由 CLI 层 src/index.js 的
89
+ // withJsonOutput 在调用 runGate/runDerive 期间统一处理(覆盖整个调用期,非仅输出瞬间)。
90
+ // 本模块只返回 { envelope, exitCode },不直接写 stdout。
91
+
92
+ // ============ gate 聚合门控 ============
93
+
94
+ /**
95
+ * 聚合「变更 <changeName> 的 <stage> 阶段此刻能否被标记完成」的综合结论。
96
+ *
97
+ * 只读:仅调 ProgressManager.read,不写状态(D-002@v1)。
98
+ * 只聚合:每个 check 复用既有策略引擎,不在本模块重写校验逻辑(design §2)。
99
+ *
100
+ * @param {string} stage - 目标阶段(brainstorm/plan/execute/verify/...)
101
+ * @param {string} changeName - 变更名
102
+ * @param {object} opts
103
+ * @param {string} opts.cwd - 项目根目录
104
+ * @param {string} [opts.specBase] - .sillyspec(或平台 specRoot)目录;默认 resolveSpecDir(cwd)
105
+ * @param {string} [opts.runtimeRoot] - .runtime 目录;默认 resolveRuntimeRoot 三级优先级解析
106
+ * @param {string} [opts.specDriftAnchor] - drift 场景主仓 specBase 锚点(坑 execute-runs-isolation)。
107
+ * drift 守卫命中时由调用方传入,task-reviews 的 execute-run-id marker 落点经
108
+ * resolveRuntimeRoot 锚主仓 .runtime,不读 worktree 副本(与 contract-matrix 调用方同语义)。
109
+ * @param {object} [opts.ctx] - MultiRepoContext 单例(W3 task-09,D-013)。缺省=null 退化单仓。
110
+ * 透传给 validateTaskReviews(execute task-reviews check)+ runVerifyTestCheck(verify-test check),
111
+ * 让两函数按 ctx 切跨仓 gitDir / per-repo cwd。null 时两函数按既有单仓行为零回归。
112
+ * @returns {Promise<{ envelope: object, exitCode: number }>}
113
+ */
114
+ export async function runGate(stage, changeName, { cwd, specBase, runtimeRoot, specDriftAnchor, ctx = null } = {}) {
115
+ const specRoot = specBase || resolveSpecDir(cwd);
116
+ // A4:pm 用 specRoot(而非默认 resolveSpecDir(cwd))——--spec-dir/平台模式下 specBase 是真实
117
+ // specDir,默认解析会指向本地孤儿库,与下方 planContent/changeDir 的 specRoot 两套事实源混拼。
118
+ const pm = new ProgressManager({ specDir: specRoot });
119
+
120
+ try {
121
+ // ── 只读契约守卫(D-002@v1):db 不存在时 fail-closed 返回 exit 2,不触发建库落盘 ──
122
+ // pm.read → _ensureDB → db.init() 在 db 不存在/schema 戳落后时会 _createSchema + _save 落盘
123
+ // (db.js:init),这会让一个声明只读的查询命令在 spec 目录凭空建 sillyspec.db,违反只读契约。
124
+ // db 还没建 = 该变更从未跑过流程,无从核验 → 显式返回「无法核验」而非建库。
125
+ const dbPath = join(specRoot, '.runtime', 'sillyspec.db');
126
+ if (!existsSync(dbPath)) {
127
+ const envelope = buildEnvelope({
128
+ command: 'gate',
129
+ stage,
130
+ change: changeName,
131
+ ok: false,
132
+ errors: [`无法核验:进度库不存在(${dbPath})——变更 ${changeName} 尚未运行过任何阶段,只读 gate 不会为其建库`],
133
+ });
134
+ return { envelope, exitCode: EXIT_UNKNOWN };
135
+ }
136
+
137
+ // ── 读进度:变更不存在 → exit 2(D-004@v1)──
138
+ const progress = pm.read(cwd, changeName);
139
+ if (!progress) {
140
+ const envelope = buildEnvelope({
141
+ command: 'gate',
142
+ stage,
143
+ change: changeName,
144
+ ok: false,
145
+ errors: [`变更不存在: ${changeName}`],
146
+ });
147
+ return { envelope, exitCode: EXIT_UNKNOWN };
148
+ }
149
+
150
+ const currentStage = progress.currentStage || '';
151
+ const checks = [];
152
+
153
+ // W4-G (D-008):execute 阶段预计算 code evidence 一次,供 artifacts check(经 runValidators
154
+ // → validateExecuteOutputs)与下方 execute-evidence check 共享——避免各调一次 checkExecuteCodeEvidence
155
+ // 各 spawn 2 个 git 进程(gate execute 一次省 ≈ 60-200ms on Windows)。
156
+ const sharedEvidence = stage === 'execute' ? checkExecuteCodeEvidence(cwd, changeName) : undefined;
157
+
158
+ // ── a. artifacts:阶段产物校验(全部阶段)──
159
+ const r = runValidators(stage, cwd, changeName, {
160
+ projectName: progress.project,
161
+ specRoot,
162
+ ...(sharedEvidence ? { evidence: sharedEvidence } : {}),
163
+ });
164
+ checks.push({
165
+ id: 'artifacts',
166
+ ok: r.ok,
167
+ errors: r.errors || [],
168
+ warnings: r.warnings || [],
169
+ });
170
+
171
+ // ── b. transition:状态转换合法性(参与综合 ok,与 completeStep 硬阻断一致)──
172
+ // 与 run.js runStage 同源:传 fromStageData 触发 failed_post_check 门控。
173
+ // transition 必须参与 ok:否则 gate 返回 ok=true、exit 0,Agent 据此 --done 却被
174
+ // runStage 的 checkTransition 硬阻断(exit 1),gate/run 判定分裂(design §8 漂移)。
175
+ const fromStageData = (progress.stages && currentStage && progress.stages[currentStage]) || undefined;
176
+ const t = checkTransition(currentStage, stage, fromStageData ? { fromStageData } : {});
177
+ checks.push({
178
+ id: 'transition',
179
+ ok: t.allowed,
180
+ errors: t.allowed ? [] : [t.reason].filter(Boolean),
181
+ warnings: [],
182
+ });
183
+
184
+ // ── c. execute 阶段追加 execute-evidence + task-reviews ──
185
+ // D-008 + W4-G:checkExecuteCodeEvidence 整个 runGate 只调一次(顶部 sharedEvidence 预计算),
186
+ // 这里复用——真正落实去重(原注释声称"只调一次"但实现里 execute-evidence check 仍重复调了第二次)。
187
+ if (stage === 'execute') {
188
+ const ev = sharedEvidence;
189
+ checks.push({
190
+ id: 'execute-evidence',
191
+ ok: ev.status !== 'unchanged',
192
+ errors: ev.status === 'unchanged' ? [`base..head 无代码变更: ${ev.detail}`] : [],
193
+ warnings: ev.status === 'unknown' ? [`无法判定代码变更: ${ev.detail}`] : [],
194
+ data: { status: ev.status, detail: ev.detail },
195
+ });
196
+
197
+ // task-reviews:参数组装照抄 run.js:3223-3249 现成范式
198
+ const planDir = join(specRoot, 'changes', changeName);
199
+ const planPath = join(planDir, 'plan.md');
200
+ let planContent = '';
201
+ if (existsSync(planPath)) {
202
+ try {
203
+ planContent = readFileSync(planPath, 'utf8');
204
+ } catch {
205
+ planContent = '';
206
+ }
207
+ }
208
+
209
+ // drift 场景经 resolveRuntimeRoot 三级优先级解析(runtimeRoot > specDriftAnchor > 本地兜底),
210
+ // 锚主仓 .runtime,不读 worktree 副本(坑 execute-runs-isolation,与 contract-matrix 调用方同语义)
211
+ const rtRoot = resolveRuntimeRoot({ runtimeRoot, specDriftAnchor }, specRoot);
212
+ // marker 缺失/为空时先扫描 execute-runs/ 找回真实 runId(与 gates.js #6 同源),
213
+ // 避免拿 '' 进 validateTaskReviews 拼出 execute-runs//tasks/... 产出全量误导 errors。
214
+ let executeRunId = '';
215
+ try {
216
+ executeRunId = resolveLatestExecuteRunId({ runtimeRoot: rtRoot, changeName }) || '';
217
+ } catch {
218
+ executeRunId = '';
219
+ }
220
+
221
+ // git 真实性交叉校验目录:worktree 存在用 worktreePath,否则 null(交由 task-review 降级 warning)
222
+ let gitDir = null;
223
+ try {
224
+ const { WorktreeManager } = await import('./worktree.js');
225
+ const wm = new WorktreeManager({ cwd });
226
+ const meta = wm.getMeta(changeName);
227
+ if (meta?.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
228
+ gitDir = meta.worktreePath;
229
+ }
230
+ } catch {
231
+ gitDir = null;
232
+ }
233
+
234
+ const tr = validateTaskReviews({
235
+ planContent,
236
+ runtimeRoot: rtRoot,
237
+ executeRunId,
238
+ changeDir: planDir,
239
+ gitDir,
240
+ ctx,
241
+ });
242
+ checks.push({
243
+ id: 'task-reviews',
244
+ ok: tr.ok,
245
+ errors: tr.errors || [],
246
+ warnings: tr.warnings || [],
247
+ });
248
+ }
249
+
250
+ // ── d. verify 阶段追加 verify-test(CLI 实测 local.yaml commands.test)──
251
+ if (stage === 'verify') {
252
+ const vt = runVerifyTestCheck({ cwd, specBase: specRoot, changeName, ctx });
253
+ const vtWarnings = [];
254
+ if (vt.status === 'skipped') {
255
+ vtWarnings.push(`⚠️ verify-test SKIPPED — gate 未核验测试(${vt.reason || 'local.yaml 未配置 commands.test 或显式无测试'})。本次 gate 结论不含测试客观核验,driver 不应据 exit 0 判定测试通过;integration-critical 变更应在 verify 阶段降级 FAIL`);
256
+ }
257
+ // known_failures 豁免披露:本次 PASS 含豁免,driver 应提示人工复核清单是否过宽
258
+ if (vt.exemptedCount > 0) {
259
+ vtWarnings.push(`⚠️ verify-test PASS 含 ${vt.exemptedCount} 个 known_failures 豁免(${vt.reason || ''});driver 应提示人工复核豁免清单是否过宽(避免误豁免本变更引入的真实失败)`);
260
+ }
261
+ // 全量 fallback 明示:跑了全量 commands.test 但非变更范围子集,失败可能含未变更
262
+ // 模块的预存错误——driver 不应据 exit 0 判定本次变更范围已客观测试(见 3.24 verify 坑1)。
263
+ if (vt.status !== 'skipped' && vt.mode === 'full' && vt.fallbackReason) {
264
+ vtWarnings.push(`⚠️ verify-test 跑的是全量 commands.test(${vt.fallbackReason});失败可能含未变更模块的预存错误,driver 不应据 exit 0 判定本次变更范围已测`);
265
+ }
266
+ checks.push({
267
+ id: 'verify-test',
268
+ ok: vt.status !== 'failed',
269
+ errors: vt.status === 'failed' ? [`测试失败: ${vt.reason || ''}`] : [],
270
+ warnings: vtWarnings,
271
+ data: {
272
+ status: vt.status,
273
+ exitCode: vt.exitCode,
274
+ durationMs: vt.durationMs,
275
+ resultPath: vt.resultPath,
276
+ mode: vt.mode ?? null,
277
+ fallbackReason: vt.fallbackReason ?? null,
278
+ },
279
+ });
280
+ }
281
+
282
+ // ── 综合结论:所有非 informational check 均 ok ──
283
+ const ok = checks.filter((c) => !c.informational).every((c) => c.ok);
284
+ const exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
285
+
286
+ const errors = [];
287
+ const warnings = [];
288
+ for (const c of checks) {
289
+ if (c.errors && c.errors.length) errors.push(...c.errors);
290
+ if (c.warnings && c.warnings.length) warnings.push(...c.warnings);
291
+ }
292
+
293
+ const envelope = buildEnvelope({
294
+ command: 'gate',
295
+ stage,
296
+ change: changeName,
297
+ ok,
298
+ errors,
299
+ warnings,
300
+ checks,
301
+ });
302
+
303
+ return { envelope, exitCode };
304
+ } catch (e) {
305
+ // 内部异常兜底(D-004@v1 / design §3.5):保证 stdout 永远是合法 JSON 结构,exit 2
306
+ const envelope = buildEnvelope({
307
+ command: 'gate',
308
+ stage,
309
+ change: changeName,
310
+ ok: false,
311
+ errors: [`internal: ${e.message}`],
312
+ });
313
+ return { envelope, exitCode: EXIT_UNKNOWN };
314
+ }
315
+ }
316
+
317
+ // ============ derive 单项事实核验 ============
318
+
319
+ /**
320
+ * facet 枚举(D-003@v1)。machine 接口对外只接受这四个值。
321
+ */
322
+ export const FACETS = ['execute-evidence', 'verify-test', 'task-reviews', 'artifacts'];
323
+
324
+ /**
325
+ * 单项事实核验:针对变更 <changeName> 查询某一 facet 的真实状态(design §3.2)。
326
+ *
327
+ * 与 gate 的差异:gate 聚合某阶段所有 check 的综合结论;derive 只返回单一 facet 的结构化 data,
328
+ * daemon 用来做细粒度事实采集(如轮询 execute-evidence 判断代码是否变更)。
329
+ *
330
+ * 只读语义边界同 gate(D-002@v1):仅调 ProgressManager.read,不写 sillyspec.db。
331
+ * 唯一例外是 verify-test 会真实执行测试并落盘 test-result.json(产物取证,非状态写入,design §3.3)。
332
+ *
333
+ * 退出码语义(D-004@v1):0=事实通过,1=事实性阻断,2=无法核验(用法错/变更不存在/内部异常)。
334
+ *
335
+ * @param {string} facet - 必须 ∈ FACETS
336
+ * @param {string} changeName - 变更名
337
+ * @param {object} opts
338
+ * @param {string} opts.cwd - 项目根目录
339
+ * @param {string} [opts.specBase] - .sillyspec(或平台 specRoot)目录;默认 resolveSpecDir(cwd)
340
+ * @param {string} [opts.runtimeRoot] - .runtime 目录;默认 resolveRuntimeRoot 三级优先级解析
341
+ * @param {string} [opts.specDriftAnchor] - drift 场景主仓 specBase 锚点(坑 execute-runs-isolation),
342
+ * task-reviews facet 的 execute-run-id marker 落点经 resolveRuntimeRoot 锚主仓 .runtime,不读副本。
343
+ * @param {object} [opts.ctx] - MultiRepoContext 单例(W3 task-09,D-013)。缺省=null 退化单仓。
344
+ * 透传给 verify-test / task-reviews facet(runVerifyTestCheck + validateTaskReviews)。
345
+ * @returns {Promise<{ envelope: object, exitCode: number }>}
346
+ */
347
+ export async function runDerive(facet, changeName, { cwd, specBase, runtimeRoot, specDriftAnchor, ctx = null } = {}) {
348
+ // ── 非法 facet:用法错 → exit 2(D-004@v1)──
349
+ if (!FACETS.includes(facet)) {
350
+ const envelope = buildEnvelope({
351
+ command: 'derive',
352
+ facet,
353
+ change: changeName,
354
+ ok: false,
355
+ errors: [`非法 facet: ${facet},合法值: ${FACETS.join(', ')}`],
356
+ });
357
+ return { envelope, exitCode: EXIT_UNKNOWN };
358
+ }
359
+
360
+ const specRoot = specBase || resolveSpecDir(cwd);
361
+ // A4:同 runGate——pm 用 specRoot 统一事实源,平台/--spec-dir 模式不读本地孤儿库。
362
+ const pm = new ProgressManager({ specDir: specRoot });
363
+
364
+ try {
365
+ // ── 只读契约守卫(D-002@v1,同 runGate):db 不存在时 fail-closed 返回 exit 2,不建库落盘 ──
366
+ const dbPath = join(specRoot, '.runtime', 'sillyspec.db');
367
+ if (!existsSync(dbPath)) {
368
+ const envelope = buildEnvelope({
369
+ command: 'derive',
370
+ facet,
371
+ change: changeName,
372
+ ok: false,
373
+ errors: [`无法核验:进度库不存在(${dbPath})——变更 ${changeName} 尚未运行过任何阶段,只读 derive 不会为其建库`],
374
+ });
375
+ return { envelope, exitCode: EXIT_UNKNOWN };
376
+ }
377
+
378
+ // ── 读进度:变更不存在 → exit 2 ──
379
+ const progress = pm.read(cwd, changeName);
380
+ if (!progress) {
381
+ const envelope = buildEnvelope({
382
+ command: 'derive',
383
+ facet,
384
+ change: changeName,
385
+ ok: false,
386
+ errors: [`变更不存在: ${changeName}`],
387
+ });
388
+ return { envelope, exitCode: EXIT_UNKNOWN };
389
+ }
390
+
391
+ const currentStage = progress.currentStage || '';
392
+
393
+ let data;
394
+ let ok;
395
+ let errors = [];
396
+ let warnings = [];
397
+ let exitCode;
398
+
399
+ switch (facet) {
400
+ // ── a. execute-evidence:base..head 代码变更判定 ──
401
+ // 语义与 validateExecuteOutputs 一致:unknown 不等于失败(无法判定不应阻断)。
402
+ case 'execute-evidence': {
403
+ const ev = checkExecuteCodeEvidence(cwd, changeName);
404
+ data = { status: ev.status, detail: ev.detail };
405
+ ok = ev.status !== 'unchanged';
406
+ errors = ev.status === 'unchanged' ? [`base..head 无代码变更: ${ev.detail}`] : [];
407
+ warnings = ev.status === 'unknown' ? [`无法判定代码变更: ${ev.detail}`] : [];
408
+ exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
409
+ break;
410
+ }
411
+
412
+ // ── b. verify-test:真实执行测试命令并取证 ──
413
+ case 'verify-test': {
414
+ const vt = runVerifyTestCheck({ cwd, specBase: specRoot, changeName, ctx });
415
+ data = {
416
+ status: vt.status,
417
+ exitCode: vt.exitCode,
418
+ durationMs: vt.durationMs,
419
+ resultPath: vt.resultPath,
420
+ mode: vt.mode ?? null,
421
+ fallbackReason: vt.fallbackReason ?? null,
422
+ };
423
+ ok = vt.status !== 'failed';
424
+ errors = vt.status === 'failed' ? [`测试失败: ${vt.reason || ''}`] : [];
425
+ warnings = vt.status === 'skipped'
426
+ ? ['测试被跳过']
427
+ : (vt.mode === 'full' && vt.fallbackReason)
428
+ ? [`⚠️ verify-test 跑的是全量 commands.test(${vt.fallbackReason});失败可能含未变更模块的预存错误`]
429
+ : [];
430
+ exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
431
+ break;
432
+ }
433
+
434
+ // ── c. task-reviews:plan 任务评审核验(参数组装照抄 runGate execute 段)──
435
+ case 'task-reviews': {
436
+ const changeDir = join(specRoot, 'changes', changeName);
437
+ const planPath = join(changeDir, 'plan.md');
438
+ let planContent = '';
439
+ if (existsSync(planPath)) {
440
+ try {
441
+ planContent = readFileSync(planPath, 'utf8');
442
+ } catch {
443
+ planContent = '';
444
+ }
445
+ }
446
+
447
+ // drift 场景经 resolveRuntimeRoot 三级优先级解析(同 runGate execute 段),锚主仓 .runtime 不读副本
448
+ const rtRoot = resolveRuntimeRoot({ runtimeRoot, specDriftAnchor }, specRoot);
449
+ // marker 缺失/为空时先扫描 execute-runs/ 找回真实 runId(同 runGate execute 段),避免拿 '' 误导校验
450
+ let executeRunId = '';
451
+ try {
452
+ executeRunId = resolveLatestExecuteRunId({ runtimeRoot: rtRoot, changeName }) || '';
453
+ } catch {
454
+ executeRunId = '';
455
+ }
456
+
457
+ // git 真实性交叉校验目录:worktree 存在用 worktreePath,否则 null(交由 task-review 降级 warning)
458
+ let gitDir = null;
459
+ try {
460
+ const { WorktreeManager } = await import('./worktree.js');
461
+ const wm = new WorktreeManager({ cwd });
462
+ const meta = wm.getMeta(changeName);
463
+ if (meta?.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath)) {
464
+ gitDir = meta.worktreePath;
465
+ }
466
+ } catch {
467
+ gitDir = null;
468
+ }
469
+
470
+ const tr = validateTaskReviews({
471
+ planContent,
472
+ runtimeRoot: rtRoot,
473
+ executeRunId,
474
+ changeDir,
475
+ gitDir,
476
+ ctx,
477
+ });
478
+ data = {
479
+ ok: tr.ok,
480
+ errors: tr.errors,
481
+ warnings: tr.warnings,
482
+ requiredEvidence: tr.requiredEvidence,
483
+ };
484
+ ok = tr.ok;
485
+ errors = tr.errors || [];
486
+ warnings = tr.warnings || [];
487
+ exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
488
+ break;
489
+ }
490
+
491
+ // ── d. artifacts:当前阶段产物校验 ──
492
+ // runValidators 需要 stage:用 progress.currentStage(若为空串则校验器内部处理)。
493
+ case 'artifacts': {
494
+ const r = runValidators(currentStage, cwd, changeName, {
495
+ projectName: progress.project,
496
+ specRoot,
497
+ });
498
+ data = { ok: r.ok, errors: r.errors, warnings: r.warnings };
499
+ ok = r.ok;
500
+ errors = r.errors || [];
501
+ warnings = r.warnings || [];
502
+ exitCode = ok ? EXIT_OK : EXIT_BLOCKED;
503
+ break;
504
+ }
505
+
506
+ // 不可达:facet 已在入口白名单校验
507
+ default: {
508
+ const envelope = buildEnvelope({
509
+ command: 'derive',
510
+ facet,
511
+ change: changeName,
512
+ ok: false,
513
+ errors: [`非法 facet: ${facet},合法值: ${FACETS.join(', ')}`],
514
+ });
515
+ return { envelope, exitCode: EXIT_UNKNOWN };
516
+ }
517
+ }
518
+
519
+ // stage 仅 artifacts 时出现(产物校验绑定阶段语义);其余 facet 不传 stage。
520
+ const envelope = buildEnvelope({
521
+ command: 'derive',
522
+ facet,
523
+ change: changeName,
524
+ ok,
525
+ errors,
526
+ warnings,
527
+ data,
528
+ stage: facet === 'artifacts' ? currentStage : undefined,
529
+ });
530
+
531
+ return { envelope, exitCode };
532
+ } catch (e) {
533
+ // 内部异常兜底(D-004@v1 / design §3.5):保证 stdout 永远是合法 JSON 结构,exit 2
534
+ const envelope = buildEnvelope({
535
+ command: 'derive',
536
+ facet,
537
+ change: changeName,
538
+ ok: false,
539
+ errors: [`internal: ${e.message}`],
540
+ });
541
+ return { envelope, exitCode: EXIT_UNKNOWN };
542
+ }
543
+ }
@@ -0,0 +1,127 @@
1
+ import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync, renameSync, copyFileSync, statSync, cpSync } from 'fs';
2
+ import { basename, join, resolve } from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ /**
6
+ * Migrate old .sillyspec/ structure to unified .sillyspec/docs/<project>/ structure
7
+ * @param {string} projectDir - Path to the project directory
8
+ */
9
+ export function migrateDocs(projectDir) {
10
+ const sillyspecDir = join(projectDir, '.sillyspec');
11
+ if (!existsSync(sillyspecDir)) {
12
+ console.error('❌ .sillyspec/ 目录不存在');
13
+ process.exit(1);
14
+ }
15
+
16
+ // Determine project name from projects/*.yaml or directory name
17
+ let projectName = basename(resolve(projectDir));
18
+ const projectsDir = join(sillyspecDir, 'projects');
19
+ if (existsSync(projectsDir)) {
20
+ const yamlFiles = readdirSync(projectsDir).filter(f => f.endsWith('.yaml'));
21
+ if (yamlFiles.length > 0) {
22
+ projectName = yamlFiles[0].replace('.yaml', '');
23
+ }
24
+ }
25
+
26
+ console.log(chalk.cyan(`📦 迁移项目: ${projectName}`));
27
+ console.log('');
28
+
29
+ const docsBase = join(sillyspecDir, 'docs', projectName);
30
+ let migrated = 0;
31
+
32
+ // 1. codebase/ → .sillyspec/docs/<project>/scan/
33
+ const codebaseDir = join(sillyspecDir, 'codebase');
34
+ if (existsSync(codebaseDir)) {
35
+ const targetDir = join(docsBase, 'scan');
36
+ mkdirSync(targetDir, { recursive: true });
37
+ const files = readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
38
+ for (const file of files) {
39
+ const src = join(codebaseDir, file);
40
+ const dest = join(targetDir, file);
41
+ if (!existsSync(dest)) {
42
+ copyFileSync(src, dest);
43
+ console.log(chalk.green(' ✅') + ` scan/${file}`);
44
+ migrated++;
45
+ } else {
46
+ console.log(chalk.yellow(' ⏭️') + ` scan/${file} (已存在)`);
47
+ }
48
+ }
49
+ }
50
+
51
+ // 2. specs/ is deprecated — designs live in changes/<变更名>/design.md
52
+
53
+ // 3. changes/archive/ → .sillyspec/docs/<project>/archive/
54
+ const archiveDir = join(sillyspecDir, 'changes', 'archive');
55
+ if (existsSync(archiveDir)) {
56
+ const targetDir = join(docsBase, 'archive');
57
+ mkdirSync(targetDir, { recursive: true });
58
+ const entries = readdirSync(archiveDir);
59
+ for (const entry of entries) {
60
+ const src = join(archiveDir, entry);
61
+ const dest = join(targetDir, entry);
62
+ if (!existsSync(dest)) {
63
+ // 归档变更本身是目录(含 design.md 等),copyFileSync 对目录源抛 EISDIR;
64
+ // 按类型分发:目录用 cpSync 递归、文件用 copyFileSync,单条失败 try/catch 不中断整体迁移
65
+ try {
66
+ if (statSync(src).isDirectory()) {
67
+ cpSync(src, dest, { recursive: true });
68
+ } else {
69
+ copyFileSync(src, dest);
70
+ }
71
+ console.log(chalk.green(' ✅') + ` archive/${entry}`);
72
+ migrated++;
73
+ } catch (err) {
74
+ console.log(chalk.yellow(' ⚠️') + ` archive/${entry} 迁移失败: ${err.message}`);
75
+ }
76
+ } else {
77
+ console.log(chalk.yellow(' ⏭️') + ` archive/${entry} (已存在)`);
78
+ }
79
+ }
80
+ }
81
+
82
+ // 4. knowledge/ → .sillyspec/docs/<project>/archive/ (append knowledge files)
83
+ const knowledgeDir = join(sillyspecDir, 'knowledge');
84
+ if (existsSync(knowledgeDir)) {
85
+ const targetDir = join(docsBase, 'archive');
86
+ mkdirSync(targetDir, { recursive: true });
87
+ const files = readdirSync(knowledgeDir).filter(f => f.endsWith('.md'));
88
+ for (const file of files) {
89
+ const src = join(knowledgeDir, file);
90
+ const dest = join(targetDir, `knowledge-${file}`);
91
+ if (!existsSync(dest)) {
92
+ copyFileSync(src, dest);
93
+ console.log(chalk.green(' ✅') + ` archive/knowledge-${file}`);
94
+ migrated++;
95
+ } else {
96
+ console.log(chalk.yellow(' ⏭️') + ` archive/knowledge-${file} (已存在)`);
97
+ }
98
+ }
99
+ }
100
+
101
+ // 5. quicklog/ → .sillyspec/docs/<project>/quicklog/
102
+ const quicklogDir = join(sillyspecDir, 'quicklog');
103
+ if (existsSync(quicklogDir)) {
104
+ const targetDir = join(docsBase, 'quicklog');
105
+ mkdirSync(targetDir, { recursive: true });
106
+ const files = readdirSync(quicklogDir).filter(f => f.endsWith('.md'));
107
+ for (const file of files) {
108
+ const src = join(quicklogDir, file);
109
+ const dest = join(targetDir, file);
110
+ if (!existsSync(dest)) {
111
+ copyFileSync(src, dest);
112
+ console.log(chalk.green(' ✅') + ` quicklog/${file}`);
113
+ migrated++;
114
+ } else {
115
+ console.log(chalk.yellow(' ⏭️') + ` quicklog/${file} (已存在)`);
116
+ }
117
+ }
118
+ }
119
+
120
+ console.log('');
121
+ if (migrated > 0) {
122
+ console.log(chalk.green(` ✅ 迁移完成,共迁移 ${migrated} 个文件`));
123
+ console.log(chalk.dim(' 旧文件保留在原位,确认无误后可手动删除'));
124
+ } else {
125
+ console.log(chalk.yellow(' 没有需要迁移的文件'));
126
+ }
127
+ }