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,231 @@
1
+ /**
2
+ * knowledge-match.js — knowledge 关键词匹配引擎
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 库时一致。
8
+ */
9
+
10
+ import { existsSync, readFileSync } from 'fs'
11
+ import { join } from 'path'
12
+
13
+ /**
14
+ * 从 INDEX.md 解析所有知识条目
15
+ * @param {string} indexDir - knowledge 目录路径
16
+ * @returns {{ category: string, keywords: string[], file: string, anchor: string, display: string, line: string }[]}
17
+ */
18
+ export function parseKnowledgeIndex(indexDir) {
19
+ const indexPath = join(indexDir, 'INDEX.md')
20
+ if (!existsSync(indexPath)) return []
21
+
22
+ const content = readFileSync(indexPath, 'utf8')
23
+ const entries = []
24
+ let currentCategory = ''
25
+
26
+ for (const line of content.split('\n')) {
27
+ // 匹配 ## Category 行
28
+ const catMatch = line.match(/^##\s+(.+)/)
29
+ if (catMatch) {
30
+ currentCategory = catMatch[1].trim()
31
+ continue
32
+ }
33
+
34
+ // 匹配条目行:- 关键词1|关键词2 → [显示名](文件名#锚点)
35
+ const entryMatch = line.match(/^-\s+(.+?)\s*→\s*\[(.+?)\]\(([^#)]+)(?:#([^)]+))?\)/)
36
+ if (entryMatch) {
37
+ const keywords = entryMatch[1].split('|').map(k => k.trim()).filter(Boolean)
38
+ const display = entryMatch[2].trim()
39
+ const file = entryMatch[3].trim()
40
+ const anchor = entryMatch[4] ? entryMatch[4].trim() : ''
41
+ entries.push({ category: currentCategory, keywords, file, anchor, display, line })
42
+ }
43
+ }
44
+
45
+ return entries
46
+ }
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
+
128
+ function escapeRegex(s) {
129
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
130
+ }
131
+
132
+ /**
133
+ * 单个关键词是否命中上下文。
134
+ * - 过短关键词(<2 字符)视为噪音,不参与匹配
135
+ * - 非 ASCII(中文等)用子串匹配
136
+ * - ASCII 关键词用词边界匹配,避免子串误命中(如 "DB" 不命中 "dashboard")
137
+ */
138
+ function keywordMatchesContext(keyword, contextLower) {
139
+ const kw = keyword.toLowerCase().trim()
140
+ if (kw.length < 2) return false
141
+ if (/[^\x00-\x7f]/.test(kw)) return contextLower.includes(kw)
142
+ return new RegExp(`(^|[^a-z0-9])${escapeRegex(kw)}([^a-z0-9]|$)`).test(contextLower)
143
+ }
144
+
145
+ /**
146
+ * 用任务上下文匹配知识条目
147
+ * @param {string} indexDir - knowledge 目录路径
148
+ * @param {string} taskContext - 任务上下文(task 名称 + 描述,用于关键词匹配)
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: [](其余字段行为与现状一致)。
154
+ */
155
+ export function matchKnowledge(indexDir, taskContext) {
156
+ const indexPath = join(indexDir, 'INDEX.md')
157
+
158
+ // INDEX.md 不存在
159
+ if (!existsSync(indexPath)) {
160
+ return {
161
+ matched: false,
162
+ entries: [],
163
+ report: 'Status: no matches (INDEX.md not found)',
164
+ json: { matched: false, entry_count: 0, entries: [] },
165
+ decisionHits: []
166
+ }
167
+ }
168
+
169
+ const allEntries = parseKnowledgeIndex(indexDir)
170
+ if (allEntries.length === 0 || !taskContext) {
171
+ return {
172
+ matched: false,
173
+ entries: [],
174
+ report: 'Status: no matches',
175
+ json: { matched: false, entry_count: 0, entries: [] },
176
+ decisionHits: []
177
+ }
178
+ }
179
+
180
+ const contextLower = taskContext.toLowerCase()
181
+ const matched = allEntries.filter(entry => {
182
+ return entry.keywords.some(kw => keywordMatchesContext(kw, contextLower))
183
+ })
184
+
185
+ if (matched.length === 0) {
186
+ return {
187
+ matched: false,
188
+ entries: [],
189
+ report: 'Status: no matches',
190
+ json: { matched: false, entry_count: 0, entries: [] },
191
+ decisionHits: []
192
+ }
193
+ }
194
+
195
+ const sources = matched.map(e => {
196
+ const base = e.anchor ? `${e.file}#${e.anchor}` : e.file
197
+ return ` - ${base}`
198
+ }).join('\n')
199
+
200
+ const report = [
201
+ 'Knowledge Context',
202
+ '─────────────────',
203
+ `Status: matched`,
204
+ `Entries: ${matched.length}`,
205
+ 'Sources:',
206
+ sources
207
+ ].join('\n')
208
+
209
+ const json = {
210
+ matched: true,
211
+ entry_count: matched.length,
212
+ entries: matched.map(e => ({
213
+ file: e.file,
214
+ anchor: e.anchor,
215
+ keywords: e.keywords,
216
+ category: e.category
217
+ }))
218
+ }
219
+
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 }
231
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Local Detect — 纯 fs 项目类型嗅探
3
+ *
4
+ * 把"生成本地配置"里的项目类型判定从 scan(半小时 + 大量 token)抽出来,
5
+ * 变成纯 fs 同步读几秒可完成的独立探测。create/gate 只需 project.type +
6
+ * commands,不该被迫跑完整 scan。
7
+ *
8
+ * 纯函数:不 spawn 任何子进程、不调用任何 AI/LLM、不消耗 token。
9
+ * 不写 local.yaml 到磁盘——只返回数据结构,落盘由调用方(CLI 路由 / scan.js)负责。
10
+ * 不引 yaml 依赖。
11
+ */
12
+
13
+ import { existsSync, readFileSync } from 'fs'
14
+ import { join } from 'path'
15
+
16
+ /**
17
+ * 从 Makefile 文本提取 test 目标的命令(轻量正则,与 verify-postcheck 同风格)。
18
+ * 支持两种常见写法:
19
+ * - 同行命令:`test: pytest` → 'pytest'
20
+ * - tab 续行:`test:\n\tpytest\n` → 'pytest'(命令在下一 tab 开头行)
21
+ * 边界:
22
+ * - 纯空目标(`test:` 无同行命令、无 tab 续行)→ 回退 'make test'
23
+ * - 命令行内 `#` 注释截断;取第一个非空命令行
24
+ * @param {string} makefileText
25
+ * @returns {string}
26
+ */
27
+ function parseMakefileTestCommand(makefileText) {
28
+ if (!makefileText) return 'make test'
29
+ // 定位 `test:` 行;捕获 `:` 后同行内容(同行命令或空)
30
+ const head = makefileText.match(/^test:\s*([^\n#]*?)\s*(?:#.*)?$/m)
31
+ if (!head) return 'make test'
32
+ const inline = (head[1] || '').trim()
33
+ if (inline) return inline
34
+ // 同行为空 → 找该行之后第一个 tab 续行命令(`\tcmd` 或 ` cmd`)
35
+ const after = makefileText.slice(head.index + head[0].length)
36
+ const cont = after.match(/^[ \t]+([^\n#]+?)\s*(?:#.*)?$/m)
37
+ if (cont && cont[1]) return cont[1].trim()
38
+ return 'make test'
39
+ }
40
+
41
+ /**
42
+ * 嗅探 workdir 的项目类型与默认 commands(纯 fs,零 AI / 零 token)。
43
+ *
44
+ * 嗅探规则(按顺序,命中即返回):
45
+ * - package.json → nodejs(核验 scripts.{build,test,lint} 存在才写对应键;缺失不写)
46
+ * - pom.xml → maven(mvn compile / mvn test / mvn checkstyle:check)
47
+ * - build.gradle → gradle(gradlew 存在用 ./gradlew 否则 gradle;build / test / check)
48
+ * - Makefile → make(test 命令从 test: 目标解析;build/lint 无则不写)
49
+ * - 都没有 → generic(commands 为空对象)
50
+ *
51
+ * @param {string} workdir - 项目根目录
52
+ * @returns {{
53
+ * project: { type: 'nodejs'|'maven'|'gradle'|'make'|'generic' },
54
+ * commands: { build?: string, test?: string, lint?: string }
55
+ * }}
56
+ */
57
+ export function detectLocalYaml(workdir) {
58
+ // 1. nodejs
59
+ if (existsSync(join(workdir, 'package.json'))) {
60
+ const pkgPath = join(workdir, 'package.json')
61
+ const raw = readFileSync(pkgPath, 'utf8')
62
+ let pkg
63
+ try {
64
+ pkg = JSON.parse(raw)
65
+ } catch (e) {
66
+ throw new Error('package.json 解析失败:' + pkgPath)
67
+ }
68
+ const scripts = (pkg && pkg.scripts) || {}
69
+ const commands = {}
70
+ if (scripts.build) commands.build = 'npm run build'
71
+ if (scripts.test) commands.test = 'npm test'
72
+ if (scripts.lint) commands.lint = 'npm run lint'
73
+ return {
74
+ project: { type: 'nodejs' },
75
+ commands,
76
+ }
77
+ }
78
+
79
+ // 2. maven
80
+ if (existsSync(join(workdir, 'pom.xml'))) {
81
+ return {
82
+ project: { type: 'maven' },
83
+ commands: {
84
+ build: 'mvn compile',
85
+ test: 'mvn test',
86
+ lint: 'mvn checkstyle:check',
87
+ },
88
+ }
89
+ }
90
+
91
+ // 3. gradle
92
+ if (existsSync(join(workdir, 'build.gradle'))) {
93
+ // Windows 上 cmd.exe 执行不了 ./gradlew(shell 脚本)——优先 gradlew.bat;
94
+ // 仅有 POSIX gradlew 且在 win32 时退回全局 gradle(体检 BUG-08)
95
+ const isWin = process.platform === 'win32'
96
+ let gradlePrefix = 'gradle'
97
+ if (isWin) {
98
+ gradlePrefix = existsSync(join(workdir, 'gradlew.bat')) ? 'gradlew.bat' : 'gradle'
99
+ } else {
100
+ gradlePrefix = existsSync(join(workdir, 'gradlew')) ? './gradlew' : 'gradle'
101
+ }
102
+ return {
103
+ project: { type: 'gradle' },
104
+ commands: {
105
+ build: `${gradlePrefix} build`,
106
+ test: `${gradlePrefix} test`,
107
+ lint: `${gradlePrefix} check`,
108
+ },
109
+ }
110
+ }
111
+
112
+ // 4. make(test 命令从 Makefile 解析;build/lint 无则省略)
113
+ const makefilePath = join(workdir, 'Makefile')
114
+ if (existsSync(makefilePath)) {
115
+ const makefileText = readFileSync(makefilePath, 'utf8')
116
+ const test = parseMakefileTestCommand(makefileText)
117
+ return {
118
+ project: { type: 'make' },
119
+ commands: { test },
120
+ }
121
+ }
122
+
123
+ // 5. generic
124
+ return {
125
+ project: { type: 'generic' },
126
+ commands: {},
127
+ }
128
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * local-register.js — `sillyspec local register-repo <key> <path>` 的 repos: 段外科手术式写入。
3
+ *
4
+ * 背景(2026-08-21 agent-手工产出审计项④):跨仓 change 的 repo key 必须在 local.yaml
5
+ * `repos:` 段注册(MultiRepoContext 约束② fail-closed),此前靠 agent 手编 YAML——正是
6
+ * agent 满目录找/在根目录乱建 local.yaml 的上游。本模块只动 `repos:` 段:已有该 key 就地
7
+ * 改值,没有就插入段内;其余内容(注释/凭据段/手调配置)逐行原样保留,绝不整文件重序列化。
8
+ *
9
+ * 写入口径与 parseRepoRegistry(plan-postcheck.js,读侧)成对:
10
+ * repos:
11
+ * sillyspec: C:/Users/you/IdeaProjects/sillyspec
12
+ * # main 不用注册(隐式 = cwd)
13
+ *
14
+ * 文件不存在时新建只含 repos: 段的 minimal local.yaml(真实 local.yaml 其余段由
15
+ * `sillyspec local detect` / `platform connect` 各自补齐)。落盘走 writeAtomicSync
16
+ * (tmp+rename,防多会话并发写半截,与 local detect 写入口径一致)。
17
+ */
18
+ import { existsSync, readFileSync, mkdirSync } from 'fs'
19
+ import { dirname } from 'path'
20
+ import { writeAtomicSync } from './fs-atomic.js'
21
+
22
+ function escapeRe(s) {
23
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
24
+ }
25
+
26
+ /**
27
+ * 把 `<key>: <path>` 注册进 local.yaml 的 repos: 段(幂等,已有该 key 则改值)。
28
+ *
29
+ * @param {string} yamlPath - local.yaml 绝对路径(不存在则新建)
30
+ * @param {string} key - repo key(限 [A-Za-z0-9_.\-]+,'main' 隐式禁止注册)
31
+ * @param {string} repoPath - 跨仓仓根绝对路径(写入时统一正斜杠,与示例格式一致)
32
+ * @returns {{ fileCreated: boolean, sectionCreated: boolean, replaced: boolean }}
33
+ * @throws {Error} key 非法 / key='main' / repoPath 空 / 读写失败
34
+ */
35
+ export function registerRepoInLocalYaml(yamlPath, key, repoPath) {
36
+ if (!yamlPath) throw new Error('registerRepoInLocalYaml: yamlPath 不能为空')
37
+ if (!key || !/^[A-Za-z0-9_.\-]+$/.test(key)) {
38
+ throw new Error(`repo key 非法: "${key}"(限字母数字 . _ -,与 parseRepoRegistry 读侧口径一致)`)
39
+ }
40
+ if (key === 'main') {
41
+ throw new Error("repo key 'main' 不用注册(隐式 = 主仓 cwd),跨仓仓才需要 register-repo")
42
+ }
43
+ if (!repoPath) throw new Error('registerRepoInLocalYaml: repoPath 不能为空')
44
+
45
+ const existed = existsSync(yamlPath)
46
+ // CRLF 归一后按 LF 写回(同 task 卡锚点写入的 CRLF 坑;local.yaml 各 CLI 写入口径均 LF)
47
+ const raw0 = existed ? readFileSync(yamlPath, 'utf8') : ''
48
+ const hadCr = raw0.includes('\r') // 磁盘原文带 CRLF → 幂等路径也要落盘治愈(见下方幂等分支)
49
+ const raw = existed ? raw0.replace(/\r\n?/g, '\n') : ''
50
+ const posixPath = String(repoPath).replace(/\\/g, '/')
51
+ const entryLine = ` ${key}: ${posixPath}`
52
+
53
+ const write = (text) => {
54
+ mkdirSync(dirname(yamlPath), { recursive: true })
55
+ writeAtomicSync(yamlPath, text)
56
+ }
57
+
58
+ const lines = raw.split('\n')
59
+ // repos: 段起点(顶层 key 行,与 parseRepoRegistry 同口径)
60
+ let reposIdx = -1
61
+ for (let i = 0; i < lines.length; i++) {
62
+ if (/^repos:\s*(?:#.*)?$/.test(lines[i])) { reposIdx = i; break }
63
+ }
64
+
65
+ if (reposIdx === -1) {
66
+ // 无 repos: 段 → 文件尾追加(保留既有内容与注释;空文件/新文件直接起段)
67
+ const sep = raw.trim() === '' ? '' : (raw.endsWith('\n') ? '' : '\n') + '\n'
68
+ write(raw + sep + `repos:\n${entryLine}\n`)
69
+ return { fileCreated: !existed, sectionCreated: true, replaced: false }
70
+ }
71
+
72
+ // 段范围:reposIdx+1 起到下一个顶层 key(行首非空白非注释)为止(与 parseRepoRegistry 同口径)
73
+ let end = lines.length
74
+ for (let i = reposIdx + 1; i < lines.length; i++) {
75
+ const l = lines[i]
76
+ if (l.length > 0 && !/^[\s#]/.test(l) && l.trim() !== '') { end = i; break }
77
+ }
78
+
79
+ // 已有该 key → 就地改值(幂等)
80
+ const keyRe = new RegExp(`^\\s+${escapeRe(key)}:\\s`)
81
+ for (let i = reposIdx + 1; i < end; i++) {
82
+ if (keyRe.test(lines[i])) {
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'))
88
+ return { fileCreated: false, sectionCreated: false, replaced: false } // 值未变,幂等跳过
89
+ }
90
+ lines[i] = entryLine
91
+ write(lines.join('\n'))
92
+ return { fileCreated: false, sectionCreated: false, replaced: true }
93
+ }
94
+ }
95
+
96
+ // 无该 key → 插到段内最后一个非空行(条目或段内注释)之后
97
+ let insertAt = reposIdx + 1
98
+ for (let i = reposIdx + 1; i < end; i++) {
99
+ if (lines[i].trim() !== '') insertAt = i + 1
100
+ }
101
+ lines.splice(insertAt, 0, entryLine)
102
+ write(lines.join('\n'))
103
+ return { fileCreated: false, sectionCreated: false, replaced: false }
104
+ }