sillyspec 3.27.12 → 3.28.0

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 (1207) hide show
  1. package/.claude/skills/sillyspec-execute/SKILL.md +214 -214
  2. package/.claude/skills/sillyspec-plan/SKILL.md +156 -156
  3. package/.claude/skills/sillyspec-quick/SKILL.md +116 -116
  4. package/package.json +1 -1
  5. package/src/agent-session-log.js +77 -10
  6. package/src/config-schema.js +2 -2
  7. package/src/contract-matrix.js +15 -2
  8. package/src/doctor-diagnostics.js +64 -1
  9. package/src/endpoint-extractor.js +100 -24
  10. package/src/index.js +36 -5
  11. package/src/machine-interface.js +63 -0
  12. package/src/progress/stage-machine.js +106 -1
  13. package/src/progress.js +3 -0
  14. package/src/run/command.js +1 -1
  15. package/src/run/complete-handlers.js +31 -3
  16. package/src/run/complete.js +12 -4
  17. package/src/run/quick-audit.js +98 -0
  18. package/src/run/shared.js +54 -0
  19. package/src/run/stage.js +18 -11
  20. package/src/spec-sync.js +191 -14
  21. package/src/stages/execute.js +6 -2
  22. package/src/sync.js +122 -4
  23. package/src/task-review.js +51 -4
  24. package/src/verify-postcheck.js +60 -8
  25. package/src/verify-probes.js +3 -0
  26. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  27. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  28. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  29. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  30. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  31. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  32. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  33. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  34. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +0 -57
  35. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +0 -177
  36. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  37. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  38. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  39. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  40. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  41. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +0 -64
  42. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +0 -54
  43. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  44. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  45. package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +0 -2
  46. package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +0 -20
  47. package/.claude/worktrees/sillyspec-data-model-research/README.md +0 -203
  48. package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +0 -91
  49. package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +0 -2
  50. package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
  51. package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +0 -977
  52. package/.claude/worktrees/sillyspec-data-model-research/package.json +0 -39
  53. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  54. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  55. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
  56. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +0 -16
  57. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
  58. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +0 -836
  59. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +0 -256
  60. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +0 -25
  61. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +0 -95
  62. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +0 -679
  63. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +0 -526
  64. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +0 -357
  65. package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +0 -803
  66. package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +0 -290
  67. package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +0 -270
  68. package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +0 -65
  69. package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +0 -109
  70. package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +0 -202
  71. package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +0 -88
  72. package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +0 -328
  73. package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +0 -97
  74. package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +0 -480
  75. package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +0 -20
  76. package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +0 -55
  77. package/.claude/worktrees/sillyspec-data-model-research/src/db.js +0 -381
  78. package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +0 -517
  79. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +0 -155
  80. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +0 -245
  81. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +0 -246
  82. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +0 -121
  83. package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +0 -825
  84. package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +0 -393
  85. package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +0 -107
  86. package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +0 -1099
  87. package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +0 -420
  88. package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +0 -78
  89. package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +0 -73
  90. package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +0 -150
  91. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +0 -130
  92. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +0 -892
  93. package/.claude/worktrees/sillyspec-data-model-research/src/index.js +0 -2798
  94. package/.claude/worktrees/sillyspec-data-model-research/src/init.js +0 -626
  95. package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +0 -231
  96. package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +0 -128
  97. package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +0 -104
  98. package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +0 -543
  99. package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +0 -127
  100. package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +0 -166
  101. package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +0 -222
  102. package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +0 -580
  103. package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +0 -336
  104. package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +0 -355
  105. package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +0 -36
  106. package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +0 -594
  107. package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +0 -265
  108. package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +0 -1304
  109. package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +0 -115
  110. package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +0 -852
  111. package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +0 -77
  112. package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +0 -1595
  113. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +0 -1552
  114. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +0 -1259
  115. package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +0 -156
  116. package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +0 -1084
  117. package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +0 -208
  118. package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +0 -128
  119. package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +0 -843
  120. package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +0 -186
  121. package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +0 -269
  122. package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +0 -1562
  123. package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +0 -584
  124. package/.claude/worktrees/sillyspec-data-model-research/src/run.js +0 -23
  125. package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +0 -388
  126. package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +0 -512
  127. package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +0 -95
  128. package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +0 -414
  129. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +0 -597
  130. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +0 -62
  131. package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +0 -50
  132. package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +0 -358
  133. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +0 -171
  134. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +0 -550
  135. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +0 -889
  136. package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +0 -597
  137. package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +0 -199
  138. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +0 -236
  139. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +0 -617
  140. package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +0 -145
  141. package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +0 -540
  142. package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +0 -1275
  143. package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +0 -43
  144. package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +0 -29
  145. package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +0 -514
  146. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +0 -1344
  147. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +0 -650
  148. package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +0 -167
  149. package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +0 -608
  150. package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +0 -64
  151. package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +0 -246
  152. package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +0 -1470
  153. package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +0 -1498
  154. package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +0 -210
  155. package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +0 -1718
  156. package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +0 -277
  157. package/.claude/worktrees/sillyspec-data-model-research/src/version.js +0 -19
  158. package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +0 -600
  159. package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +0 -125
  160. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +0 -1446
  161. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +0 -576
  162. package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +0 -1715
  163. package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +0 -23
  164. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +0 -28
  165. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +0 -12
  166. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +0 -32
  167. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +0 -79
  168. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +0 -132
  169. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  170. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  171. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  172. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  173. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  174. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  175. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  176. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  177. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-export/SKILL.md +0 -57
  178. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-init/SKILL.md +0 -177
  179. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  180. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  181. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-propose/SKILL.md +0 -87
  182. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  183. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  184. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  185. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-state/SKILL.md +0 -64
  186. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-status/SKILL.md +0 -54
  187. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  188. package/.worktrees/2c37b1d7/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  189. package/.worktrees/2c37b1d7/.claude/skills/verify-per-user/SKILL.md +0 -6
  190. package/.worktrees/2c37b1d7/.gitattributes +0 -2
  191. package/.worktrees/2c37b1d7/.husky/pre-push +0 -20
  192. package/.worktrees/2c37b1d7/README.md +0 -203
  193. package/.worktrees/2c37b1d7/SKILL.md +0 -91
  194. package/.worktrees/2c37b1d7/architecture-analysis.md +0 -448
  195. package/.worktrees/2c37b1d7/bin/sillyspec.js +0 -2
  196. package/.worktrees/2c37b1d7/eval/README.md +0 -86
  197. package/.worktrees/2c37b1d7/eval/eval.config.json +0 -28
  198. package/.worktrees/2c37b1d7/eval/lib/adapters/cli.mjs +0 -63
  199. package/.worktrees/2c37b1d7/eval/lib/adapters/dryrun.mjs +0 -27
  200. package/.worktrees/2c37b1d7/eval/lib/config.mjs +0 -82
  201. package/.worktrees/2c37b1d7/eval/lib/db.mjs +0 -76
  202. package/.worktrees/2c37b1d7/eval/lib/report.mjs +0 -120
  203. package/.worktrees/2c37b1d7/eval/lib/runner.mjs +0 -157
  204. package/.worktrees/2c37b1d7/eval/lib/tasks.mjs +0 -73
  205. package/.worktrees/2c37b1d7/eval/lib/util.mjs +0 -107
  206. package/.worktrees/2c37b1d7/eval/lib/workdir.mjs +0 -30
  207. package/.worktrees/2c37b1d7/eval/run.mjs +0 -83
  208. package/.worktrees/2c37b1d7/eval/tasks/001-slugify/files/package.json +0 -6
  209. package/.worktrees/2c37b1d7/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  210. package/.worktrees/2c37b1d7/eval/tasks/001-slugify/task.json +0 -6
  211. package/.worktrees/2c37b1d7/eval/tasks/001-slugify/verify.mjs +0 -28
  212. package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/package.json +0 -6
  213. package/.worktrees/2c37b1d7/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  214. package/.worktrees/2c37b1d7/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  215. package/.worktrees/2c37b1d7/eval/tasks/002-each-day/task.json +0 -6
  216. package/.worktrees/2c37b1d7/eval/tasks/002-each-day/verify.mjs +0 -31
  217. package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  218. package/.worktrees/2c37b1d7/eval/tasks/003-word-report/files/package.json +0 -6
  219. package/.worktrees/2c37b1d7/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  220. package/.worktrees/2c37b1d7/eval/tasks/003-word-report/task.json +0 -6
  221. package/.worktrees/2c37b1d7/eval/tasks/003-word-report/verify.mjs +0 -38
  222. package/.worktrees/2c37b1d7/logo.jpg +0 -0
  223. package/.worktrees/2c37b1d7/package-lock.json +0 -977
  224. package/.worktrees/2c37b1d7/package.json +0 -41
  225. package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  226. package/.worktrees/2c37b1d7/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  227. package/.worktrees/2c37b1d7/packages/dashboard/dist/favicon.jpg +0 -0
  228. package/.worktrees/2c37b1d7/packages/dashboard/dist/index.html +0 -16
  229. package/.worktrees/2c37b1d7/packages/dashboard/dist/logo.jpg +0 -0
  230. package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-dashboard.html +0 -836
  231. package/.worktrees/2c37b1d7/packages/dashboard/dist/prototype-overview.html +0 -256
  232. package/.worktrees/2c37b1d7/packages/dashboard/package.json +0 -25
  233. package/.worktrees/2c37b1d7/packages/dashboard/server/executor.js +0 -95
  234. package/.worktrees/2c37b1d7/packages/dashboard/server/index.js +0 -679
  235. package/.worktrees/2c37b1d7/packages/dashboard/server/parser.js +0 -526
  236. package/.worktrees/2c37b1d7/packages/dashboard/server/watcher.js +0 -357
  237. package/.worktrees/2c37b1d7/src/agent-session-log.js +0 -803
  238. package/.worktrees/2c37b1d7/src/change-list.js +0 -290
  239. package/.worktrees/2c37b1d7/src/change-risk-profile.js +0 -339
  240. package/.worktrees/2c37b1d7/src/check-primitives.js +0 -65
  241. package/.worktrees/2c37b1d7/src/classify-change.js +0 -109
  242. package/.worktrees/2c37b1d7/src/commit-suggest.js +0 -202
  243. package/.worktrees/2c37b1d7/src/config-cat.js +0 -88
  244. package/.worktrees/2c37b1d7/src/config-schema.js +0 -328
  245. package/.worktrees/2c37b1d7/src/constants.js +0 -97
  246. package/.worktrees/2c37b1d7/src/contract-matrix.js +0 -533
  247. package/.worktrees/2c37b1d7/src/datetime.js +0 -20
  248. package/.worktrees/2c37b1d7/src/db-engine.js +0 -55
  249. package/.worktrees/2c37b1d7/src/db.js +0 -381
  250. package/.worktrees/2c37b1d7/src/decision-distill.js +0 -517
  251. package/.worktrees/2c37b1d7/src/dispatch/backends/local-agent.js +0 -155
  252. package/.worktrees/2c37b1d7/src/dispatch/backends/sillyhub-mcp.js +0 -245
  253. package/.worktrees/2c37b1d7/src/dispatch/probe.js +0 -246
  254. package/.worktrees/2c37b1d7/src/dispatch/strategy.js +0 -121
  255. package/.worktrees/2c37b1d7/src/docs-check.js +0 -825
  256. package/.worktrees/2c37b1d7/src/docs-debt.js +0 -393
  257. package/.worktrees/2c37b1d7/src/docs-gate.js +0 -107
  258. package/.worktrees/2c37b1d7/src/doctor-diagnostics.js +0 -1099
  259. package/.worktrees/2c37b1d7/src/endpoint-extractor.js +0 -409
  260. package/.worktrees/2c37b1d7/src/foreign-declared.js +0 -155
  261. package/.worktrees/2c37b1d7/src/fs-atomic.js +0 -73
  262. package/.worktrees/2c37b1d7/src/git-helper.js +0 -150
  263. package/.worktrees/2c37b1d7/src/hooks/claude-pre-tool-use.cjs +0 -130
  264. package/.worktrees/2c37b1d7/src/hooks/worktree-guard.js +0 -892
  265. package/.worktrees/2c37b1d7/src/index.js +0 -2854
  266. package/.worktrees/2c37b1d7/src/init.js +0 -626
  267. package/.worktrees/2c37b1d7/src/knowledge-match.js +0 -231
  268. package/.worktrees/2c37b1d7/src/local-detect.js +0 -128
  269. package/.worktrees/2c37b1d7/src/local-register.js +0 -104
  270. package/.worktrees/2c37b1d7/src/machine-interface.js +0 -543
  271. package/.worktrees/2c37b1d7/src/migrate.js +0 -127
  272. package/.worktrees/2c37b1d7/src/module-impact.js +0 -166
  273. package/.worktrees/2c37b1d7/src/module-resolve.js +0 -222
  274. package/.worktrees/2c37b1d7/src/modules.js +0 -580
  275. package/.worktrees/2c37b1d7/src/plan-adopt-waves.js +0 -126
  276. package/.worktrees/2c37b1d7/src/progress/change-registry.js +0 -336
  277. package/.worktrees/2c37b1d7/src/progress/consistency-doctor.js +0 -355
  278. package/.worktrees/2c37b1d7/src/progress/shared.js +0 -36
  279. package/.worktrees/2c37b1d7/src/progress/stage-machine.js +0 -594
  280. package/.worktrees/2c37b1d7/src/progress/step-store.js +0 -265
  281. package/.worktrees/2c37b1d7/src/progress.js +0 -1304
  282. package/.worktrees/2c37b1d7/src/quick-recommend.js +0 -115
  283. package/.worktrees/2c37b1d7/src/quicklog.js +0 -883
  284. package/.worktrees/2c37b1d7/src/review-tier.js +0 -77
  285. package/.worktrees/2c37b1d7/src/run/command.js +0 -1641
  286. package/.worktrees/2c37b1d7/src/run/complete-handlers.js +0 -1552
  287. package/.worktrees/2c37b1d7/src/run/complete.js +0 -1259
  288. package/.worktrees/2c37b1d7/src/run/concurrent-detect.js +0 -156
  289. package/.worktrees/2c37b1d7/src/run/gates.js +0 -1111
  290. package/.worktrees/2c37b1d7/src/run/multi-repo-context.js +0 -208
  291. package/.worktrees/2c37b1d7/src/run/next.js +0 -128
  292. package/.worktrees/2c37b1d7/src/run/prompt.js +0 -843
  293. package/.worktrees/2c37b1d7/src/run/quick-audit.js +0 -186
  294. package/.worktrees/2c37b1d7/src/run/scan-profile.js +0 -269
  295. package/.worktrees/2c37b1d7/src/run/shared.js +0 -1562
  296. package/.worktrees/2c37b1d7/src/run/stage.js +0 -587
  297. package/.worktrees/2c37b1d7/src/run.js +0 -23
  298. package/.worktrees/2c37b1d7/src/scan-diff.js +0 -388
  299. package/.worktrees/2c37b1d7/src/scan-postcheck.js +0 -524
  300. package/.worktrees/2c37b1d7/src/scan-staleness.js +0 -95
  301. package/.worktrees/2c37b1d7/src/setup.js +0 -414
  302. package/.worktrees/2c37b1d7/src/sillyhub-mcp/client.js +0 -597
  303. package/.worktrees/2c37b1d7/src/sillyhub-mcp/config.js +0 -62
  304. package/.worktrees/2c37b1d7/src/spec-dir-typo.js +0 -50
  305. package/.worktrees/2c37b1d7/src/spec-sync.js +0 -358
  306. package/.worktrees/2c37b1d7/src/stage-contract-engine.js +0 -171
  307. package/.worktrees/2c37b1d7/src/stage-contract-spec.js +0 -551
  308. package/.worktrees/2c37b1d7/src/stage-contract.js +0 -948
  309. package/.worktrees/2c37b1d7/src/stage-review.js +0 -597
  310. package/.worktrees/2c37b1d7/src/stages/archive.js +0 -199
  311. package/.worktrees/2c37b1d7/src/stages/brainstorm-auto.js +0 -285
  312. package/.worktrees/2c37b1d7/src/stages/brainstorm.js +0 -624
  313. package/.worktrees/2c37b1d7/src/stages/cmd-existence.js +0 -145
  314. package/.worktrees/2c37b1d7/src/stages/doctor.js +0 -540
  315. package/.worktrees/2c37b1d7/src/stages/execute.js +0 -1277
  316. package/.worktrees/2c37b1d7/src/stages/explore.js +0 -43
  317. package/.worktrees/2c37b1d7/src/stages/index.js +0 -29
  318. package/.worktrees/2c37b1d7/src/stages/knowledge.js +0 -514
  319. package/.worktrees/2c37b1d7/src/stages/plan-postcheck.js +0 -1398
  320. package/.worktrees/2c37b1d7/src/stages/plan.js +0 -655
  321. package/.worktrees/2c37b1d7/src/stages/quick.js +0 -167
  322. package/.worktrees/2c37b1d7/src/stages/scan.js +0 -608
  323. package/.worktrees/2c37b1d7/src/stages/status.js +0 -64
  324. package/.worktrees/2c37b1d7/src/stages/verify.js +0 -246
  325. package/.worktrees/2c37b1d7/src/sync.js +0 -1470
  326. package/.worktrees/2c37b1d7/src/task-review.js +0 -1498
  327. package/.worktrees/2c37b1d7/src/taskcard-placeholders.js +0 -21
  328. package/.worktrees/2c37b1d7/src/taskcard.js +0 -250
  329. package/.worktrees/2c37b1d7/src/verify-postcheck.js +0 -1718
  330. package/.worktrees/2c37b1d7/src/verify-probes.js +0 -327
  331. package/.worktrees/2c37b1d7/src/version.js +0 -19
  332. package/.worktrees/2c37b1d7/src/workflow.js +0 -600
  333. package/.worktrees/2c37b1d7/src/workspace.js +0 -125
  334. package/.worktrees/2c37b1d7/src/worktree-apply.js +0 -1611
  335. package/.worktrees/2c37b1d7/src/worktree-deps.js +0 -668
  336. package/.worktrees/2c37b1d7/src/worktree.js +0 -1849
  337. package/.worktrees/2c37b1d7/templates/claude-instruction.md +0 -23
  338. package/.worktrees/2c37b1d7/templates/prompts/taskcard-rules.md +0 -29
  339. package/.worktrees/2c37b1d7/templates/prompts/testcase-design.md +0 -12
  340. package/.worktrees/2c37b1d7/templates/prompts/verify-probes.md +0 -32
  341. package/.worktrees/2c37b1d7/templates/workflows/archive-impact.yaml +0 -79
  342. package/.worktrees/2c37b1d7/templates/workflows/scan-docs.yaml +0 -132
  343. package/.worktrees/542c4415/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  344. package/.worktrees/542c4415/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  345. package/.worktrees/542c4415/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  346. package/.worktrees/542c4415/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  347. package/.worktrees/542c4415/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  348. package/.worktrees/542c4415/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  349. package/.worktrees/542c4415/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  350. package/.worktrees/542c4415/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  351. package/.worktrees/542c4415/.claude/skills/sillyspec-export/SKILL.md +0 -57
  352. package/.worktrees/542c4415/.claude/skills/sillyspec-init/SKILL.md +0 -177
  353. package/.worktrees/542c4415/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  354. package/.worktrees/542c4415/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  355. package/.worktrees/542c4415/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  356. package/.worktrees/542c4415/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  357. package/.worktrees/542c4415/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  358. package/.worktrees/542c4415/.claude/skills/sillyspec-state/SKILL.md +0 -64
  359. package/.worktrees/542c4415/.claude/skills/sillyspec-status/SKILL.md +0 -54
  360. package/.worktrees/542c4415/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  361. package/.worktrees/542c4415/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  362. package/.worktrees/542c4415/.gitattributes +0 -2
  363. package/.worktrees/542c4415/.husky/pre-push +0 -20
  364. package/.worktrees/542c4415/README.md +0 -203
  365. package/.worktrees/542c4415/SKILL.md +0 -91
  366. package/.worktrees/542c4415/architecture-analysis.md +0 -448
  367. package/.worktrees/542c4415/bin/sillyspec.js +0 -2
  368. package/.worktrees/542c4415/eval/README.md +0 -86
  369. package/.worktrees/542c4415/eval/eval.config.json +0 -28
  370. package/.worktrees/542c4415/eval/lib/adapters/cli.mjs +0 -63
  371. package/.worktrees/542c4415/eval/lib/adapters/dryrun.mjs +0 -27
  372. package/.worktrees/542c4415/eval/lib/config.mjs +0 -82
  373. package/.worktrees/542c4415/eval/lib/db.mjs +0 -76
  374. package/.worktrees/542c4415/eval/lib/report.mjs +0 -120
  375. package/.worktrees/542c4415/eval/lib/runner.mjs +0 -157
  376. package/.worktrees/542c4415/eval/lib/tasks.mjs +0 -73
  377. package/.worktrees/542c4415/eval/lib/util.mjs +0 -107
  378. package/.worktrees/542c4415/eval/lib/workdir.mjs +0 -30
  379. package/.worktrees/542c4415/eval/run.mjs +0 -83
  380. package/.worktrees/542c4415/eval/tasks/001-slugify/files/package.json +0 -6
  381. package/.worktrees/542c4415/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  382. package/.worktrees/542c4415/eval/tasks/001-slugify/task.json +0 -6
  383. package/.worktrees/542c4415/eval/tasks/001-slugify/verify.mjs +0 -28
  384. package/.worktrees/542c4415/eval/tasks/002-each-day/files/package.json +0 -6
  385. package/.worktrees/542c4415/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  386. package/.worktrees/542c4415/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  387. package/.worktrees/542c4415/eval/tasks/002-each-day/task.json +0 -6
  388. package/.worktrees/542c4415/eval/tasks/002-each-day/verify.mjs +0 -31
  389. package/.worktrees/542c4415/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  390. package/.worktrees/542c4415/eval/tasks/003-word-report/files/package.json +0 -6
  391. package/.worktrees/542c4415/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  392. package/.worktrees/542c4415/eval/tasks/003-word-report/task.json +0 -6
  393. package/.worktrees/542c4415/eval/tasks/003-word-report/verify.mjs +0 -38
  394. package/.worktrees/542c4415/logo.jpg +0 -0
  395. package/.worktrees/542c4415/package-lock.json +0 -977
  396. package/.worktrees/542c4415/package.json +0 -41
  397. package/.worktrees/542c4415/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  398. package/.worktrees/542c4415/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  399. package/.worktrees/542c4415/packages/dashboard/dist/favicon.jpg +0 -0
  400. package/.worktrees/542c4415/packages/dashboard/dist/index.html +0 -16
  401. package/.worktrees/542c4415/packages/dashboard/dist/logo.jpg +0 -0
  402. package/.worktrees/542c4415/packages/dashboard/dist/prototype-dashboard.html +0 -836
  403. package/.worktrees/542c4415/packages/dashboard/dist/prototype-overview.html +0 -256
  404. package/.worktrees/542c4415/packages/dashboard/package.json +0 -25
  405. package/.worktrees/542c4415/packages/dashboard/server/executor.js +0 -95
  406. package/.worktrees/542c4415/packages/dashboard/server/index.js +0 -679
  407. package/.worktrees/542c4415/packages/dashboard/server/parser.js +0 -526
  408. package/.worktrees/542c4415/packages/dashboard/server/watcher.js +0 -357
  409. package/.worktrees/542c4415/src/agent-session-log.js +0 -803
  410. package/.worktrees/542c4415/src/change-list.js +0 -290
  411. package/.worktrees/542c4415/src/change-risk-profile.js +0 -339
  412. package/.worktrees/542c4415/src/check-primitives.js +0 -65
  413. package/.worktrees/542c4415/src/classify-change.js +0 -109
  414. package/.worktrees/542c4415/src/commit-suggest.js +0 -202
  415. package/.worktrees/542c4415/src/config-cat.js +0 -88
  416. package/.worktrees/542c4415/src/config-schema.js +0 -328
  417. package/.worktrees/542c4415/src/constants.js +0 -97
  418. package/.worktrees/542c4415/src/contract-matrix.js +0 -533
  419. package/.worktrees/542c4415/src/datetime.js +0 -20
  420. package/.worktrees/542c4415/src/db-engine.js +0 -55
  421. package/.worktrees/542c4415/src/db.js +0 -381
  422. package/.worktrees/542c4415/src/decision-distill.js +0 -517
  423. package/.worktrees/542c4415/src/dispatch/backends/local-agent.js +0 -155
  424. package/.worktrees/542c4415/src/dispatch/backends/sillyhub-mcp.js +0 -245
  425. package/.worktrees/542c4415/src/dispatch/probe.js +0 -246
  426. package/.worktrees/542c4415/src/dispatch/strategy.js +0 -121
  427. package/.worktrees/542c4415/src/docs-check.js +0 -825
  428. package/.worktrees/542c4415/src/docs-debt.js +0 -393
  429. package/.worktrees/542c4415/src/docs-gate.js +0 -107
  430. package/.worktrees/542c4415/src/doctor-diagnostics.js +0 -1099
  431. package/.worktrees/542c4415/src/endpoint-extractor.js +0 -409
  432. package/.worktrees/542c4415/src/foreign-declared.js +0 -155
  433. package/.worktrees/542c4415/src/fs-atomic.js +0 -73
  434. package/.worktrees/542c4415/src/git-helper.js +0 -150
  435. package/.worktrees/542c4415/src/hooks/claude-pre-tool-use.cjs +0 -130
  436. package/.worktrees/542c4415/src/hooks/worktree-guard.js +0 -892
  437. package/.worktrees/542c4415/src/index.js +0 -2854
  438. package/.worktrees/542c4415/src/init.js +0 -626
  439. package/.worktrees/542c4415/src/knowledge-match.js +0 -231
  440. package/.worktrees/542c4415/src/local-detect.js +0 -128
  441. package/.worktrees/542c4415/src/local-register.js +0 -104
  442. package/.worktrees/542c4415/src/machine-interface.js +0 -543
  443. package/.worktrees/542c4415/src/migrate.js +0 -127
  444. package/.worktrees/542c4415/src/module-impact.js +0 -166
  445. package/.worktrees/542c4415/src/module-resolve.js +0 -222
  446. package/.worktrees/542c4415/src/modules.js +0 -580
  447. package/.worktrees/542c4415/src/plan-adopt-waves.js +0 -126
  448. package/.worktrees/542c4415/src/progress/change-registry.js +0 -336
  449. package/.worktrees/542c4415/src/progress/consistency-doctor.js +0 -355
  450. package/.worktrees/542c4415/src/progress/shared.js +0 -36
  451. package/.worktrees/542c4415/src/progress/stage-machine.js +0 -594
  452. package/.worktrees/542c4415/src/progress/step-store.js +0 -265
  453. package/.worktrees/542c4415/src/progress.js +0 -1304
  454. package/.worktrees/542c4415/src/quick-recommend.js +0 -115
  455. package/.worktrees/542c4415/src/quicklog.js +0 -883
  456. package/.worktrees/542c4415/src/review-tier.js +0 -77
  457. package/.worktrees/542c4415/src/run/command.js +0 -1641
  458. package/.worktrees/542c4415/src/run/complete-handlers.js +0 -1552
  459. package/.worktrees/542c4415/src/run/complete.js +0 -1259
  460. package/.worktrees/542c4415/src/run/concurrent-detect.js +0 -156
  461. package/.worktrees/542c4415/src/run/gates.js +0 -1111
  462. package/.worktrees/542c4415/src/run/multi-repo-context.js +0 -208
  463. package/.worktrees/542c4415/src/run/next.js +0 -128
  464. package/.worktrees/542c4415/src/run/prompt.js +0 -843
  465. package/.worktrees/542c4415/src/run/quick-audit.js +0 -186
  466. package/.worktrees/542c4415/src/run/scan-profile.js +0 -269
  467. package/.worktrees/542c4415/src/run/shared.js +0 -1562
  468. package/.worktrees/542c4415/src/run/stage.js +0 -587
  469. package/.worktrees/542c4415/src/run.js +0 -23
  470. package/.worktrees/542c4415/src/scan-diff.js +0 -388
  471. package/.worktrees/542c4415/src/scan-postcheck.js +0 -524
  472. package/.worktrees/542c4415/src/scan-staleness.js +0 -95
  473. package/.worktrees/542c4415/src/setup.js +0 -414
  474. package/.worktrees/542c4415/src/sillyhub-mcp/client.js +0 -597
  475. package/.worktrees/542c4415/src/sillyhub-mcp/config.js +0 -62
  476. package/.worktrees/542c4415/src/spec-dir-typo.js +0 -50
  477. package/.worktrees/542c4415/src/spec-sync.js +0 -358
  478. package/.worktrees/542c4415/src/stage-contract-engine.js +0 -171
  479. package/.worktrees/542c4415/src/stage-contract-spec.js +0 -551
  480. package/.worktrees/542c4415/src/stage-contract.js +0 -948
  481. package/.worktrees/542c4415/src/stage-review.js +0 -597
  482. package/.worktrees/542c4415/src/stages/archive.js +0 -199
  483. package/.worktrees/542c4415/src/stages/brainstorm-auto.js +0 -285
  484. package/.worktrees/542c4415/src/stages/brainstorm.js +0 -624
  485. package/.worktrees/542c4415/src/stages/cmd-existence.js +0 -145
  486. package/.worktrees/542c4415/src/stages/doctor.js +0 -540
  487. package/.worktrees/542c4415/src/stages/execute.js +0 -1277
  488. package/.worktrees/542c4415/src/stages/explore.js +0 -43
  489. package/.worktrees/542c4415/src/stages/index.js +0 -29
  490. package/.worktrees/542c4415/src/stages/knowledge.js +0 -514
  491. package/.worktrees/542c4415/src/stages/plan-postcheck.js +0 -1398
  492. package/.worktrees/542c4415/src/stages/plan.js +0 -655
  493. package/.worktrees/542c4415/src/stages/quick.js +0 -167
  494. package/.worktrees/542c4415/src/stages/scan.js +0 -608
  495. package/.worktrees/542c4415/src/stages/status.js +0 -64
  496. package/.worktrees/542c4415/src/stages/verify.js +0 -246
  497. package/.worktrees/542c4415/src/sync.js +0 -1470
  498. package/.worktrees/542c4415/src/task-review.js +0 -1498
  499. package/.worktrees/542c4415/src/taskcard-placeholders.js +0 -21
  500. package/.worktrees/542c4415/src/taskcard.js +0 -250
  501. package/.worktrees/542c4415/src/verify-postcheck.js +0 -1718
  502. package/.worktrees/542c4415/src/verify-probes.js +0 -327
  503. package/.worktrees/542c4415/src/version.js +0 -19
  504. package/.worktrees/542c4415/src/workflow.js +0 -600
  505. package/.worktrees/542c4415/src/workspace.js +0 -125
  506. package/.worktrees/542c4415/src/worktree-apply.js +0 -1611
  507. package/.worktrees/542c4415/src/worktree-deps.js +0 -668
  508. package/.worktrees/542c4415/src/worktree.js +0 -1849
  509. package/.worktrees/542c4415/templates/claude-instruction.md +0 -23
  510. package/.worktrees/542c4415/templates/prompts/taskcard-rules.md +0 -29
  511. package/.worktrees/542c4415/templates/prompts/testcase-design.md +0 -12
  512. package/.worktrees/542c4415/templates/prompts/verify-probes.md +0 -32
  513. package/.worktrees/542c4415/templates/workflows/archive-impact.yaml +0 -79
  514. package/.worktrees/542c4415/templates/workflows/scan-docs.yaml +0 -132
  515. package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  516. package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  517. package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  518. package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  519. package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  520. package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  521. package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  522. package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  523. package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +0 -57
  524. package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +0 -177
  525. package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  526. package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  527. package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +0 -87
  528. package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  529. package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  530. package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  531. package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +0 -64
  532. package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +0 -54
  533. package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  534. package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  535. package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +0 -6
  536. package/.worktrees/8d2d0392/.gitattributes +0 -2
  537. package/.worktrees/8d2d0392/.husky/pre-push +0 -20
  538. package/.worktrees/8d2d0392/README.md +0 -203
  539. package/.worktrees/8d2d0392/SKILL.md +0 -91
  540. package/.worktrees/8d2d0392/architecture-analysis.md +0 -448
  541. package/.worktrees/8d2d0392/bin/sillyspec.js +0 -2
  542. package/.worktrees/8d2d0392/eval/README.md +0 -86
  543. package/.worktrees/8d2d0392/eval/eval.config.json +0 -28
  544. package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +0 -63
  545. package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +0 -27
  546. package/.worktrees/8d2d0392/eval/lib/config.mjs +0 -82
  547. package/.worktrees/8d2d0392/eval/lib/db.mjs +0 -76
  548. package/.worktrees/8d2d0392/eval/lib/report.mjs +0 -120
  549. package/.worktrees/8d2d0392/eval/lib/runner.mjs +0 -157
  550. package/.worktrees/8d2d0392/eval/lib/tasks.mjs +0 -73
  551. package/.worktrees/8d2d0392/eval/lib/util.mjs +0 -107
  552. package/.worktrees/8d2d0392/eval/lib/workdir.mjs +0 -30
  553. package/.worktrees/8d2d0392/eval/run.mjs +0 -83
  554. package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +0 -6
  555. package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  556. package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +0 -6
  557. package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +0 -28
  558. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +0 -6
  559. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  560. package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  561. package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +0 -6
  562. package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +0 -31
  563. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  564. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +0 -6
  565. package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  566. package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +0 -6
  567. package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +0 -38
  568. package/.worktrees/8d2d0392/logo.jpg +0 -0
  569. package/.worktrees/8d2d0392/package-lock.json +0 -977
  570. package/.worktrees/8d2d0392/package.json +0 -41
  571. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  572. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  573. package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
  574. package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +0 -16
  575. package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
  576. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +0 -836
  577. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +0 -256
  578. package/.worktrees/8d2d0392/packages/dashboard/package.json +0 -25
  579. package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +0 -95
  580. package/.worktrees/8d2d0392/packages/dashboard/server/index.js +0 -679
  581. package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +0 -526
  582. package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +0 -357
  583. package/.worktrees/8d2d0392/src/agent-session-log.js +0 -803
  584. package/.worktrees/8d2d0392/src/change-list.js +0 -290
  585. package/.worktrees/8d2d0392/src/change-risk-profile.js +0 -339
  586. package/.worktrees/8d2d0392/src/check-primitives.js +0 -65
  587. package/.worktrees/8d2d0392/src/classify-change.js +0 -109
  588. package/.worktrees/8d2d0392/src/commit-suggest.js +0 -202
  589. package/.worktrees/8d2d0392/src/config-cat.js +0 -88
  590. package/.worktrees/8d2d0392/src/config-schema.js +0 -328
  591. package/.worktrees/8d2d0392/src/constants.js +0 -97
  592. package/.worktrees/8d2d0392/src/contract-matrix.js +0 -533
  593. package/.worktrees/8d2d0392/src/datetime.js +0 -20
  594. package/.worktrees/8d2d0392/src/db-engine.js +0 -55
  595. package/.worktrees/8d2d0392/src/db.js +0 -381
  596. package/.worktrees/8d2d0392/src/decision-distill.js +0 -517
  597. package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +0 -155
  598. package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +0 -245
  599. package/.worktrees/8d2d0392/src/dispatch/probe.js +0 -246
  600. package/.worktrees/8d2d0392/src/dispatch/strategy.js +0 -121
  601. package/.worktrees/8d2d0392/src/docs-check.js +0 -825
  602. package/.worktrees/8d2d0392/src/docs-debt.js +0 -393
  603. package/.worktrees/8d2d0392/src/docs-gate.js +0 -107
  604. package/.worktrees/8d2d0392/src/doctor-diagnostics.js +0 -1099
  605. package/.worktrees/8d2d0392/src/endpoint-extractor.js +0 -409
  606. package/.worktrees/8d2d0392/src/foreign-declared.js +0 -78
  607. package/.worktrees/8d2d0392/src/fs-atomic.js +0 -73
  608. package/.worktrees/8d2d0392/src/git-helper.js +0 -150
  609. package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +0 -130
  610. package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +0 -892
  611. package/.worktrees/8d2d0392/src/index.js +0 -2854
  612. package/.worktrees/8d2d0392/src/init.js +0 -626
  613. package/.worktrees/8d2d0392/src/knowledge-match.js +0 -231
  614. package/.worktrees/8d2d0392/src/local-detect.js +0 -128
  615. package/.worktrees/8d2d0392/src/local-register.js +0 -104
  616. package/.worktrees/8d2d0392/src/machine-interface.js +0 -543
  617. package/.worktrees/8d2d0392/src/migrate.js +0 -127
  618. package/.worktrees/8d2d0392/src/module-impact.js +0 -166
  619. package/.worktrees/8d2d0392/src/module-resolve.js +0 -222
  620. package/.worktrees/8d2d0392/src/modules.js +0 -580
  621. package/.worktrees/8d2d0392/src/plan-adopt-waves.js +0 -126
  622. package/.worktrees/8d2d0392/src/progress/change-registry.js +0 -336
  623. package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +0 -355
  624. package/.worktrees/8d2d0392/src/progress/shared.js +0 -36
  625. package/.worktrees/8d2d0392/src/progress/stage-machine.js +0 -594
  626. package/.worktrees/8d2d0392/src/progress/step-store.js +0 -265
  627. package/.worktrees/8d2d0392/src/progress.js +0 -1304
  628. package/.worktrees/8d2d0392/src/quick-recommend.js +0 -115
  629. package/.worktrees/8d2d0392/src/quicklog.js +0 -883
  630. package/.worktrees/8d2d0392/src/review-tier.js +0 -77
  631. package/.worktrees/8d2d0392/src/run/command.js +0 -1641
  632. package/.worktrees/8d2d0392/src/run/complete-handlers.js +0 -1552
  633. package/.worktrees/8d2d0392/src/run/complete.js +0 -1259
  634. package/.worktrees/8d2d0392/src/run/concurrent-detect.js +0 -156
  635. package/.worktrees/8d2d0392/src/run/gates.js +0 -1094
  636. package/.worktrees/8d2d0392/src/run/multi-repo-context.js +0 -208
  637. package/.worktrees/8d2d0392/src/run/next.js +0 -128
  638. package/.worktrees/8d2d0392/src/run/prompt.js +0 -843
  639. package/.worktrees/8d2d0392/src/run/quick-audit.js +0 -186
  640. package/.worktrees/8d2d0392/src/run/scan-profile.js +0 -269
  641. package/.worktrees/8d2d0392/src/run/shared.js +0 -1562
  642. package/.worktrees/8d2d0392/src/run/stage.js +0 -587
  643. package/.worktrees/8d2d0392/src/run.js +0 -23
  644. package/.worktrees/8d2d0392/src/scan-diff.js +0 -388
  645. package/.worktrees/8d2d0392/src/scan-postcheck.js +0 -524
  646. package/.worktrees/8d2d0392/src/scan-staleness.js +0 -95
  647. package/.worktrees/8d2d0392/src/setup.js +0 -414
  648. package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +0 -597
  649. package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +0 -62
  650. package/.worktrees/8d2d0392/src/spec-dir-typo.js +0 -50
  651. package/.worktrees/8d2d0392/src/spec-sync.js +0 -358
  652. package/.worktrees/8d2d0392/src/stage-contract-engine.js +0 -171
  653. package/.worktrees/8d2d0392/src/stage-contract-spec.js +0 -551
  654. package/.worktrees/8d2d0392/src/stage-contract.js +0 -948
  655. package/.worktrees/8d2d0392/src/stage-review.js +0 -597
  656. package/.worktrees/8d2d0392/src/stages/archive.js +0 -199
  657. package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +0 -285
  658. package/.worktrees/8d2d0392/src/stages/brainstorm.js +0 -624
  659. package/.worktrees/8d2d0392/src/stages/cmd-existence.js +0 -145
  660. package/.worktrees/8d2d0392/src/stages/doctor.js +0 -540
  661. package/.worktrees/8d2d0392/src/stages/execute.js +0 -1277
  662. package/.worktrees/8d2d0392/src/stages/explore.js +0 -43
  663. package/.worktrees/8d2d0392/src/stages/index.js +0 -29
  664. package/.worktrees/8d2d0392/src/stages/knowledge.js +0 -514
  665. package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +0 -1398
  666. package/.worktrees/8d2d0392/src/stages/plan.js +0 -651
  667. package/.worktrees/8d2d0392/src/stages/quick.js +0 -167
  668. package/.worktrees/8d2d0392/src/stages/scan.js +0 -608
  669. package/.worktrees/8d2d0392/src/stages/status.js +0 -64
  670. package/.worktrees/8d2d0392/src/stages/verify.js +0 -246
  671. package/.worktrees/8d2d0392/src/sync.js +0 -1470
  672. package/.worktrees/8d2d0392/src/task-review.js +0 -1498
  673. package/.worktrees/8d2d0392/src/taskcard-placeholders.js +0 -21
  674. package/.worktrees/8d2d0392/src/taskcard.js +0 -217
  675. package/.worktrees/8d2d0392/src/verify-postcheck.js +0 -1718
  676. package/.worktrees/8d2d0392/src/verify-probes.js +0 -327
  677. package/.worktrees/8d2d0392/src/version.js +0 -19
  678. package/.worktrees/8d2d0392/src/workflow.js +0 -600
  679. package/.worktrees/8d2d0392/src/workspace.js +0 -125
  680. package/.worktrees/8d2d0392/src/worktree-apply.js +0 -1611
  681. package/.worktrees/8d2d0392/src/worktree-deps.js +0 -576
  682. package/.worktrees/8d2d0392/src/worktree.js +0 -1838
  683. package/.worktrees/8d2d0392/templates/claude-instruction.md +0 -23
  684. package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +0 -29
  685. package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +0 -12
  686. package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +0 -32
  687. package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +0 -79
  688. package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +0 -132
  689. package/.worktrees/c1eae35e/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  690. package/.worktrees/c1eae35e/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  691. package/.worktrees/c1eae35e/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  692. package/.worktrees/c1eae35e/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  693. package/.worktrees/c1eae35e/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  694. package/.worktrees/c1eae35e/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  695. package/.worktrees/c1eae35e/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  696. package/.worktrees/c1eae35e/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  697. package/.worktrees/c1eae35e/.claude/skills/sillyspec-export/SKILL.md +0 -57
  698. package/.worktrees/c1eae35e/.claude/skills/sillyspec-init/SKILL.md +0 -177
  699. package/.worktrees/c1eae35e/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  700. package/.worktrees/c1eae35e/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  701. package/.worktrees/c1eae35e/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  702. package/.worktrees/c1eae35e/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  703. package/.worktrees/c1eae35e/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  704. package/.worktrees/c1eae35e/.claude/skills/sillyspec-state/SKILL.md +0 -64
  705. package/.worktrees/c1eae35e/.claude/skills/sillyspec-status/SKILL.md +0 -54
  706. package/.worktrees/c1eae35e/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  707. package/.worktrees/c1eae35e/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  708. package/.worktrees/c1eae35e/.gitattributes +0 -2
  709. package/.worktrees/c1eae35e/.husky/pre-push +0 -20
  710. package/.worktrees/c1eae35e/README.md +0 -203
  711. package/.worktrees/c1eae35e/SKILL.md +0 -91
  712. package/.worktrees/c1eae35e/architecture-analysis.md +0 -448
  713. package/.worktrees/c1eae35e/bin/sillyspec.js +0 -2
  714. package/.worktrees/c1eae35e/eval/README.md +0 -86
  715. package/.worktrees/c1eae35e/eval/eval.config.json +0 -28
  716. package/.worktrees/c1eae35e/eval/lib/adapters/cli.mjs +0 -63
  717. package/.worktrees/c1eae35e/eval/lib/adapters/dryrun.mjs +0 -27
  718. package/.worktrees/c1eae35e/eval/lib/config.mjs +0 -82
  719. package/.worktrees/c1eae35e/eval/lib/db.mjs +0 -76
  720. package/.worktrees/c1eae35e/eval/lib/report.mjs +0 -120
  721. package/.worktrees/c1eae35e/eval/lib/runner.mjs +0 -157
  722. package/.worktrees/c1eae35e/eval/lib/tasks.mjs +0 -73
  723. package/.worktrees/c1eae35e/eval/lib/util.mjs +0 -107
  724. package/.worktrees/c1eae35e/eval/lib/workdir.mjs +0 -30
  725. package/.worktrees/c1eae35e/eval/run.mjs +0 -83
  726. package/.worktrees/c1eae35e/eval/tasks/001-slugify/files/package.json +0 -6
  727. package/.worktrees/c1eae35e/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  728. package/.worktrees/c1eae35e/eval/tasks/001-slugify/task.json +0 -6
  729. package/.worktrees/c1eae35e/eval/tasks/001-slugify/verify.mjs +0 -28
  730. package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/package.json +0 -6
  731. package/.worktrees/c1eae35e/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  732. package/.worktrees/c1eae35e/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  733. package/.worktrees/c1eae35e/eval/tasks/002-each-day/task.json +0 -6
  734. package/.worktrees/c1eae35e/eval/tasks/002-each-day/verify.mjs +0 -31
  735. package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  736. package/.worktrees/c1eae35e/eval/tasks/003-word-report/files/package.json +0 -6
  737. package/.worktrees/c1eae35e/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  738. package/.worktrees/c1eae35e/eval/tasks/003-word-report/task.json +0 -6
  739. package/.worktrees/c1eae35e/eval/tasks/003-word-report/verify.mjs +0 -38
  740. package/.worktrees/c1eae35e/logo.jpg +0 -0
  741. package/.worktrees/c1eae35e/package-lock.json +0 -977
  742. package/.worktrees/c1eae35e/package.json +0 -41
  743. package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  744. package/.worktrees/c1eae35e/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  745. package/.worktrees/c1eae35e/packages/dashboard/dist/favicon.jpg +0 -0
  746. package/.worktrees/c1eae35e/packages/dashboard/dist/index.html +0 -16
  747. package/.worktrees/c1eae35e/packages/dashboard/dist/logo.jpg +0 -0
  748. package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-dashboard.html +0 -836
  749. package/.worktrees/c1eae35e/packages/dashboard/dist/prototype-overview.html +0 -256
  750. package/.worktrees/c1eae35e/packages/dashboard/package.json +0 -25
  751. package/.worktrees/c1eae35e/packages/dashboard/server/executor.js +0 -95
  752. package/.worktrees/c1eae35e/packages/dashboard/server/index.js +0 -679
  753. package/.worktrees/c1eae35e/packages/dashboard/server/parser.js +0 -526
  754. package/.worktrees/c1eae35e/packages/dashboard/server/watcher.js +0 -357
  755. package/.worktrees/c1eae35e/src/agent-session-log.js +0 -803
  756. package/.worktrees/c1eae35e/src/change-list.js +0 -290
  757. package/.worktrees/c1eae35e/src/change-risk-profile.js +0 -339
  758. package/.worktrees/c1eae35e/src/check-primitives.js +0 -65
  759. package/.worktrees/c1eae35e/src/classify-change.js +0 -109
  760. package/.worktrees/c1eae35e/src/commit-suggest.js +0 -202
  761. package/.worktrees/c1eae35e/src/config-cat.js +0 -88
  762. package/.worktrees/c1eae35e/src/config-schema.js +0 -328
  763. package/.worktrees/c1eae35e/src/constants.js +0 -97
  764. package/.worktrees/c1eae35e/src/contract-matrix.js +0 -533
  765. package/.worktrees/c1eae35e/src/datetime.js +0 -20
  766. package/.worktrees/c1eae35e/src/db-engine.js +0 -55
  767. package/.worktrees/c1eae35e/src/db.js +0 -381
  768. package/.worktrees/c1eae35e/src/decision-distill.js +0 -517
  769. package/.worktrees/c1eae35e/src/dispatch/backends/local-agent.js +0 -155
  770. package/.worktrees/c1eae35e/src/dispatch/backends/sillyhub-mcp.js +0 -245
  771. package/.worktrees/c1eae35e/src/dispatch/probe.js +0 -246
  772. package/.worktrees/c1eae35e/src/dispatch/strategy.js +0 -121
  773. package/.worktrees/c1eae35e/src/docs-check.js +0 -825
  774. package/.worktrees/c1eae35e/src/docs-debt.js +0 -393
  775. package/.worktrees/c1eae35e/src/docs-gate.js +0 -107
  776. package/.worktrees/c1eae35e/src/doctor-diagnostics.js +0 -1099
  777. package/.worktrees/c1eae35e/src/endpoint-extractor.js +0 -409
  778. package/.worktrees/c1eae35e/src/foreign-declared.js +0 -155
  779. package/.worktrees/c1eae35e/src/fs-atomic.js +0 -73
  780. package/.worktrees/c1eae35e/src/git-helper.js +0 -150
  781. package/.worktrees/c1eae35e/src/hooks/claude-pre-tool-use.cjs +0 -130
  782. package/.worktrees/c1eae35e/src/hooks/worktree-guard.js +0 -892
  783. package/.worktrees/c1eae35e/src/index.js +0 -2854
  784. package/.worktrees/c1eae35e/src/init.js +0 -626
  785. package/.worktrees/c1eae35e/src/knowledge-match.js +0 -231
  786. package/.worktrees/c1eae35e/src/local-detect.js +0 -128
  787. package/.worktrees/c1eae35e/src/local-register.js +0 -104
  788. package/.worktrees/c1eae35e/src/machine-interface.js +0 -543
  789. package/.worktrees/c1eae35e/src/migrate.js +0 -127
  790. package/.worktrees/c1eae35e/src/module-impact.js +0 -166
  791. package/.worktrees/c1eae35e/src/module-resolve.js +0 -222
  792. package/.worktrees/c1eae35e/src/modules.js +0 -580
  793. package/.worktrees/c1eae35e/src/plan-adopt-waves.js +0 -126
  794. package/.worktrees/c1eae35e/src/progress/change-registry.js +0 -336
  795. package/.worktrees/c1eae35e/src/progress/consistency-doctor.js +0 -355
  796. package/.worktrees/c1eae35e/src/progress/shared.js +0 -36
  797. package/.worktrees/c1eae35e/src/progress/stage-machine.js +0 -594
  798. package/.worktrees/c1eae35e/src/progress/step-store.js +0 -265
  799. package/.worktrees/c1eae35e/src/progress.js +0 -1304
  800. package/.worktrees/c1eae35e/src/quick-recommend.js +0 -115
  801. package/.worktrees/c1eae35e/src/quicklog.js +0 -883
  802. package/.worktrees/c1eae35e/src/review-tier.js +0 -77
  803. package/.worktrees/c1eae35e/src/run/command.js +0 -1641
  804. package/.worktrees/c1eae35e/src/run/complete-handlers.js +0 -1552
  805. package/.worktrees/c1eae35e/src/run/complete.js +0 -1259
  806. package/.worktrees/c1eae35e/src/run/concurrent-detect.js +0 -156
  807. package/.worktrees/c1eae35e/src/run/gates.js +0 -1111
  808. package/.worktrees/c1eae35e/src/run/multi-repo-context.js +0 -208
  809. package/.worktrees/c1eae35e/src/run/next.js +0 -128
  810. package/.worktrees/c1eae35e/src/run/prompt.js +0 -843
  811. package/.worktrees/c1eae35e/src/run/quick-audit.js +0 -186
  812. package/.worktrees/c1eae35e/src/run/scan-profile.js +0 -269
  813. package/.worktrees/c1eae35e/src/run/shared.js +0 -1562
  814. package/.worktrees/c1eae35e/src/run/stage.js +0 -587
  815. package/.worktrees/c1eae35e/src/run.js +0 -23
  816. package/.worktrees/c1eae35e/src/scan-diff.js +0 -388
  817. package/.worktrees/c1eae35e/src/scan-postcheck.js +0 -524
  818. package/.worktrees/c1eae35e/src/scan-staleness.js +0 -95
  819. package/.worktrees/c1eae35e/src/setup.js +0 -414
  820. package/.worktrees/c1eae35e/src/sillyhub-mcp/client.js +0 -597
  821. package/.worktrees/c1eae35e/src/sillyhub-mcp/config.js +0 -62
  822. package/.worktrees/c1eae35e/src/spec-dir-typo.js +0 -50
  823. package/.worktrees/c1eae35e/src/spec-sync.js +0 -358
  824. package/.worktrees/c1eae35e/src/stage-contract-engine.js +0 -171
  825. package/.worktrees/c1eae35e/src/stage-contract-spec.js +0 -551
  826. package/.worktrees/c1eae35e/src/stage-contract.js +0 -948
  827. package/.worktrees/c1eae35e/src/stage-review.js +0 -597
  828. package/.worktrees/c1eae35e/src/stages/archive.js +0 -199
  829. package/.worktrees/c1eae35e/src/stages/brainstorm-auto.js +0 -285
  830. package/.worktrees/c1eae35e/src/stages/brainstorm.js +0 -624
  831. package/.worktrees/c1eae35e/src/stages/cmd-existence.js +0 -145
  832. package/.worktrees/c1eae35e/src/stages/doctor.js +0 -540
  833. package/.worktrees/c1eae35e/src/stages/execute.js +0 -1277
  834. package/.worktrees/c1eae35e/src/stages/explore.js +0 -43
  835. package/.worktrees/c1eae35e/src/stages/index.js +0 -29
  836. package/.worktrees/c1eae35e/src/stages/knowledge.js +0 -514
  837. package/.worktrees/c1eae35e/src/stages/plan-postcheck.js +0 -1398
  838. package/.worktrees/c1eae35e/src/stages/plan.js +0 -655
  839. package/.worktrees/c1eae35e/src/stages/quick.js +0 -167
  840. package/.worktrees/c1eae35e/src/stages/scan.js +0 -608
  841. package/.worktrees/c1eae35e/src/stages/status.js +0 -64
  842. package/.worktrees/c1eae35e/src/stages/verify.js +0 -246
  843. package/.worktrees/c1eae35e/src/sync.js +0 -1470
  844. package/.worktrees/c1eae35e/src/task-review.js +0 -1498
  845. package/.worktrees/c1eae35e/src/taskcard-placeholders.js +0 -21
  846. package/.worktrees/c1eae35e/src/taskcard.js +0 -250
  847. package/.worktrees/c1eae35e/src/verify-postcheck.js +0 -1718
  848. package/.worktrees/c1eae35e/src/verify-probes.js +0 -327
  849. package/.worktrees/c1eae35e/src/version.js +0 -19
  850. package/.worktrees/c1eae35e/src/workflow.js +0 -600
  851. package/.worktrees/c1eae35e/src/workspace.js +0 -125
  852. package/.worktrees/c1eae35e/src/worktree-apply.js +0 -1611
  853. package/.worktrees/c1eae35e/src/worktree-deps.js +0 -668
  854. package/.worktrees/c1eae35e/src/worktree.js +0 -1849
  855. package/.worktrees/c1eae35e/templates/claude-instruction.md +0 -23
  856. package/.worktrees/c1eae35e/templates/prompts/taskcard-rules.md +0 -29
  857. package/.worktrees/c1eae35e/templates/prompts/testcase-design.md +0 -12
  858. package/.worktrees/c1eae35e/templates/prompts/verify-probes.md +0 -32
  859. package/.worktrees/c1eae35e/templates/workflows/archive-impact.yaml +0 -79
  860. package/.worktrees/c1eae35e/templates/workflows/scan-docs.yaml +0 -132
  861. package/.worktrees/dafc71ad/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  862. package/.worktrees/dafc71ad/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  863. package/.worktrees/dafc71ad/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  864. package/.worktrees/dafc71ad/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  865. package/.worktrees/dafc71ad/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  866. package/.worktrees/dafc71ad/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  867. package/.worktrees/dafc71ad/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  868. package/.worktrees/dafc71ad/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  869. package/.worktrees/dafc71ad/.claude/skills/sillyspec-export/SKILL.md +0 -57
  870. package/.worktrees/dafc71ad/.claude/skills/sillyspec-init/SKILL.md +0 -177
  871. package/.worktrees/dafc71ad/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  872. package/.worktrees/dafc71ad/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  873. package/.worktrees/dafc71ad/.claude/skills/sillyspec-propose/SKILL.md +0 -87
  874. package/.worktrees/dafc71ad/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  875. package/.worktrees/dafc71ad/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  876. package/.worktrees/dafc71ad/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  877. package/.worktrees/dafc71ad/.claude/skills/sillyspec-state/SKILL.md +0 -64
  878. package/.worktrees/dafc71ad/.claude/skills/sillyspec-status/SKILL.md +0 -54
  879. package/.worktrees/dafc71ad/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  880. package/.worktrees/dafc71ad/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  881. package/.worktrees/dafc71ad/.gitattributes +0 -2
  882. package/.worktrees/dafc71ad/.husky/pre-push +0 -20
  883. package/.worktrees/dafc71ad/README.md +0 -203
  884. package/.worktrees/dafc71ad/SKILL.md +0 -91
  885. package/.worktrees/dafc71ad/analysis.md +0 -366
  886. package/.worktrees/dafc71ad/architecture-analysis.md +0 -448
  887. package/.worktrees/dafc71ad/bin/sillyspec.js +0 -2
  888. package/.worktrees/dafc71ad/eval/README.md +0 -86
  889. package/.worktrees/dafc71ad/eval/eval.config.json +0 -28
  890. package/.worktrees/dafc71ad/eval/lib/adapters/cli.mjs +0 -63
  891. package/.worktrees/dafc71ad/eval/lib/adapters/dryrun.mjs +0 -27
  892. package/.worktrees/dafc71ad/eval/lib/config.mjs +0 -82
  893. package/.worktrees/dafc71ad/eval/lib/db.mjs +0 -76
  894. package/.worktrees/dafc71ad/eval/lib/report.mjs +0 -120
  895. package/.worktrees/dafc71ad/eval/lib/runner.mjs +0 -157
  896. package/.worktrees/dafc71ad/eval/lib/tasks.mjs +0 -73
  897. package/.worktrees/dafc71ad/eval/lib/util.mjs +0 -107
  898. package/.worktrees/dafc71ad/eval/lib/workdir.mjs +0 -30
  899. package/.worktrees/dafc71ad/eval/run.mjs +0 -83
  900. package/.worktrees/dafc71ad/eval/tasks/001-slugify/files/package.json +0 -6
  901. package/.worktrees/dafc71ad/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  902. package/.worktrees/dafc71ad/eval/tasks/001-slugify/task.json +0 -6
  903. package/.worktrees/dafc71ad/eval/tasks/001-slugify/verify.mjs +0 -28
  904. package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/package.json +0 -6
  905. package/.worktrees/dafc71ad/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  906. package/.worktrees/dafc71ad/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  907. package/.worktrees/dafc71ad/eval/tasks/002-each-day/task.json +0 -6
  908. package/.worktrees/dafc71ad/eval/tasks/002-each-day/verify.mjs +0 -31
  909. package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  910. package/.worktrees/dafc71ad/eval/tasks/003-word-report/files/package.json +0 -6
  911. package/.worktrees/dafc71ad/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  912. package/.worktrees/dafc71ad/eval/tasks/003-word-report/task.json +0 -6
  913. package/.worktrees/dafc71ad/eval/tasks/003-word-report/verify.mjs +0 -38
  914. package/.worktrees/dafc71ad/logo.jpg +0 -0
  915. package/.worktrees/dafc71ad/package-lock.json +0 -977
  916. package/.worktrees/dafc71ad/package.json +0 -41
  917. package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  918. package/.worktrees/dafc71ad/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  919. package/.worktrees/dafc71ad/packages/dashboard/dist/favicon.jpg +0 -0
  920. package/.worktrees/dafc71ad/packages/dashboard/dist/index.html +0 -16
  921. package/.worktrees/dafc71ad/packages/dashboard/dist/logo.jpg +0 -0
  922. package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-dashboard.html +0 -836
  923. package/.worktrees/dafc71ad/packages/dashboard/dist/prototype-overview.html +0 -256
  924. package/.worktrees/dafc71ad/packages/dashboard/package.json +0 -25
  925. package/.worktrees/dafc71ad/packages/dashboard/server/executor.js +0 -95
  926. package/.worktrees/dafc71ad/packages/dashboard/server/index.js +0 -679
  927. package/.worktrees/dafc71ad/packages/dashboard/server/parser.js +0 -526
  928. package/.worktrees/dafc71ad/packages/dashboard/server/watcher.js +0 -357
  929. package/.worktrees/dafc71ad/src/agent-session-log.js +0 -803
  930. package/.worktrees/dafc71ad/src/change-list.js +0 -290
  931. package/.worktrees/dafc71ad/src/change-risk-profile.js +0 -339
  932. package/.worktrees/dafc71ad/src/check-primitives.js +0 -65
  933. package/.worktrees/dafc71ad/src/classify-change.js +0 -109
  934. package/.worktrees/dafc71ad/src/commit-suggest.js +0 -202
  935. package/.worktrees/dafc71ad/src/config-cat.js +0 -88
  936. package/.worktrees/dafc71ad/src/config-schema.js +0 -328
  937. package/.worktrees/dafc71ad/src/constants.js +0 -97
  938. package/.worktrees/dafc71ad/src/contract-matrix.js +0 -533
  939. package/.worktrees/dafc71ad/src/datetime.js +0 -20
  940. package/.worktrees/dafc71ad/src/db-engine.js +0 -55
  941. package/.worktrees/dafc71ad/src/db.js +0 -381
  942. package/.worktrees/dafc71ad/src/decision-distill.js +0 -517
  943. package/.worktrees/dafc71ad/src/dispatch/backends/local-agent.js +0 -155
  944. package/.worktrees/dafc71ad/src/dispatch/backends/sillyhub-mcp.js +0 -245
  945. package/.worktrees/dafc71ad/src/dispatch/probe.js +0 -246
  946. package/.worktrees/dafc71ad/src/dispatch/strategy.js +0 -121
  947. package/.worktrees/dafc71ad/src/docs-check.js +0 -825
  948. package/.worktrees/dafc71ad/src/docs-debt.js +0 -393
  949. package/.worktrees/dafc71ad/src/docs-gate.js +0 -107
  950. package/.worktrees/dafc71ad/src/doctor-diagnostics.js +0 -1099
  951. package/.worktrees/dafc71ad/src/endpoint-extractor.js +0 -409
  952. package/.worktrees/dafc71ad/src/foreign-declared.js +0 -155
  953. package/.worktrees/dafc71ad/src/fs-atomic.js +0 -73
  954. package/.worktrees/dafc71ad/src/git-helper.js +0 -150
  955. package/.worktrees/dafc71ad/src/hooks/claude-pre-tool-use.cjs +0 -130
  956. package/.worktrees/dafc71ad/src/hooks/worktree-guard.js +0 -892
  957. package/.worktrees/dafc71ad/src/index.js +0 -2854
  958. package/.worktrees/dafc71ad/src/init.js +0 -626
  959. package/.worktrees/dafc71ad/src/knowledge-match.js +0 -231
  960. package/.worktrees/dafc71ad/src/local-detect.js +0 -128
  961. package/.worktrees/dafc71ad/src/local-register.js +0 -104
  962. package/.worktrees/dafc71ad/src/machine-interface.js +0 -543
  963. package/.worktrees/dafc71ad/src/migrate.js +0 -127
  964. package/.worktrees/dafc71ad/src/module-impact.js +0 -166
  965. package/.worktrees/dafc71ad/src/module-resolve.js +0 -222
  966. package/.worktrees/dafc71ad/src/modules.js +0 -580
  967. package/.worktrees/dafc71ad/src/plan-adopt-waves.js +0 -126
  968. package/.worktrees/dafc71ad/src/progress/change-registry.js +0 -336
  969. package/.worktrees/dafc71ad/src/progress/consistency-doctor.js +0 -355
  970. package/.worktrees/dafc71ad/src/progress/shared.js +0 -36
  971. package/.worktrees/dafc71ad/src/progress/stage-machine.js +0 -594
  972. package/.worktrees/dafc71ad/src/progress/step-store.js +0 -265
  973. package/.worktrees/dafc71ad/src/progress.js +0 -1304
  974. package/.worktrees/dafc71ad/src/quick-recommend.js +0 -115
  975. package/.worktrees/dafc71ad/src/quicklog.js +0 -883
  976. package/.worktrees/dafc71ad/src/review-tier.js +0 -77
  977. package/.worktrees/dafc71ad/src/run/command.js +0 -1641
  978. package/.worktrees/dafc71ad/src/run/complete-handlers.js +0 -1552
  979. package/.worktrees/dafc71ad/src/run/complete.js +0 -1259
  980. package/.worktrees/dafc71ad/src/run/concurrent-detect.js +0 -156
  981. package/.worktrees/dafc71ad/src/run/gates.js +0 -1111
  982. package/.worktrees/dafc71ad/src/run/multi-repo-context.js +0 -208
  983. package/.worktrees/dafc71ad/src/run/next.js +0 -128
  984. package/.worktrees/dafc71ad/src/run/prompt.js +0 -843
  985. package/.worktrees/dafc71ad/src/run/quick-audit.js +0 -186
  986. package/.worktrees/dafc71ad/src/run/scan-profile.js +0 -269
  987. package/.worktrees/dafc71ad/src/run/shared.js +0 -1562
  988. package/.worktrees/dafc71ad/src/run/stage.js +0 -587
  989. package/.worktrees/dafc71ad/src/run.js +0 -23
  990. package/.worktrees/dafc71ad/src/scan-diff.js +0 -388
  991. package/.worktrees/dafc71ad/src/scan-postcheck.js +0 -524
  992. package/.worktrees/dafc71ad/src/scan-staleness.js +0 -95
  993. package/.worktrees/dafc71ad/src/setup.js +0 -414
  994. package/.worktrees/dafc71ad/src/sillyhub-mcp/client.js +0 -597
  995. package/.worktrees/dafc71ad/src/sillyhub-mcp/config.js +0 -62
  996. package/.worktrees/dafc71ad/src/spec-dir-typo.js +0 -50
  997. package/.worktrees/dafc71ad/src/spec-sync.js +0 -358
  998. package/.worktrees/dafc71ad/src/stage-contract-engine.js +0 -171
  999. package/.worktrees/dafc71ad/src/stage-contract-spec.js +0 -551
  1000. package/.worktrees/dafc71ad/src/stage-contract.js +0 -948
  1001. package/.worktrees/dafc71ad/src/stage-review.js +0 -597
  1002. package/.worktrees/dafc71ad/src/stages/archive.js +0 -199
  1003. package/.worktrees/dafc71ad/src/stages/brainstorm-auto.js +0 -285
  1004. package/.worktrees/dafc71ad/src/stages/brainstorm.js +0 -624
  1005. package/.worktrees/dafc71ad/src/stages/cmd-existence.js +0 -145
  1006. package/.worktrees/dafc71ad/src/stages/doctor.js +0 -540
  1007. package/.worktrees/dafc71ad/src/stages/execute.js +0 -1277
  1008. package/.worktrees/dafc71ad/src/stages/explore.js +0 -43
  1009. package/.worktrees/dafc71ad/src/stages/index.js +0 -29
  1010. package/.worktrees/dafc71ad/src/stages/knowledge.js +0 -514
  1011. package/.worktrees/dafc71ad/src/stages/plan-postcheck.js +0 -1398
  1012. package/.worktrees/dafc71ad/src/stages/plan.js +0 -655
  1013. package/.worktrees/dafc71ad/src/stages/quick.js +0 -167
  1014. package/.worktrees/dafc71ad/src/stages/scan.js +0 -608
  1015. package/.worktrees/dafc71ad/src/stages/status.js +0 -64
  1016. package/.worktrees/dafc71ad/src/stages/verify.js +0 -246
  1017. package/.worktrees/dafc71ad/src/sync.js +0 -1470
  1018. package/.worktrees/dafc71ad/src/task-review.js +0 -1498
  1019. package/.worktrees/dafc71ad/src/taskcard-placeholders.js +0 -21
  1020. package/.worktrees/dafc71ad/src/taskcard.js +0 -250
  1021. package/.worktrees/dafc71ad/src/verify-postcheck.js +0 -1718
  1022. package/.worktrees/dafc71ad/src/verify-probes.js +0 -327
  1023. package/.worktrees/dafc71ad/src/version.js +0 -19
  1024. package/.worktrees/dafc71ad/src/workflow.js +0 -600
  1025. package/.worktrees/dafc71ad/src/workspace.js +0 -125
  1026. package/.worktrees/dafc71ad/src/worktree-apply.js +0 -1611
  1027. package/.worktrees/dafc71ad/src/worktree-deps.js +0 -668
  1028. package/.worktrees/dafc71ad/src/worktree.js +0 -1849
  1029. package/.worktrees/dafc71ad/templates/claude-instruction.md +0 -23
  1030. package/.worktrees/dafc71ad/templates/prompts/taskcard-rules.md +0 -29
  1031. package/.worktrees/dafc71ad/templates/prompts/testcase-design.md +0 -12
  1032. package/.worktrees/dafc71ad/templates/prompts/verify-probes.md +0 -32
  1033. package/.worktrees/dafc71ad/templates/workflows/archive-impact.yaml +0 -79
  1034. package/.worktrees/dafc71ad/templates/workflows/scan-docs.yaml +0 -132
  1035. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-archive/SKILL.md +0 -87
  1036. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-auto/SKILL.md +0 -93
  1037. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -114
  1038. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-commit/SKILL.md +0 -67
  1039. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-continue/SKILL.md +0 -47
  1040. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-doctor/SKILL.md +0 -76
  1041. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-execute/SKILL.md +0 -214
  1042. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-explore/SKILL.md +0 -102
  1043. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-export/SKILL.md +0 -57
  1044. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-init/SKILL.md +0 -177
  1045. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  1046. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-plan/SKILL.md +0 -156
  1047. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-propose/SKILL.md +0 -87
  1048. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-quick/SKILL.md +0 -116
  1049. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-resume/SKILL.md +0 -70
  1050. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-scan/SKILL.md +0 -79
  1051. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-state/SKILL.md +0 -64
  1052. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-status/SKILL.md +0 -54
  1053. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-verify/SKILL.md +0 -87
  1054. package/.worktrees/e58fcc4c/.claude/skills/sillyspec-workspace/SKILL.md +0 -175
  1055. package/.worktrees/e58fcc4c/.gitattributes +0 -2
  1056. package/.worktrees/e58fcc4c/.husky/pre-push +0 -20
  1057. package/.worktrees/e58fcc4c/README.md +0 -203
  1058. package/.worktrees/e58fcc4c/SKILL.md +0 -91
  1059. package/.worktrees/e58fcc4c/architecture-analysis.md +0 -503
  1060. package/.worktrees/e58fcc4c/bin/sillyspec.js +0 -2
  1061. package/.worktrees/e58fcc4c/eval/README.md +0 -86
  1062. package/.worktrees/e58fcc4c/eval/eval.config.json +0 -28
  1063. package/.worktrees/e58fcc4c/eval/lib/adapters/cli.mjs +0 -63
  1064. package/.worktrees/e58fcc4c/eval/lib/adapters/dryrun.mjs +0 -27
  1065. package/.worktrees/e58fcc4c/eval/lib/config.mjs +0 -82
  1066. package/.worktrees/e58fcc4c/eval/lib/db.mjs +0 -76
  1067. package/.worktrees/e58fcc4c/eval/lib/report.mjs +0 -120
  1068. package/.worktrees/e58fcc4c/eval/lib/runner.mjs +0 -157
  1069. package/.worktrees/e58fcc4c/eval/lib/tasks.mjs +0 -73
  1070. package/.worktrees/e58fcc4c/eval/lib/util.mjs +0 -107
  1071. package/.worktrees/e58fcc4c/eval/lib/workdir.mjs +0 -30
  1072. package/.worktrees/e58fcc4c/eval/run.mjs +0 -83
  1073. package/.worktrees/e58fcc4c/eval/tasks/001-slugify/files/package.json +0 -6
  1074. package/.worktrees/e58fcc4c/eval/tasks/001-slugify/solution/src/slugify.mjs +0 -26
  1075. package/.worktrees/e58fcc4c/eval/tasks/001-slugify/task.json +0 -6
  1076. package/.worktrees/e58fcc4c/eval/tasks/001-slugify/verify.mjs +0 -28
  1077. package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/package.json +0 -6
  1078. package/.worktrees/e58fcc4c/eval/tasks/002-each-day/files/src/dates.mjs +0 -4
  1079. package/.worktrees/e58fcc4c/eval/tasks/002-each-day/solution/src/dates.mjs +0 -30
  1080. package/.worktrees/e58fcc4c/eval/tasks/002-each-day/task.json +0 -6
  1081. package/.worktrees/e58fcc4c/eval/tasks/002-each-day/verify.mjs +0 -31
  1082. package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/data/notes.txt +0 -5
  1083. package/.worktrees/e58fcc4c/eval/tasks/003-word-report/files/package.json +0 -6
  1084. package/.worktrees/e58fcc4c/eval/tasks/003-word-report/solution/bin/report.mjs +0 -36
  1085. package/.worktrees/e58fcc4c/eval/tasks/003-word-report/task.json +0 -6
  1086. package/.worktrees/e58fcc4c/eval/tasks/003-word-report/verify.mjs +0 -38
  1087. package/.worktrees/e58fcc4c/logo.jpg +0 -0
  1088. package/.worktrees/e58fcc4c/package-lock.json +0 -977
  1089. package/.worktrees/e58fcc4c/package.json +0 -41
  1090. package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-Bq_Z2hne.js +0 -7446
  1091. package/.worktrees/e58fcc4c/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  1092. package/.worktrees/e58fcc4c/packages/dashboard/dist/favicon.jpg +0 -0
  1093. package/.worktrees/e58fcc4c/packages/dashboard/dist/index.html +0 -16
  1094. package/.worktrees/e58fcc4c/packages/dashboard/dist/logo.jpg +0 -0
  1095. package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-dashboard.html +0 -836
  1096. package/.worktrees/e58fcc4c/packages/dashboard/dist/prototype-overview.html +0 -256
  1097. package/.worktrees/e58fcc4c/packages/dashboard/package.json +0 -25
  1098. package/.worktrees/e58fcc4c/packages/dashboard/server/executor.js +0 -95
  1099. package/.worktrees/e58fcc4c/packages/dashboard/server/index.js +0 -679
  1100. package/.worktrees/e58fcc4c/packages/dashboard/server/parser.js +0 -526
  1101. package/.worktrees/e58fcc4c/packages/dashboard/server/watcher.js +0 -357
  1102. package/.worktrees/e58fcc4c/src/agent-session-log.js +0 -803
  1103. package/.worktrees/e58fcc4c/src/change-list.js +0 -290
  1104. package/.worktrees/e58fcc4c/src/change-risk-profile.js +0 -339
  1105. package/.worktrees/e58fcc4c/src/check-primitives.js +0 -65
  1106. package/.worktrees/e58fcc4c/src/classify-change.js +0 -109
  1107. package/.worktrees/e58fcc4c/src/commit-suggest.js +0 -202
  1108. package/.worktrees/e58fcc4c/src/config-cat.js +0 -88
  1109. package/.worktrees/e58fcc4c/src/config-schema.js +0 -328
  1110. package/.worktrees/e58fcc4c/src/constants.js +0 -97
  1111. package/.worktrees/e58fcc4c/src/contract-matrix.js +0 -533
  1112. package/.worktrees/e58fcc4c/src/datetime.js +0 -20
  1113. package/.worktrees/e58fcc4c/src/db-engine.js +0 -55
  1114. package/.worktrees/e58fcc4c/src/db.js +0 -381
  1115. package/.worktrees/e58fcc4c/src/decision-distill.js +0 -517
  1116. package/.worktrees/e58fcc4c/src/dispatch/backends/local-agent.js +0 -155
  1117. package/.worktrees/e58fcc4c/src/dispatch/backends/sillyhub-mcp.js +0 -245
  1118. package/.worktrees/e58fcc4c/src/dispatch/probe.js +0 -246
  1119. package/.worktrees/e58fcc4c/src/dispatch/strategy.js +0 -121
  1120. package/.worktrees/e58fcc4c/src/docs-check.js +0 -825
  1121. package/.worktrees/e58fcc4c/src/docs-debt.js +0 -393
  1122. package/.worktrees/e58fcc4c/src/docs-gate.js +0 -107
  1123. package/.worktrees/e58fcc4c/src/doctor-diagnostics.js +0 -1099
  1124. package/.worktrees/e58fcc4c/src/endpoint-extractor.js +0 -409
  1125. package/.worktrees/e58fcc4c/src/foreign-declared.js +0 -155
  1126. package/.worktrees/e58fcc4c/src/fs-atomic.js +0 -73
  1127. package/.worktrees/e58fcc4c/src/git-helper.js +0 -150
  1128. package/.worktrees/e58fcc4c/src/hooks/claude-pre-tool-use.cjs +0 -130
  1129. package/.worktrees/e58fcc4c/src/hooks/worktree-guard.js +0 -892
  1130. package/.worktrees/e58fcc4c/src/index.js +0 -2854
  1131. package/.worktrees/e58fcc4c/src/init.js +0 -626
  1132. package/.worktrees/e58fcc4c/src/knowledge-match.js +0 -231
  1133. package/.worktrees/e58fcc4c/src/local-detect.js +0 -128
  1134. package/.worktrees/e58fcc4c/src/local-register.js +0 -104
  1135. package/.worktrees/e58fcc4c/src/machine-interface.js +0 -543
  1136. package/.worktrees/e58fcc4c/src/migrate.js +0 -127
  1137. package/.worktrees/e58fcc4c/src/module-impact.js +0 -166
  1138. package/.worktrees/e58fcc4c/src/module-resolve.js +0 -222
  1139. package/.worktrees/e58fcc4c/src/modules.js +0 -580
  1140. package/.worktrees/e58fcc4c/src/plan-adopt-waves.js +0 -126
  1141. package/.worktrees/e58fcc4c/src/progress/change-registry.js +0 -336
  1142. package/.worktrees/e58fcc4c/src/progress/consistency-doctor.js +0 -355
  1143. package/.worktrees/e58fcc4c/src/progress/shared.js +0 -36
  1144. package/.worktrees/e58fcc4c/src/progress/stage-machine.js +0 -594
  1145. package/.worktrees/e58fcc4c/src/progress/step-store.js +0 -265
  1146. package/.worktrees/e58fcc4c/src/progress.js +0 -1304
  1147. package/.worktrees/e58fcc4c/src/quick-recommend.js +0 -115
  1148. package/.worktrees/e58fcc4c/src/quicklog.js +0 -883
  1149. package/.worktrees/e58fcc4c/src/review-tier.js +0 -77
  1150. package/.worktrees/e58fcc4c/src/run/command.js +0 -1641
  1151. package/.worktrees/e58fcc4c/src/run/complete-handlers.js +0 -1552
  1152. package/.worktrees/e58fcc4c/src/run/complete.js +0 -1259
  1153. package/.worktrees/e58fcc4c/src/run/concurrent-detect.js +0 -156
  1154. package/.worktrees/e58fcc4c/src/run/gates.js +0 -1111
  1155. package/.worktrees/e58fcc4c/src/run/multi-repo-context.js +0 -208
  1156. package/.worktrees/e58fcc4c/src/run/next.js +0 -128
  1157. package/.worktrees/e58fcc4c/src/run/prompt.js +0 -843
  1158. package/.worktrees/e58fcc4c/src/run/quick-audit.js +0 -186
  1159. package/.worktrees/e58fcc4c/src/run/scan-profile.js +0 -269
  1160. package/.worktrees/e58fcc4c/src/run/shared.js +0 -1562
  1161. package/.worktrees/e58fcc4c/src/run/stage.js +0 -587
  1162. package/.worktrees/e58fcc4c/src/run.js +0 -23
  1163. package/.worktrees/e58fcc4c/src/scan-diff.js +0 -388
  1164. package/.worktrees/e58fcc4c/src/scan-postcheck.js +0 -524
  1165. package/.worktrees/e58fcc4c/src/scan-staleness.js +0 -95
  1166. package/.worktrees/e58fcc4c/src/setup.js +0 -414
  1167. package/.worktrees/e58fcc4c/src/sillyhub-mcp/client.js +0 -597
  1168. package/.worktrees/e58fcc4c/src/sillyhub-mcp/config.js +0 -62
  1169. package/.worktrees/e58fcc4c/src/spec-dir-typo.js +0 -50
  1170. package/.worktrees/e58fcc4c/src/spec-sync.js +0 -358
  1171. package/.worktrees/e58fcc4c/src/stage-contract-engine.js +0 -171
  1172. package/.worktrees/e58fcc4c/src/stage-contract-spec.js +0 -551
  1173. package/.worktrees/e58fcc4c/src/stage-contract.js +0 -948
  1174. package/.worktrees/e58fcc4c/src/stage-review.js +0 -597
  1175. package/.worktrees/e58fcc4c/src/stages/archive.js +0 -199
  1176. package/.worktrees/e58fcc4c/src/stages/brainstorm-auto.js +0 -285
  1177. package/.worktrees/e58fcc4c/src/stages/brainstorm.js +0 -624
  1178. package/.worktrees/e58fcc4c/src/stages/cmd-existence.js +0 -145
  1179. package/.worktrees/e58fcc4c/src/stages/doctor.js +0 -540
  1180. package/.worktrees/e58fcc4c/src/stages/execute.js +0 -1277
  1181. package/.worktrees/e58fcc4c/src/stages/explore.js +0 -43
  1182. package/.worktrees/e58fcc4c/src/stages/index.js +0 -29
  1183. package/.worktrees/e58fcc4c/src/stages/knowledge.js +0 -514
  1184. package/.worktrees/e58fcc4c/src/stages/plan-postcheck.js +0 -1398
  1185. package/.worktrees/e58fcc4c/src/stages/plan.js +0 -655
  1186. package/.worktrees/e58fcc4c/src/stages/quick.js +0 -167
  1187. package/.worktrees/e58fcc4c/src/stages/scan.js +0 -608
  1188. package/.worktrees/e58fcc4c/src/stages/status.js +0 -64
  1189. package/.worktrees/e58fcc4c/src/stages/verify.js +0 -246
  1190. package/.worktrees/e58fcc4c/src/sync.js +0 -1470
  1191. package/.worktrees/e58fcc4c/src/task-review.js +0 -1498
  1192. package/.worktrees/e58fcc4c/src/taskcard-placeholders.js +0 -21
  1193. package/.worktrees/e58fcc4c/src/taskcard.js +0 -250
  1194. package/.worktrees/e58fcc4c/src/verify-postcheck.js +0 -1718
  1195. package/.worktrees/e58fcc4c/src/verify-probes.js +0 -327
  1196. package/.worktrees/e58fcc4c/src/version.js +0 -19
  1197. package/.worktrees/e58fcc4c/src/workflow.js +0 -600
  1198. package/.worktrees/e58fcc4c/src/workspace.js +0 -125
  1199. package/.worktrees/e58fcc4c/src/worktree-apply.js +0 -1611
  1200. package/.worktrees/e58fcc4c/src/worktree-deps.js +0 -668
  1201. package/.worktrees/e58fcc4c/src/worktree.js +0 -1849
  1202. package/.worktrees/e58fcc4c/templates/claude-instruction.md +0 -23
  1203. package/.worktrees/e58fcc4c/templates/prompts/taskcard-rules.md +0 -29
  1204. package/.worktrees/e58fcc4c/templates/prompts/testcase-design.md +0 -12
  1205. package/.worktrees/e58fcc4c/templates/prompts/verify-probes.md +0 -32
  1206. package/.worktrees/e58fcc4c/templates/workflows/archive-impact.yaml +0 -79
  1207. package/.worktrees/e58fcc4c/templates/workflows/scan-docs.yaml +0 -132
@@ -1,1718 +0,0 @@
1
- /**
2
- * Verify Postcheck — CLI 客观测试执行与自报告对账
3
- *
4
- * verify 阶段历史上完全依赖 agent 自报告(跑没跑测试、结果如何全写在
5
- * verify-result.md 里),可被文案绕过。此模块让 CLI 在 verify 完成时
6
- * 亲自执行 local.yaml 配置的测试命令,与 verify-result.md 的结论对账:
7
- * 自报告 PASS 但实测失败 → 阻断 verify 完成。
8
- *
9
- * 未配置 commands.test(或标记 unavailable)时降级为 warning 不阻断,
10
- * 兼容无测试项目。
11
- *
12
- * test_strategy 支持(D-002@v1;D-005@v2 扩 skip/evidence-auto):
13
- * - full(默认):整跑 commands.test(brownfield 行为不变)
14
- * - module:按 local.yaml modules 映射,仅跑 git diff 命中的模块子集
15
- * 测试,避免 monorepo 全量测试超 gate timeout。
16
- * - skip:真跳过测试(不再回退全量——兑现声明语义,verify 输出显式
17
- * 标注留审计痕迹,R-07;既有 skipped 状态机承载)。
18
- * - evidence-auto:按变更目录 module-impact.md 影响类型推荐检查组合
19
- * (行为→module 聚焦测试、文档/prompt→docs-check、门禁
20
- * 契约→gate;缺失/不可解析降级 module 并注记),推荐结果
21
- * 由 resolveTestStrategy 统一产出(契约 test_strategy_resolution,
22
- * task-12 经 run/prompt.js 注入 prompt 供用户否决)。
23
- */
24
-
25
- import { execSync } from 'child_process'
26
- import { gitQuiet } from './git-helper.js'
27
- import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'fs'
28
- import { join } from 'path'
29
- import { verifyApiParity } from './contract-matrix.js'
30
- import { parseFileChangeListDetailed, pathMatches } from './change-list.js'
31
- import { filterDeliverableFiles } from './worktree-apply.js'
32
-
33
- // 测试命令最长执行时间;超时视为失败(防止 CLI 被挂起的测试卡死)
34
- const TEST_TIMEOUT_MS = Number(process.env.SILLYSPEC_TEST_TIMEOUT_MS) || 10 * 60 * 1000
35
- const OUTPUT_TAIL_CHARS = 4000
36
-
37
- /**
38
- * 行尾归一(坑 verify-modules-crlf-blanket-fallback,2026-08-20 实证):Windows 仓的
39
- * local.yaml 常为 CRLF(编辑器/CLI 写入),手写行扫描器的逐行正则里 `.` 不匹配 `\r`、
40
- * `$`(无 m 标志)又要求真串尾——`\r` 残留行尾导致条目正则整条失配。实证受害:
41
- * extractModules 返回 null(modules 映射恒失效 → 永远回退全量 → 600s 默认超时必炸)、
42
- * extractKnownFailures 块式只捕获第一条。统一在解析入口归一,JS 的 `\r?\n` 拆分与
43
- * yaml 库均兼容 LF 文本(零回归)。
44
- */
45
- function normalizeLineEndings(text) {
46
- return String(text || '').replace(/\r\n?/g, '\n')
47
- }
48
-
49
- /**
50
- * 从 local.yaml 文本提取 commands.test。
51
- * 轻量正则(与 worktree-deps/scan-postcheck 同风格,不引 yaml 依赖):
52
- * 支持带引号与不带引号两种写法;'unavailable' 视为未配置。
53
- */
54
- export function extractTestCommand(yamlText) {
55
- if (!yamlText) return null
56
- const doubleQuoted = yamlText.match(/^\s*test:\s*"([^"]+)"\s*(?:#.*)?$/m)
57
- const singleQuoted = yamlText.match(/^\s*test:\s*'([^']+)'\s*(?:#.*)?$/m)
58
- const quoted = doubleQuoted || singleQuoted
59
- if (quoted && quoted[1]) {
60
- return quoted[1].toLowerCase() === 'unavailable' ? null : quoted[1].trim()
61
- }
62
- const bare = yamlText.match(/^\s*test:\s*([^\n#"']+?)\s*(?:#.*)?$/m)
63
- if (bare && bare[1]) {
64
- const cmd = bare[1].trim()
65
- return cmd.toLowerCase() === 'unavailable' ? null : cmd
66
- }
67
- return null
68
- }
69
-
70
- /**
71
- * 从 local.yaml 文本提取 commands.lint(2026-08-21 审查 CLI-1:lint 对账)。
72
- * 与 extractTestCommand 同风格同容错(带引号/不带引号/unavailable)。
73
- * 模块内私有(runVerifyLintCheck 消费;extractTestCommand 系 export 供 test)。
74
- */
75
- function extractLintCommand(yamlText) {
76
- if (!yamlText) return null
77
- const doubleQuoted = yamlText.match(/^\s*lint:\s*"([^"]+)"\s*(?:#.*)?$/m)
78
- const singleQuoted = yamlText.match(/^\s*lint:\s*'([^']+)'\s*(?:#.*)?$/m)
79
- const quoted = doubleQuoted || singleQuoted
80
- if (quoted && quoted[1]) {
81
- return quoted[1].toLowerCase() === 'unavailable' ? null : quoted[1].trim()
82
- }
83
- const bare = yamlText.match(/^\s*lint:\s*([^\n#"']+?)\s*(?:#.*)?$/m)
84
- if (bare && bare[1]) {
85
- const cmd = bare[1].trim()
86
- return cmd.toLowerCase() === 'unavailable' ? null : cmd
87
- }
88
- return null
89
- }
90
-
91
- /**
92
- * verify --done 实测跑 local.yaml commands.lint(2026-08-21 审查 CLI-1)。
93
- * 此前 lint 全靠 agent 自跑自报("我跑过 lint 了"纯口头),与 test 侧的对账不对称——
94
- * agent 偷懒漏跑时格式债被推迟到用户 commit 才被 pre-commit hook 炸出。
95
- * advisory 起步:失败只打印不阻断(test 门已 fail-closed,lint 门观察期后再升级)。
96
- * 信任边界与 runVerifyTestCheck 一致:命令只来源于主仓 .sillyspec/local.yaml。
97
- */
98
- export function runVerifyLintCheck({ cwd, specBase }) {
99
- const localYamlPath = join(specBase, 'local.yaml')
100
- const yamlText = existsSync(localYamlPath) ? readFileSync(localYamlPath, 'utf8') : null
101
- const command = extractLintCommand(yamlText)
102
-
103
- if (!command) {
104
- return {
105
- status: 'skipped',
106
- command: null,
107
- exitCode: null,
108
- durationMs: null,
109
- outputTail: null,
110
- reason: yamlText
111
- ? 'local.yaml 未配置 commands.lint(或标记 unavailable)'
112
- : `local.yaml 不存在(${localYamlPath})`,
113
- }
114
- }
115
-
116
- const LINT_TIMEOUT_MS = Number(process.env.SILLYSPEC_LINT_TIMEOUT_MS) || 3 * 60 * 1000
117
- const startedAt = Date.now()
118
- let exitCode = 0
119
- let output = ''
120
- let reason = null
121
- try {
122
- output = execSync(command, {
123
- cwd,
124
- encoding: 'utf8',
125
- timeout: LINT_TIMEOUT_MS,
126
- maxBuffer: 32 * 1024 * 1024,
127
- stdio: ['ignore', 'pipe', 'pipe'],
128
- })
129
- } catch (e) {
130
- exitCode = typeof e.status === 'number' ? e.status : 1
131
- output = [e.stdout, e.stderr].filter(Boolean).join('\n') || e.message
132
- reason = e.signal === 'SIGTERM' && Date.now() - startedAt >= LINT_TIMEOUT_MS
133
- ? `lint 命令超时(>${LINT_TIMEOUT_MS / 1000}s)`
134
- : `lint 命令退出码 ${exitCode}`
135
- }
136
- const durationMs = Date.now() - startedAt
137
- const outputTail = output.length > OUTPUT_TAIL_CHARS ? '…' + output.slice(-OUTPUT_TAIL_CHARS) : output
138
-
139
- return {
140
- status: exitCode === 0 ? 'passed' : 'failed',
141
- command,
142
- exitCode,
143
- durationMs,
144
- outputTail,
145
- reason: exitCode === 0 ? null : reason,
146
- }
147
- }
148
-
149
- /** 打印 lint 实测结果(advisory:失败不阻断,只把口头汇报对上账) */
150
- export function printVerifyLintCheck(result) {
151
- if (result.status === 'skipped') {
152
- console.warn(`\n⚠️ Verify lint 实测跳过:${result.reason}`)
153
- return
154
- }
155
- if (result.status === 'passed') {
156
- console.log(`\n✅ Verify lint 实测通过:\`${result.command}\` 退出码 0(${(result.durationMs / 1000).toFixed(1)}s)`)
157
- return
158
- }
159
- console.error(`\n⚠️ Verify lint 实测失败(advisory,不阻断本次完成):\`${result.command}\` — ${result.reason}`)
160
- console.error(' agent 的 lint 自报告与实测不符时以实测为准;请修复后重跑,避免格式债推迟到 commit 被 pre-commit hook 拦截。')
161
- if (result.outputTail) {
162
- const tail = result.outputTail.split('\n').slice(-15).join('\n')
163
- console.error(' 输出(末尾):')
164
- for (const line of tail.split('\n')) console.error(` | ${line}`)
165
- }
166
- }
167
-
168
- /**
169
- * 从 local.yaml 文本提取顶层 test_strategy。
170
- * 轻量正则(与 extractTestCommand 同风格,不引 yaml 依赖)。
171
- *
172
- * D-005@v2:识别 skip(真跳过)与 evidence-auto(按 module-impact 推荐)两新值;
173
- * 未知值仍回 null(缺省全量口径不动)。
174
- *
175
- * @param {string} yamlText
176
- * @returns {'full'|'module'|'skip'|'evidence-auto'|null} - 解析到的策略;缺省/无法解析返回 null(调用方按 full 处理)
177
- */
178
- export function extractTestStrategy(yamlText) {
179
- if (!yamlText) return null
180
- // 值字符集含 '-'(evidence-auto);不含 '.'/空格,与顶层标量枚举写法一致
181
- const m = yamlText.match(/^\s*test_strategy:\s*([A-Za-z_-]+)\s*(?:#.*)?$/m)
182
- if (!m || !m[1]) return null
183
- const v = m[1].trim().toLowerCase()
184
- if (v === 'module') return 'module'
185
- if (v === 'full') return 'full'
186
- if (v === 'skip') return 'skip'
187
- if (v === 'evidence-auto') return 'evidence-auto'
188
- return null
189
- }
190
-
191
- /**
192
- * 计算全量 fallback 的原因文本(供 printVerifyTestCheck / facet 给 agent/daemon 明示)。
193
- *
194
- * 返回 null 表示不需要 hint:显式 test_strategy:full(用户有意跑全量),
195
- * 或 test_strategy:module 已成功命中模块子集(该情况不会走到全量路径)。
196
- * 其余走全量路径的情况都返回原因字符串,让结果可正确解读——
197
- * 否则 agent/daemon 会把"全量 commands.test"当成"按变更范围测的",误把
198
- * 未变更模块的预存错误归因到本次变更(见 3.24 verify 坑1)。
199
- *
200
- * 语义对齐 runVerifyTestCheck 的分支:
201
- * - strategy==='full' → null
202
- * - strategy==='module' 但无有效 modules 块 → hint
203
- * - strategy==='module' 有块但 git 不可用(hitCount=-1)→ hint
204
- * - strategy==='module' 有块但 0 命中(hitCount=0)→ hint
205
- * - strategy==='module' 有块且命中(hitCount>0)→ null(走子集)
206
- * - strategy===null(缺省)→ hint(默认全量)
207
- *
208
- * 注:strategy 仅接收 full/module/null——skip 短路在其上游(runVerifyTestCheck 的
209
- * skip 分支)、evidence-auto 经 resolveTestStrategy 解析为生效策略后才进本函数,
210
- * 两者的 hint 语义由各自分支承载,本函数行为不变(D-005@v2)。
211
- *
212
- * @param {object} ctx
213
- * @param {'full'|'module'|null} ctx.strategy
214
- * @param {boolean} ctx.modulesPresent - extractModules 是否返回有效映射
215
- * @param {number} ctx.hitCount - git diff 命中的模块数;-1 表示 git 不可用/非仓库
216
- * @returns {string|null}
217
- */
218
- export function computeFullFallbackReason({ strategy, modulesPresent, hitCount }) {
219
- if (strategy === 'full') return null
220
- if (strategy === 'module') {
221
- if (!modulesPresent) {
222
- return 'test_strategy: module 但 local.yaml 未配置有效的 modules: 块(需 inline flow: name: { path, test }),回退全量'
223
- }
224
- if (hitCount < 0) {
225
- return 'test_strategy: module 但 git 不可用/非 git 仓库,无法判定命中模块,回退全量'
226
- }
227
- if (hitCount === 0) {
228
- return 'test_strategy: module 但本次 git diff 未命中任何已配置 modules,回退全量'
229
- }
230
- return null
231
- }
232
- // strategy === null(缺省 → 默认全量)
233
- return 'local.yaml 未配置 test_strategy(默认全量 commands.test,未按变更范围收窄)'
234
- }
235
-
236
- // ── evidence-auto 推荐逻辑(D-005@v2 / task-11,契约 test_strategy_resolution)──
237
- // 按 W3 检查选择口径把 module-impact.md 的影响面映射为检查组合:
238
- // 行为类(源码/逻辑/数据结构/接口/调用关系/配置/新增/修改)→ module 聚焦测试
239
- // 文档/prompt 类(*.md、docs/** 等)→ docs-check
240
- // 门禁/契约类(路径含 gate/contract)→ sillyspec gate
241
- // module-impact.md 缺失/不可解析 → 降级 module 策略并注记(多测不漏测)
242
-
243
- /** 行为类影响信号词(module-impact.js 骨架「影响类型说明」词表 + 通用「修改/删除」)。 */
244
- const IMPACT_BEHAVIORAL_TOKENS = ['逻辑变更', '数据结构变更', '接口变更', '调用关系变更', '配置变更', '新增', '修改', '删除']
245
-
246
- /** 文档/prompt 面:md 系扩展名或 docs/ 前缀(.sillyspec/docs 同入)。 */
247
- function isDocsImpactPath(p) {
248
- const n = String(p).replace(/\\/g, '/')
249
- return /\.(mdx?|markdown|txt)$/i.test(n) || n.startsWith('docs/') || n.startsWith('doc/') || n.startsWith('.sillyspec/docs/')
250
- }
251
-
252
- /** 门禁/契约面:路径含 gate/contract(stage-contract*.js / docs-gate.js / contract-matrix.js 等)。 */
253
- function isGateImpactPath(p) {
254
- return /(gate|contract)/i.test(String(p))
255
- }
256
-
257
- /** 从行文本提取路径样 token:优先反引号包裹(骨架表格用),再裸路径(扩展名必须字母开头)。 */
258
- function collectPathTokens(text) {
259
- const tokens = new Set()
260
- for (const m of String(text).matchAll(/`([^`]+)`/g)) {
261
- const t = m[1].trim()
262
- if (t) tokens.add(t)
263
- }
264
- const stripped = String(text).replace(/`[^`]*`/g, ' ')
265
- for (const m of stripped.matchAll(/[A-Za-z_][\w./\\-]*\.[A-Za-z][\w]{0,9}/g)) {
266
- tokens.add(m[0])
267
- }
268
- return [...tokens]
269
- }
270
-
271
- /**
272
- * 解析 module-impact.md 的「模块影响矩阵」+「未匹配文件」两节,按检查面归类影响证据。
273
- * 纯机械启发式(确定性:同输入同输出);矩阵行 <!--TODO--> 未回填 → 保守计行为类
274
- * (影响面未知时多测不漏测)。矩阵节缺失 / 无数据行 → parseable=false(调用方降级)。
275
- *
276
- * @param {string|null} mdText
277
- * @returns {{ parseable: boolean, behavioral: string[], docs: string[], gate: string[] }}
278
- */
279
- function classifyModuleImpactEvidence(mdText) {
280
- const out = { parseable: false, behavioral: [], docs: [], gate: [] }
281
- if (!mdText || !String(mdText).trim()) return out
282
- const lines = normalizeLineEndings(String(mdText)).split('\n')
283
- let section = null // 'matrix' | 'unmatched' | null
284
- let matrixRows = 0
285
- const consumeRow = (rowText) => {
286
- const tokens = collectPathTokens(rowText)
287
- let classified = 0
288
- for (const t of tokens) {
289
- if (isDocsImpactPath(t)) { out.docs.push(t); classified++ }
290
- else if (isGateImpactPath(t)) { out.gate.push(t); classified++ }
291
- else { out.behavioral.push(t); classified++ }
292
- }
293
- // 无路径 token 的行:落回影响类型信号词(如「| setup | 修改 | 枚举与新键 |」)
294
- if (classified === 0) {
295
- const tok = IMPACT_BEHAVIORAL_TOKENS.find((w) => rowText.includes(w))
296
- if (tok) { out.behavioral.push(`(影响类型:${tok})`); classified++ }
297
- }
298
- // 矩阵行 <!--TODO--> 未回填 → 影响面未知,保守计行为类
299
- if (String(rowText).includes('<!--TODO')) { out.behavioral.push('<!--TODO--> 未回填行'); classified++ }
300
- return classified
301
- }
302
- for (const line of lines) {
303
- const h = line.match(/^##+\s*(.+?)\s*$/)
304
- if (h) {
305
- const t = h[1]
306
- section = t.includes('模块影响矩阵') ? 'matrix' : t.includes('未匹配文件') ? 'unmatched' : null
307
- continue
308
- }
309
- if (!section) continue
310
- const trimmed = line.trim()
311
- if (section === 'matrix' && trimmed.startsWith('|')) {
312
- const cells = line.split('|').slice(1, -1).map((c) => c.trim())
313
- if (cells.length === 0) continue
314
- if (cells.every((c) => /^[-:\s]*$/.test(c))) continue // 分隔行 |---|---|
315
- if (cells[0] === '模块' || cells.includes('变更文件') || cells.includes('影响类型')) continue // 表头
316
- matrixRows++
317
- consumeRow(trimmed)
318
- } else if (section === 'unmatched') {
319
- // 骨架产出 `- \`path\` <!--TODO-->` 列表行;手写形态可能是 `| 文件 | 处置说明 |` 表行
320
- const bullet = trimmed.match(/^-\s+(.+)$/)
321
- if (bullet) { consumeRow(bullet[1]); continue }
322
- if (trimmed.startsWith('|')) {
323
- const cells = line.split('|').slice(1, -1).map((c) => c.trim())
324
- if (cells.length === 0) continue
325
- if (cells.every((c) => /^[-:\s]*$/.test(c))) continue
326
- if (cells[0] === '文件') continue
327
- consumeRow(trimmed)
328
- }
329
- }
330
- }
331
- out.parseable = matrixRows > 0 && (out.behavioral.length + out.docs.length + out.gate.length) > 0
332
- return out
333
- }
334
-
335
- /**
336
- * resolveTestStrategy — test_strategy 解析 + evidence-auto 推荐统一入口
337
- * (契约 test_strategy_resolution,2026-08-23 adopt-harness-practices task-11)。
338
- *
339
- * 非 evidence-auto(full/module/skip/未配置 null)→ 原样透传 strategy 且
340
- * evidence_auto_recommendation=null(full/module/缺省消费路径逐字不变);
341
- * evidence-auto → 按 module-impact.md 影响面解析生效策略 + 推荐检查组合:
342
- * - 含行为类影响 → strategy='module'(聚焦测试)
343
- * - 纯文档/prompt、门禁/契约影响(无行为类)→ strategy='skip'(测试不在推荐组合内)
344
- * - module-impact.md 缺失/不可解析 → 降级 strategy='module' 且 degraded 注记
345
- *
346
- * @param {object} opts
347
- * @param {string|null} opts.yamlText - local.yaml 全文(与 extractTestStrategy 同源)
348
- * @param {string|null} [opts.changeDir] - 变更目录(定位 module-impact.md;evidence-auto 时缺省 → 降级)
349
- * @param {string|null} [opts.moduleImpactText] - module-impact.md 文本(测试注入用;提供则不读盘)
350
- * @returns {{ strategy: 'full'|'module'|'skip'|'evidence-auto'|null, evidence_auto_recommendation: object|null }}
351
- * 下游契约:task-12 消费 evidence_auto_recommendation(run/prompt.js 注入),
352
- * task-13 消费 strategy(语义回归锁定)。两字段为 provides 契约的全部内容。
353
- */
354
- export function resolveTestStrategy({ yamlText, changeDir = null, moduleImpactText = null }) {
355
- const configured = extractTestStrategy(yamlText ?? null)
356
- if (configured !== 'evidence-auto') {
357
- // full / module / skip / 未配置(null)——原样透传,不掺推荐语义
358
- return { strategy: configured, evidence_auto_recommendation: null }
359
- }
360
-
361
- let mdText = moduleImpactText
362
- if (mdText == null && changeDir) {
363
- const p = join(changeDir, 'module-impact.md')
364
- try {
365
- mdText = existsSync(p) ? readFileSync(p, 'utf8') : null
366
- } catch { mdText = null }
367
- }
368
- const ev = classifyModuleImpactEvidence(mdText)
369
- const sample = (arr) => arr.slice(0, 5).join('、') + (arr.length > 5 ? ` 等 ${arr.length} 处` : '')
370
-
371
- if (!ev.parseable) {
372
- const degradedReason = changeDir == null && moduleImpactText == null
373
- ? '未提供变更目录(changeDir),无法定位 module-impact.md'
374
- : 'module-impact.md 缺失或不可解析(无「模块影响矩阵」数据行)'
375
- const summary = [
376
- 'test_strategy: evidence-auto 推荐:',
377
- `- ⚠️ 降级注记:${degradedReason}——已降级 module 策略(多测不漏测),推荐结果不可信时请显式设 test_strategy: full/module。`,
378
- '- 可在 verify-result.md 否决本推荐并改跑全量(显式设 test_strategy: full)。',
379
- ].join('\n')
380
- return {
381
- strategy: 'module',
382
- evidence_auto_recommendation: {
383
- configured_strategy: 'evidence-auto',
384
- resolved_strategy: 'module',
385
- degraded: true,
386
- degraded_reason: degradedReason,
387
- impact: { behavioral: [], docs: [], gate: [] },
388
- checks: [
389
- { kind: 'module-tests', reason: `${degradedReason} → 降级 test_strategy=module(多测不漏测)` },
390
- ],
391
- summary,
392
- },
393
- }
394
- }
395
-
396
- const checks = []
397
- if (ev.behavioral.length > 0) {
398
- checks.push({ kind: 'module-tests', reason: `行为类影响 ${ev.behavioral.length} 处(${sample(ev.behavioral)})→ test_strategy=module 聚焦测试` })
399
- }
400
- if (ev.docs.length > 0) {
401
- checks.push({ kind: 'docs-check', reason: `文档/prompt 类影响 ${ev.docs.length} 处(${sample(ev.docs)})→ sillyspec docs check` })
402
- }
403
- if (ev.gate.length > 0) {
404
- checks.push({ kind: 'gate', reason: `门禁/契约类影响 ${ev.gate.length} 处(${sample(ev.gate)})→ sillyspec gate` })
405
- }
406
- // 生效测试策略:有行为类影响 → module;纯文档/门禁面 → skip(测试不在推荐组合内)
407
- const resolved = ev.behavioral.length > 0 ? 'module' : 'skip'
408
- const summaryLines = ['test_strategy: evidence-auto 推荐(依据变更目录 module-impact.md 影响面):']
409
- for (const c of checks) summaryLines.push(`- ${c.reason}`)
410
- if (resolved === 'skip') {
411
- summaryLines.push('- 测试不在推荐组合内(module-impact.md 无行为类影响)——CLI 实测将跳过;如需全量实测,可在 verify-result.md 否决本推荐并显式设 test_strategy: full。')
412
- } else {
413
- summaryLines.push('- 可在 verify-result.md 否决本推荐并改跑全量(显式设 test_strategy: full)。')
414
- }
415
- return {
416
- strategy: resolved,
417
- evidence_auto_recommendation: {
418
- configured_strategy: 'evidence-auto',
419
- resolved_strategy: resolved,
420
- degraded: false,
421
- degraded_reason: null,
422
- impact: { behavioral: ev.behavioral, docs: ev.docs, gate: ev.gate },
423
- checks,
424
- summary: summaryLines.join('\n'),
425
- },
426
- }
427
- }
428
-
429
- /**
430
- * 从 local.yaml 文本解析 modules 映射块。
431
- * 设计约定(见 change 2026-07-10-tooling-followups design.md #2 方案 A):
432
- *
433
- * modules:
434
- * backend: { path: "backend/", test: "cd backend && uv run pytest" }
435
- * frontend: { path: "frontend/", test: "cd frontend && pnpm test" }
436
- *
437
- * 每个模块一行 inline flow mapping,含 path 与 test 两个键。
438
- * 轻量行扫描(与 modules.js parseModuleMapSimple 同风格,不引 yaml 依赖)。
439
- *
440
- * @param {string} yamlText
441
- * @returns {Record<string, {path:string, test:string}>|null}
442
- * - 找不到 modules 块 → null(调用方 fallback commands.test)
443
- * - 找到块但无有效条目 → null
444
- */
445
- export function extractModules(yamlText) {
446
- if (!yamlText) return null
447
- const lines = normalizeLineEndings(yamlText).split('\n')
448
-
449
- // 定位 modules: 起始行(必须是顶层 key,行首无缩进或仅注释后顶层)
450
- let startIdx = -1
451
- for (let i = 0; i < lines.length; i++) {
452
- const m = lines[i].match(/^modules:\s*(?:#.*)?$/)
453
- if (m) { startIdx = i; break }
454
- }
455
- if (startIdx === -1) return null
456
-
457
- const modules = {}
458
- for (let i = startIdx + 1; i < lines.length; i++) {
459
- const line = lines[i]
460
- // 子条目:以 2 空格缩进 + key + ':' 开头
461
- const entry = line.match(/^ ([A-Za-z0-9_.\-]+):\s*(.*)$/)
462
- if (!entry) {
463
- // 遇到新的顶层 key(行首非空格且非注释)→ modules 块结束
464
- if (line.length > 0 && !line.startsWith(' ') && !line.startsWith('#') && line.trim() !== '') break
465
- continue
466
- }
467
- const name = entry[1]
468
- const rest = entry[2].trim()
469
- if (rest === '' || rest.startsWith('#')) continue // 子块展开式(本实现只支持 inline flow)
470
- // 解析 inline flow mapping: { path: "...", test: "..." }
471
- const pathVal = parseFlowValue(rest, 'path')
472
- const testVal = parseFlowValue(rest, 'test')
473
- if (pathVal && testVal) {
474
- modules[name] = { path: pathVal, test: testVal }
475
- }
476
- }
477
-
478
- return Object.keys(modules).length > 0 ? modules : null
479
- }
480
-
481
- /**
482
- * 从 inline flow mapping 文本(如 `{ path: "backend/", test: "cd ..." }`)
483
- * 提取指定键的值。支持双引号/单引号/bare 值。
484
- */
485
- function parseFlowValue(flowText, key) {
486
- // 键可能带引号也可能不带:path: "x" 或 "path": "x"
487
- const re = new RegExp(String.raw`(?:^|[{,]\s*)"?${key}"?\s*:\s*("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|(?:[^,}]+?))\s*(?=[,}]|$)`)
488
- const m = flowText.match(re)
489
- if (!m) return null
490
- let v = m[1].trim()
491
- if (v.startsWith('"') && v.endsWith('"')) {
492
- // 双引号值剥壳后解开转义(坑 verify-modules-crlf-blanket-fallback 次生发现):modules 的
493
- // test 命令常含嵌套引号(node -e "…" / pytest "…"),yaml 源里写作 \";此前只剥外层引号
494
- // 不解 \\ 与 \",解析结果残留字面反斜杠 → 命令直接坏。其余冷门转义(\n 等)按 YAML 规范
495
- // 应真转义,但保守留字面(可见优于静默变换,测试命令不含它们)
496
- v = v.slice(1, -1).replace(/\\(["\\])/g, '$1')
497
- } else if (v.startsWith("'") && v.endsWith("'")) {
498
- // 单引号值的 YAML 转义是 '' → '
499
- v = v.slice(1, -1).replace(/''/g, "'")
500
- }
501
- return v.length > 0 ? v : null
502
- }
503
-
504
- /**
505
- * 根据变更文件列表 + modules 映射,算出被命中的模块(去重保序)。
506
- * 文件路径以 module.path 为前缀(含子目录)即视为命中。
507
- *
508
- * @param {string[]} changedFiles - git diff 产出的相对路径列表
509
- * @param {Record<string, {path:string, test:string}>} modules - extractModules 解析结果
510
- * @returns {Array<{name:string, path:string, test:string}>} - 命中的模块(按 modules 声明顺序去重)
511
- */
512
- export function pickHitModules(changedFiles, modules) {
513
- if (!Array.isArray(changedFiles) || changedFiles.length === 0) return []
514
- if (!modules || typeof modules !== 'object') return []
515
-
516
- const files = changedFiles.map(f => String(f).replace(/\\/g, '/'))
517
- const hits = []
518
- const looseHits = []
519
- for (const [name, mod] of Object.entries(modules)) {
520
- if (!mod || !mod.path) continue
521
- const modPath = String(mod.path).replace(/\\/g, '/')
522
- const prefix = modPath.endsWith('/') ? modPath : modPath + '/'
523
- // path 本身被改 或 path/ 下任意文件被改
524
- const hit = files.some(f => f === modPath || f.startsWith(prefix))
525
- if (hit) { hits.push({ name, path: modPath, test: mod.test }); continue }
526
- // 宽松段匹配 fallback(坑 module-path-layout-mismatch,2026-08-22 实证:pnpm monorepo
527
- // 常见 packages/frontend 布局 vs modules 配 frontend/ 前缀——严格前缀 0 命中时按
528
- // 「路径段等于模块首段」兜底(packages/frontend/src/x → 命中 frontend),多测不漏测。
529
- // 首段去斜杠后比对,防 frontend-guide 之类前缀误蹭)
530
- const firstSeg = prefix.split('/')[0]
531
- if (firstSeg && files.some(f => ('/' + f + '/').includes('/' + firstSeg + '/'))) {
532
- looseHits.push({ name, path: modPath, test: mod.test, looseMatch: true })
533
- }
534
- }
535
- // 严格命中优先;全部严格 0 命中才用宽松兜底(并 warn 可见——宽松规则可能多命中)
536
- if (hits.length > 0) return hits
537
- if (looseHits.length > 0) {
538
- console.warn(`⚠️ 模块命中用宽松段匹配(modules path 前缀与 diff 布局不一致,如 packages/<name> vs <name>/):命中 ${looseHits.map(h => h.name).join(', ')}——建议 local.yaml modules 的 path 对齐实际目录布局`)
539
- return looseHits
540
- }
541
- return []
542
- }
543
-
544
- /**
545
- * 聚合多个模块测试结果为单一 status。
546
- * - 全 passed → 'passed'
547
- * - 任一 failed → 'failed'
548
- * - 空 → null(调用方按 fallback 处理)
549
- *
550
- * @param {Array<{status:'passed'|'failed'}>} results
551
- * @returns {'passed'|'failed'|null}
552
- */
553
- export function aggregateStatus(results) {
554
- if (!Array.isArray(results) || results.length === 0) return null
555
- if (results.every(r => r && r.status === 'passed')) return 'passed'
556
- return 'failed'
557
- }
558
-
559
- /**
560
- * 从 local.yaml 提取 known_failures 声明(预存失败豁免清单,坑 verify-worktree-... 修复方向 2)。
561
- * 支持块式与流式两种写法:
562
- * known_failures:
563
- * - "tests/test_ppm.py::test_legacy"
564
- * - app/modules/plan/test_old
565
- * 或 known_failures: [a, b]
566
- * 每条作为子串(大小写不敏感)匹配测试输出中的失败行。
567
- *
568
- * @param {string} yamlText
569
- * @returns {string[]} 模式列表;无声明返回 []
570
- */
571
- export function extractKnownFailures(yamlText) {
572
- if (!yamlText) return []
573
- // CRLF 归一(坑 verify-modules-crlf-blanket-fallback):块式正则的 `.+`/`\n?` 在 CRLF 行
574
- // 间失配,只捕获到第一条豁免项就停——归一后整块捕获恢复
575
- const yaml = normalizeLineEndings(yamlText)
576
- const inline = yaml.match(/^known_failures:\s*\[([^\]]*)\]\s*(?:#.*)?$/m)
577
- if (inline) {
578
- return inline[1].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, '')).filter(Boolean)
579
- }
580
- const block = yaml.match(/^known_failures:\s*\n((?:[ \t]+-[ \t].+\n?)+)/m)
581
- if (block) {
582
- return (block[1].match(/^[ \t]+-[ \t]+(.+)/gm) || [])
583
- .map(s => s.replace(/^[ \t]+-[ \t]+/, '').trim().replace(/^['"]|['"]$/g, '').replace(/#.*$/, '').trim())
584
- .filter(Boolean)
585
- }
586
- return []
587
- }
588
-
589
- // 单条失败行标记(跨 pytest/jest/vitest/go/generic)。大小写不敏感。
590
- // 刻意用 FAIL/FAILED + 配合 SUMMARY_LINE_RE 排除汇总行:否则 pytest/jest 的
591
- // "N failed" 汇总会被误判为「需豁免的失败行」→ 永远 remaining>0 → known_failures 失效。
592
- const PER_TEST_FAIL_RE = /(FAILED|\bFAIL\b|✕|✗|✘|panic\s*:|assertionerror|traceback|---\s*fail|error:|exception)/i
593
- // 汇总/计数行(非单条失败):pytest === 框、jest "Tests:"、裸 "N failed/passed"、go "FAILED in Ns" 等。
594
- const SUMMARY_LINE_RE = /(={2,}.*={2,}|^\s*\d+\s+(failed|passed|skipped|pending)\b|tests?\s*:|test\s+suites?\s*:|failed\s+in\s+\d)/i
595
-
596
- /**
597
- * 把测试输出按行筛出「失败行」,再按 known_failures 模式分为已豁免 / 未豁免。
598
- * @param {string} output
599
- * @param {string[]} knownFailures 子串模式列表(大小写不敏感)
600
- * @returns {{ failureLines: string[], exempted: string[], remaining: string[] }}
601
- */
602
- export function partitionFailures(output, knownFailures) {
603
- const lines = String(output || '').split(/\r?\n/)
604
- const failureLines = lines.filter(l => PER_TEST_FAIL_RE.test(l) && !SUMMARY_LINE_RE.test(l))
605
- const pats = (knownFailures || []).map(p => String(p).toLowerCase()).filter(Boolean)
606
- const exempted = []
607
- const remaining = []
608
- for (const l of failureLines) {
609
- const ll = l.toLowerCase()
610
- if (pats.some(p => ll.includes(p))) exempted.push(l)
611
- else remaining.push(l)
612
- }
613
- return { failureLines, exempted, remaining }
614
- }
615
-
616
- /**
617
- * 结合 known_failures 判定单次测试运行的状态(fail-safe)。
618
- * - exitCode 0 → passed
619
- * - exitCode≠0 且无 known_failures → failed(原行为)
620
- * - exitCode≠0 且有 known_failures:
621
- * 检测到失败行且全部命中豁免 → passed(披露:请人工复核清单是否过宽)
622
- * 有未豁免失败行 / 检测不到失败行(保守)→ failed
623
- * fail-safe:检测不到失败行绝不自动 pass(避免解析盲区导致假 PASS)。
624
- *
625
- * @returns {{ status: 'passed'|'failed', reason: string|null, exemptedCount: number }}
626
- */
627
- export function judgeWithKnownFailures(exitCode, output, baseReason, knownFailures) {
628
- if (exitCode === 0) return { status: 'passed', reason: baseReason, exemptedCount: 0 }
629
- if (!knownFailures || knownFailures.length === 0) {
630
- return { status: 'failed', reason: baseReason, exemptedCount: 0 }
631
- }
632
- const { failureLines, exempted, remaining } = partitionFailures(output, knownFailures)
633
- if (failureLines.length > 0 && remaining.length === 0) {
634
- return {
635
- status: 'passed',
636
- reason: `全部 ${failureLines.length} 个失败行命中 known_failures 已豁免(${exempted.length} 条)— 请人工复核豁免清单是否过宽`,
637
- exemptedCount: exempted.length,
638
- }
639
- }
640
- // 剩余未豁免失败行:列出具体行 + 预存债指引(坑 verify-known-failures-stale-list)。
641
- // known_failures 清单常滞后于新预存测试 → 同源预存债漏入清单,agent 跑完才发现要手动补。
642
- // 这里点出具体未命中行,让 agent 一眼分辨"补清单 vs 修代码",不替它判断(确定性:列已算出的 remaining)。
643
- let detail
644
- if (remaining.length > 0) {
645
- const sample = remaining.slice(0, 5).map(l => {
646
- const t = String(l).trim()
647
- return t.length > 120 ? t.slice(0, 120) + '…' : t
648
- })
649
- const more = remaining.length > 5 ? `\n …(其余 ${remaining.length - 5} 行见上方测试输出)` : ''
650
- detail = `${remaining.length} 个失败行未命中 known_failures 清单:\n - ${sample.join('\n - ')}${more}\n → 若是预存债(变更前就失败),加入 local.yaml 的 known_failures 清单;若是本次变更引入的真实失败,请修复`
651
- } else {
652
- detail = '失败输出未检测到可豁免的失败行(保守判 fail)'
653
- }
654
- return {
655
- status: 'failed',
656
- reason: baseReason ? `${baseReason}(${detail})` : detail,
657
- exemptedCount: exempted.length,
658
- }
659
- }
660
-
661
- /**
662
- * 决定 verify 实测的执行动作(纯函数,便于测试;坑 verify-worktree-... 修复方向 3)。
663
- * - skip → 'skip'(真跳过,D-005@v2——不落 full 兜底;evidence-auto 经
664
- * resolveTestStrategy 解析出生效 skip 时同走此动作)
665
- * - module + 命中模块 → 'module-subset'
666
- * - module + 0 命中 → 'module-zero-hit-skip'(不静默回退注定超时/预存失败的全量)
667
- * - 其余(full / module 无块 / module git 不可用 hitCount=-1)→ 'full'
668
- * @returns {'skip'|'module-subset'|'module-zero-hit-skip'|'full'}
669
- */
670
- export function decideVerifyTestAction({ strategy, modulesPresent, hitCount }) {
671
- if (strategy === 'skip') return 'skip'
672
- if (strategy === 'module' && modulesPresent) {
673
- if (hitCount > 0) return 'module-subset'
674
- if (hitCount === 0) return 'module-zero-hit-skip'
675
- return 'full' // hitCount === -1(git 不可用)→ 落全量兜底
676
- }
677
- return 'full'
678
- }
679
-
680
- /**
681
- * 跑单个模块的 test 命令(串行调用方逐个调用)。
682
- * @returns {{name, status:'passed'|'failed', command, exitCode, durationMs, outputTail, reason}}
683
- */
684
- function runOneModule(name, testCommand, cwd, knownFailures = []) {
685
- const startedAt = Date.now()
686
- let exitCode = 0
687
- let output = ''
688
- let reason = null
689
- warnPortRaceBeforeRun(testCommand)
690
- try {
691
- output = execSync(testCommand, {
692
- cwd,
693
- encoding: 'utf8',
694
- timeout: TEST_TIMEOUT_MS,
695
- maxBuffer: 32 * 1024 * 1024,
696
- stdio: ['ignore', 'pipe', 'pipe'],
697
- })
698
- } catch (e) {
699
- exitCode = typeof e.status === 'number' ? e.status : 1
700
- output = [e.stdout, e.stderr].filter(Boolean).join('\n') || e.message
701
- reason = e.signal === 'SIGTERM' && Date.now() - startedAt >= TEST_TIMEOUT_MS
702
- ? `模块 ${name} 测试超时(>${TEST_TIMEOUT_MS / 1000}s)`
703
- : `模块 ${name} 测试退出码 ${exitCode}`
704
- // 资源竞争鉴别提示(坑 verify-devserver-port-race,同 runFullCommand)
705
- if (/EADDRINUSE|address already in use|端口.*被占用|port.*already/i.test(output)) {
706
- reason += '。⚠️ 输出含端口占用信号(EADDRINUSE)——极可能是与你自留 dev server 的资源竞争而非代码问题:停掉占用服务后重跑 verify 再定论'
707
- }
708
- }
709
- const durationMs = Date.now() - startedAt
710
- const outputTail = output.length > OUTPUT_TAIL_CHARS ? '…' + output.slice(-OUTPUT_TAIL_CHARS) : output
711
- const judged = judgeWithKnownFailures(exitCode, output, reason, knownFailures)
712
- return {
713
- name,
714
- status: judged.status,
715
- command: testCommand,
716
- exitCode,
717
- durationMs,
718
- outputTail,
719
- reason: judged.reason,
720
- exemptedCount: judged.exemptedCount,
721
- }
722
- }
723
-
724
- // refSpec 来源 meta.json(agent 可写),仅放行 git ref/range 安全字符(含 HEAD~1..HEAD 类区间),
725
- // 防经 shell 的命令/参数注入。剥空白与引号/分号/反引号/$ 等 shell 元字符。
726
- // 注:允许 ".."/"../.."(相对路径 ref 语法上合法)不影响安全——execFileSync 数组形式下它只是
727
- // 一个 git rev 参数,git 自会报 not a valid ref,无 shell 解释面。
728
- function assertSafeRefSpec(refSpec) {
729
- if (typeof refSpec !== 'string') return null
730
- if (!/^[A-Za-z0-9._~/^-]+$/.test(refSpec)) return null
731
- if (/~~/.test(refSpec)) return null // 连续 ~(垃圾串)
732
- return refSpec
733
- }
734
-
735
- /**
736
- * 在指定 cwd 跑 `git diff --name-only <refSpec>`,返回相对仓库根的文件列表。
737
- * git 不可用 / 非仓库 / ref 无效 → 返回 null(调用方 fallback)。
738
- * QUAL-01 收口:本地 execFileSync 裸调 → git-helper gitQuiet(统一 safe.directory),timeout 30s 保留。
739
- */
740
- function runGitDiffNameOnly(cwd, refSpec) {
741
- const ref = refSpec ? assertSafeRefSpec(refSpec) : null
742
- if (refSpec && !ref) return null
743
- const args = ['diff', '--name-only']
744
- if (ref) args.push(ref)
745
- const out = gitQuiet(cwd, args, { timeout: 30 * 1000, trim: false })
746
- if (out === null) return null
747
- return out.split('\n').map(l => l.trim()).filter(Boolean)
748
- }
749
-
750
- /**
751
- * 在指定 cwd 跑 `git diff --name-status <refSpec>`,返回原始文本(调用方按行解析,
752
- * 保留状态字母 D/R/C 供删除探针识别删除/重命名)。git 不可用 / 非仓库 / ref 无效 → 返回 null。
753
- * QUAL-01 收口:同上走 gitQuiet(trim:false 保留原始文本)。
754
- */
755
- function runGitDiffNameStatus(cwd, refSpec) {
756
- const ref = refSpec ? assertSafeRefSpec(refSpec) : null
757
- if (refSpec && !ref) return null
758
- const args = ['diff', '--name-status']
759
- if (ref) args.push(ref)
760
- return gitQuiet(cwd, args, { timeout: 30 * 1000, trim: false })
761
- }
762
-
763
- /**
764
- * 取主工作区 git 变更文件列表(unstaged + staged,相对仓库根)。
765
- * `git diff --name-only HEAD` 同时覆盖已暂存与未暂存改动(相对 HEAD),
766
- * 最适合 brownfield(apply 后未 commit / in-place 改动)场景。
767
- * git 不可用 / 非仓库 → 返回 null(调用方 fallback)。
768
- *
769
- * 注意:worktree 隔离模式下主仓只剩 .sillyspec/ 文档改动、代码在 worktree,
770
- * 本函数看不到——runVerifyTestCheck 用 resolveVerifyChangedFiles 统一处理。
771
- */
772
- function gitChangedFiles(cwd) {
773
- const head = runGitDiffNameOnly(cwd, 'HEAD')
774
- if (head !== null) return head
775
- // HEAD 不存在(空仓库)或 git 不可用 → 尝试纯 unstaged
776
- return runGitDiffNameOnly(cwd, '')
777
- }
778
-
779
- // 他者声明归属过滤(坑 verify-reconcile-foreign-wip):实现在零环模块 foreign-declared.js
780
- // (contract-matrix 被 verify-postcheck import,parity 侧不能反向 import 本模块),此处
781
- // re-export 保持既有消费方路径不变
782
- export { collectForeignDeclaredFiles, splitOwnVsForeignDiffFiles } from './foreign-declared.js'
783
- import { splitOwnVsForeignDiffFiles } from './foreign-declared.js'
784
-
785
- /**
786
- * 解析 verify 对账用的变更文件集(worktree-aware)。
787
- *
788
- * worktree 隔离模式下 execute 的代码改动落在 worktree,主仓工作区只剩
789
- * .sillyspec/ 文档改动。若仍用主仓 `git diff --name-only HEAD`,hitCount=0
790
- * → 回退注定超时且含预存失败的全量 commands.test → verify 完成被阻断
791
- * (坑 verify-worktree-mode-test-reconciliation-fallback-full)。
792
- *
793
- * 判定(与 checkExecuteCodeEvidence / task-review 同源,meta.json 为权威):
794
- * 1. change 有 worktree meta 且 baseHash 存在 → 在 worktree(或 in-place 的 cwd)
795
- * 跑 `git diff --name-only <baseHash>..HEAD` 取真实代码改动集
796
- * ⚠️ baseline checkpoint 修复:优先用 baselineCommit/actualBaseHash(baseline overlay
797
- * 之后),否则 baseHash(pre-baseline)会把 baseline 同步的跨模块文件算进 verify diff
798
- * → 命中无关模块(如 ppm 变更误测 daemon/frontend)。与 task-review.js 同源。
799
- * 2. 无 worktree meta / diff 异常 → 主仓 `git diff --name-only HEAD`(brownfield 原行为)
800
- *
801
- * 跨仓支持(task-06 / D-004 / design §6 A6):ctx 参数可选,缺省走单仓原逻辑(零回归,
802
- * GOAL-2)。ctx 非空且含跨仓 entry 时,主仓 diff 走原逻辑,再 per-repo 在各跨仓仓
803
- * gitDir 跑 `git diff --name-only HEAD` 合并入结果(design §6 行 136 「per-repo 取 diff
804
- * 合并」字面契约)。跨仓仓 diff 路径相对各自仓根。
805
- *
806
- * 注:runVerifyTestCheck 的 module 子集策略只消费主仓 diff(跨仓仓不参与 module 子集,
807
- * 跨仓仓无 module 映射,design §6 + §5.4),故本函数的跨仓合并 diff 在 module 子集
808
- * 路径无副作用——本函数仅供「per-repo diff 合并」语义契约 + 未来 consumer 复用。
809
- *
810
- * @param {string} cwd - 项目根目录(主仓)
811
- * @param {string|null} changeName
812
- * @param {object|null} [ctx] - MultiRepoContext 实例(可选,缺省/null 走单仓原逻辑)
813
- * @returns {string[]|null} 变更文件列表;git 不可用返回 null(调用方按 hitCount=-1 处理)
814
- */
815
- export function resolveVerifyChangedFiles(cwd, changeName, ctx = null, opts = {}) {
816
- const { includeWorkingTree = false } = opts
817
- // 主仓 diff(原逻辑不动,单仓零回归)
818
- let mainFiles = resolveMainChangedFiles(cwd, changeName)
819
-
820
- // 并入 worktree 未提交改动(坑 module-subset-zero-hit-uncommitted,2026-08-21 实证:
821
- // 子代理默认不 commit,真实改动全在 worktree working-tree——只看 base..HEAD commit diff
822
- // 时 module 映射 0 命中直接跳过(frontend/** 变更未命中 frontend 模块)。与
823
- // generateTaskReviewDrafts 的并入口径同源:meta.worktreePath 下 status --porcelain 文件
824
- // (排除 .sillyspec/ 运行时产物)。opt-in(默认关):d drafts 有自己的并入点,避免双并。
825
- if (includeWorkingTree && mainFiles !== null) {
826
- try {
827
- const metaPath = join(cwd, '.sillyspec', '.runtime', 'worktrees', changeName, 'meta.json')
828
- if (changeName && existsSync(metaPath)) {
829
- const meta = JSON.parse(readFileSync(metaPath, 'utf8'))
830
- const wtGitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
831
- ? meta.worktreePath
832
- : cwd
833
- const wtStatus = gitQuiet(wtGitDir, ['status', '--porcelain', '--untracked-files=all'], { timeout: 30000, trim: false })
834
- const wtFiles = String(wtStatus || '').split('\n')
835
- .map(l => l.slice(3).trim().split(' -> ').pop() || '')
836
- .map(p => p.replace(/^"|"$/g, '').replace(/\\/g, '/'))
837
- .filter(p => p && p !== '.sillyspec' && !p.startsWith('.sillyspec/'))
838
- if (wtFiles.length > 0) {
839
- mainFiles = [...new Set([...(mainFiles || []), ...wtFiles])]
840
- }
841
- }
842
- } catch { /* working-tree 并入失败退回 commit diff 口径(fail-open) */ }
843
- }
844
-
845
- // 无 ctx / ctx 无跨仓 entry → 主仓 diff 即结果(零回归)
846
- if (!ctx || typeof ctx.repos !== 'object' || ctx.repos === null) return mainFiles
847
- const crossEntries = []
848
- for (const entry of ctx.repos.values()) {
849
- if (entry && entry.isMain === false) crossEntries.push(entry)
850
- }
851
- if (crossEntries.length === 0) return mainFiles
852
-
853
- // 主仓 git 不可用(null)→ 不强制兜底,保留 null 语义让调用方按 hitCount=-1 处理。
854
- // 跨仓仓 diff 各自取,任一可用即合并;全不可用且主仓 null → 返 null。
855
- // 跨仓仓 diff 锚点:HEAD~1..HEAD(跨仓 task 子代理 commit 到主干,verify 时最近一笔 commit
856
- // 即本次 task 改动;多 task 同仓时仅反映最近一笔,精确范围由 task 卡 base/head 锡点锚定,
857
- // 那是 task-04 的 scope,本函数不消费锡点——跨仓合并 diff 在 verify-postcheck 内仅供
858
- // 「per-repo diff 合并」语义契约 + 未来 consumer,module 子集只用主仓 diff)。
859
- const merged = mainFiles ? mainFiles.slice() : []
860
- let anyAvailable = mainFiles !== null
861
- for (const entry of crossEntries) {
862
- // 跨仓仓 gitDir = 跨仓仓根(MultiRepoContext._buildCrossRepoEntry 已 fail-closed 保证可达)
863
- const files = runGitDiffNameOnly(entry.gitDir, 'HEAD~1..HEAD')
864
- if (files !== null) {
865
- anyAvailable = true
866
- for (const f of files) {
867
- if (!merged.includes(f)) merged.push(f)
868
- }
869
- }
870
- }
871
- return anyAvailable ? merged : null
872
- }
873
-
874
- /**
875
- * 主仓变更文件解析(原 resolveVerifyChangedFiles 逻辑,单仓零回归基线)。
876
- * 抽出供 resolveVerifyChangedFiles 复用,跨仓合并时主仓部分走此函数(不动)。
877
- *
878
- * @param {string} cwd - 主仓根
879
- * @param {string|null} changeName
880
- * @returns {string[]|null}
881
- */
882
- function resolveMainChangedFiles(cwd, changeName) {
883
- if (changeName) {
884
- const metaPath = join(cwd, '.sillyspec', '.runtime', 'worktrees', changeName, 'meta.json')
885
- if (existsSync(metaPath)) {
886
- let meta = null
887
- try { meta = JSON.parse(readFileSync(metaPath, 'utf8')) } catch {}
888
- // 优先 baselineCommit/actualBaseHash(baseline checkpoint 之后),回退 baseHash
889
- const diffBase = meta?.baselineCommit || meta?.actualBaseHash || meta?.baseHash
890
- if (diffBase) {
891
- const gitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
892
- ? meta.worktreePath
893
- : cwd
894
- const files = runGitDiffNameOnly(gitDir, `${diffBase}..HEAD`)
895
- if (files !== null) return files
896
- // worktree diff 异常 → 落主仓兜底(保持与原 gitChangedFiles 相同的 null 语义)
897
- }
898
- }
899
- }
900
- const fallback = gitChangedFiles(cwd)
901
- // 无 meta 回退(主仓 HEAD diff 全量)撞并行会话在途 WIP 的归属过滤(坑
902
- // verify-reconcile-foreign-wip):他者显式声明(quick --files / 他者 design 清单)的
903
- // 文件剔除归他者——不混入本变更 module 命中。无主文件保留(fail-closed)。
904
- if (fallback !== null && changeName && fallback.length > 0) {
905
- const { own, foreign } = splitOwnVsForeignDiffFiles(cwd, changeName, fallback)
906
- if (foreign.length > 0) {
907
- console.warn(`⚠️ verify 对账已排除 ${foreign.length} 个并行会话声明的文件(不参与本变更判定):${foreign.slice(0, 5).map(x => `${x.file}←${x.owners[0]}`).join(', ')}${foreign.length > 5 ? ' 等' : ''}`)
908
- return own
909
- }
910
- }
911
- return fallback
912
- }
913
-
914
- /**
915
- * 执行 verify 实测:读取 local.yaml 配置,按 test_strategy 决定全量或模块子集。
916
- *
917
- * 跨仓支持(task-06 / D-004 / design §5.4 + §6 A6 + §9):opts.ctx 可选,缺省走单仓
918
- * 原逻辑(零回归,GOAL-2)。ctx 非空且含跨仓 entry 时,主仓跑原 module 子集 / full npm
919
- * test(行为不变),再 per-repo cwd 在各跨仓仓根跑 full npm test(跨仓仓不参与 module
920
- * 子集策略——跨仓仓无主仓的 module 映射,design §6 + §5.4);跨仓仓无 package.json 则
921
- * 跳过 + warn 不阻断 verify(design §9 兼容策略「跨仓仓无 package.json 跳过 warn」)。
922
- * 任一仓 fail → 整体 fail(fail-fast 语义,跨仓仓的真实失败不能被主仓 PASS 掩盖)。
923
- *
924
- * @param {object} opts
925
- * @param {string} opts.cwd - 项目根目录(主仓,测试执行目录)
926
- * @param {string} opts.specBase - .sillyspec(或平台 specRoot)目录
927
- * @param {string|null} [opts.changeName]
928
- * @param {object|null} [opts.ctx] - MultiRepoContext 实例(可选,缺省/null 走单仓原逻辑)
929
- * @returns {{
930
- * status: 'passed'|'failed'|'skipped',
931
- * command: string|null,
932
- * exitCode: number|null,
933
- * durationMs: number|null,
934
- * outputTail: string|null,
935
- * reason: string|null,
936
- * resultPath: string|null,
937
- * }}
938
- */
939
- export function runVerifyTestCheck({ cwd, specBase, changeName = null, ctx = null }) {
940
- // 信任边界声明(体检 SEC-02 核实):本函数三处 execSync(command) 的命令只来源于
941
- // ① 主仓 specBase(resolveSpecDir → 主仓 .sillyspec/local.yaml)② 跨仓仓根
942
- // <repo>/.sillyspec/local.yaml——均为仓库自有配置(与 `npm test` 同信任级:跑测试
943
- // 本就是执行项目代码)。永不读取 agent 可写的 worktree 副本(对照 worktree-deps.js
944
- // SEC-01 的源级分流);修改 yaml 来源时必须维持此边界。
945
- const localYamlPath = join(specBase, 'local.yaml')
946
- const yamlText = existsSync(localYamlPath) ? readFileSync(localYamlPath, 'utf8') : null
947
-
948
- const rawStrategy = extractTestStrategy(yamlText)
949
- const knownFailures = extractKnownFailures(yamlText)
950
-
951
- // —— evidence-auto 生效策略解析(D-005@v2 / task-11)——
952
- // 按变更目录 module-impact.md 影响面取生效策略(行为→module、纯文档/门禁→skip、
953
- // 缺失/不可解析→降级 module 并注记)再进既有链路;full/module/skip/缺省四路径
954
- // 不经此分支(消费语义逐字不变)。
955
- let strategy = rawStrategy
956
- let evidenceAuto = null
957
- if (rawStrategy === 'evidence-auto') {
958
- const changeDir = changeName ? join(specBase, 'changes', changeName) : null
959
- const resolution = resolveTestStrategy({ yamlText, changeDir })
960
- strategy = resolution.strategy
961
- evidenceAuto = resolution.evidence_auto_recommendation
962
- }
963
- // evidence-auto 解析为 module 后的 hint/reason 追加注记(full/module 路径为空串,输出逐字不变)
964
- const eaNote = rawStrategy === 'evidence-auto' ? '(生效策略来自 test_strategy: evidence-auto 推荐)' : ''
965
-
966
- // —— 模块子集路径(test_strategy: module):算 modulesPresent / hitCount / hits ——
967
- // resolveVerifyChangedFiles 返回 null 表示 git 不可用 → hitCount=-1(与 0 命中区分)。
968
- // 注:module 子集策略只用主仓 diff(跨仓仓不参与 module 子集,design §6 + §5.4),
969
- // 故此处不传 ctx(避免跨仓路径误命中主仓 module 映射)。
970
- let modulesPresent = false
971
- let hitCount = 0
972
- let hits = []
973
- let lastChangedFiles = [] // 0 命中诊断用(diff 文件样例可见性,坑 module-path-layout-mismatch)
974
- if (strategy === 'module') {
975
- const modules = extractModules(yamlText)
976
- if (modules) {
977
- modulesPresent = true
978
- // includeWorkingTree(坑 module-subset-zero-hit-uncommitted):子代理不 commit 的改动
979
- // 也参与 module 命中判定,0 命中跳过不再误伤 worktree 未提交的真实变更
980
- const changedFiles = resolveVerifyChangedFiles(cwd, changeName, null, { includeWorkingTree: true })
981
- lastChangedFiles = Array.isArray(changedFiles) ? changedFiles : []
982
- if (changedFiles === null) {
983
- hitCount = -1 // git 不可用 / 非仓库
984
- } else {
985
- hits = pickHitModules(changedFiles, modules)
986
- hitCount = hits.length
987
- }
988
- }
989
- }
990
-
991
- const action = decideVerifyTestAction({ strategy, modulesPresent, hitCount })
992
- let mainResult
993
- if (action === 'skip') {
994
- // —— skip 真跳过(D-005@v2 / R-07)——
995
- // 显式 skip:兑现声明语义,不回退全量;输出显式标注留审计痕迹(R-07 行为变化提示:
996
- // 此前配置 skip 实际仍跑全量,本版本起真跳过)。
997
- // evidence-auto→skip:测试不在推荐组合内(module-impact.md 无行为类影响),
998
- // reason 附推荐依据与否决路径。
999
- const reason = rawStrategy === 'skip'
1000
- ? '测试已按 test_strategy=skip 配置跳过(D-005@v2 兑现声明语义:不回退全量 commands.test)。⚠️ 行为变化提示(R-07):此前配置 skip 实际仍跑全量,本版本起真跳过——本次 verify 结论不含测试客观核验;如需恢复实测,把 local.yaml 的 test_strategy 改回 full/module。'
1001
- : `测试已按 test_strategy=evidence-auto 推荐跳过:${evidenceAuto && evidenceAuto.summary ? evidenceAuto.summary : 'module-impact.md 判定无行为类影响'}。本次 verify 结论不含测试客观核验。`
1002
- mainResult = {
1003
- status: 'skipped',
1004
- command: null,
1005
- exitCode: null,
1006
- durationMs: null,
1007
- outputTail: null,
1008
- reason,
1009
- resultPath: null,
1010
- mode: 'strategy-skip',
1011
- fallbackReason: null,
1012
- }
1013
- // 审计痕迹落盘(R-07):skip 决策与依据写入 verify-runs 时间线(test-result.json),供追溯
1014
- writeRunResult({
1015
- specBase,
1016
- changeName,
1017
- result: mainResult,
1018
- extra: {
1019
- strategy: rawStrategy,
1020
- ...(evidenceAuto ? {
1021
- evidence_auto: {
1022
- resolved_strategy: evidenceAuto.resolved_strategy,
1023
- degraded: evidenceAuto.degraded,
1024
- degraded_reason: evidenceAuto.degraded_reason,
1025
- checks: evidenceAuto.checks,
1026
- },
1027
- } : {}),
1028
- },
1029
- })
1030
- } else if (action === 'module-subset') {
1031
- mainResult = runModuleSubset({ cwd, specBase, changeName, hits, knownFailures })
1032
- } else if (action === 'module-zero-hit-skip') {
1033
- // module 模式 0 命中:不静默回退注定超时/含预存失败的全量(坑 verify-worktree-... 修复方向 3)。
1034
- // 据 verify-result.md 自报告判定;想跑全量请显式设 test_strategy: full。
1035
- // 诊断可见性(坑 module-path-layout-mismatch,2026-08-22 实证:0 命中「靠第一次跑过的
1036
- // 记录兜底」——为何没命中完全黑箱):落 modules 配置 path vs diff 文件样例,配置前缀
1037
- // 对不上(如 packages/frontend vs frontend/)一眼可见
1038
- const modules_ = extractModules(yamlText) || {}
1039
- const diagLines = [
1040
- `已配置 modules(${Object.keys(modules_).length} 个): ${Object.entries(modules_).map(([k, m]) => `${k}→${m.path}`).join('、') || '(无)'}`,
1041
- `本次 diff(${lastChangedFiles.length} 个文件,前 5): ${lastChangedFiles.slice(0, 5).join(', ') || '(空)'}`,
1042
- ]
1043
- console.warn(`⚠️ 模块 0 命中诊断(对照 path 前缀与 diff 布局是否一致,如 packages/<name> vs <name>/):`)
1044
- for (const l of diagLines) console.warn(` ${l}`)
1045
- mainResult = {
1046
- status: 'skipped',
1047
- command: null,
1048
- exitCode: null,
1049
- durationMs: null,
1050
- outputTail: null,
1051
- reason: 'test_strategy: module 但本次变更未命中任何已配置 modules(0 命中)。为避免回退到注定超时/含预存失败的全量 commands.test,CLI 未自动跑全量——据 verify-result.md 自报告判定测试。若需全量覆盖,显式设 test_strategy: full。' +
1052
- ` 诊断:${diagLines.join(';')}` + eaNote,
1053
- resultPath: null,
1054
- mode: 'module-zero-hit',
1055
- fallbackReason: null,
1056
- }
1057
- } else {
1058
- // —— 全量路径(full / module 无块 / module git 不可用)——
1059
- // fallbackReason 非 null 表示本次全量是"非显式"的(缺省/配置不全/未命中),需明示。
1060
- // evidence-auto 解析为 module 后落全量兜底时追加推荐来源注记(eaNote;其余路径空串零变化)。
1061
- let fallbackReason = computeFullFallbackReason({ strategy, modulesPresent, hitCount })
1062
- if (fallbackReason && eaNote) fallbackReason = fallbackReason + eaNote
1063
- mainResult = runFullCommand({ yamlText, localYamlPath, cwd, specBase, changeName, fallbackReason, knownFailures })
1064
- }
1065
-
1066
- // —— 跨仓仓 per-repo cwd 跑 full npm test(task-06 / D-004 / design §5.4 + §6 A6)——
1067
- // ctx 为空或无跨仓 entry → 直接返主仓结果(单仓零回归,GOAL-2)。
1068
- // 跨仓仓不参与 module 子集策略,只跑 full npm test(design §6 + §5.4);
1069
- // 跨仓仓无 package.json → 跳过 + warn 不阻断(design §9 兼容策略)。
1070
- // 任一跨仓仓 fail → 整体 fail(合并语义)。
1071
- return mergeCrossRepoResults(mainResult, ctx)
1072
- }
1073
-
1074
- /**
1075
- * per-repo cwd 跑跨仓仓 full npm test,合并进主仓结果。
1076
- *
1077
- * design §6 A6 + §5.4 + §9 兼容策略:
1078
- * - 跨仓仓有 package.json → 在该仓 projectRoot cwd 跑 full npm test(跨仓仓 own local.yaml
1079
- * 若有 commands.test 用之,否则 fallback `npm test`)
1080
- * - 跨仓仓无 package.json → 跳过 + console.warn(不阻断 verify)
1081
- * - 跨仓仓只跑 full npm test,不参与 module 子集策略(module 映射主仓强相关)
1082
- * - 任一仓 fail → 整体 fail;主仓 skipped + 跨仓仓 passed → 整体 passed(跨仓仓有测试即有效)
1083
- *
1084
- * 单仓 ctx(无跨仓 entry)→ 直接返主仓结果,零行为变化(GOAL-2)。
1085
- *
1086
- * @param {object} mainResult - 主仓 runVerifyTestCheck 结果
1087
- * @param {object|null} ctx - MultiRepoContext 实例
1088
- * @returns {object} 合并后结果(shape 同 mainResult)
1089
- */
1090
- function mergeCrossRepoResults(mainResult, ctx) {
1091
- if (!ctx || typeof ctx.repos !== 'object' || ctx.repos === null) return mainResult
1092
- const crossEntries = []
1093
- for (const entry of ctx.repos.values()) {
1094
- if (entry && entry.isMain === false) crossEntries.push(entry)
1095
- }
1096
- if (crossEntries.length === 0) return mainResult
1097
-
1098
- const crossResults = []
1099
- for (const entry of crossEntries) {
1100
- const crossResult = runCrossRepoFullTest(entry)
1101
- crossResults.push({ repoKey: entry.repoKey, projectRoot: entry.projectRoot, result: crossResult })
1102
- }
1103
-
1104
- // 合并:任一 fail → fail;否则取主仓 status(passed/skipped 与跨仓 passed 合并)
1105
- const failedRepos = crossResults.filter(r => r.result.status === 'failed')
1106
- if (failedRepos.length > 0) {
1107
- return mergeResultStatus({
1108
- status: 'failed',
1109
- mainResult,
1110
- crossResults,
1111
- reason: `跨仓仓测试失败:${failedRepos.map(r => r.repoKey).join(', ')}`,
1112
- })
1113
- }
1114
- // 跨仓仓全 passed 或 skipped(无 package.json)→ 主仓 status 不变(合并跨仓信息到 outputTail)
1115
- return mergeResultInfo(mainResult, crossResults)
1116
- }
1117
-
1118
- /**
1119
- * 在单个跨仓仓根跑 full npm test(跨仓仓不参与 module 子集,只跑 full)。
1120
- * 跨仓仓 own local.yaml 若存在且配 commands.test → 用之;否则 fallback `npm test`。
1121
- * 跨仓仓无 package.json → 跳过 + warn。
1122
- *
1123
- * @param {object} entry - RepoEntry(isMain=false)
1124
- * @returns {object} 结果 shape 对齐 runFullCommand 返回
1125
- */
1126
- function runCrossRepoFullTest(entry) {
1127
- const projectRoot = entry.projectRoot
1128
- // 跨仓仓无 package.json → 跳过 + warn(design §9 兼容策略,不阻断 verify)
1129
- if (!existsSync(join(projectRoot, 'package.json'))) {
1130
- console.warn(`⚠️ 跨仓 repo "${entry.repoKey}"(${projectRoot})无 package.json,跳过该仓 npm test(design §9 兼容策略,不阻断 verify)。`)
1131
- return {
1132
- status: 'skipped',
1133
- command: null,
1134
- exitCode: null,
1135
- durationMs: null,
1136
- outputTail: null,
1137
- reason: `跨仓 repo "${entry.repoKey}" 无 package.json,跳过 npm test`,
1138
- resultPath: null,
1139
- mode: 'cross-repo-skip',
1140
- repoKey: entry.repoKey,
1141
- }
1142
- }
1143
-
1144
- // 跨仓仓 own local.yaml(在跨仓仓 .sillyspec/ 下,若存在)配 commands.test → 用之;否则 `npm test`
1145
- // 注:跨仓仓按 NG-1 不建 .sillyspec/,但容错读取(用户可手动放 local.yaml 配跨仓仓特定测试命令)
1146
- const crossLocalYaml = join(projectRoot, '.sillyspec', 'local.yaml')
1147
- let command = 'npm test'
1148
- let crossKnownFailures = []
1149
- if (existsSync(crossLocalYaml)) {
1150
- try {
1151
- const crossYaml = readFileSync(crossLocalYaml, 'utf8')
1152
- const extracted = extractTestCommand(crossYaml)
1153
- if (extracted) command = extracted
1154
- crossKnownFailures = extractKnownFailures(crossYaml)
1155
- } catch { /* 读取失败 fallback npm test */ }
1156
- }
1157
-
1158
- const startedAt = Date.now()
1159
- let exitCode = 0
1160
- let output = ''
1161
- let reason = null
1162
- try {
1163
- output = execSync(command, {
1164
- cwd: projectRoot,
1165
- encoding: 'utf8',
1166
- timeout: TEST_TIMEOUT_MS,
1167
- maxBuffer: 32 * 1024 * 1024,
1168
- stdio: ['ignore', 'pipe', 'pipe'],
1169
- })
1170
- } catch (e) {
1171
- exitCode = typeof e.status === 'number' ? e.status : 1
1172
- output = [e.stdout, e.stderr].filter(Boolean).join('\n') || e.message
1173
- reason = e.signal === 'SIGTERM' && Date.now() - startedAt >= TEST_TIMEOUT_MS
1174
- ? `跨仓 repo "${entry.repoKey}" 测试超时(>${TEST_TIMEOUT_MS / 1000}s)`
1175
- : `跨仓 repo "${entry.repoKey}" 测试退出码 ${exitCode}`
1176
- }
1177
- const durationMs = Date.now() - startedAt
1178
- const outputTail = output.length > OUTPUT_TAIL_CHARS ? '…' + output.slice(-OUTPUT_TAIL_CHARS) : output
1179
- const judged = judgeWithKnownFailures(exitCode, output, reason, crossKnownFailures)
1180
-
1181
- return {
1182
- status: judged.status,
1183
- command,
1184
- exitCode,
1185
- durationMs,
1186
- outputTail,
1187
- reason: judged.reason,
1188
- resultPath: null,
1189
- mode: 'cross-repo-full',
1190
- repoKey: entry.repoKey,
1191
- exemptedCount: judged.exemptedCount,
1192
- }
1193
- }
1194
-
1195
- /**
1196
- * 合并失败状态:整体 failed,保留主仓 + 各跨仓仓明细到 outputTail / reason。
1197
- */
1198
- function mergeResultStatus({ status, mainResult, crossResults, reason }) {
1199
- const parts = []
1200
- parts.push(`── main (${mainResult.status}) ──\n${mainResult.outputTail || mainResult.reason || ''}`)
1201
- for (const cr of crossResults) {
1202
- parts.push(`── cross-repo ${cr.repoKey} (${cr.result.status}) ──\n${cr.result.outputTail || cr.result.reason || ''}`)
1203
- }
1204
- const mergedTail = parts.join('\n')
1205
- return {
1206
- status,
1207
- command: mainResult.command ? `${mainResult.command} + cross-repo[${crossResults.map(r => r.repoKey).join(',')}]` : `cross-repo[${crossResults.map(r => r.repoKey).join(',')}]`,
1208
- exitCode: 1,
1209
- durationMs: (mainResult.durationMs || 0) + crossResults.reduce((n, r) => n + (r.result.durationMs || 0), 0),
1210
- outputTail: mergedTail.length > OUTPUT_TAIL_CHARS ? '…' + mergedTail.slice(-OUTPUT_TAIL_CHARS) : mergedTail,
1211
- reason,
1212
- resultPath: mainResult.resultPath,
1213
- mode: 'cross-repo-merged',
1214
- fallbackReason: mainResult.fallbackReason || null,
1215
- }
1216
- }
1217
-
1218
- /**
1219
- * 合并信息(跨仓仓全 passed/skipped):主仓 status 保留,跨仓仓 PASSED 信息附入 outputTail。
1220
- */
1221
- function mergeResultInfo(mainResult, crossResults) {
1222
- const crossPassed = crossResults.filter(r => r.result.status === 'passed')
1223
- const crossSkipped = crossResults.filter(r => r.result.status === 'skipped')
1224
- if (crossPassed.length === 0 && crossSkipped.length === 0) return mainResult
1225
- const crossSummary = []
1226
- for (const cr of crossPassed) crossSummary.push(`cross-repo ${cr.repoKey}: PASS`)
1227
- for (const cr of crossSkipped) crossSummary.push(`cross-repo ${cr.repoKey}: SKIP(${cr.result.reason || 'no package.json'})`)
1228
- const crossLine = `\n── 跨仓仓 npm test ──\n${crossSummary.join('\n')}`
1229
- const mergedTail = (mainResult.outputTail || '') + crossLine
1230
- return {
1231
- ...mainResult,
1232
- outputTail: mergedTail.length > OUTPUT_TAIL_CHARS ? '…' + mergedTail.slice(-OUTPUT_TAIL_CHARS) : mergedTail,
1233
- mode: mainResult.mode ? `${mainResult.mode}+cross-repo` : 'cross-repo-merged',
1234
- }
1235
- }
1236
-
1237
- /**
1238
- * 全量跑 commands.test(现有逻辑,brownfield 行为不变)。
1239
- */
1240
- /**
1241
- * 从测试命令文本提取疑似服务端口(坑 verify-devserver-port-race,2026-08-22 实证:CLI 全量
1242
- * 对账与用户自留 dev server 资源竞争——端口被占导致测试失败,差点误报 FAIL 成代码问题)。
1243
- * 认 --port=N / --port N / PORT=N。
1244
- * @param {string} cmd
1245
- * @returns {number[]}
1246
- */
1247
- function extractPortsFromCommand(cmd) {
1248
- const s = String(cmd || '')
1249
- const ports = new Set()
1250
- for (const m of s.matchAll(/--port[=\s]+(\d{2,5})/gi)) ports.add(Number(m[1]))
1251
- for (const m of s.matchAll(/\bPORT=(\d{2,5})/gi)) ports.add(Number(m[1]))
1252
- return [...ports]
1253
- }
1254
-
1255
- /**
1256
- * 端口占用探测(同步 spawnSync node 试连——verify 实测是同步 execSync 流,无法 await)。
1257
- * @param {number} port
1258
- * @returns {boolean} true=已被占用(疑似自留 dev server/长驻服务在跑)
1259
- */
1260
- function isPortOccupiedSync(port) {
1261
- try {
1262
- const { spawnSync } = require('node:child_process')
1263
- const r = spawnSync(process.execPath, ['-e',
1264
- `const n=require('node:net');const s=n.connect(${port},'127.0.0.1',()=>{console.log('Y');s.end()});s.on('error',()=>console.log('N'));setTimeout(()=>{console.log('N');process.exit(0)},1500)`],
1265
- { encoding: 'utf8', timeout: 4000 })
1266
- return (r.stdout || '').trim().endsWith('Y')
1267
- } catch { return false }
1268
- }
1269
-
1270
- /**
1271
- * 实测前资源竞争预警(坑 verify-devserver-port-race):测试命令涉及的端口已被占用 →
1272
- * 显著 warn「疑似自留 dev server」+ 建议停服务重跑——防把资源竞争误判成代码问题报 FAIL。
1273
- * best-effort:探测失败静默。
1274
- */
1275
- function warnPortRaceBeforeRun(command) {
1276
- try {
1277
- const ports = extractPortsFromCommand(command)
1278
- for (const p of ports) {
1279
- if (isPortOccupiedSync(p)) {
1280
- console.warn(`⚠️ 端口 ${p} 已被占用(测试命令 ${command.slice(0, 50)}… 引用)——疑似你自留的 dev server/长驻服务。`)
1281
- console.warn(` 测试若因此失败(端口冲突/EADDRINUSE),是资源竞争而非代码问题——停掉占用服务(或换端口)后重跑 verify 再定论,勿直接报 FAIL。`)
1282
- }
1283
- }
1284
- } catch { /* 探测失败不阻断实测 */ }
1285
- }
1286
-
1287
- function runFullCommand({ yamlText, localYamlPath, cwd, specBase, changeName, fallbackReason = null, knownFailures = [] }) {
1288
- const command = extractTestCommand(yamlText)
1289
-
1290
- if (!command) {
1291
- return {
1292
- status: 'skipped',
1293
- command: null,
1294
- exitCode: null,
1295
- durationMs: null,
1296
- outputTail: null,
1297
- reason: yamlText
1298
- ? 'local.yaml 未配置 commands.test(或标记 unavailable)'
1299
- : `local.yaml 不存在(${localYamlPath})`,
1300
- resultPath: null,
1301
- mode: 'full',
1302
- fallbackReason,
1303
- }
1304
- }
1305
-
1306
- const startedAt = Date.now()
1307
- let exitCode = 0
1308
- let output = ''
1309
- let reason = null
1310
- warnPortRaceBeforeRun(command)
1311
- try {
1312
- output = execSync(command, {
1313
- cwd,
1314
- encoding: 'utf8',
1315
- timeout: TEST_TIMEOUT_MS,
1316
- maxBuffer: 32 * 1024 * 1024,
1317
- stdio: ['ignore', 'pipe', 'pipe'],
1318
- })
1319
- } catch (e) {
1320
- exitCode = typeof e.status === 'number' ? e.status : 1
1321
- output = [e.stdout, e.stderr].filter(Boolean).join('\n') || e.message
1322
- reason = e.signal === 'SIGTERM' && Date.now() - startedAt >= TEST_TIMEOUT_MS
1323
- ? `测试命令超时(>${TEST_TIMEOUT_MS / 1000}s)`
1324
- : `测试命令退出码 ${exitCode}`
1325
- // 资源竞争鉴别提示(坑 verify-devserver-port-race):EADDRINUSE/端口占用类失败极可能是
1326
- // 自留 dev server 竞争而非代码问题——输出里明示鉴别路径,防误报 FAIL
1327
- if (/EADDRINUSE|address already in use|端口.*被占用|port.*already/i.test(output)) {
1328
- reason += '。⚠️ 输出含端口占用信号(EADDRINUSE)——极可能是与你自留 dev server 的资源竞争而非代码问题:停掉占用服务后重跑 verify 再定论'
1329
- }
1330
- }
1331
- const durationMs = Date.now() - startedAt
1332
- const outputTail = output.length > OUTPUT_TAIL_CHARS ? '…' + output.slice(-OUTPUT_TAIL_CHARS) : output
1333
-
1334
- const judged = judgeWithKnownFailures(exitCode, output, reason, knownFailures)
1335
- const result = {
1336
- status: judged.status,
1337
- command,
1338
- exitCode,
1339
- durationMs,
1340
- outputTail,
1341
- reason: judged.reason,
1342
- resultPath: null,
1343
- mode: 'full',
1344
- fallbackReason,
1345
- exemptedCount: judged.exemptedCount,
1346
- }
1347
-
1348
- writeRunResult({ specBase, changeName, result, extra: fallbackReason ? { fallback_reason: fallbackReason } : {} })
1349
- return result
1350
- }
1351
-
1352
- /**
1353
- * 串行跑命中的模块子集,聚合结果。
1354
- * 返回 shape 与 runFullCommand 一致(status/command/exitCode/durationMs/outputTail/reason/resultPath)。
1355
- */
1356
- function runModuleSubset({ cwd, specBase, changeName, hits, knownFailures = [] }) {
1357
- const subsetStartedAt = Date.now()
1358
- const perModule = hits.map(h => runOneModule(h.name, h.test, cwd, knownFailures))
1359
- const status = aggregateStatus(perModule)
1360
-
1361
- const command = `module[${hits.map(h => h.name).join(',')}]`
1362
- const exitCode = status === 'passed' ? 0 : 1
1363
- const durationMs = Date.now() - subsetStartedAt
1364
-
1365
- // 合并各模块输出尾部(标注模块名)
1366
- const outputTail = perModule
1367
- .map(r => `── module ${r.name} (${r.status}) ──\n${r.outputTail || ''}`)
1368
- .join('\n')
1369
- const reason = status === 'passed'
1370
- ? null
1371
- : `模块子集测试失败:${perModule.filter(r => r.status === 'failed').map(r => r.name).join(', ')}`
1372
- // 失败模块的 reason 明细透传(坑 verify-devserver-port-race:EADDRINUSE 资源竞争鉴别
1373
- // 提示在 runOneModule 的 reason 里,不透传会被顶层 reason 吞掉)
1374
- + (perModule.filter(r => r.status === 'failed' && r.reason).some(r => /EADDRINUSE|资源竞争/.test(r.reason))
1375
- ? '。' + perModule.filter(r => r.status === 'failed' && r.reason && /EADDRINUSE|资源竞争/.test(r.reason)).map(r => r.reason).join(';')
1376
- : '')
1377
-
1378
- const result = {
1379
- status,
1380
- command,
1381
- exitCode,
1382
- durationMs,
1383
- outputTail: outputTail.length > OUTPUT_TAIL_CHARS ? '…' + outputTail.slice(-OUTPUT_TAIL_CHARS) : outputTail,
1384
- reason,
1385
- resultPath: null,
1386
- mode: 'module-subset',
1387
- fallbackReason: null,
1388
- exemptedCount: perModule.reduce((n, r) => n + (r.exemptedCount || 0), 0),
1389
- }
1390
-
1391
- writeRunResult({
1392
- specBase,
1393
- changeName,
1394
- result,
1395
- extra: {
1396
- modules: perModule.map(r => ({
1397
- name: r.name,
1398
- command: r.command,
1399
- exit_code: r.exitCode,
1400
- status: r.status,
1401
- duration_ms: r.durationMs,
1402
- output_tail: r.outputTail,
1403
- reason: r.reason,
1404
- })),
1405
- },
1406
- })
1407
- return result
1408
- }
1409
-
1410
- /**
1411
- * 结果落盘到 .runtime/verify-runs/<ts>/test-result.json(供追溯与 SillyHub 消费)。
1412
- * 多模块时 extra.modules 描述各模块明细。
1413
- */
1414
- function writeRunResult({ specBase, changeName, result, extra = {} }) {
1415
- try {
1416
- const ts = new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '')
1417
- const runDir = join(specBase, '.runtime', 'verify-runs', ts)
1418
- mkdirSync(runDir, { recursive: true })
1419
- const resultPath = join(runDir, 'test-result.json')
1420
- writeFileSync(resultPath, JSON.stringify({
1421
- change: changeName,
1422
- command: result.command,
1423
- exit_code: result.exitCode,
1424
- status: result.status,
1425
- duration_ms: result.durationMs,
1426
- output_tail: result.outputTail,
1427
- reason: result.reason,
1428
- ran_at: new Date().toISOString(),
1429
- ...extra,
1430
- }, null, 2) + '\n')
1431
- result.resultPath = resultPath
1432
- } catch (e) {
1433
- console.warn(`⚠️ verify 实测结果落盘失败: ${e.message}`)
1434
- }
1435
- }
1436
-
1437
- /** 打印实测结果(人类/agent 可读) */
1438
- export function printVerifyTestCheck(result) {
1439
- if (result.status === 'skipped') {
1440
- console.warn(`\n⚠️ Verify 实测跳过:${result.reason}`)
1441
- if (result.mode === 'strategy-skip') {
1442
- // R-07:skip 由 test_strategy 显式生效(skip 配置 / evidence-auto 推荐),非「未配命令」——
1443
- // 不给「去配 commands.test」的误导建议,改标审计口径
1444
- console.warn(' (跳过由 test_strategy 配置生效,本次 verify 结论不含测试客观核验;跳过依据见上方 reason 并已落盘 test-result.json 留审计痕迹。)')
1445
- } else {
1446
- console.warn(' 建议在 local.yaml 的 commands.test 配置真实测试命令,让 CLI 可客观对账。')
1447
- }
1448
- return
1449
- }
1450
- if (result.status === 'passed') {
1451
- if (result.exemptedCount > 0) {
1452
- console.log(`\n✅ Verify 实测通过(含 ${result.exemptedCount} 个 known_failures 豁免):\`${result.command}\` — ${result.reason}`)
1453
- console.warn(' ⚠️ 本次 PASS 依赖 known_failures 豁免清单——请人工复核清单是否过宽(避免误豁免本变更引入的真实失败)。')
1454
- } else {
1455
- console.log(`\n✅ Verify 实测通过:\`${result.command}\` 退出码 0(${(result.durationMs / 1000).toFixed(1)}s)`)
1456
- }
1457
- } else {
1458
- console.error(`\n❌ Verify 实测失败:\`${result.command}\` — ${result.reason}`)
1459
- if (result.outputTail) {
1460
- const tail = result.outputTail.split('\n').slice(-20).join('\n')
1461
- console.error(' 输出(末尾):')
1462
- for (const line of tail.split('\n')) console.error(` | ${line}`)
1463
- }
1464
- }
1465
- // —— 全量 fallback 明示(skipped 已提前 return,此处仅 passed/failed)——
1466
- // 让 agent 知道本次跑的是全量 commands.test、非变更范围子集;失败可能含未变更模块
1467
- // 的预存错误,需先核对用例归属再归因到本次变更(见 3.24 verify 坑1)。
1468
- if (result.mode === 'full' && result.fallbackReason) {
1469
- if (result.status === 'failed') {
1470
- console.warn(` ⚠️ 本次跑的是 commands.test 全量(${result.fallbackReason})。`)
1471
- console.warn(' 失败可能含与本变更无关的预存错误——先核对失败用例是否属于你的变更范围;')
1472
- console.warn(' 或在 local.yaml 配置 test_strategy: module + modules: 块以收窄到变更模块。')
1473
- } else {
1474
- console.warn(` ⚠️ 本次跑的是 commands.test 全量(${result.fallbackReason})。`)
1475
- console.warn(' 如耗时过长,可在 local.yaml 配置 test_strategy: module + modules: 块按模块收窄。')
1476
- }
1477
- }
1478
- if (result.resultPath) {
1479
- console.log(`📄 实测结果已写入: ${result.resultPath}`)
1480
- }
1481
- }
1482
-
1483
- /**
1484
- * API parity 对账(advisory):前端调用 vs execute 提取的后端 endpoint artifact。
1485
- * 三态:skipped(无 provider artifact → 非全栈项目不打扰)/ warning(missingBackend>0)/ passed。
1486
- * 启发式正则、多假阳源 → advisory 不阻断 verify 完成(与 SillySpec 确定性校验定位一致)。
1487
- *
1488
- * @param {object} opts
1489
- * @param {string} opts.cwd - 扫描前端调用的根(主工作区,verify 时代码在此)
1490
- * @param {string} opts.specBase
1491
- * @param {string|null} [opts.changeName]
1492
- * @param {string|null} [opts.runtimeRoot]
1493
- * @returns {{ status: 'skipped'|'warning'|'passed', missingBackend: Array, unusedBackend: Array, summary: string, reason: string|null }}
1494
- */
1495
- export function runVerifyParityCheck({ cwd, specBase, changeName = null, runtimeRoot = null }) {
1496
- const r = verifyApiParity(specBase, cwd, runtimeRoot, changeName)
1497
- // 无 provider artifact(execute 未提取 / 非后端项目)→ 不打扰
1498
- if (r.backendCount === 0) {
1499
- return { status: 'skipped', missingBackend: [], unusedBackend: [], summary: r.summary, reason: '无后端契约 artifact(非全栈项目或 execute 未提取端点)' }
1500
- }
1501
- if (r.missingBackend.length > 0) {
1502
- return { status: 'warning', missingBackend: r.missingBackend, unusedBackend: r.unusedBackend, summary: r.summary, reason: null }
1503
- }
1504
- return { status: 'passed', missingBackend: [], unusedBackend: r.unusedBackend, summary: r.summary, reason: null }
1505
- }
1506
-
1507
- /** 打印 parity 对账结果(advisory,不阻断) */
1508
- export function printVerifyParityCheck(result) {
1509
- if (result.status === 'skipped') return // 静默,不打扰非全栈项目
1510
- if (result.status === 'passed') {
1511
- console.log(`\n✅ API parity 对账通过:${result.summary}`)
1512
- return
1513
- }
1514
- // warning
1515
- console.warn(`\n⚠️ API parity 对账发现 ${result.missingBackend.length} 个前端调用无对应后端端点(advisory,不阻断归档):`)
1516
- for (const m of result.missingBackend.slice(0, 20)) {
1517
- console.warn(` - ${m.method} ${m.path} ← ${m.consumerFile}:${m.consumerLine}`)
1518
- }
1519
- if (result.missingBackend.length > 20) console.warn(` …还有 ${result.missingBackend.length - 20} 个`)
1520
- console.warn(' 提示:检查是否后端漏实现,或前端调用了尚未实现的端点。确认无误可在 design.md 标注豁免。')
1521
- }
1522
-
1523
- /**
1524
- * 删除探针(advisory):用 git 事实客观对账本次变更删除的文件 vs design.md 声明的操作。
1525
- *
1526
- * 切斯特顿栅栏护栏——verify 对「agent 静默删除代码」本是盲区:agent 删一段它看不懂的
1527
- * 旧代码,只要路径合规、不碰风险关键词,5 探针 + 风险分级 + 测试对账全都不会响。本探针
1528
- * 不信任 agent 自报告,用 `git diff --name-status HEAD` 客观提取删除文件,对账 design
1529
- * 清单声明的操作(声明「新增/修改」却整文件删除 = 高风险)。warning 不阻断 verify 完成
1530
- * (advisory 起步)——「检测到删除」是确定性事实(做),「该不该删」是意图(只报不拦)。
1531
- *
1532
- * 信号源:apply(git apply --3way)不 commit,verify 时主仓 HEAD 仍是变更前 commit,
1533
- * 删除的文件在工作树消失但仍在 HEAD → `git diff --name-status HEAD` 显示 D。
1534
- *
1535
- * @param {object} opts
1536
- * @param {string} opts.cwd - 项目根(主仓,代码在此)
1537
- * @param {string} opts.specBase - .sillyspec(或平台 specRoot)
1538
- * @param {string|null} [opts.changeName]
1539
- * @returns {{
1540
- * status: 'skipped'|'warning'|'passed',
1541
- * highRisk: Array<{path:string, declaredOp:string, reason:string}>,
1542
- * mediumRisk: Array<{path:string, reason:string}>,
1543
- * compliant: Array<{path:string, declaredOp:string}>,
1544
- * summary: string,
1545
- * reason: string|null,
1546
- * }}
1547
- */
1548
- export function runVerifyDeletionCheck({ cwd, specBase, changeName = null }) {
1549
- const statusRaw = runGitDiffNameStatus(cwd, 'HEAD')
1550
- if (statusRaw === null) {
1551
- return { status: 'skipped', highRisk: [], mediumRisk: [], compliant: [],
1552
- summary: '', reason: 'git 不可用或非仓库,删除对账跳过' }
1553
- }
1554
-
1555
- // 解析 D(删除);R/C 的旧路径等价删除(防御 committed rename;标准 apply 流程
1556
- // rename 表现为纯 D,故本探针不加 -M,D 统一处理)。
1557
- const deletions = []
1558
- for (const line of statusRaw.split('\n').filter(Boolean)) {
1559
- const parts = line.split('\t')
1560
- const st = parts[0]
1561
- if (!st) continue
1562
- if (st.startsWith('D')) {
1563
- deletions.push({ path: parts[1], kind: 'D' })
1564
- } else if ((st.startsWith('R') || st.startsWith('C')) && parts.length >= 3) {
1565
- // rename/copy 旧路径(parts[1])等价删除,新路径 parts[2]
1566
- deletions.push({ path: parts[1], kind: 'R-old', renamedTo: parts[2] })
1567
- }
1568
- }
1569
-
1570
- // 排除交付物外文件(.sillyspec/ 变更包/运行时/quicklog + meta.json),避免污染删除信号。
1571
- // 复用 worktree-apply.js 的 filterDeliverableFiles 去双写(坑3:保留 .sillyspec/docs/)。
1572
- let deliverable = filterDeliverableFiles(deletions.map(d => d.path))
1573
- .map(p => deletions.find(d => d.path === p))
1574
-
1575
- // 他者声明归属过滤(坑 verify-reconcile-foreign-wip):主仓 HEAD diff 撞并行会话在途
1576
- // WIP 时,他者显式声明(quick --files / 他者 design 清单)的删除不参与本变更删除对账
1577
- // (否则「他者删的文件 × 本变更 design 三态」产出未声明删除误报)。无主删除保留(fail-closed)。
1578
- if (changeName && deliverable.length > 0) {
1579
- const { own, foreign } = splitOwnVsForeignDiffFiles(cwd, changeName, deliverable.map(d => d.path))
1580
- if (foreign.length > 0) {
1581
- console.warn(`⚠️ 删除对账已排除 ${foreign.length} 个并行会话声明的删除(${foreign.slice(0, 5).map(x => `${x.file}←${x.owners[0]}`).join(', ')}${foreign.length > 5 ? ' 等' : ''})`)
1582
- const keep = new Set(own)
1583
- deliverable = deliverable.filter(d => keep.has(d.path))
1584
- }
1585
- }
1586
-
1587
- if (deliverable.length === 0) {
1588
- return { status: 'skipped', highRisk: [], mediumRisk: [], compliant: [],
1589
- summary: '', reason: '本次变更无文件删除(或改动已被 commit,主仓 HEAD 已推进,删除对账无锚点)' }
1590
- }
1591
-
1592
- // 读 design 声明(operation)。无清单章节 → [],所有删除归「未声明」。
1593
- const designPath = changeName
1594
- ? join(specBase, 'changes', changeName, 'design.md') : null
1595
- const designEntries = designPath && existsSync(designPath)
1596
- ? parseFileChangeListDetailed(designPath) : []
1597
-
1598
- const highRisk = []
1599
- const mediumRisk = []
1600
- const compliant = []
1601
- for (const d of deliverable) {
1602
- const hit = designEntries.find(e => pathMatches(d.path, e.path))
1603
- if (!hit) {
1604
- mediumRisk.push({ path: d.path, reason: d.kind === 'R-old'
1605
- ? `重命名源文件未在 design 清单(→ ${d.renamedTo})`
1606
- : 'design 清单未列出该删除文件' })
1607
- continue
1608
- }
1609
- if (hit.operation === '新增' || hit.operation === '修改') {
1610
- highRisk.push({ path: d.path, declaredOp: hit.operation,
1611
- reason: `design 声明「${hit.operation}」但 git 显示整文件删除` })
1612
- } else if (hit.operation === '删除') {
1613
- compliant.push({ path: d.path, declaredOp: '删除' })
1614
- } else {
1615
- // operation=null(未声明操作)或 重命名:删除发生但声明不明确
1616
- mediumRisk.push({ path: d.path,
1617
- reason: `design 列出但操作为「${hit.operation || '未声明'}」,与删除不一致` })
1618
- }
1619
- }
1620
-
1621
- if (highRisk.length > 0 || mediumRisk.length > 0) {
1622
- return { status: 'warning', highRisk, mediumRisk, compliant,
1623
- summary: `${highRisk.length} 个高风险删除 + ${mediumRisk.length} 个未声明删除`, reason: null }
1624
- }
1625
- return { status: 'passed', highRisk: [], mediumRisk: [], compliant,
1626
- summary: `所有 ${compliant.length} 个删除均在 design 声明为「删除」`, reason: null }
1627
- }
1628
-
1629
- /** 打印删除对账结果(advisory,不阻断 verify 完成) */
1630
- export function printVerifyDeletionCheck(result) {
1631
- if (result.status === 'skipped') return // 静默:无删除 / git 不可用 / 改动已 commit
1632
- if (result.status === 'passed') {
1633
- console.log(`\n✅ 删除对账通过:${result.summary}`)
1634
- return
1635
- }
1636
- // warning
1637
- if (result.highRisk.length > 0) {
1638
- console.warn(`\n⚠️ 删除对账发现 ${result.highRisk.length} 个高风险删除(design 声明新增/修改却被整文件删除,advisory 不阻断):`)
1639
- for (const m of result.highRisk.slice(0, 20)) console.warn(` - ${m.path} (${m.reason})`)
1640
- if (result.highRisk.length > 20) console.warn(` …还有 ${result.highRisk.length - 20} 个`)
1641
- }
1642
- if (result.mediumRisk.length > 0) {
1643
- console.warn(`⚠️ ${result.mediumRisk.length} 个未声明删除(design 清单未列出 / 操作不一致):`)
1644
- for (const m of result.mediumRisk.slice(0, 20)) console.warn(` - ${m.path} (${m.reason})`)
1645
- if (result.mediumRisk.length > 20) console.warn(` …还有 ${result.mediumRisk.length - 20} 个`)
1646
- }
1647
- console.warn(' 提示:确认删除是否预期。预期删除请在 design.md 清单用「删除」操作显式声明;误删请恢复。')
1648
- }
1649
-
1650
- /**
1651
- * required-evidence 对账(advisory,不阻断 verify 完成)。
1652
- *
1653
- * execute 阶段 Task Review Gate 把 cannot_verify 任务的 requiredEvidence 写入
1654
- * changes/<change>/verify-required-evidence.json(schema: {generatedAt, schemaVersion, items:[{task, verdict, evidence:string[]}]})。
1655
- * 历史"死链"(sss1.md 矛盾2):只写不读——verify agent 不在 verify-result.md 体现也不会被发现,
1656
- * 且 verify.js prompt 让 agent 读 `requiredEvidence` 键(字段名错配,实际是 items[].evidence),照做必落空。
1657
- * 本探针闭合该链:读 evidence 文件,对每个 cannot_verify 任务检查 verify-result.md 是否提及该任务 id;
1658
- * 未提及 → warning(advisory)。CLI 只做"任务被提及"的机械存在性检查,evidence 是否真正满足
1659
- * (satisfied/missing/partial)由 agent 在 verify-result.md 诚实自报告——不假装语义判定(与删除探针同 altitude)。
1660
- *
1661
- * @param {{cwd:string, specBase:string, changeName?:string}} args
1662
- * @returns {{status:'skipped'|'passed'|'warning', items:Array, unacknowledged:Array, summary:string, reason:string|null}}
1663
- */
1664
- export function runVerifyRequiredEvidenceCheck({ cwd, specBase, changeName = null }) {
1665
- if (!changeName) {
1666
- return { status: 'skipped', items: [], unacknowledged: [], summary: '', reason: '无 changeName(quick 等无关联变更场景),evidence 对账跳过' }
1667
- }
1668
- const evidencePath = join(specBase, 'changes', changeName, 'verify-required-evidence.json')
1669
- if (!existsSync(evidencePath)) {
1670
- return { status: 'skipped', items: [], unacknowledged: [], summary: '', reason: '无 verify-required-evidence.json(execute 无 cannot_verify 任务),evidence 对账跳过' }
1671
- }
1672
-
1673
- let data
1674
- try {
1675
- data = JSON.parse(readFileSync(evidencePath, 'utf8'))
1676
- } catch (e) {
1677
- return { status: 'skipped', items: [], unacknowledged: [], summary: '', reason: `verify-required-evidence.json 解析失败(${e.message}),evidence 对账跳过` }
1678
- }
1679
- const items = Array.isArray(data.items) ? data.items : []
1680
-
1681
- // 读 verify-result.md(不存在则所有 evidence 任务都"未体现")
1682
- const verifyResultPath = join(specBase, 'changes', changeName, 'verify-result.md')
1683
- const report = existsSync(verifyResultPath) ? readFileSync(verifyResultPath, 'utf8') : ''
1684
-
1685
- const unacknowledged = []
1686
- for (const item of items) {
1687
- const task = item && item.task
1688
- if (!task) continue
1689
- // 机械存在性检查:verify-result.md 是否提及该 cannot_verify 任务 id。
1690
- // evidence 数组的具体满足度(satisfied/missing/partial)由 agent 自报告,CLI 不判定。
1691
- if (!report.includes(task)) {
1692
- const evidenceCount = Array.isArray(item.evidence) ? item.evidence.length : 0
1693
- unacknowledged.push({ task, verdict: item.verdict || 'cannot_verify', evidenceCount,
1694
- reason: `cannot_verify 任务 ${task} 未在 verify-result.md 中体现(需逐条 evidence 给结论 satisfied/missing/partial)` })
1695
- }
1696
- }
1697
-
1698
- if (unacknowledged.length > 0) {
1699
- return { status: 'warning', items, unacknowledged,
1700
- summary: `${items.length} 个 cannot_verify evidence 任务中 ${unacknowledged.length} 个未在 verify-result.md 体现`, reason: null }
1701
- }
1702
- return { status: 'passed', items, unacknowledged: [],
1703
- summary: `${items.length} 个 cannot_verify evidence 任务均在 verify-result.md 体现(满足度由 agent 自报告)`, reason: null }
1704
- }
1705
-
1706
- /** 打印 required-evidence 对账结果(advisory,不阻断 verify 完成) */
1707
- export function printVerifyRequiredEvidenceCheck(result) {
1708
- if (result.status === 'skipped') return // 静默:无 evidence 文件 / 无 changeName / 解析失败
1709
- if (result.status === 'passed') {
1710
- console.log(`\n✅ required-evidence 对账通过:${result.summary}`)
1711
- return
1712
- }
1713
- // warning
1714
- console.warn(`\n⚠️ required-evidence 对账发现 ${result.unacknowledged.length} 个 cannot_verify 任务未在 verify-result.md 体现(advisory 不阻断):`)
1715
- for (const u of result.unacknowledged.slice(0, 20)) console.warn(` - ${u.task} (${u.reason})`)
1716
- if (result.unacknowledged.length > 20) console.warn(` …还有 ${result.unacknowledged.length - 20} 个`)
1717
- console.warn(' 提示:execute 标记的 cannot_verify 任务需在 verify-result.md 逐条给 evidence 结论(satisfied/missing/partial)。CLI 仅查任务被提及,是否真满足由你诚实判定。')
1718
- }