sillyspec 3.27.2 → 3.27.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (398) hide show
  1. package/.claude/skills/sillyspec-execute/SKILL.md +8 -0
  2. package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
  3. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  4. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  5. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  6. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  7. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  8. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  9. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  10. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  11. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
  12. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
  13. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  14. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  15. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  16. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  17. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  18. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
  19. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
  20. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  21. package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  22. package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
  23. package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
  24. package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
  25. package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
  26. package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
  27. package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
  28. package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
  29. package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
  30. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  31. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  32. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
  33. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
  34. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
  35. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
  36. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
  37. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
  38. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
  39. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
  40. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
  41. package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
  42. package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
  43. package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
  44. package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
  45. package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
  46. package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
  47. package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
  48. package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
  49. package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
  50. package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
  51. package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
  52. package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
  53. package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
  54. package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
  55. package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
  56. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
  57. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
  58. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
  59. package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
  60. package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
  61. package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
  62. package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
  63. package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
  64. package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
  65. package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
  66. package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
  67. package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
  68. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
  69. package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
  70. package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
  71. package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
  72. package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
  73. package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
  74. package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
  75. package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
  76. package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
  77. package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
  78. package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
  79. package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
  80. package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
  81. package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
  82. package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
  83. package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
  84. package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
  85. package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
  86. package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
  87. package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
  88. package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
  89. package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
  90. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
  91. package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
  92. package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
  93. package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
  94. package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
  95. package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
  96. package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
  97. package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
  98. package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
  99. package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
  100. package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
  101. package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
  102. package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
  103. package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
  104. package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
  105. package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
  106. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
  107. package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
  108. package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
  109. package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
  110. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
  111. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
  112. package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
  113. package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
  114. package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
  115. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
  116. package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
  117. package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
  118. package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
  119. package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
  120. package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
  121. package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
  122. package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
  123. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
  124. package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
  125. package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
  126. package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
  127. package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
  128. package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
  129. package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
  130. package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
  131. package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
  132. package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
  133. package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
  134. package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
  135. package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
  136. package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
  137. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
  138. package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
  139. package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
  140. package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
  141. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
  142. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
  143. package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
  144. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
  145. package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
  146. package/.worktrees/8d2d0392/.claude/skills/sillyspec-archive/SKILL.md +87 -0
  147. package/.worktrees/8d2d0392/.claude/skills/sillyspec-auto/SKILL.md +93 -0
  148. package/.worktrees/8d2d0392/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
  149. package/.worktrees/8d2d0392/.claude/skills/sillyspec-commit/SKILL.md +67 -0
  150. package/.worktrees/8d2d0392/.claude/skills/sillyspec-continue/SKILL.md +47 -0
  151. package/.worktrees/8d2d0392/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
  152. package/.worktrees/8d2d0392/.claude/skills/sillyspec-execute/SKILL.md +214 -0
  153. package/.worktrees/8d2d0392/.claude/skills/sillyspec-explore/SKILL.md +102 -0
  154. package/.worktrees/8d2d0392/.claude/skills/sillyspec-export/SKILL.md +57 -0
  155. package/.worktrees/8d2d0392/.claude/skills/sillyspec-init/SKILL.md +177 -0
  156. package/.worktrees/8d2d0392/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  157. package/.worktrees/8d2d0392/.claude/skills/sillyspec-plan/SKILL.md +156 -0
  158. package/.worktrees/8d2d0392/.claude/skills/sillyspec-propose/SKILL.md +87 -0
  159. package/.worktrees/8d2d0392/.claude/skills/sillyspec-quick/SKILL.md +116 -0
  160. package/.worktrees/8d2d0392/.claude/skills/sillyspec-resume/SKILL.md +70 -0
  161. package/.worktrees/8d2d0392/.claude/skills/sillyspec-scan/SKILL.md +79 -0
  162. package/.worktrees/8d2d0392/.claude/skills/sillyspec-state/SKILL.md +64 -0
  163. package/.worktrees/8d2d0392/.claude/skills/sillyspec-status/SKILL.md +54 -0
  164. package/.worktrees/8d2d0392/.claude/skills/sillyspec-verify/SKILL.md +87 -0
  165. package/.worktrees/8d2d0392/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
  166. package/.worktrees/8d2d0392/.claude/skills/verify-per-user/SKILL.md +6 -0
  167. package/.worktrees/8d2d0392/.gitattributes +2 -0
  168. package/.worktrees/8d2d0392/.husky/pre-push +20 -0
  169. package/.worktrees/8d2d0392/README.md +203 -0
  170. package/.worktrees/8d2d0392/SKILL.md +91 -0
  171. package/.worktrees/8d2d0392/architecture-analysis.md +448 -0
  172. package/.worktrees/8d2d0392/bin/sillyspec.js +2 -0
  173. package/.worktrees/8d2d0392/eval/README.md +86 -0
  174. package/.worktrees/8d2d0392/eval/eval.config.json +28 -0
  175. package/.worktrees/8d2d0392/eval/lib/adapters/cli.mjs +63 -0
  176. package/.worktrees/8d2d0392/eval/lib/adapters/dryrun.mjs +27 -0
  177. package/.worktrees/8d2d0392/eval/lib/config.mjs +82 -0
  178. package/.worktrees/8d2d0392/eval/lib/db.mjs +76 -0
  179. package/.worktrees/8d2d0392/eval/lib/report.mjs +120 -0
  180. package/.worktrees/8d2d0392/eval/lib/runner.mjs +157 -0
  181. package/.worktrees/8d2d0392/eval/lib/tasks.mjs +73 -0
  182. package/.worktrees/8d2d0392/eval/lib/util.mjs +107 -0
  183. package/.worktrees/8d2d0392/eval/lib/workdir.mjs +30 -0
  184. package/.worktrees/8d2d0392/eval/run.mjs +83 -0
  185. package/.worktrees/8d2d0392/eval/tasks/001-slugify/files/package.json +6 -0
  186. package/.worktrees/8d2d0392/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  187. package/.worktrees/8d2d0392/eval/tasks/001-slugify/task.json +6 -0
  188. package/.worktrees/8d2d0392/eval/tasks/001-slugify/verify.mjs +28 -0
  189. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/package.json +6 -0
  190. package/.worktrees/8d2d0392/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  191. package/.worktrees/8d2d0392/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  192. package/.worktrees/8d2d0392/eval/tasks/002-each-day/task.json +6 -0
  193. package/.worktrees/8d2d0392/eval/tasks/002-each-day/verify.mjs +31 -0
  194. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  195. package/.worktrees/8d2d0392/eval/tasks/003-word-report/files/package.json +6 -0
  196. package/.worktrees/8d2d0392/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  197. package/.worktrees/8d2d0392/eval/tasks/003-word-report/task.json +6 -0
  198. package/.worktrees/8d2d0392/eval/tasks/003-word-report/verify.mjs +38 -0
  199. package/.worktrees/8d2d0392/logo.jpg +0 -0
  200. package/.worktrees/8d2d0392/package-lock.json +977 -0
  201. package/.worktrees/8d2d0392/package.json +41 -0
  202. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
  203. package/.worktrees/8d2d0392/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  204. package/.worktrees/8d2d0392/packages/dashboard/dist/favicon.jpg +0 -0
  205. package/.worktrees/8d2d0392/packages/dashboard/dist/index.html +16 -0
  206. package/.worktrees/8d2d0392/packages/dashboard/dist/logo.jpg +0 -0
  207. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-dashboard.html +836 -0
  208. package/.worktrees/8d2d0392/packages/dashboard/dist/prototype-overview.html +256 -0
  209. package/.worktrees/8d2d0392/packages/dashboard/package.json +25 -0
  210. package/.worktrees/8d2d0392/packages/dashboard/server/executor.js +95 -0
  211. package/.worktrees/8d2d0392/packages/dashboard/server/index.js +679 -0
  212. package/.worktrees/8d2d0392/packages/dashboard/server/parser.js +526 -0
  213. package/.worktrees/8d2d0392/packages/dashboard/server/watcher.js +357 -0
  214. package/.worktrees/8d2d0392/src/agent-session-log.js +803 -0
  215. package/.worktrees/8d2d0392/src/change-list.js +290 -0
  216. package/.worktrees/8d2d0392/src/change-risk-profile.js +339 -0
  217. package/.worktrees/8d2d0392/src/check-primitives.js +65 -0
  218. package/.worktrees/8d2d0392/src/classify-change.js +109 -0
  219. package/.worktrees/8d2d0392/src/commit-suggest.js +202 -0
  220. package/.worktrees/8d2d0392/src/config-cat.js +88 -0
  221. package/.worktrees/8d2d0392/src/config-schema.js +328 -0
  222. package/.worktrees/8d2d0392/src/constants.js +97 -0
  223. package/.worktrees/8d2d0392/src/contract-matrix.js +533 -0
  224. package/.worktrees/8d2d0392/src/datetime.js +20 -0
  225. package/.worktrees/8d2d0392/src/db-engine.js +55 -0
  226. package/.worktrees/8d2d0392/src/db.js +381 -0
  227. package/.worktrees/8d2d0392/src/decision-distill.js +517 -0
  228. package/.worktrees/8d2d0392/src/dispatch/backends/local-agent.js +155 -0
  229. package/.worktrees/8d2d0392/src/dispatch/backends/sillyhub-mcp.js +245 -0
  230. package/.worktrees/8d2d0392/src/dispatch/probe.js +246 -0
  231. package/.worktrees/8d2d0392/src/dispatch/strategy.js +121 -0
  232. package/.worktrees/8d2d0392/src/docs-check.js +825 -0
  233. package/.worktrees/8d2d0392/src/docs-debt.js +393 -0
  234. package/.worktrees/8d2d0392/src/docs-gate.js +107 -0
  235. package/.worktrees/8d2d0392/src/doctor-diagnostics.js +1099 -0
  236. package/.worktrees/8d2d0392/src/endpoint-extractor.js +409 -0
  237. package/.worktrees/8d2d0392/src/foreign-declared.js +78 -0
  238. package/.worktrees/8d2d0392/src/fs-atomic.js +73 -0
  239. package/.worktrees/8d2d0392/src/git-helper.js +150 -0
  240. package/.worktrees/8d2d0392/src/hooks/claude-pre-tool-use.cjs +130 -0
  241. package/.worktrees/8d2d0392/src/hooks/worktree-guard.js +892 -0
  242. package/.worktrees/8d2d0392/src/index.js +2854 -0
  243. package/.worktrees/8d2d0392/src/init.js +626 -0
  244. package/.worktrees/8d2d0392/src/knowledge-match.js +231 -0
  245. package/.worktrees/8d2d0392/src/local-detect.js +128 -0
  246. package/.worktrees/8d2d0392/src/local-register.js +104 -0
  247. package/.worktrees/8d2d0392/src/machine-interface.js +543 -0
  248. package/.worktrees/8d2d0392/src/migrate.js +127 -0
  249. package/.worktrees/8d2d0392/src/module-impact.js +166 -0
  250. package/.worktrees/8d2d0392/src/module-resolve.js +222 -0
  251. package/.worktrees/8d2d0392/src/modules.js +580 -0
  252. package/.worktrees/8d2d0392/src/plan-adopt-waves.js +126 -0
  253. package/.worktrees/8d2d0392/src/progress/change-registry.js +336 -0
  254. package/.worktrees/8d2d0392/src/progress/consistency-doctor.js +355 -0
  255. package/.worktrees/8d2d0392/src/progress/shared.js +36 -0
  256. package/.worktrees/8d2d0392/src/progress/stage-machine.js +594 -0
  257. package/.worktrees/8d2d0392/src/progress/step-store.js +265 -0
  258. package/.worktrees/8d2d0392/src/progress.js +1304 -0
  259. package/.worktrees/8d2d0392/src/quick-recommend.js +115 -0
  260. package/.worktrees/8d2d0392/src/quicklog.js +883 -0
  261. package/.worktrees/8d2d0392/src/review-tier.js +77 -0
  262. package/.worktrees/8d2d0392/src/run/command.js +1641 -0
  263. package/.worktrees/8d2d0392/src/run/complete-handlers.js +1552 -0
  264. package/.worktrees/8d2d0392/src/run/complete.js +1259 -0
  265. package/.worktrees/8d2d0392/src/run/concurrent-detect.js +156 -0
  266. package/.worktrees/8d2d0392/src/run/gates.js +1094 -0
  267. package/.worktrees/8d2d0392/src/run/multi-repo-context.js +208 -0
  268. package/.worktrees/8d2d0392/src/run/next.js +128 -0
  269. package/.worktrees/8d2d0392/src/run/prompt.js +843 -0
  270. package/.worktrees/8d2d0392/src/run/quick-audit.js +186 -0
  271. package/.worktrees/8d2d0392/src/run/scan-profile.js +269 -0
  272. package/.worktrees/8d2d0392/src/run/shared.js +1562 -0
  273. package/.worktrees/8d2d0392/src/run/stage.js +587 -0
  274. package/.worktrees/8d2d0392/src/run.js +23 -0
  275. package/.worktrees/8d2d0392/src/scan-diff.js +388 -0
  276. package/.worktrees/8d2d0392/src/scan-postcheck.js +524 -0
  277. package/.worktrees/8d2d0392/src/scan-staleness.js +95 -0
  278. package/.worktrees/8d2d0392/src/setup.js +414 -0
  279. package/.worktrees/8d2d0392/src/sillyhub-mcp/client.js +597 -0
  280. package/.worktrees/8d2d0392/src/sillyhub-mcp/config.js +62 -0
  281. package/.worktrees/8d2d0392/src/spec-dir-typo.js +50 -0
  282. package/.worktrees/8d2d0392/src/spec-sync.js +358 -0
  283. package/.worktrees/8d2d0392/src/stage-contract-engine.js +171 -0
  284. package/.worktrees/8d2d0392/src/stage-contract-spec.js +551 -0
  285. package/.worktrees/8d2d0392/src/stage-contract.js +948 -0
  286. package/.worktrees/8d2d0392/src/stage-review.js +597 -0
  287. package/.worktrees/8d2d0392/src/stages/archive.js +199 -0
  288. package/.worktrees/8d2d0392/src/stages/brainstorm-auto.js +285 -0
  289. package/.worktrees/8d2d0392/src/stages/brainstorm.js +624 -0
  290. package/.worktrees/8d2d0392/src/stages/cmd-existence.js +145 -0
  291. package/.worktrees/8d2d0392/src/stages/doctor.js +540 -0
  292. package/.worktrees/8d2d0392/src/stages/execute.js +1277 -0
  293. package/.worktrees/8d2d0392/src/stages/explore.js +43 -0
  294. package/.worktrees/8d2d0392/src/stages/index.js +29 -0
  295. package/.worktrees/8d2d0392/src/stages/knowledge.js +514 -0
  296. package/.worktrees/8d2d0392/src/stages/plan-postcheck.js +1398 -0
  297. package/.worktrees/8d2d0392/src/stages/plan.js +651 -0
  298. package/.worktrees/8d2d0392/src/stages/quick.js +167 -0
  299. package/.worktrees/8d2d0392/src/stages/scan.js +608 -0
  300. package/.worktrees/8d2d0392/src/stages/status.js +64 -0
  301. package/.worktrees/8d2d0392/src/stages/verify.js +246 -0
  302. package/.worktrees/8d2d0392/src/sync.js +1470 -0
  303. package/.worktrees/8d2d0392/src/task-review.js +1498 -0
  304. package/.worktrees/8d2d0392/src/taskcard-placeholders.js +21 -0
  305. package/.worktrees/8d2d0392/src/taskcard.js +217 -0
  306. package/.worktrees/8d2d0392/src/verify-postcheck.js +1718 -0
  307. package/.worktrees/8d2d0392/src/verify-probes.js +327 -0
  308. package/.worktrees/8d2d0392/src/version.js +19 -0
  309. package/.worktrees/8d2d0392/src/workflow.js +600 -0
  310. package/.worktrees/8d2d0392/src/workspace.js +125 -0
  311. package/.worktrees/8d2d0392/src/worktree-apply.js +1611 -0
  312. package/.worktrees/8d2d0392/src/worktree-deps.js +576 -0
  313. package/.worktrees/8d2d0392/src/worktree.js +1838 -0
  314. package/.worktrees/8d2d0392/templates/claude-instruction.md +23 -0
  315. package/.worktrees/8d2d0392/templates/prompts/taskcard-rules.md +29 -0
  316. package/.worktrees/8d2d0392/templates/prompts/testcase-design.md +12 -0
  317. package/.worktrees/8d2d0392/templates/prompts/verify-probes.md +32 -0
  318. package/.worktrees/8d2d0392/templates/workflows/archive-impact.yaml +79 -0
  319. package/.worktrees/8d2d0392/templates/workflows/scan-docs.yaml +132 -0
  320. package/architecture-analysis.md +448 -0
  321. package/eval/README.md +86 -0
  322. package/eval/eval.config.json +28 -0
  323. package/eval/lib/adapters/cli.mjs +63 -0
  324. package/eval/lib/adapters/dryrun.mjs +27 -0
  325. package/eval/lib/config.mjs +82 -0
  326. package/eval/lib/db.mjs +76 -0
  327. package/eval/lib/report.mjs +120 -0
  328. package/eval/lib/runner.mjs +157 -0
  329. package/eval/lib/tasks.mjs +73 -0
  330. package/eval/lib/util.mjs +107 -0
  331. package/eval/lib/workdir.mjs +30 -0
  332. package/eval/run.mjs +83 -0
  333. package/eval/tasks/001-slugify/files/package.json +6 -0
  334. package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
  335. package/eval/tasks/001-slugify/task.json +6 -0
  336. package/eval/tasks/001-slugify/verify.mjs +28 -0
  337. package/eval/tasks/002-each-day/files/package.json +6 -0
  338. package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
  339. package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
  340. package/eval/tasks/002-each-day/task.json +6 -0
  341. package/eval/tasks/002-each-day/verify.mjs +31 -0
  342. package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
  343. package/eval/tasks/003-word-report/files/package.json +6 -0
  344. package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
  345. package/eval/tasks/003-word-report/task.json +6 -0
  346. package/eval/tasks/003-word-report/verify.mjs +38 -0
  347. package/package.json +4 -2
  348. package/src/agent-session-log.js +45 -5
  349. package/src/change-risk-profile.js +83 -14
  350. package/src/config-schema.js +18 -3
  351. package/src/contract-matrix.js +90 -29
  352. package/src/datetime.js +20 -0
  353. package/src/decision-distill.js +517 -0
  354. package/src/dispatch/backends/local-agent.js +4 -4
  355. package/src/docs-check.js +227 -0
  356. package/src/docs-debt.js +187 -24
  357. package/src/doctor-diagnostics.js +102 -2
  358. package/src/endpoint-extractor.js +41 -52
  359. package/src/foreign-declared.js +155 -0
  360. package/src/index.js +95 -13
  361. package/src/init.js +9 -7
  362. package/src/knowledge-match.js +107 -6
  363. package/src/local-register.js +7 -1
  364. package/src/module-resolve.js +12 -1
  365. package/src/modules.js +2 -1
  366. package/src/plan-adopt-waves.js +126 -0
  367. package/src/quicklog.js +50 -4
  368. package/src/run/command.js +124 -44
  369. package/src/run/complete-handlers.js +48 -19
  370. package/src/run/complete.js +5 -2
  371. package/src/run/gates.js +104 -22
  372. package/src/run/prompt.js +84 -42
  373. package/src/run/quick-audit.js +11 -0
  374. package/src/run/shared.js +152 -10
  375. package/src/run/stage.js +8 -5
  376. package/src/run.js +2 -2
  377. package/src/scan-postcheck.js +30 -17
  378. package/src/stage-contract-spec.js +3 -2
  379. package/src/stage-contract.js +68 -4
  380. package/src/stages/archive.js +53 -12
  381. package/src/stages/brainstorm-auto.js +50 -1
  382. package/src/stages/brainstorm.js +13 -0
  383. package/src/stages/doctor.js +157 -1
  384. package/src/stages/execute.js +32 -6
  385. package/src/stages/plan-postcheck.js +76 -17
  386. package/src/stages/plan.js +9 -4
  387. package/src/stages/quick.js +6 -1
  388. package/src/stages/verify.js +32 -15
  389. package/src/sync.js +41 -3
  390. package/src/task-review.js +2 -2
  391. package/src/taskcard-placeholders.js +21 -0
  392. package/src/taskcard.js +43 -1
  393. package/src/verify-postcheck.js +315 -13
  394. package/src/verify-probes.js +73 -10
  395. package/src/worktree-apply.js +569 -227
  396. package/src/worktree-deps.js +150 -1
  397. package/src/worktree.js +285 -77
  398. package/templates/prompts/taskcard-rules.md +2 -1
@@ -0,0 +1,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
+ }
@@ -0,0 +1,336 @@
1
+ // W6 Step9b: 变更注册表(changes 表生命周期)—— 注册/注销/重命名/隔离状态/平台同步戳/审批状态。
2
+ // 从 src/progress.js 单体 ProgressManager 抽出。持有 pm 引用(构造注入),调 pm._ensureDB /
3
+ // pm._changePath(persistence-core 留 facade 本体)。无共享常量依赖。
4
+ import { existsSync, mkdirSync, renameSync } from 'fs';
5
+
6
+ export class ChangeRegistry {
7
+ constructor(pm) {
8
+ this.pm = pm;
9
+ }
10
+
11
+ /**
12
+ * 列出所有活跃变更名
13
+ * SQL: SELECT name FROM changes WHERE status = 'active'
14
+ */
15
+ listChanges(cwd) {
16
+ const db = this.pm._ensureDB(cwd);
17
+ const sqlDb = db.getDb();
18
+ const rows = sqlDb.prepare("SELECT name FROM changes WHERE status = 'active' ORDER BY name").all();
19
+ return rows.map(r => r.name);
20
+ }
21
+
22
+ /**
23
+ * 查询单个变更的流程阶段与状态(quick 轻量归档阶段闸用)。
24
+ * 与 readChangeIsolation 不同(展示读,catch → null 宽容):本方法服务权限判定,读失败
25
+ * 直接抛给调用方 catch → skip(fail-closed),不静默降级为"无记录"放行。
26
+ * @param {string} cwd - 项目根目录
27
+ * @param {string} changeName - 变更名
28
+ * @returns {{ current_stage: string, status: string }|null} 无该行返回 null(未注册目录桩)
29
+ */
30
+ getChangeStage(cwd, changeName) {
31
+ const db = this.pm._ensureDB(cwd);
32
+ const sqlDb = db.getDb();
33
+ // ql-20260819-010:LEFT JOIN stages 带 current_stage 对应阶段行的 status(stage_status)。
34
+ // quick 轻量归档闸除了「停在哪个阶段」还需要「该阶段是否已完成」——brainstorm 完成
35
+ // 到 plan 开始之间存在 current_stage 仍读 brainstorm 的空窗,只看阶段名会把即将进
36
+ // plan 的变更误判为僵尸(2026-08-19 quick-done-autoarchive-misfire 缺陷①)。
37
+ // 无阶段行(未 initChange 的目录桩 / brownfield)→ stage_status=null,调用方按
38
+ // 未完成放行(维持旧行为)。
39
+ const row = sqlDb.prepare(
40
+ `SELECT c.current_stage, c.status, s.status AS stage_status
41
+ FROM changes c
42
+ LEFT JOIN stages s ON s.change_id = c.id AND s.stage = c.current_stage
43
+ WHERE c.name = ?`
44
+ ).get(changeName);
45
+ if (row === undefined) return null;
46
+ return {
47
+ current_stage: row.current_stage || '',
48
+ status: row.status || '',
49
+ stage_status: row.stage_status || null,
50
+ };
51
+ }
52
+
53
+ /**
54
+ * 注册变更到活跃列表
55
+ * SQL: INSERT OR IGNORE → 若已 archived 则 UPDATE status='active'
56
+ */
57
+ registerChange(cwd, changeName) {
58
+ if (!changeName) {
59
+ console.warn('⚠️ registerChange: changeName 为空,跳过');
60
+ return;
61
+ }
62
+ const db = this.pm._ensureDB(cwd);
63
+ db.transaction(() => {
64
+ const sqlDb = db.getDb();
65
+ const now = new Date().toISOString();
66
+ // 尝试插入新行
67
+ const ins = sqlDb.prepare(
68
+ `INSERT OR IGNORE INTO changes (name, created_at, last_active)
69
+ VALUES (?, ?, ?)`
70
+ ).run(changeName, now, now);
71
+ // 只在真正创建 change 时标脏(D-013/task-04);已存在行不标(读路径/重复调用不误判脏)
72
+ if (ins.changes > 0) this.pm._touchLocalModified(cwd, changeName, now);
73
+ // 注意:不复活已归档的变更——归档是不可逆操作
74
+ // 如果变更已存在且为 archived,保持 archived 状态不变
75
+ });
76
+ }
77
+
78
+ /**
79
+ * 更新变更的隔离状态
80
+ * @param {string} cwd - 项目根目录
81
+ * @param {string} changeName - 变更名
82
+ * @param {{ status: string, mode?: string, reason?: string }} isolation
83
+ */
84
+ updateChangeIsolation(cwd, changeName, isolation) {
85
+ const db = this.pm._ensureDB(cwd);
86
+ try {
87
+ db.transaction(() => {
88
+ const sqlDb = db.getDb();
89
+ const now = new Date().toISOString();
90
+ sqlDb.prepare(
91
+ `UPDATE changes SET isolation_status = ?, isolation_mode = ?, isolation_reason = ?, last_active = ? WHERE name = ?`
92
+ ).run(isolation.status, isolation.mode || null, isolation.reason || null, now, changeName);
93
+ // 本地脏度(D-013 / task-04):隔离状态变更也是本地推进
94
+ this.pm._touchLocalModified(cwd, changeName, now);
95
+ });
96
+ } catch (err) {
97
+ console.warn('⚠️ 更新 isolation 状态失败:', err.message);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * 更新变更的人类可读元信息(title / quicklog_id),让 quick-<hex> 行可读、DB↔QUICKLOG 可对账。
103
+ * quick 启动时回填(title 从任务描述、quicklog_id 用分配的 qlId);--done 时从 step3「需求:」刷新 title。
104
+ * 部分更新(只传 title 不动 quicklog_id,反之亦然)。不调 _touchLocalModified:title/quicklog_id 是
105
+ * 本地展示用元信息,纳入脏度会扰动平台同步(平台 changes 表无此列)。
106
+ * @param {string} cwd
107
+ * @param {string} changeName
108
+ * @param {{ title?: string, quicklogId?: string }} meta
109
+ */
110
+ updateChangeMeta(cwd, changeName, meta) {
111
+ if (!changeName || !meta) return;
112
+ const db = this.pm._ensureDB(cwd);
113
+ try {
114
+ db.transaction(() => {
115
+ const sqlDb = db.getDb();
116
+ const sets = [];
117
+ const params = [];
118
+ if (meta.title !== undefined) { sets.push('title = ?'); params.push(meta.title); }
119
+ if (meta.quicklogId !== undefined) { sets.push('quicklog_id = ?'); params.push(meta.quicklogId); }
120
+ if (sets.length === 0) return;
121
+ params.push(changeName);
122
+ sqlDb.prepare(`UPDATE changes SET ${sets.join(', ')} WHERE name = ?`).run(...params);
123
+ });
124
+ } catch (err) {
125
+ console.warn('⚠️ 更新 change 元信息失败:', err.message);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * 读取变更的隔离状态
131
+ * @param {string} cwd - 项目根目录
132
+ * @param {string} changeName - 变更名
133
+ * @returns {{ status: string|null, mode: string|null, reason: string|null }|null}
134
+ */
135
+ readChangeIsolation(cwd, changeName) {
136
+ const db = this.pm._ensureDB(cwd);
137
+ const sqlDb = db.getDb();
138
+ try {
139
+ const row = sqlDb.prepare(
140
+ `SELECT isolation_status, isolation_mode, isolation_reason FROM changes WHERE name = ?`
141
+ ).get(changeName);
142
+ if (row === undefined) return null;
143
+ const { isolation_status: status, isolation_mode: mode, isolation_reason: reason } = row;
144
+ return { status: status || null, mode: mode || null, reason: reason || null };
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+
150
+ _updatePlatformLastSync(cwd, changeName, syncedTs = null) {
151
+ if (!changeName) return;
152
+ const db = this.pm._ensureDB(cwd);
153
+ db.transaction(() => {
154
+ const sqlDb = db.getDb();
155
+ // ql-20260818-008:push 成功后同时推进 base_ts(last_synced_platform_ts)。原实现只写
156
+ // 展示列 platform_last_sync,而 sync() 取 base_ts(sync.js)与 pull 脏度检测读的是
157
+ // last_synced_platform_ts——写 A 读 B 致 CLI 直跑场景该列恒 NULL:X-SillySpec-Base-Ts
158
+ // 永不携带(乐观锁失效)、本地脏度恒 false、platform status behind 恒跳过。值优先
159
+ // 平台回执 last_pushed_at,缺省回退本次 X-SillySpec-Pushed-At(后端 _apply 存的就是
160
+ // 该 header 原值,回写与服务器精确一致)。COALESCE 保旧值:无 syncedTs 只推进展示列。
161
+ sqlDb.prepare(
162
+ 'UPDATE changes SET platform_last_sync = ?, platform_sync_enabled = 1, last_synced_platform_ts = COALESCE(?, last_synced_platform_ts) WHERE name = ?'
163
+ ).run(new Date().toISOString(), syncedTs, changeName);
164
+ });
165
+ }
166
+
167
+ _updateApprovalStatus(cwd, changeName, status, reason = null) {
168
+ if (!changeName || !status) return;
169
+ const db = this.pm._ensureDB(cwd);
170
+ db.transaction(() => {
171
+ const sqlDb = db.getDb();
172
+ const row = sqlDb.prepare('SELECT id FROM changes WHERE name = ?').get(changeName);
173
+ if (row === undefined) return;
174
+ const changeId = row.id;
175
+ const now = new Date().toISOString();
176
+ sqlDb.prepare(
177
+ `INSERT INTO approvals (change_id, status, requested_at, approved_at, rejection_reason)
178
+ VALUES (?, ?, ?, ?, ?)
179
+ ON CONFLICT(change_id) DO UPDATE SET
180
+ status = excluded.status,
181
+ approved_at = excluded.approved_at,
182
+ rejection_reason = excluded.rejection_reason`
183
+ ).run(
184
+ changeId,
185
+ status,
186
+ now,
187
+ status === 'approved' ? now : null,
188
+ status === 'rejected' ? reason : null,
189
+ );
190
+ // 本地脏度(D-013 / task-04):审批状态变更也是本地推进
191
+ this.pm._touchLocalModified(cwd, changeName, now);
192
+ });
193
+ }
194
+
195
+ /**
196
+ * 重命名变更:同步更新 DB + 目录
197
+ * @param {string} cwd - 项目根目录
198
+ * @param {string} oldName - 旧变更名
199
+ * @param {string} newName - 新变更名
200
+ */
201
+ renameChange(cwd, oldName, newName) {
202
+ if (!oldName || !newName) {
203
+ console.warn('⚠️ renameChange: 旧名或新名为空,跳过');
204
+ return;
205
+ }
206
+ if (oldName === newName) {
207
+ console.warn('⚠️ renameChange: 新旧名称相同,跳过');
208
+ return;
209
+ }
210
+ const db = this.pm._ensureDB(cwd);
211
+ // 检查旧名是否存在
212
+ const existing = db.transaction(() => {
213
+ const sqlDb = db.getDb();
214
+ const row = sqlDb.prepare(`SELECT name, status FROM changes WHERE name = ?`).get(oldName);
215
+ if (row === undefined) return null;
216
+ return { name: row.name, status: row.status };
217
+ });
218
+ if (!existing) {
219
+ console.error(`❌ 变更 ${oldName} 不存在`);
220
+ return;
221
+ }
222
+ // 检查新名是否已存在
223
+ const conflict = db.transaction(() => {
224
+ const sqlDb = db.getDb();
225
+ const row = sqlDb.prepare(`SELECT name FROM changes WHERE name = ?`).get(newName);
226
+ return row !== undefined;
227
+ });
228
+ if (conflict) {
229
+ console.error(`❌ 变更 ${newName} 已存在`);
230
+ return;
231
+ }
232
+ // 先更新 DB,再重命名目录;FS 失败则回滚 DB,避免"目录已改名但 DB 旧名"的孤儿
233
+ // (旧实现 FS-first 无补偿:renameSync 成功后 DB transaction 抛 EPERM/EBUSY 会让
234
+ // 目录已是 newName、DB 仍是 oldName,read(两名) 都失联且无自动恢复)。
235
+ const oldDir = this.pm._changePath(cwd, oldName);
236
+ const newDir = this.pm._changePath(cwd, newName);
237
+ const now = new Date().toISOString();
238
+ try {
239
+ db.transaction(() => {
240
+ const sqlDb = db.getDb();
241
+ sqlDb.prepare(`UPDATE changes SET name = ?, last_active = ? WHERE name = ?`).run(newName, now, oldName);
242
+ // 本地脏度(D-013 / task-04):重命名也是本地推进(标新名)
243
+ this.pm._touchLocalModified(cwd, newName, now);
244
+ });
245
+ } catch (e) {
246
+ console.error(`❌ 重命名失败:更新数据库时出错(${e.message})`);
247
+ return;
248
+ }
249
+ let renamed = true;
250
+ if (existsSync(oldDir)) {
251
+ try {
252
+ renameSync(oldDir, newDir);
253
+ } catch (e) {
254
+ renamed = false;
255
+ // FS 重命名失败:回滚 DB 恢复 oldName,保持 DB 与目录一致
256
+ try {
257
+ db.transaction(() => {
258
+ const sqlDb = db.getDb();
259
+ sqlDb.prepare(`UPDATE changes SET name = ?, last_active = ? WHERE name = ?`).run(oldName, now, newName);
260
+ // 回滚也是写(恢复 oldName),对称标脏旧名
261
+ this.pm._touchLocalModified(cwd, oldName, now);
262
+ });
263
+ console.error(`❌ 重命名失败:移动目录出错(${e.message}),已回滚数据库`);
264
+ } catch (rollbackErr) {
265
+ // 回滚本身也失败:DB 是 newName、目录是 oldName,两端分裂且无自动恢复。
266
+ // 不能再撒谎"已回滚"——必须显式报错让用户跑 doctor 修复。
267
+ console.error(`❌ 重命名失败且数据库回滚也失败(状态分裂,需手动修复):原错=${e.message} 回滚错=${rollbackErr.message}。请跑 sillyspec doctor --json`);
268
+ }
269
+ }
270
+ } else {
271
+ mkdirSync(newDir, { recursive: true });
272
+ }
273
+ if (renamed) console.log(`✅ 变更已重命名:${oldName} → ${newName}`);
274
+ }
275
+
276
+ /**
277
+ * 从活跃列表移除变更(归档时调用,不物理删除)
278
+ * SQL: UPDATE changes SET status = 'archived'
279
+ *
280
+ * 归档终态一致化(坑 manual-archive-desync-status-only,2026-08-21 实证):手动搬目录绕过
281
+ * `run archive --done --confirm` 后,自愈/幽灵清理路径只改 status 一个字段,留下「已归档 +
282
+ * current_stage 停在 execute + 归档 0/5 步」的自相矛盾终态,推送平台后渲染成「进度丢失」。
283
+ * opts.archiveStepNames(调用方取自 stageRegistry 单一真相)给定时同事务收尾:
284
+ * current_stage='archive' + stages.archive=completed + 其步骤行全 completed
285
+ * (缺行按定义补种——平台按步骤数展示完成度,零行会显示 0/5)。
286
+ */
287
+ unregisterChange(cwd, changeName, opts = {}) {
288
+ if (!changeName) {
289
+ console.warn('⚠️ unregisterChange: changeName 为空,跳过');
290
+ return;
291
+ }
292
+ const db = this.pm._ensureDB(cwd);
293
+ db.transaction(() => {
294
+ const sqlDb = db.getDb();
295
+ const now = new Date().toISOString();
296
+ let sql = `UPDATE changes SET status = 'archived', last_active = ?`;
297
+ const params = [now];
298
+ if (Array.isArray(opts.archiveStepNames)) sql += `, current_stage = 'archive'`;
299
+ sql += ` WHERE name = ?`;
300
+ params.push(changeName);
301
+ sqlDb.prepare(sql).run(...params);
302
+ if (Array.isArray(opts.archiveStepNames)) {
303
+ const row = sqlDb.prepare('SELECT id FROM changes WHERE name = ?').get(changeName);
304
+ if (row) {
305
+ sqlDb.prepare(
306
+ `INSERT INTO stages (change_id, stage, status, started_at, completed_at)
307
+ VALUES (?, 'archive', 'completed', ?, ?)
308
+ ON CONFLICT(change_id, stage) DO UPDATE SET status = 'completed', completed_at = excluded.completed_at`
309
+ ).run(row.id, now, now);
310
+ const stageRow = sqlDb.prepare(
311
+ 'SELECT id FROM stages WHERE change_id = ? AND stage = ?'
312
+ ).get(row.id, 'archive');
313
+ if (stageRow) {
314
+ // 现有步骤行(含 pending/waiting)全收尾;定义里有而行里没有的(阶段从未初始化)按定义补种
315
+ sqlDb.prepare(
316
+ `UPDATE steps SET status = 'completed', completed_at = ? WHERE stage_id = ?`
317
+ ).run(now, stageRow.id);
318
+ const existing = new Set(
319
+ sqlDb.prepare('SELECT name FROM steps WHERE stage_id = ?').all(stageRow.id).map(r => r.name)
320
+ );
321
+ let order = existing.size;
322
+ const ins = sqlDb.prepare(
323
+ `INSERT INTO steps (stage_id, name, status, completed_at, ordering) VALUES (?, ?, 'completed', ?, ?)`
324
+ );
325
+ for (const name of opts.archiveStepNames) {
326
+ if (!existing.has(name)) { ins.run(stageRow.id, name, now, order++) }
327
+ }
328
+ }
329
+ }
330
+ }
331
+ // 本地脏度(D-013 / task-04):归档也是本地状态推进
332
+ this.pm._touchLocalModified(cwd, changeName, now);
333
+ });
334
+ }
335
+ }
336
+