sillyspec 3.27.2 → 3.27.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/.claude/skills/sillyspec-execute/SKILL.md +8 -0
  2. package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
  3. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  4. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  5. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  6. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  7. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  8. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  9. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  10. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  11. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
  12. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
  13. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  14. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  15. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  16. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  17. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  18. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
  19. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
  20. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  21. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  22. package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
  23. package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
  24. package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
  25. package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
  26. package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
  27. package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
  28. package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
  29. package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
  30. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  31. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  32. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
  33. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
  34. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
  35. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
  36. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
  37. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
  38. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
  39. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
  40. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
  41. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
  42. package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
  43. package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
  44. package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
  45. package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
  46. package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
  47. package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
  48. package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
  49. package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
  50. package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
  51. package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
  52. package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
  53. package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
  54. package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
  55. package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
  56. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
  57. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
  58. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
  59. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
  60. package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
  61. package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
  62. package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
  63. package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
  64. package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
  65. package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
  66. package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
  67. package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
  68. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
  69. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
  70. package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
  71. package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
  72. package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
  73. package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
  74. package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
  75. package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
  76. package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
  77. package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
  78. package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
  79. package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
  80. package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
  81. package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
  82. package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
  83. package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
  84. package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
  85. package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
  86. package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
  87. package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
  88. package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
  89. package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
  90. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
  91. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
  92. package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
  93. package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
  94. package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
  95. package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
  96. package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
  97. package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
  98. package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
  99. package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
  100. package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
  101. package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
  102. package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
  103. package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
  104. package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
  105. package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
  106. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
  107. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
  108. package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
  109. package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
  110. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
  111. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
  112. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
  113. package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
  114. package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
  115. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
  116. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
  117. package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
  118. package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
  119. package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
  120. package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
  121. package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
  122. package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
  123. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
  124. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
  125. package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
  126. package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
  127. package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
  128. package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
  129. package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
  130. package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
  131. package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
  132. package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
  133. package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
  134. package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
  135. package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
  136. package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
  137. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
  138. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
  139. package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
  140. package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
  141. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
  142. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
  143. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
  144. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
  145. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
  146. package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  147. package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  148. package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  149. package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  150. package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  151. package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  152. package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  153. package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  154. package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
  155. package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
  156. package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  157. package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  158. package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
  159. package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  160. package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  161. package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  162. package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
  163. package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
  164. package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  165. package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  166. package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
  167. package/.worktrees/8d2d0392/.gitattributes +2 -0
  168. package/.worktrees/8d2d0392/.husky/pre-push +20 -0
  169. package/.worktrees/8d2d0392/README.md +203 -0
  170. package/.worktrees/8d2d0392/SKILL.md +91 -0
  171. package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
  172. package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
  173. package/.worktrees/8d2d0392/eval/README.md +86 -0
  174. package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
  175. package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
  176. package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
  177. package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
  178. package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
  179. package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
  180. package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
  181. package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
  182. package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
  183. package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
  184. package/.worktrees/8d2d0392/eval/run.mjs +83 -0
  185. package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
  186. package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  187. package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
  188. package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
  189. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
  190. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  191. package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  192. package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
  193. package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
  194. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  195. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
  196. package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  197. package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
  198. package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
  199. package/.worktrees/8d2d0392/logo.jpg +0 -0
  200. package/.worktrees/8d2d0392/package-lock.json +977 -0
  201. package/.worktrees/8d2d0392/package.json +41 -0
  202. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  203. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  204. package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
  205. package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
  206. package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
  207. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
  208. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
  209. package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
  210. package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
  211. package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
  212. package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
  213. package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
  214. package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
  215. package/.worktrees/8d2d0392/src/change-list.js +290 -0
  216. package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
  217. package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
  218. package/.worktrees/8d2d0392/src/classify-change.js +109 -0
  219. package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
  220. package/.worktrees/8d2d0392/src/config-cat.js +88 -0
  221. package/.worktrees/8d2d0392/src/config-schema.js +328 -0
  222. package/.worktrees/8d2d0392/src/constants.js +97 -0
  223. package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
  224. package/.worktrees/8d2d0392/src/datetime.js +20 -0
  225. package/.worktrees/8d2d0392/src/db-engine.js +55 -0
  226. package/.worktrees/8d2d0392/src/db.js +381 -0
  227. package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
  228. package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
  229. package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
  230. package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
  231. package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
  232. package/.worktrees/8d2d0392/src/docs-check.js +825 -0
  233. package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
  234. package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
  235. package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
  236. package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
  237. package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
  238. package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
  239. package/.worktrees/8d2d0392/src/git-helper.js +150 -0
  240. package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
  241. package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
  242. package/.worktrees/8d2d0392/src/index.js +2854 -0
  243. package/.worktrees/8d2d0392/src/init.js +626 -0
  244. package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
  245. package/.worktrees/8d2d0392/src/local-detect.js +128 -0
  246. package/.worktrees/8d2d0392/src/local-register.js +104 -0
  247. package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
  248. package/.worktrees/8d2d0392/src/migrate.js +127 -0
  249. package/.worktrees/8d2d0392/src/module-impact.js +166 -0
  250. package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
  251. package/.worktrees/8d2d0392/src/modules.js +580 -0
  252. package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
  253. package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
  254. package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
  255. package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
  256. package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
  257. package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
  258. package/.worktrees/8d2d0392/src/progress.js +1304 -0
  259. package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
  260. package/.worktrees/8d2d0392/src/quicklog.js +883 -0
  261. package/.worktrees/8d2d0392/src/review-tier.js +77 -0
  262. package/.worktrees/8d2d0392/src/run/command.js +1641 -0
  263. package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
  264. package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
  265. package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
  266. package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
  267. package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
  268. package/.worktrees/8d2d0392/src/run/next.js +128 -0
  269. package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
  270. package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
  271. package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
  272. package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
  273. package/.worktrees/8d2d0392/src/run/stage.js +587 -0
  274. package/.worktrees/8d2d0392/src/run.js +23 -0
  275. package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
  276. package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
  277. package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
  278. package/.worktrees/8d2d0392/src/setup.js +414 -0
  279. package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
  280. package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
  281. package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
  282. package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
  283. package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
  284. package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
  285. package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
  286. package/.worktrees/8d2d0392/src/stage-review.js +597 -0
  287. package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
  288. package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
  289. package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
  290. package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
  291. package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
  292. package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
  293. package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
  294. package/.worktrees/8d2d0392/src/stages/index.js +29 -0
  295. package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
  296. package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
  297. package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
  298. package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
  299. package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
  300. package/.worktrees/8d2d0392/src/stages/status.js +64 -0
  301. package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
  302. package/.worktrees/8d2d0392/src/sync.js +1470 -0
  303. package/.worktrees/8d2d0392/src/task-review.js +1498 -0
  304. package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
  305. package/.worktrees/8d2d0392/src/taskcard.js +217 -0
  306. package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
  307. package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
  308. package/.worktrees/8d2d0392/src/version.js +19 -0
  309. package/.worktrees/8d2d0392/src/workflow.js +600 -0
  310. package/.worktrees/8d2d0392/src/workspace.js +125 -0
  311. package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
  312. package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
  313. package/.worktrees/8d2d0392/src/worktree.js +1838 -0
  314. package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
  315. package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
  316. package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
  317. package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
  318. package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
  319. package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
  320. package/architecture-analysis.md +448 -0
  321. package/eval/README.md +86 -0
  322. package/eval/eval.config.json +28 -0
  323. package/eval/lib/adapters/cli.mjs +63 -0
  324. package/eval/lib/adapters/dryrun.mjs +27 -0
  325. package/eval/lib/config.mjs +82 -0
  326. package/eval/lib/db.mjs +76 -0
  327. package/eval/lib/report.mjs +120 -0
  328. package/eval/lib/runner.mjs +157 -0
  329. package/eval/lib/tasks.mjs +73 -0
  330. package/eval/lib/util.mjs +107 -0
  331. package/eval/lib/workdir.mjs +30 -0
  332. package/eval/run.mjs +83 -0
  333. package/eval/tasks/001-slugify/files/package.json +6 -0
  334. package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  335. package/eval/tasks/001-slugify/task.json +6 -0
  336. package/eval/tasks/001-slugify/verify.mjs +28 -0
  337. package/eval/tasks/002-each-day/files/package.json +6 -0
  338. package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  339. package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  340. package/eval/tasks/002-each-day/task.json +6 -0
  341. package/eval/tasks/002-each-day/verify.mjs +31 -0
  342. package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  343. package/eval/tasks/003-word-report/files/package.json +6 -0
  344. package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  345. package/eval/tasks/003-word-report/task.json +6 -0
  346. package/eval/tasks/003-word-report/verify.mjs +38 -0
  347. package/package.json +4 -2
  348. package/src/agent-session-log.js +45 -5
  349. package/src/change-risk-profile.js +83 -14
  350. package/src/config-schema.js +18 -3
  351. package/src/contract-matrix.js +90 -29
  352. package/src/datetime.js +20 -0
  353. package/src/decision-distill.js +517 -0
  354. package/src/dispatch/backends/local-agent.js +4 -4
  355. package/src/docs-check.js +227 -0
  356. package/src/docs-debt.js +187 -24
  357. package/src/doctor-diagnostics.js +102 -2
  358. package/src/endpoint-extractor.js +41 -52
  359. package/src/foreign-declared.js +155 -0
  360. package/src/index.js +95 -13
  361. package/src/init.js +9 -7
  362. package/src/knowledge-match.js +107 -6
  363. package/src/local-register.js +7 -1
  364. package/src/module-resolve.js +12 -1
  365. package/src/modules.js +2 -1
  366. package/src/plan-adopt-waves.js +126 -0
  367. package/src/quicklog.js +50 -4
  368. package/src/run/command.js +124 -44
  369. package/src/run/complete-handlers.js +48 -19
  370. package/src/run/complete.js +5 -2
  371. package/src/run/gates.js +104 -22
  372. package/src/run/prompt.js +84 -42
  373. package/src/run/quick-audit.js +11 -0
  374. package/src/run/shared.js +152 -10
  375. package/src/run/stage.js +8 -5
  376. package/src/run.js +2 -2
  377. package/src/scan-postcheck.js +30 -17
  378. package/src/stage-contract-spec.js +3 -2
  379. package/src/stage-contract.js +68 -4
  380. package/src/stages/archive.js +53 -12
  381. package/src/stages/brainstorm-auto.js +50 -1
  382. package/src/stages/brainstorm.js +13 -0
  383. package/src/stages/doctor.js +157 -1
  384. package/src/stages/execute.js +32 -6
  385. package/src/stages/plan-postcheck.js +76 -17
  386. package/src/stages/plan.js +9 -4
  387. package/src/stages/quick.js +6 -1
  388. package/src/stages/verify.js +32 -15
  389. package/src/sync.js +41 -3
  390. package/src/task-review.js +2 -2
  391. package/src/taskcard-placeholders.js +21 -0
  392. package/src/taskcard.js +43 -1
  393. package/src/verify-postcheck.js +315 -13
  394. package/src/verify-probes.js +73 -10
  395. package/src/worktree-apply.js +569 -227
  396. package/src/worktree-deps.js +150 -1
  397. package/src/worktree.js +285 -77
  398. package/templates/prompts/taskcard-rules.md +2 -1
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * knowledge-match.js — knowledge 关键词匹配引擎
3
- * 从 INDEX.md 解析知识条目,按任务上下文匹配并生成 hit report
3
+ * 从 INDEX.md 解析知识条目,按任务上下文匹配并生成 hit report;
4
+ * 扫描范围含 decisions 决策库(knowledge/decisions/<域>.md,经 INDEX.md ## Decisions 段
5
+ * 路由行发现——路由行由 decision-distill 幂等写入,本引擎只消费不写)——命中路由行的
6
+ * 决策文件解析为 decisionHits(rejected 优先),供 brainstorm Step2 防复潮注入(task-04,FR-05)。
7
+ * decisions 库不存在时(INDEX 无 Decisions 段/文件不存在)一切行为与无 decisions 库时一致。
4
8
  */
5
9
 
6
10
  import { existsSync, readFileSync } from 'fs'
@@ -41,6 +45,86 @@ export function parseKnowledgeIndex(indexDir) {
41
45
  return entries
42
46
  }
43
47
 
48
+ // ---------------------------------------------------------------------------
49
+ // decisions 决策库扫描(task-04,FR-05):经 INDEX.md ## Decisions 段路由行发现
50
+ // knowledge/decisions/<域>.md 并解析 D-xxx@vN 条目。条目格式与 decision-distill 的
51
+ // renderBlockLines 逐字对齐(字段行是机械解析契约):`## D-xxx@vN <短标题>` +
52
+ // `状态:implemented|rejected` / `锚点:` / `最近确认:` / `理由:`(rejected 追加
53
+ // `否决理由:` / `复潮条件:`)。
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /** INDEX 条目是否为 decisions 库路由行(目标文件在 decisions/ 下) */
57
+ function isDecisionRoute(entry) {
58
+ return /^decisions\//.test(String(entry.file || '').replace(/\\/g, '/'))
59
+ }
60
+
61
+ const DECISION_HEADER_RE = /^##\s+(D-\d+@v\d+)\s*(.*)$/
62
+ const DECISION_FIELD_RE = /^(状态|理由|否决理由|复潮条件)\s*[::]\s*(.*)$/
63
+
64
+ /**
65
+ * 解析单个 decisions/<域>.md 的 D-xxx@vN 条目。
66
+ * reason 语义:rejected 条目取「否决理由」(expects_from task-02 的 reject_reason),
67
+ * 其余条目回退「理由」一句话;revisitWhen 仅 rejected 条目非空(复潮条件)。
68
+ * @param {string} filePath 决策文件绝对路径
69
+ * @param {string} file INDEX 相对路径(decisions/<域>.md),原样进 decisionHits.file
70
+ * @returns {{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }[]}
71
+ */
72
+ function parseDecisionFile(filePath, file) {
73
+ let content
74
+ try { content = readFileSync(filePath, 'utf8') } catch { return [] }
75
+ const hits = []
76
+ let cur = null
77
+ const flush = () => {
78
+ if (cur) hits.push(cur)
79
+ cur = null
80
+ }
81
+ for (const line of content.replace(/\r\n/g, '\n').split('\n')) {
82
+ const h = line.match(DECISION_HEADER_RE)
83
+ if (h) {
84
+ flush()
85
+ cur = { file, id: h[1], title: h[2].trim(), status: '', reason: '', revisitWhen: '' }
86
+ continue
87
+ }
88
+ if (!cur) continue
89
+ const f = line.match(DECISION_FIELD_RE)
90
+ if (!f) continue
91
+ const value = f[2].trim()
92
+ if (f[1] === '状态') cur.status = value.toLowerCase()
93
+ else if (f[1] === '否决理由') cur.reason = value
94
+ else if (f[1] === '复潮条件') cur.revisitWhen = value
95
+ else if (!cur.reason) cur.reason = value // 理由:仅作 implemented(或否决理由缺失)时的回填
96
+ }
97
+ flush()
98
+ return hits
99
+ }
100
+
101
+ /**
102
+ * 解析 knowledge/decisions/ 决策库——扫描范围扩到 decisions/*.md,但只经 INDEX.md
103
+ * Decisions 段路由行发现目标文件(路由行由 decision-distill 幂等维护)。
104
+ * @param {string} indexDir knowledge 目录路径
105
+ * @param {Array} [indexEntries] parseKnowledgeIndex 输出(缺省时自行解析 INDEX;传入时
106
+ * 只解析这些条目中指向 decisions/ 的路由行,matchKnowledge 用它做「路由行已命中」过滤)
107
+ * @returns {{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }[]}
108
+ * 路由行不存在/目标文件不存在/解析失败 → [](与无 decisions 库时行为完全一致)
109
+ */
110
+ export function parseDecisionEntries(indexDir, indexEntries = null) {
111
+ const routes = (indexEntries || parseKnowledgeIndex(indexDir)).filter(isDecisionRoute)
112
+ const hits = []
113
+ for (const route of routes) {
114
+ const filePath = join(indexDir, route.file)
115
+ if (!existsSync(filePath)) continue // 路由行失效(域文件已删)→ 跳过不阻断
116
+ hits.push(...parseDecisionFile(filePath, route.file))
117
+ }
118
+ // 多条路由行指向同一域文件时按 file+id 去重
119
+ const seen = new Set()
120
+ return hits.filter(h => {
121
+ const key = `${h.file}#${h.id}`
122
+ if (seen.has(key)) return false
123
+ seen.add(key)
124
+ return true
125
+ })
126
+ }
127
+
44
128
  function escapeRegex(s) {
45
129
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
46
130
  }
@@ -62,7 +146,11 @@ function keywordMatchesContext(keyword, contextLower) {
62
146
  * 用任务上下文匹配知识条目
63
147
  * @param {string} indexDir - knowledge 目录路径
64
148
  * @param {string} taskContext - 任务上下文(task 名称 + 描述,用于关键词匹配)
65
- * @returns {{ matched: boolean, entries: Array, report: string, json: object }}
149
+ * @returns {{ matched: boolean, entries: Array, report: string, json: object,
150
+ * decisionHits: Array<{ file: string, id: string, title: string, status: string, reason: string, revisitWhen: string }> }}
151
+ * matched/entries/report/json 既有四字段结构与语义不变;decisionHits(task-04 新增)= 任务上下文
152
+ * 命中的 Decisions 路由行所指向 decisions/<域>.md 内的全部 D-xxx@vN 条目,rejected 优先排序;
153
+ * 无 decisions 库 / 路由行未命中 → decisionHits: [](其余字段行为与现状一致)。
66
154
  */
67
155
  export function matchKnowledge(indexDir, taskContext) {
68
156
  const indexPath = join(indexDir, 'INDEX.md')
@@ -73,7 +161,8 @@ export function matchKnowledge(indexDir, taskContext) {
73
161
  matched: false,
74
162
  entries: [],
75
163
  report: 'Status: no matches (INDEX.md not found)',
76
- json: { matched: false, entry_count: 0, entries: [] }
164
+ json: { matched: false, entry_count: 0, entries: [] },
165
+ decisionHits: []
77
166
  }
78
167
  }
79
168
 
@@ -83,7 +172,8 @@ export function matchKnowledge(indexDir, taskContext) {
83
172
  matched: false,
84
173
  entries: [],
85
174
  report: 'Status: no matches',
86
- json: { matched: false, entry_count: 0, entries: [] }
175
+ json: { matched: false, entry_count: 0, entries: [] },
176
+ decisionHits: []
87
177
  }
88
178
  }
89
179
 
@@ -97,7 +187,8 @@ export function matchKnowledge(indexDir, taskContext) {
97
187
  matched: false,
98
188
  entries: [],
99
189
  report: 'Status: no matches',
100
- json: { matched: false, entry_count: 0, entries: [] }
190
+ json: { matched: false, entry_count: 0, entries: [] },
191
+ decisionHits: []
101
192
  }
102
193
  }
103
194
 
@@ -126,5 +217,15 @@ export function matchKnowledge(indexDir, taskContext) {
126
217
  }))
127
218
  }
128
219
 
129
- return { matched: true, entries: matched, report, json }
220
+ // decisionHits(task-04):任务上下文命中的 Decisions 路由行 → 解析其指向的
221
+ // decisions/<域>.md 内全部条目;rejected 优先排序(防复潮信息最先可见,组内保持文件序)。
222
+ // 不引入新顶层 hits 字段,不改 matched/entries/report/json 四个既有键。
223
+ const decisionRoutes = matched.filter(isDecisionRoute)
224
+ const allDecisionHits = decisionRoutes.length > 0 ? parseDecisionEntries(indexDir, decisionRoutes) : []
225
+ const decisionHits = [
226
+ ...allDecisionHits.filter(h => h.status === 'rejected'),
227
+ ...allDecisionHits.filter(h => h.status !== 'rejected')
228
+ ]
229
+
230
+ return { matched: true, entries: matched, report, json, decisionHits }
130
231
  }
@@ -44,7 +44,9 @@ export function registerRepoInLocalYaml(yamlPath, key, repoPath) {
44
44
 
45
45
  const existed = existsSync(yamlPath)
46
46
  // CRLF 归一后按 LF 写回(同 task 卡锚点写入的 CRLF 坑;local.yaml 各 CLI 写入口径均 LF)
47
- const raw = existed ? readFileSync(yamlPath, 'utf8').replace(/\r\n?/g, '\n') : ''
47
+ const raw0 = existed ? readFileSync(yamlPath, 'utf8') : ''
48
+ const hadCr = raw0.includes('\r') // 磁盘原文带 CRLF → 幂等路径也要落盘治愈(见下方幂等分支)
49
+ const raw = existed ? raw0.replace(/\r\n?/g, '\n') : ''
48
50
  const posixPath = String(repoPath).replace(/\\/g, '/')
49
51
  const entryLine = ` ${key}: ${posixPath}`
50
52
 
@@ -79,6 +81,10 @@ export function registerRepoInLocalYaml(yamlPath, key, repoPath) {
79
81
  for (let i = reposIdx + 1; i < end; i++) {
80
82
  if (keyRe.test(lines[i])) {
81
83
  if (lines[i] === entryLine) {
84
+ // 坑 register-repo-crlf-idempotent-loop:磁盘原文带 CRLF 时(agent Write 工具/Windows
85
+ // 编辑器写入),内存归一后比对相等直接跳过 → 磁盘永不治愈 + CLI 报 ✅ 假成功 → 解析侧
86
+ // (修复前)空 Map → MultiRepoContext 报「未注册」→ 死循环。幂等路径也落盘一次治愈。
87
+ if (hadCr) write(lines.join('\n'))
82
88
  return { fileCreated: false, sectionCreated: false, replaced: false } // 值未变,幂等跳过
83
89
  }
84
90
  lines[i] = entryLine
@@ -20,6 +20,11 @@
20
20
  * - 判定语义(哪个模块才是「对的」)仍归 agent——本表只是机械最优匹配
21
21
  */
22
22
  import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
23
+
24
+ /** 模块卡字数预算(字节):超限在 resolve 表标 ⚠️ 并提示精简——文档是 agent 的读取税
25
+ * (对标 deepseek-harness verify-doc-budgets 理念:预算只降不升;2026-08-24 起 runtime.md
26
+ * 28KB/worktree.md 24KB 已在付税)。advisory 不阻断,16 为 dogfood 校准前缺省。 */
27
+ const MODULE_CARD_BUDGET_BYTES = 16 * 1024
23
28
  import { join, relative } from 'path'
24
29
  import { parseModuleMapSimple } from './modules.js'
25
30
  import { parseTaskRegistry } from './stages/execute.js'
@@ -197,9 +202,12 @@ export function renderModuleResolveTable({ cwd, specBase, changeName }) {
197
202
  '| task | 模块 | 粒度 | 模块卡(只读命中的卡,勿按目录整读) | 体量 | 读取建议 |',
198
203
  '|---|---|---|---|---|---|',
199
204
  ]
205
+ const budgetBreached = new Set()
200
206
  for (const r of rows) {
201
207
  if (r.moduleId) {
202
- L.push(`| ${r.taskId} | ${r.moduleId} | ${r.granularity === 'fine' ? '细' : '粗'} | \`${r.cardPath}\` | ${kb(r.cardBytes)} | ${r.advice} |`)
208
+ const over = r.cardBytes > MODULE_CARD_BUDGET_BYTES
209
+ if (over) budgetBreached.add(r.moduleId)
210
+ L.push(`| ${r.taskId} | ${r.moduleId} | ${r.granularity === 'fine' ? '细' : '粗'} | \`${r.cardPath}\` | ${kb(r.cardBytes)}${over ? ' ⚠️超预算' : ''} | ${r.advice} |`)
203
211
  } else {
204
212
  L.push(`| ${r.taskId} | — | — | (无命中,跳过模块文档) | — | — |`)
205
213
  }
@@ -207,5 +215,8 @@ export function renderModuleResolveTable({ cwd, specBase, changeName }) {
207
215
  L.push('')
208
216
  L.push('> 匹配规则:全部 _module-map.yaml 跨层最长前缀(子项目细卡优先于根层大卡),源=tasks 卡 allowed_paths。')
209
217
  L.push('> 细卡整卡可读;仅粗卡命中且体量大时**按节读**——只读「契约摘要/注意事项/定位」,跳过「变更索引/人工备注」历史累积段。')
218
+ if (budgetBreached.size > 0) {
219
+ L.push(`> ⚠️ 模块卡超预算(>${Math.round(MODULE_CARD_BUDGET_BYTES / 1024)}KB):${[...budgetBreached].join('、')}——文档是 agent 的读取税,本次变更触及该模块,收尾时顺手 \`sillyspec modules split-changelog\` 迁出历史段或精简正文(对标 deepseek-harness verify-doc-budgets:预算只降不升)。`)
220
+ }
210
221
  return L.join('\n')
211
222
  }
package/src/modules.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readdirSync, readFileSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { gitQuiet } from './git-helper.js';
4
+ import { nowWallClock } from './datetime.js';
4
5
 
5
6
 
6
7
  /**
@@ -112,7 +113,7 @@ export async function rebuildModuleMap(cwd, { force = false } = {}) {
112
113
 
113
114
  // 生成新的 _module-map.yaml
114
115
  // 保留已有的完整字段,补齐新卡片
115
- const now = new Date().toISOString().replace('T', ' ').slice(0, 19);
116
+ const now = nowWallClock();
116
117
  let headCommit = '';
117
118
  try {
118
119
  // QUAL-01 收口:走 git-helper 统一入口(safe.directory + 数组形式)
@@ -0,0 +1,126 @@
1
+ /**
2
+ * plan-adopt-waves.js — `sillyspec plan-adopt-waves` 把 plan.md 的 Wave 段一键重排为
3
+ * depends_on 拓扑分组(坑 wave-manual-mismatch-noise,2026-08-24 用户反馈二期:主控手排
4
+ * Wave 与 CLI 拓扑比对不一致只能手动改;依赖方向违规修复后,本命令给一条零手写出路)。
5
+ *
6
+ * 行为:
7
+ * - depMap(tasks/*.md 的 depends_on,collectTaskDepMap 与 postcheck 同源)→ topoSortWaves
8
+ * - 重写 plan.md 的 `## Wave N` 段块(段内按编号排序;首段「并行,无依赖」、其余「依赖前序 Wave」)
9
+ * - 无显式 Wave 标题 → 插在「## 任务总表」前(无总表则文末追加)
10
+ * - best-effort 同步任务总表的 W 列(仅认 7 列模板行;不匹配的行 warn 不强改)
11
+ * - Wave 段内若含非引用内容(正文/表格)→ 拒绝重写(防误删),提示先手动整理
12
+ * - 写后复跑 validateBlueprintConsistency 打印结果(防 adopt 把手工安全串行收敛出
13
+ * 同 Wave 共享路径冲突——topo 只看依赖不看文件重叠)
14
+ * - --dry-run 只打印将写入的 Wave 段不落盘;幂等(重复跑产出相同结构);行尾统一 LF
15
+ */
16
+ import { existsSync, readFileSync, writeFileSync } from 'fs'
17
+ import { join } from 'path'
18
+ import { topoSortWaves, collectTaskDepMap, validateBlueprintConsistency } from './stages/plan-postcheck.js'
19
+
20
+ const WAVE_HEADING_RE = /^#+\s*Wave\s+\d+/i
21
+ const TASK_REF_RE = /^[-*]\s+(?:\[[ x]\]\s*)?task-\d+\s*[::\s]*$/i
22
+ const LEGACY_TASK_REF_RE = /^[-*]\s*\[[ x]\]\s*task-\d+/i
23
+ const SUMMARY_HEADING_RE = /^#+\s*任务总表/
24
+
25
+ /** 渲染标准 Wave 段块(段落间空行分隔,结尾不带多余空行——由调用方控制拼接) */
26
+ function renderWaveBlock(waves) {
27
+ const L = []
28
+ waves.forEach((wave, i) => {
29
+ const sorted = [...wave].sort((a, b) =>
30
+ parseInt(String(a).replace(/\D/g, ''), 10) - parseInt(String(b).replace(/\D/g, ''), 10))
31
+ L.push(`## Wave ${i + 1}(${i === 0 ? '并行,无依赖' : '依赖前序 Wave'})`)
32
+ for (const t of sorted) L.push(`- ${t}`)
33
+ if (i < waves.length - 1) L.push('')
34
+ })
35
+ return L
36
+ }
37
+
38
+ /** best-effort 更新任务总表 W 列:仅认 `| task-XX | … | W1 | … |` 形态的 7+ 列模板行 */
39
+ function updateSummaryWaveColumn(lines, waveOf) {
40
+ let inSummary = false
41
+ let updated = 0
42
+ let skipped = 0
43
+ for (let i = 0; i < lines.length; i++) {
44
+ const line = lines[i]
45
+ if (/^#+\s/.test(line)) { inSummary = SUMMARY_HEADING_RE.test(line); continue }
46
+ if (!inSummary) continue
47
+ const m = line.match(/^\|\s*task-(\d+)\s*\|/)
48
+ if (!m) continue
49
+ const cells = line.split('|')
50
+ // 模板 7 列:| 编号 | 任务 | Wave | 优先级 | 依赖 | 覆盖 FR/D | 说明 | → split 后首尾空串
51
+ if (cells.length < 8 || !/^\s*W\d+\s*$/.test(cells[3] || '')) { skipped++; continue }
52
+ const taskId = `task-${String(m[1]).padStart(2, '0')}`
53
+ const waveIdx = waveOf.get(taskId)
54
+ if (waveIdx === undefined) { skipped++; continue }
55
+ cells[3] = ` W${waveIdx + 1} `
56
+ lines[i] = cells.join('|')
57
+ updated++
58
+ }
59
+ return { updated, skipped }
60
+ }
61
+
62
+ /**
63
+ * @param {{ changeDir: string, dryRun?: boolean }} opts
64
+ * @returns {{ ok: boolean, error?: string, waves?: string[][], planPath: string, dryRun: boolean,
65
+ * waveBlock?: string[], tableRowsUpdated?: number, tableRowsSkipped?: number,
66
+ * postcheck?: { errors: string[], warnings: string[] } }}
67
+ */
68
+ export function adoptPlanWaves({ changeDir, dryRun = false }) {
69
+ const planPath = join(changeDir, 'plan.md')
70
+ if (!existsSync(planPath)) return { ok: false, error: `plan.md 不存在: ${planPath}`, planPath, dryRun }
71
+ const tasksDir = join(changeDir, 'tasks')
72
+ if (!existsSync(tasksDir)) return { ok: false, error: `tasks/ 目录不存在: ${tasksDir}`, planPath, dryRun }
73
+ const depMap = collectTaskDepMap(tasksDir)
74
+ if (depMap.size === 0) return { ok: false, error: 'tasks/ 下没有 task-NN.md 卡片,无从推导 Wave 分组', planPath, dryRun }
75
+
76
+ const { waves, error: topoError } = topoSortWaves(depMap)
77
+ if (topoError) return { ok: false, error: `拓扑排序失败: ${topoError}`, planPath, dryRun }
78
+
79
+ const original = readFileSync(planPath, 'utf8')
80
+ const lines = original.split(/\r?\n/)
81
+ const waveBlock = renderWaveBlock(waves)
82
+ const waveOf = new Map()
83
+ waves.forEach((ws, i) => { for (const t of ws) waveOf.set(t, i) })
84
+
85
+ const firstWaveIdx = lines.findIndex(l => WAVE_HEADING_RE.test(l))
86
+ if (firstWaveIdx >= 0) {
87
+ // Wave 段块末尾 = 最后一个 Wave 标题之后连续的任务引用行(空行容忍但不断段;
88
+ // 遇非 Wave 标题即止)。段内混入非引用内容 → 拒绝重写(防误删正文/表格)。
89
+ let endIdx = firstWaveIdx
90
+ for (let i = firstWaveIdx; i < lines.length; i++) {
91
+ if (WAVE_HEADING_RE.test(lines[i])) { endIdx = i; continue }
92
+ if (TASK_REF_RE.test(lines[i]) || LEGACY_TASK_REF_RE.test(lines[i])) { endIdx = i; continue }
93
+ if (lines[i].trim() === '') continue
94
+ if (/^#+\s/.test(lines[i])) break
95
+ return { ok: false, error: `Wave 段内含非引用内容(第 ${i + 1} 行「${lines[i].slice(0, 40)}」)——为防误删拒绝重写,请先把 Wave 段整理为纯 "- task-XX" 引用行`, planPath, dryRun }
96
+ }
97
+ lines.splice(firstWaveIdx, endIdx - firstWaveIdx + 1, ...waveBlock)
98
+ } else {
99
+ // 无显式 Wave 标题:插在「## 任务总表」前;无总表则文末追加
100
+ const summaryIdx = lines.findIndex(l => SUMMARY_HEADING_RE.test(l))
101
+ if (summaryIdx >= 0) {
102
+ lines.splice(summaryIdx, 0, ...waveBlock, '')
103
+ } else {
104
+ while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop()
105
+ lines.push('', ...waveBlock)
106
+ }
107
+ }
108
+
109
+ const { updated, skipped } = updateSummaryWaveColumn(lines, waveOf)
110
+ const content = lines.join('\n').replace(/\n*$/, '\n')
111
+
112
+ if (dryRun) {
113
+ return { ok: true, waves, planPath, dryRun: true, waveBlock, tableRowsUpdated: updated, tableRowsSkipped: skipped }
114
+ }
115
+
116
+ writeFileSync(planPath, content, 'utf8')
117
+ // 复跑 blueprint 一致性(advisory 打印):topo 只看依赖不看文件重叠——adopt 可能把手工
118
+ // 安全串行收敛出同 Wave 共享路径冲突,立即暴露而非留到 execute 撞
119
+ let postcheck = null
120
+ try {
121
+ postcheck = validateBlueprintConsistency(changeDir)
122
+ } catch (e) {
123
+ postcheck = { errors: [`复跑校验异常: ${e?.message || e}`], warnings: [] }
124
+ }
125
+ return { ok: true, waves, planPath, dryRun: false, waveBlock, tableRowsUpdated: updated, tableRowsSkipped: skipped, postcheck }
126
+ }
package/src/quicklog.js CHANGED
@@ -32,13 +32,15 @@ const sleep = (ms) => new Promise(r => setTimeout(r, ms))
32
32
  * 与 rename 之间),相比旧实现的必现双进已可忽略。
33
33
  * @param {string} lockPath 锁文件路径(建议与被保护文件同目录)
34
34
  * @param {() => (any|Promise<any>)} fn 临界区
35
- * @param {{staleMs?:number, timeoutMs?:number, retryMs?:number}} opts
35
+ * @param {{staleMs?:number, timeoutMs?:number, retryMs?:number, content?:string}} opts
36
+ * content:锁文件内容(默认 pid-randomId)。供超时报错时展示持有者语义(如 apply 锁写
37
+ * {pid, changeName})——仅展示用途,抢占/偷锁逻辑只比对内容一致性不解析语义。
36
38
  */
37
39
  export async function withFileLock(lockPath, fn, opts = {}) {
38
- const { staleMs = 30000, timeoutMs = 10000, retryMs = 50 } = opts
40
+ const { staleMs = 30000, timeoutMs = 10000, retryMs = 50, content = null } = opts
39
41
  mkdirSync(dirname(lockPath), { recursive: true })
40
42
  const start = Date.now()
41
- const myId = `${process.pid}-${randomBytes(6).toString('hex')}`
43
+ const myId = content || `${process.pid}-${randomBytes(6).toString('hex')}`
42
44
  let fd = null
43
45
  // 抢锁循环
44
46
  while (true) {
@@ -174,6 +176,9 @@ function buildPushPayloadFromRaw(rawBlock, { ql_id, author_raw, status, linked_c
174
176
  payload.timestamp = parts[1] || null
175
177
  payload.title = parts.slice(2).join('|').trim() || payload.title
176
178
  }
179
+ // 顶层标签白名单(^ 行首锚定):D-004@v1 根因块嵌套四子字段(- 现象:/- 根因:/- 护栏:/- 证据: 列表行)
180
+ // 因「- 」前缀不匹配本正则——它们是根因块正文内的列表行续行,不是新顶层标签,经 lastLabel 挂载
181
+ // 进 body_sections[根因](见下方 inFiles 复位注释)。顶层四字段边界解析不受影响(R-03)。
177
182
  const labelRe = /^(状态|关联变更|文件|审计|需求|根因|方案|结果)\s*[::]\s*(.*)$/
178
183
  const bulletRe = /^-\s+(.*)$/
179
184
  let inFiles = false
@@ -190,7 +195,9 @@ function buildPushPayloadFromRaw(rawBlock, { ql_id, author_raw, status, linked_c
190
195
  else if (label === '关联变更') { payload.linked_changes = value.split(/[,,、+;;]/).map(s => s.trim()).filter(Boolean); inLinked = true; inFiles = false }
191
196
  else if (label === '文件') { if (value) payload.files.push(...value.split(/[,,、+;;]/).map(s => s.trim()).filter(Boolean).map(p => ({ path: p, note: null }))); inFiles = true; inLinked = false }
192
197
  else if (label === '审计') { /* D-8 advisory 行:只进 raw_block 不进结构化段(body_sections 不扩 schema),并阻断续行误挂 */ lastLabel = null; inFiles = false; inLinked = false }
193
- else { payload.body_sections[label] = value; lastLabel = label }
198
+ // 进入 需求/根因/方案/结果 字段块须关闭 inFiles/inLinked 续行模式(task-07 / D-004@v1):否则根因块内
199
+ // 嵌套子字段列表行(- 现象:… 等)会命中下方「文件 bullet」分支被劫进 payload.files,从根因正文截断丢失。
200
+ else { payload.body_sections[label] = value; lastLabel = label; inFiles = false; inLinked = false }
194
201
  continue
195
202
  }
196
203
  if (bulletRe.test(stripped) && inFiles) {
@@ -332,6 +339,37 @@ export function parseFileNotes(raw) {
332
339
  .filter(Boolean)
333
340
  }
334
341
 
342
+ /**
343
+ * 校验 --file-notes 原文格式(坑 quick-file-notes-format-silent,2026-08-24 用户反馈二期②:
344
+ * 多文件分隔符是 `||` 双竖线,写错成 `|`/`,` 时整段被当成第一个文件的括注静默落盘,只能手工修
345
+ * QUICKLOG)。命令入口 fail-fast 用:每个 `||` 段必须是 `path::括注`(`::` 必填,括注可空);
346
+ * 括注内再出现 `::` 视为疑似漏写 `||` 分隔符。返回问题清单供调用方拼报错。
347
+ * @param {string} raw
348
+ * @returns {{ ok: boolean, problems: Array<{ seg: string, reason: string, hint: string }> }}
349
+ */
350
+ export function validateFileNotesFormat(raw) {
351
+ const problems = []
352
+ if (!raw) return { ok: true, problems }
353
+ for (const seg of String(raw).split('||')) {
354
+ const s = seg.trim()
355
+ if (!s) continue
356
+ const idx = s.indexOf('::')
357
+ if (idx === -1) {
358
+ problems.push({ seg: s, reason: '缺 `::` 路径/括注分隔符', hint: '格式为 path::括注;不要括注也要写 path::(括注可空)' })
359
+ continue
360
+ }
361
+ const path = s.slice(0, idx).trim()
362
+ if (!path) {
363
+ problems.push({ seg: s, reason: '`::` 前路径为空', hint: '格式为 path::括注' })
364
+ continue
365
+ }
366
+ if (s.slice(idx + 2).includes('::')) {
367
+ problems.push({ seg: s, reason: '括注内出现 `::`', hint: '疑似多文件漏写 `||` 分隔符(双竖线)——多文件写法:path1::括注1 || path2::括注2' })
368
+ }
369
+ }
370
+ return { ok: problems.length === 0, problems }
371
+ }
372
+
335
373
  // 结果块必填字段(quick step3 --done --output 的结构化结果模板,见 src/stages/quick.js)。
336
374
  // 4 个必填字段标签从 manifest 同源(stage-contract-spec.js quick.result-labels),prompt 事前契约与本校验单源。
337
375
  const RESULT_REQUIRED_LABELS = getRule('quick.result-labels').data.literals
@@ -344,6 +382,8 @@ const RESULT_REQUIRED_LABELS = getRule('quick.result-labels').data.literals
344
382
  * @returns {{ ok: boolean, missing: string[] }} ok=true 通过;missing=缺失的字段名列表
345
383
  */
346
384
  export function validateQuickResult(text) {
385
+ // 子串包含判定:根因块含嵌套四子字段列表行(- 现象:… 等,task-07 / D-004@v1 合法形态)时,
386
+ // 顶层四标签仍须齐备(模板契约),嵌套行不影响判定(「- 」前缀不构成顶层标签,亦不缺字段)。
347
387
  const missing = RESULT_REQUIRED_LABELS.filter(label => !String(text || '').includes(label))
348
388
  return { ok: missing.length === 0, missing }
349
389
  }
@@ -486,6 +526,9 @@ async function checkTaskCheckbox(specBase, change, qlId) {
486
526
  // 前缀」或正则 split(/(?=需求:|根因:|方案:|结果:)/))因前导是「/|( 等非边界字符而跳过。严格失败
487
527
  // (如真实标签前导是「,」这类弱标点)退回宽松顺序扫描(上一标签之后首次出现)。缺标签返回 null → 落单行
488
528
  // 兜底(--done 契约校验仍会拦缺字段)。残余边界:正文引用标签且前导恰好是空白/句末标点时仍可能错位。
529
+ // task-07 / D-004@v1 声明:本切分只作用于「单行四字段压缩归一」路径,嵌套四子字段(- 现象:/- 根因:/
530
+ // - 护栏:/- 证据: 列表行)必须以多行列表行形态写入根因块正文——按序扫描先命中顶层「根因:」标签,
531
+ // 其后的嵌套「- 根因:」等字样落在根因字段正文内不构成新边界,无需改动三个边界函数即天然兼容(Grill C-15)。
489
532
  function isFieldBoundary(body, idx) {
490
533
  if (idx <= 0) return true
491
534
  const prev = body[idx - 1]
@@ -567,6 +610,9 @@ function flipEntryInContent(content, qlId, result, changedFiles = [], fileNotes
567
610
  if (segs) body = segs.join('\n')
568
611
  }
569
612
  // 多行结果(结构化 需求/根因/方案/结果 字段块):逐行插入为独立字段行。
613
+ // 根因块嵌套四子字段(- 现象:/- 根因:/- 护栏:/- 证据: 列表行,D-004@v1 postmortem 形态)属
614
+ // 根因块正文:在此随多行结果逐行原样落盘(带「- 」前缀、保序含换行),不被字段边界扫描误切——
615
+ // 单行归一切分只认「- 」前缀之外的需求:/根因:/方案:/结果: 标签,嵌套行天然不参与边界判定。
570
616
  // 单行结果:保持「结果:<一句话>」一行,向后兼容简单用例。
571
617
  const resultLines = /\r?\n/.test(body)
572
618
  ? body.split(/\r?\n/).filter(l => l.trim() !== '')