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,166 @@
1
+ /**
2
+ * module-impact.js — `sillyspec module-impact` 的归类骨架生成
3
+ * (2026-08-21 agent-手工产出审计第三批 D3)。
4
+ *
5
+ * archive 阶段的 module-impact.md 要求「模块影响矩阵」+「未匹配文件」两章节、≥20 行,
6
+ * agent 此前从零手写整份矩阵。文件 × 模块的归属是纯机械分类(module-map paths 前缀匹配,
7
+ * 与 scan diff 归属同源),影响类型判定(逻辑/数据结构/接口/调用关系/配置/新增)是语义——
8
+ * 骨架预填「模块|文件|状态」三列,影响类型列留 <!--TODO--> 由 agent 逐行填。
9
+ *
10
+ * diff 源:resolveVerifyChangedFiles(worktree-aware,与 task-review 同源);
11
+ * module-map:.sillyspec/docs/<p>/modules/_module-map.yaml 的 modules.<id>.paths
12
+ * (目录条目以 / 结尾按前缀匹配,与模块上下文索引读侧口径一致)。
13
+ */
14
+ import { existsSync, readFileSync, readdirSync } from 'fs'
15
+ import { join } from 'path'
16
+ import { resolveVerifyChangedFiles } from './verify-postcheck.js'
17
+ import { resolveSpecDir } from './run/shared.js'
18
+
19
+ /**
20
+ * 轻量解析 _module-map.yaml:modules.<id>.paths 列表(手写解析同 parseRepoRegistry 风格,
21
+ * 只取 paths 平面信息,status/doc 等忽略)。
22
+ * @returns {Map<string, string[]>} moduleId → paths(posix)
23
+ */
24
+ export function parseModuleMapPaths(yamlText) {
25
+ const map = new Map()
26
+ if (!yamlText) return map
27
+ let currentModule = null
28
+ let inPaths = false
29
+ for (const line of yamlText.split('\n')) {
30
+ if (!line.trim() || line.trim().startsWith('#')) continue
31
+ if (!/^\s/.test(line)) {
32
+ inPaths = line.startsWith('modules:')
33
+ currentModule = null
34
+ continue
35
+ }
36
+ const modMatch = line.match(/^ ([A-Za-z0-9_.\-]+):\s*$/)
37
+ if (modMatch) {
38
+ currentModule = modMatch[1]
39
+ inPaths = false
40
+ continue
41
+ }
42
+ if (currentModule && /^ paths:\s*$/.test(line)) {
43
+ inPaths = true
44
+ if (!map.has(currentModule)) map.set(currentModule, [])
45
+ continue
46
+ }
47
+ if (inPaths && currentModule) {
48
+ const item = line.match(/^ - (.+)$/)
49
+ if (item) map.get(currentModule).push(item[1].trim().replace(/\\/g, '/'))
50
+ }
51
+ }
52
+ return map
53
+ }
54
+
55
+ function classifyFile(posixPath, modulePaths) {
56
+ for (const [moduleId, paths] of modulePaths) {
57
+ for (const p of paths) {
58
+ // 目录条目以 / 结尾 → 前缀匹配;文件条目 → 精确或子路径(与模块上下文索引读侧口径一致)
59
+ if (p.endsWith('/')) {
60
+ if (posixPath.startsWith(p)) return moduleId
61
+ } else if (posixPath === p || posixPath.startsWith(p + '/')) {
62
+ return moduleId
63
+ }
64
+ }
65
+ }
66
+ return null
67
+ }
68
+
69
+ /**
70
+ * 生成 module-impact.md 骨架。
71
+ * @param {{ cwd: string, changeName: string, specDir?: string|null }} opts
72
+ * @returns {{ markdown: string, matchedCount: number, unmatchedCount: number }|null}
73
+ * 无 module-map / 无 diff → null(无可归类输入,agent 全手写)
74
+ */
75
+ export function generateModuleImpactSkeleton({ cwd, changeName, specDir = null }) {
76
+ const specBase = resolveSpecDir(cwd, { specDir })
77
+
78
+ // 找 _module-map.yaml(docs/<p>/modules/;多项目取首个含 modules 索引的)
79
+ let moduleMapPath = null
80
+ try {
81
+ for (const p of readdirSync(join(specBase, 'docs'), { withFileTypes: true })) {
82
+ if (!p.isDirectory()) continue
83
+ const candidate = join(specBase, 'docs', p.name, 'modules', '_module-map.yaml')
84
+ if (existsSync(candidate)) {
85
+ moduleMapPath = candidate
86
+ break
87
+ }
88
+ }
89
+ } catch { /* 无 docs/ */ }
90
+ if (!moduleMapPath) return null
91
+
92
+ const modulePaths = parseModuleMapPaths(readFileSync(moduleMapPath, 'utf8'))
93
+ if (modulePaths.size === 0) return null
94
+
95
+ // includeWorkingTree 同 verify module 子集(坑 module-subset-zero-hit-uncommitted):
96
+ // worktree 未提交改动也计入模块影响面(module-impact 按实际 diff 归属模块)
97
+ const diffFiles = resolveVerifyChangedFiles(cwd, changeName, null, { includeWorkingTree: true }) || []
98
+ const sourceFiles = diffFiles.map(f => f.split('\\').join('/')).filter(f => !f.startsWith('.sillyspec/'))
99
+ if (sourceFiles.length === 0) return null
100
+
101
+ const byModule = new Map()
102
+ const unmatched = []
103
+ for (const f of sourceFiles) {
104
+ const mod = classifyFile(f, modulePaths)
105
+ if (mod) {
106
+ if (!byModule.has(mod)) byModule.set(mod, [])
107
+ byModule.get(mod).push(f)
108
+ } else {
109
+ unmatched.push(f)
110
+ }
111
+ }
112
+
113
+ const L = [
114
+ '# 模块影响分析(骨架由 `sillyspec module-impact --change <变更名>` 生成)',
115
+ '',
116
+ '> 文件×模块归属由 CLI 按 _module-map.yaml paths 前缀匹配预填;',
117
+ '> **影响类型**(逻辑变更/数据结构变更/接口变更/调用关系变更/配置变更/新增)与 review 标记是语义判断,',
118
+ '> 逐行把 <!--TODO--> 替换为真实结论——以 git diff 为准(真实 > 声明)。',
119
+ '',
120
+ '## 模块影响矩阵',
121
+ '',
122
+ '| 模块 | 变更文件 | 影响类型 | 需 review |',
123
+ '|---|---|---|---|',
124
+ ]
125
+ const rows = [...byModule.entries()].sort((a, b) => a[0].localeCompare(b[0]))
126
+ for (const [moduleId, files] of rows) {
127
+ for (const f of files) {
128
+ L.push(`| ${moduleId} | \`${f}\` | <!--TODO--> | <!--TODO--> |`)
129
+ }
130
+ }
131
+ L.push('')
132
+ L.push('## 未匹配文件')
133
+ L.push('')
134
+ if (unmatched.length === 0) {
135
+ L.push('无(全部变更文件已归属到模块)。')
136
+ } else {
137
+ L.push('以下变更文件未命中 _module-map.yaml 任何模块 paths——确认是模块索引过期(该跑 `sillyspec modules rebuild`)还是真的游离文件:')
138
+ L.push('')
139
+ for (const f of unmatched) L.push(`- \`${f}\` <!--TODO: 归属判定-->`)
140
+ }
141
+ L.push('')
142
+ L.push('## 影响类型说明')
143
+ L.push('')
144
+ L.push('逻辑变更 / 数据结构变更 / 接口变更 / 调用关系变更 / 配置变更 / 新增;不确定的影响标 needs review。')
145
+ L.push('')
146
+ // 「更新结果」表骨架(2026-08-21 审查 CLI-3):verify --done 死信门(extractPendingDocSyncRows)
147
+ // 与 archive 移动前校验同一口径硬校验本表无 pending 行,但骨架此前不产出该表——agent 只能
148
+ // 从 gate 报错反推格式(plan.js prompt 自认的坑)。此处按矩阵命中模块机械生成行,agent 只回填状态。
149
+ L.push('## 更新结果')
150
+ L.push('')
151
+ L.push('| 目标 | 操作 | 状态 |')
152
+ L.push('|------|------|------|')
153
+ for (const [moduleId] of rows) {
154
+ L.push(`| \`modules/${moduleId}.md\` | 更新${moduleId}模块卡(本次变更涉及) | pending |`)
155
+ }
156
+ if (unmatched.length > 0) {
157
+ L.push('| `_module-map.yaml` | <!--TODO: 有未匹配文件,判定模块索引是否需增改(modules rebuild)--> | pending |')
158
+ } else {
159
+ L.push('| `_module-map.yaml` | 无变化(未增删模块) | skipped |')
160
+ }
161
+ L.push('')
162
+ L.push('规则:execute/verify 完成文档同步后把对应行回填 done;确定不同步的行改 skipped 并在操作列写明原因。')
163
+ L.push('')
164
+
165
+ return { markdown: L.join('\n'), matchedCount: sourceFiles.length - unmatched.length, unmatchedCount: unmatched.length }
166
+ }
@@ -0,0 +1,222 @@
1
+ /**
2
+ * module-resolve.js — 模块卡两级级联解析(token 成本优化 P0a,2026-08-22-token-cost-optimization)
3
+ *
4
+ * 背景(multi-agent-platform 2026-08-22 实测):monorepo 根层 _module-map.yaml 把整个子项目
5
+ * (backend/**)映射到单张大卡(backend.md 58KB),而子项目细粒度卡(docs/backend/modules/
6
+ * agent.md,~6KB)由 scan 生成却无人消费——execute 每个 task 子代理都被指引去读整张大卡,
7
+ * 单卡一项全流程烧 20 万+ tokens 输入,且大卡「变更索引」段每变更追加、单调膨胀。
8
+ *
9
+ * 本模块 = 纯机械分类(与 module-impact.js 同性质,CLI 算事实):
10
+ * - collectModuleMaps:收齐 <spec>/docs/<project>/modules/_module-map.yaml 全部层级;
11
+ * project 名恰为仓库顶层目录(monorepo 子项目,如 backend/)→ 其 paths 视为相对该
12
+ * 子目录(effective = `<project>/` + path);否则视为仓库根相对(根层粗粒度 map)
13
+ * - matchModuleCard:跨全部 map 最长有效前缀匹配(细卡 agent/** 胜过粗卡 backend/**)
14
+ * - resolveChangeModuleCards:tasks.md 注册表 × tasks/task-NN.md allowed_paths → per-task
15
+ * 最优卡表;卡的体量(字节数)一并给出,读取建议按体量分级(>12KB 按节读)
16
+ *
17
+ * 铁律(对齐仓内先例):
18
+ * - 纯读:不写任何文件,不跑 git
19
+ * - 无 map / 无 tasks.md / 无 task 卡 → 空结果(调用方注入占位说明,不抛)
20
+ * - 判定语义(哪个模块才是「对的」)仍归 agent——本表只是机械最优匹配
21
+ */
22
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
23
+
24
+ /** 模块卡字数预算(字节):超限在 resolve 表标 ⚠️ 并提示精简——文档是 agent 的读取税
25
+ * (对标 deepseek-harness verify-doc-budgets 理念:预算只降不升;2026-08-24 起 runtime.md
26
+ * 28KB/worktree.md 24KB 已在付税)。advisory 不阻断,16 为 dogfood 校准前缺省。 */
27
+ const MODULE_CARD_BUDGET_BYTES = 16 * 1024
28
+ import { join, relative } from 'path'
29
+ import { parseModuleMapSimple } from './modules.js'
30
+ import { parseTaskRegistry } from './stages/execute.js'
31
+ import { parseAllowedPaths } from './stages/plan-postcheck.js'
32
+
33
+ /** 模块卡「整卡可读」软上限(字节)。超过则建议按节读(契约摘要/注意事项/定位),跳过历史累积段。 */
34
+ export const MODULE_CARD_SOFT_LIMIT_BYTES = 12 * 1024
35
+
36
+ /**
37
+ * 收齐 spec 下全部模块映射层。
38
+ * @param {{ cwd: string, specBase: string }} opts
39
+ * @returns {Array<{ project: string, mapPath: string, modulesDir: string, prefix: string,
40
+ * entries: Map<string, { paths: string[], doc: string|null }> }>}
41
+ * prefix:project 名为仓库顶层目录时 `<project>/`(子项目细 map),否则 ''(根层粗 map)
42
+ */
43
+ export function collectModuleMaps({ cwd, specBase }) {
44
+ const maps = []
45
+ const docsDir = join(specBase, 'docs')
46
+ if (!existsSync(docsDir)) return maps
47
+ let projects = []
48
+ try {
49
+ projects = readdirSync(docsDir, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name)
50
+ } catch { return maps }
51
+ for (const project of projects) {
52
+ const modulesDir = join(docsDir, project, 'modules')
53
+ const mapPath = join(modulesDir, '_module-map.yaml')
54
+ if (!existsSync(mapPath)) continue
55
+ let parsed = {}
56
+ try {
57
+ parsed = parseModuleMapSimple(readFileSync(mapPath, 'utf8'))
58
+ } catch { continue }
59
+ const entries = new Map()
60
+ for (const [id, data] of Object.entries(parsed)) {
61
+ const paths = Array.isArray(data?.paths) ? data.paths : []
62
+ if (paths.length === 0) continue
63
+ entries.set(id, { paths, doc: typeof data?.doc === 'string' ? data.doc : null })
64
+ }
65
+ if (entries.size === 0) continue
66
+ // 子项目判定:project 名恰为仓库顶层目录 → map 的 paths 相对该子目录(monorepo 细 map)。
67
+ // 根层 map(project = 仓名)paths 本就仓库根相对,prefix=''。
68
+ let prefix = ''
69
+ try {
70
+ const topDir = join(cwd, project)
71
+ if (existsSync(topDir) && statSync(topDir).isDirectory()) prefix = `${project}/`
72
+ } catch { /* stat 失败按根层处理 */ }
73
+ maps.push({ project, mapPath, modulesDir, prefix, entries })
74
+ }
75
+ return maps
76
+ }
77
+
78
+ /**
79
+ * 路径归一:反斜杠→正斜杠,剥尾部 glob(/** 与 /*)与目录斜杠。
80
+ * `backend/**` / `backend/` / `backend` → `backend`。
81
+ */
82
+ function normalizeMapPath(raw) {
83
+ return String(raw).replace(/\\/g, '/').replace(/\/\*\*$/, '').replace(/\/\*$/, '').replace(/\/$/, '')
84
+ }
85
+
86
+ /**
87
+ * 跨全部 map 最长有效前缀匹配一个仓库根相对路径。
88
+ * @param {string} posixPath 仓库根相对 posix 路径
89
+ * @param {Array} maps collectModuleMaps 产物
90
+ * @returns {{ moduleId: string, map: object, effectivePrefix: string }|null}
91
+ */
92
+ export function matchModuleCard(posixPath, maps) {
93
+ const p = String(posixPath).replace(/\\/g, '/')
94
+ let best = null
95
+ for (const map of maps) {
96
+ for (const [moduleId, entry] of map.entries) {
97
+ for (const raw of entry.paths) {
98
+ const effective = (map.prefix + normalizeMapPath(raw)).replace(/\/+$/, '')
99
+ if (!effective) continue
100
+ if (p === effective || p.startsWith(effective + '/')) {
101
+ if (!best || effective.length > best.effectivePrefix.length) {
102
+ best = { moduleId, map, effectivePrefix: effective }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return best
109
+ }
110
+
111
+ /**
112
+ * 解析变更全部 task 的最优模块卡。
113
+ * @param {{ cwd: string, specBase: string, changeName: string }} opts
114
+ * @returns {{ hasMaps: boolean, rows: Array<{ taskId: string, taskName: string,
115
+ * moduleId: string|null, granularity: 'fine'|'coarse'|null,
116
+ * cardPath: string|null, cardBytes: number, advice: string,
117
+ * matchedCount: number, pathCount: number }> }}
118
+ * granularity:按胜者有效前缀段数判——1 段(整子项目)=coarse 大卡,≥2 段=fine 细卡
119
+ */
120
+ export function resolveChangeModuleCards({ cwd, specBase, changeName }) {
121
+ const maps = collectModuleMaps({ cwd, specBase })
122
+ const changeDir = join(specBase, 'changes', changeName || '')
123
+ let registry = []
124
+ const tasksMd = join(changeDir, 'tasks.md')
125
+ if (existsSync(tasksMd)) {
126
+ registry = parseTaskRegistry(readFileSync(tasksMd, 'utf8'))
127
+ }
128
+ const rows = []
129
+ for (const task of registry) {
130
+ // 任务路径源:task 卡 allowed_paths(主)> 注册表行内 (文件路径) 尾注(兜底)
131
+ let paths = []
132
+ const cardFile = join(changeDir, 'tasks', `${task.id}.md`)
133
+ if (existsSync(cardFile)) {
134
+ paths = parseAllowedPaths(readFileSync(cardFile, 'utf8'))
135
+ }
136
+ if (paths.length === 0 && task.file) paths = [task.file]
137
+ paths = paths.map(p => p.replace(/\\/g, '/')).filter(Boolean)
138
+
139
+ // 全路径逐个匹配,取「最长有效前缀」的模块为该 task 的最优卡。粒度按有效前缀段数判:
140
+ // 1 段(backend/frontend 整子项目)=粗层大卡;≥2 段=细层卡(段数与卡体量正相关,
141
+ // SillyHub 这类根相对细 map 同样正确——不能按 map 的 prefix 有无判,会误标)
142
+ let winner = null
143
+ let matchedCount = 0
144
+ for (const p of paths) {
145
+ const m = matchModuleCard(p, maps)
146
+ if (!m) continue
147
+ matchedCount++
148
+ if (!winner || m.effectivePrefix.length > winner.effectivePrefix.length) winner = m
149
+ }
150
+ let granularity = null
151
+ if (winner) {
152
+ const segs = winner.effectivePrefix.split('/').filter(Boolean).length
153
+ granularity = segs >= 2 ? 'fine' : 'coarse'
154
+ }
155
+
156
+ let cardPath = null
157
+ let cardBytes = 0
158
+ let advice = '—'
159
+ if (winner) {
160
+ const docRel = winner.map.entries.get(winner.moduleId)?.doc || `modules/${winner.moduleId}.md`
161
+ const abs = join(winner.map.modulesDir, '..', docRel)
162
+ if (existsSync(abs)) {
163
+ const rel = relative(cwd, abs).replace(/\\/g, '/')
164
+ cardPath = rel.startsWith('..') ? abs.replace(/\\/g, '/') : rel
165
+ try { cardBytes = statSync(abs).size } catch { cardBytes = 0 }
166
+ advice = cardBytes > MODULE_CARD_SOFT_LIMIT_BYTES
167
+ ? `按节读(契约摘要/注意事项/定位;跳过变更索引/人工备注)`
168
+ : '整卡可读'
169
+ } else {
170
+ cardPath = relative(cwd, abs).replace(/\\/g, '/')
171
+ advice = '卡文件缺失(modules rebuild?)'
172
+ }
173
+ }
174
+ rows.push({
175
+ taskId: task.id,
176
+ taskName: task.name,
177
+ moduleId: winner ? winner.moduleId : null,
178
+ granularity,
179
+ cardPath,
180
+ cardBytes,
181
+ advice,
182
+ matchedCount,
183
+ pathCount: paths.length,
184
+ })
185
+ }
186
+ return { hasMaps: maps.length > 0, rows }
187
+ }
188
+
189
+ /**
190
+ * 渲染 per-task 模块卡表(注入 execute「加载上下文」步 prompt 用)。
191
+ * 无 map → 提示跳过;有 map 无命中行 → 单行说明。恒返回非空字符串(占位符必被替换)。
192
+ */
193
+ export function renderModuleResolveTable({ cwd, specBase, changeName }) {
194
+ const { hasMaps, rows } = resolveChangeModuleCards({ cwd, specBase, changeName })
195
+ if (!hasMaps) return '(未找到 _module-map.yaml——本项目无模块卡,跳过模块文档加载)'
196
+ const withMatch = rows.filter(r => r.moduleId)
197
+ if (withMatch.length === 0) {
198
+ return '(已找到 _module-map.yaml,但当前变更任务未命中任何模块 paths——跳过模块文档加载;游离文件可在 Wave 收尾后跑 `sillyspec modules rebuild`)'
199
+ }
200
+ const kb = (n) => n > 0 ? `${(n / 1024).toFixed(1)}KB` : '?'
201
+ const L = [
202
+ '| task | 模块 | 粒度 | 模块卡(只读命中的卡,勿按目录整读) | 体量 | 读取建议 |',
203
+ '|---|---|---|---|---|---|',
204
+ ]
205
+ const budgetBreached = new Set()
206
+ for (const r of rows) {
207
+ if (r.moduleId) {
208
+ const over = r.cardBytes > MODULE_CARD_BUDGET_BYTES
209
+ if (over) budgetBreached.add(r.moduleId)
210
+ L.push(`| ${r.taskId} | ${r.moduleId} | ${r.granularity === 'fine' ? '细' : '粗'} | \`${r.cardPath}\` | ${kb(r.cardBytes)}${over ? ' ⚠️超预算' : ''} | ${r.advice} |`)
211
+ } else {
212
+ L.push(`| ${r.taskId} | — | — | (无命中,跳过模块文档) | — | — |`)
213
+ }
214
+ }
215
+ L.push('')
216
+ L.push('> 匹配规则:全部 _module-map.yaml 跨层最长前缀(子项目细卡优先于根层大卡),源=tasks 卡 allowed_paths。')
217
+ L.push('> 细卡整卡可读;仅粗卡命中且体量大时**按节读**——只读「契约摘要/注意事项/定位」,跳过「变更索引/人工备注」历史累积段。')
218
+ if (budgetBreached.size > 0) {
219
+ L.push(`> ⚠️ 模块卡超预算(>${Math.round(MODULE_CARD_BUDGET_BYTES / 1024)}KB):${[...budgetBreached].join('、')}——文档是 agent 的读取税,本次变更触及该模块,收尾时顺手 \`sillyspec modules split-changelog\` 迁出历史段或精简正文(对标 deepseek-harness verify-doc-budgets:预算只降不升)。`)
220
+ }
221
+ return L.join('\n')
222
+ }