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,43 @@
1
+ export const definition = {
2
+ name: 'explore',
3
+ title: '自由探索',
4
+ description: '讨论、调研、画图,不写实现代码',
5
+ auxiliary: true,
6
+ steps: [
7
+ {
8
+ name: '自由探索',
9
+ prompt: `围绕用户给出的话题做技术探索,不进入实现。
10
+
11
+ ### 操作
12
+ 1. 明确探索边界:这次只讨论、调研、画图和识别风险
13
+ 2. 如果需要代码库上下文,可以读取:
14
+ - \`.sillyspec/projects/*.yaml\`
15
+ - \`.sillyspec/docs/<project>/scan/ARCHITECTURE.md\`
16
+ - \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\`
17
+ - \`.sillyspec/changes/<change-name>/design.md\`
18
+ 3. 可以用 \`rg\` / \`ls\` / \`cat\` 调查已有结构和集成点
19
+ 4. 输出 2-3 个有价值方向、关键风险和下一步建议
20
+ 5. 如果用户要求保存结论,先明确保存位置,再写入对应文档
21
+ 6. 讨论 UI/交互方案且用户明确要求原型时,按下方「HTML 原型生成」执行
22
+
23
+ ### HTML 原型生成(仅用户明确要求时)
24
+ 探索保持只读姿态:不主动写原型文件;UI 讨论成形时可以提议("要不要出个原型看效果"),用户同意后再生成。生成要求与 brainstorm 阶段的原型对齐:
25
+ - 单文件 HTML(内联 CSS + JS),浏览器直接打开
26
+ - 高保真呈现讨论中的布局/组件/交互流程——用户看到的是"这个方案做出来长什么样",不是示意图
27
+ - 与项目现有界面风格一致:先读 scan 文档与现有前端代码,复用现有组件库/设计 token 的观感,不另起风格
28
+ - 保存到 \`{SPEC_ROOT}/explore/prototype-<名称>.html\`(目录不存在则先创建;用户指定了其他位置则从其指定)
29
+ - 原型是探索讨论工具、不是交付物,也不是实现代码——不要顺手把原型接进项目源码或构建;话题后续进入 brainstorm 时,把原型文件复制到 \`{SPEC_ROOT}/changes/<变更名>/\` 可直接复用为该变更的原型
30
+
31
+ ### 输出
32
+ 探索结论、选项对比、风险清单或 ASCII 图;如生成了原型,附原型文件路径
33
+
34
+ ### 铁律
35
+ - 不写实现代码
36
+ - 不安装依赖
37
+ - 不修改文件,除非用户明确要求保存探索结论或生成原型
38
+ - 不强行推进到 brainstorm/plan/execute`,
39
+ outputHint: '探索结论',
40
+ optional: false
41
+ }
42
+ ]
43
+ }
@@ -0,0 +1,29 @@
1
+ import { definition as brainstorm } from './brainstorm.js'
2
+ import { definition as plan } from './plan.js'
3
+ import { definition as execute } from './execute.js'
4
+ import { definition as verify } from './verify.js'
5
+ import { definition as scan } from './scan.js'
6
+ import { definition as quick } from './quick.js'
7
+ import { definition as explore } from './explore.js'
8
+ import { definition as archive } from './archive.js'
9
+ import { definition as status } from './status.js'
10
+ import { definition as doctor } from './doctor.js'
11
+
12
+ // 标记辅助阶段
13
+ const auxiliaryFlag = { auxiliary: true }
14
+
15
+ export const stageRegistry = {
16
+ brainstorm,
17
+ plan,
18
+ execute,
19
+ verify,
20
+ scan: { ...scan, ...auxiliaryFlag },
21
+ quick: { ...quick, ...auxiliaryFlag },
22
+ explore: { ...explore, ...auxiliaryFlag },
23
+ archive: { ...archive, ...auxiliaryFlag },
24
+ status: { ...status, ...auxiliaryFlag },
25
+ doctor: { ...doctor, ...auxiliaryFlag }
26
+ }
27
+
28
+ // 辅助命令(在无活跃变更时也可执行)
29
+ export { AUXILIARY_STAGES as auxiliaryStages } from '../constants.js'
@@ -0,0 +1,514 @@
1
+ /**
2
+ * knowledge.js — agent-safe knowledge 管理命令
3
+ *
4
+ * 设计原则:
5
+ * - 所有输出为 JSON(--json 是默认行为,不需要显式传)
6
+ * - agent 可安全调用,不打开编辑器,不直接覆盖人工区
7
+ * - 失败有明确错误码
8
+ *
9
+ * 子命令:
10
+ * search — 关键词搜索知识库
11
+ * inspect — 读取单条知识详情
12
+ * validate — 校验知识库完整性
13
+ * refresh — 从 scan 文档刷新自动知识(仅写 generated/)
14
+ * propose — 提议新知识(写入 proposed/)
15
+ */
16
+
17
+ import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync, statSync } from 'fs'
18
+ import { join, basename } from 'path'
19
+ import { parseKnowledgeIndex, matchKnowledge } from '../knowledge-match.js'
20
+
21
+ // ── 工具函数 ──
22
+
23
+ function resolveKnowledgeDir(dir, specDir) {
24
+ const base = specDir || join(dir, '.sillyspec')
25
+ return join(base, 'knowledge')
26
+ }
27
+
28
+ function output(ok, data, error) {
29
+ const result = { ok, ...data }
30
+ if (error) result.error = error
31
+ console.log(JSON.stringify(result, null, 2))
32
+ }
33
+
34
+ /**
35
+ * 从文件路径生成知识 ID
36
+ * knowledge/conventions.md → conventions
37
+ * knowledge/generated/patterns.md → generated/patterns
38
+ */
39
+ function pathToId(basePath, knowledgeDir) {
40
+ let rel = basePath
41
+ if (rel.startsWith(knowledgeDir + '/')) rel = rel.slice(knowledgeDir.length + 1)
42
+ if (rel.endsWith('.md')) rel = rel.slice(0, -3)
43
+ return rel
44
+ }
45
+
46
+ /**
47
+ * 从知识条目提取摘要(取第一段非空非标题文本)
48
+ */
49
+ function extractSummary(content, maxLen = 120) {
50
+ const lines = content.split('\n')
51
+ for (const line of lines) {
52
+ const trimmed = line.trim()
53
+ if (!trimmed) continue
54
+ if (trimmed.startsWith('#')) continue
55
+ if (trimmed.startsWith('---')) continue
56
+ if (trimmed.startsWith('author:') || trimmed.startsWith('created_at:')) continue
57
+ if (trimmed.startsWith('>')) continue
58
+ if (trimmed.startsWith('<!--')) continue
59
+ return trimmed.slice(0, maxLen) + (trimmed.length > maxLen ? '...' : '')
60
+ }
61
+ return ''
62
+ }
63
+
64
+ /**
65
+ * 提取文件标题(第一个 # 标题)
66
+ */
67
+ function extractTitle(content) {
68
+ const match = content.match(/^#\s+(.+)$/m)
69
+ return match ? match[1].trim() : ''
70
+ }
71
+
72
+ // ── search ──
73
+
74
+ export async function cmdSearch(dir, args, opts = {}) {
75
+ const knowledgeDir = resolveKnowledgeDir(dir, opts.specDir)
76
+ const queryIdx = args.indexOf('--query')
77
+ const query = queryIdx >= 0 && args[queryIdx + 1] ? args[queryIdx + 1] : ''
78
+ const limitIdx = args.indexOf('--limit')
79
+ const limit = limitIdx >= 0 && args[limitIdx + 1] ? parseInt(args[limitIdx + 1]) : 10
80
+
81
+ if (!query) {
82
+ output(false, {}, '--query is required')
83
+ return
84
+ }
85
+
86
+ if (!existsSync(knowledgeDir)) {
87
+ output(false, {}, { code: 'knowledge_dir_missing', path: knowledgeDir })
88
+ return
89
+ }
90
+
91
+ // 复用 knowledge-match 引擎
92
+ const result = matchKnowledge(knowledgeDir, query)
93
+
94
+ if (!result.matched) {
95
+ output(true, { query, matches: [] })
96
+ return
97
+ }
98
+
99
+ // 增强:为每个匹配项补充 path、title、summary、score
100
+ const matches = result.entries.slice(0, limit).map(entry => {
101
+ const filePath = join(knowledgeDir, entry.file)
102
+ let title = entry.display
103
+ let summary = ''
104
+ let score = entry.keywords.length // 简单评分:匹配关键词数量
105
+
106
+ if (existsSync(filePath)) {
107
+ const content = readFileSync(filePath, 'utf8')
108
+ title = extractTitle(content) || entry.display
109
+ summary = extractSummary(content)
110
+ }
111
+
112
+ return {
113
+ id: pathToId(entry.file, knowledgeDir),
114
+ path: join('knowledge', entry.file),
115
+ title,
116
+ summary,
117
+ score,
118
+ tags: entry.keywords,
119
+ category: entry.category,
120
+ }
121
+ })
122
+
123
+ output(true, { query, matches })
124
+ }
125
+
126
+ // ── inspect ──
127
+
128
+ export async function cmdInspect(dir, args, opts = {}) {
129
+ const knowledgeDir = resolveKnowledgeDir(dir, opts.specDir)
130
+ const idIdx = args.indexOf('--id')
131
+ const id = idIdx >= 0 && args[idIdx + 1] ? args[idIdx + 1] : ''
132
+
133
+ if (!id) {
134
+ output(false, {}, '--id is required')
135
+ return
136
+ }
137
+
138
+ if (!existsSync(knowledgeDir)) {
139
+ output(false, {}, { code: 'knowledge_dir_missing', path: knowledgeDir })
140
+ return
141
+ }
142
+
143
+ // ID → 文件路径:conventions → knowledge/conventions.md
144
+ // generated/patterns → knowledge/generated/patterns.md
145
+ const filePath = join(knowledgeDir, id + '.md')
146
+
147
+ if (!existsSync(filePath)) {
148
+ output(false, {}, { code: 'not_found', id, path: filePath })
149
+ return
150
+ }
151
+
152
+ const content = readFileSync(filePath, 'utf8')
153
+ const title = extractTitle(content)
154
+ const summary = extractSummary(content)
155
+
156
+ // 元数据
157
+ const meta = {}
158
+ const authorMatch = content.match(/^author:\s*(.+)$/m)
159
+ const createdAtMatch = content.match(/^created_at:\s*(.+)$/m)
160
+ if (authorMatch) meta.author = authorMatch[1].trim()
161
+ if (createdAtMatch) meta.created_at = createdAtMatch[1].trim()
162
+
163
+ // 文件修改时间
164
+ const stat = statSync(filePath)
165
+ meta.updated_at = stat.mtime.toISOString()
166
+
167
+ // 分区检测
168
+ let zone = 'manual'
169
+ if (id.startsWith('generated/')) zone = 'generated'
170
+ else if (id.startsWith('proposed/')) zone = 'proposed'
171
+
172
+ output(true, {
173
+ entry: {
174
+ id,
175
+ title,
176
+ summary,
177
+ zone,
178
+ path: join('knowledge', id + '.md'),
179
+ meta,
180
+ body: content,
181
+ }
182
+ })
183
+ }
184
+
185
+ // ── validate ──
186
+
187
+ export async function cmdValidate(dir, args, opts = {}) {
188
+ const knowledgeDir = resolveKnowledgeDir(dir, opts.specDir)
189
+ const errors = []
190
+ const warnings = []
191
+
192
+ if (!existsSync(knowledgeDir)) {
193
+ output(false, { errors, warnings }, { code: 'knowledge_dir_missing', path: knowledgeDir })
194
+ return
195
+ }
196
+
197
+ // 1. INDEX.md 存在
198
+ const indexPath = join(knowledgeDir, 'INDEX.md')
199
+ if (!existsSync(indexPath)) {
200
+ errors.push({ code: 'missing_index', path: 'knowledge/INDEX.md' })
201
+ } else {
202
+ // 2. INDEX.md 引用的文件是否存在
203
+ const entries = parseKnowledgeIndex(knowledgeDir)
204
+ for (const entry of entries) {
205
+ const refPath = join(knowledgeDir, entry.file)
206
+ if (!existsSync(refPath)) {
207
+ errors.push({
208
+ code: 'broken_reference',
209
+ path: join('knowledge', entry.file),
210
+ referenced_in: 'INDEX.md',
211
+ display: entry.display,
212
+ })
213
+ }
214
+ }
215
+ }
216
+
217
+ // 3. 扫描所有 .md 文件,检查是否在 INDEX 中注册
218
+ const allMdFiles = scanMdFiles(knowledgeDir, '')
219
+ const indexedFiles = new Set(
220
+ parseKnowledgeIndex(knowledgeDir).map(e => e.file)
221
+ )
222
+
223
+ for (const mdFile of allMdFiles) {
224
+ if (mdFile === 'INDEX.md') continue
225
+ // generated/ 和 proposed/ 区不强制要求 INDEX 注册
226
+ if (mdFile.startsWith('generated/') || mdFile.startsWith('proposed/')) continue
227
+ if (!indexedFiles.has(mdFile)) {
228
+ warnings.push({
229
+ code: 'unregistered_file',
230
+ path: join('knowledge', mdFile),
231
+ })
232
+ }
233
+ }
234
+
235
+ // 4. uncategorized.md 条目数(多了提示需清理)。条目行契约是 `## <qlId> | <标题>`
236
+ //(quick 自动候选与手工条目同格式),h3 形态一并兼容;原 `^###` 只数 h3 恒为 0
237
+ const uncategorizedPath = join(knowledgeDir, 'uncategorized.md')
238
+ if (existsSync(uncategorizedPath)) {
239
+ const content = readFileSync(uncategorizedPath, 'utf8')
240
+ const entryCount = (content.match(/^#{2,3}\s+\S/gm) || []).length
241
+ if (entryCount >= 10) {
242
+ warnings.push({
243
+ code: 'too_many_uncategorized',
244
+ count: entryCount,
245
+ path: 'knowledge/uncategorized.md',
246
+ })
247
+ }
248
+ }
249
+
250
+ // 5. 空文件检测
251
+ for (const mdFile of allMdFiles) {
252
+ if (mdFile === 'INDEX.md') continue
253
+ const fullPath = join(knowledgeDir, mdFile)
254
+ const content = readFileSync(fullPath, 'utf8')
255
+ if (content.trim().length === 0) {
256
+ errors.push({
257
+ code: 'empty_file',
258
+ path: join('knowledge', mdFile),
259
+ })
260
+ }
261
+ }
262
+
263
+ output(errors.length === 0, { errors, warnings })
264
+ }
265
+
266
+ // ── refresh ──
267
+
268
+ export async function cmdRefresh(dir, args, opts = {}) {
269
+ const knowledgeDir = resolveKnowledgeDir(dir, opts.specDir)
270
+ const generatedDir = join(knowledgeDir, 'generated')
271
+
272
+ if (!existsSync(knowledgeDir)) {
273
+ output(false, {}, { code: 'knowledge_dir_missing', path: knowledgeDir })
274
+ return
275
+ }
276
+
277
+ // refresh 只写 generated/ 区
278
+ mkdirSync(generatedDir, { recursive: true })
279
+
280
+ // 扫描 scan 文档。项目名用 DB 注册名优先(坑 knowledge-basename-project-mismatch):
281
+ // scan 写侧 docs/<project> 的 project 来自 dbProjectName || basename(cwd),注册名 ≠ 目录名
282
+ // (projects yaml name/path 分离、平台模式 specRoot≠sourceRoot)时,用 basename(dir) 拼
283
+ // scanDir 永远找不到 → refresh 恒报 scan_docs_missing。DB 读失败回退 basename(与写侧
284
+ // default 同口径)。查不到注册名对应目录时再回退 basename 试一次(双形态兼容)。
285
+ const base = opts.specDir || join(dir, '.sillyspec')
286
+ let projectName = null
287
+ try {
288
+ const { DatabaseSync } = await import('node:sqlite')
289
+ const db = new DatabaseSync(join(base, '.runtime', 'sillyspec.db'), { readOnly: true })
290
+ const row = db.prepare('SELECT name FROM project LIMIT 1').get()
291
+ db.close()
292
+ if (row && row.name) projectName = row.name
293
+ } catch { /* db 不可读 → 走 basename 兜底 */ }
294
+ if (!projectName) projectName = basename(dir)
295
+ let scanDir = join(base, 'docs', projectName, 'scan')
296
+ if (!existsSync(scanDir) && projectName !== basename(dir)) {
297
+ scanDir = join(base, 'docs', basename(dir), 'scan')
298
+ }
299
+
300
+ if (!existsSync(scanDir)) {
301
+ output(false, {}, { code: 'scan_docs_missing', path: scanDir })
302
+ return
303
+ }
304
+
305
+ const scanFiles = readdirSync(scanDir).filter(f => f.endsWith('.md'))
306
+ const generated = []
307
+ const overwritten = []
308
+
309
+ for (const scanFile of scanFiles) {
310
+ const scanPath = join(scanDir, scanFile)
311
+ const content = readFileSync(scanPath, 'utf8')
312
+ const title = extractTitle(content) || scanFile.replace('.md', '')
313
+
314
+ // 简单提取:取每个 ## 章节作为一个知识条目候选
315
+ const sections = extractSections(content)
316
+ for (const section of sections) {
317
+ if (section.lines < 3) continue // 太短的章节跳过
318
+
319
+ const slug = section.heading.toLowerCase()
320
+ .replace(/[^\w\u4e00-\u9fff]+/g, '-')
321
+ .replace(/^-|-$/g, '')
322
+ .slice(0, 60)
323
+
324
+ const fileName = `${slug}.md`
325
+ const genPath = join(generatedDir, fileName)
326
+ const isNew = !existsSync(genPath)
327
+
328
+ const entryContent = [
329
+ `---`,
330
+ `source: scan/${scanFile}`,
331
+ `section: ${section.heading}`,
332
+ `generated_at: ${new Date().toISOString()}`,
333
+ `---`,
334
+ ``,
335
+ `# ${title} — ${section.heading}`,
336
+ ``,
337
+ section.body,
338
+ ].join('\n')
339
+
340
+ writeFileSync(genPath, entryContent)
341
+ generated.push({ file: `generated/${fileName}`, title: `${title} — ${section.heading}`, new: isNew })
342
+ if (!isNew) overwritten.push(`generated/${fileName}`)
343
+ }
344
+ }
345
+
346
+ // 更新 generated/INDEX.md
347
+ const genIndexPath = join(generatedDir, 'INDEX.md')
348
+ const indexLines = [
349
+ '---',
350
+ `generated_at: ${new Date().toISOString()}`,
351
+ '---',
352
+ '',
353
+ '# Generated Knowledge Index',
354
+ '',
355
+ '> Auto-generated from scan documents. Do not edit manually.',
356
+ '',
357
+ ]
358
+ for (const g of generated) {
359
+ indexLines.push(`- ${g.title} → [${g.file}](${g.file})`)
360
+ }
361
+ writeFileSync(genIndexPath, indexLines.join('\n'))
362
+
363
+ output(true, {
364
+ generated_count: generated.length,
365
+ new_count: generated.filter(g => g.new).length,
366
+ overwritten_count: overwritten.length,
367
+ files: generated,
368
+ })
369
+ }
370
+
371
+ // ── propose ──
372
+
373
+ export async function cmdPropose(dir, args, opts = {}) {
374
+ const knowledgeDir = resolveKnowledgeDir(dir, opts.specDir)
375
+ const proposedDir = join(knowledgeDir, 'proposed')
376
+
377
+ const titleIdx = args.indexOf('--title')
378
+ const title = titleIdx >= 0 && args[titleIdx + 1] ? args[titleIdx + 1] : ''
379
+ const categoryIdx = args.indexOf('--category')
380
+ const category = categoryIdx >= 0 && args[categoryIdx + 1] ? args[categoryIdx + 1] : 'uncategorized'
381
+ const bodyIdx = args.indexOf('--body')
382
+ const body = bodyIdx >= 0 && args[bodyIdx + 1] ? args[bodyIdx + 1] : ''
383
+ const fromIdx = args.indexOf('--from')
384
+ const from = fromIdx >= 0 && args[fromIdx + 1] ? args[fromIdx + 1] : ''
385
+
386
+ if (!title) {
387
+ output(false, {}, '--title is required')
388
+ return
389
+ }
390
+
391
+ mkdirSync(proposedDir, { recursive: true })
392
+
393
+ // 生成 slug
394
+ const slug = title.toLowerCase()
395
+ .replace(/[^\w\u4e00-\u9fff]+/g, '-')
396
+ .replace(/^-|-$/g, '')
397
+ .slice(0, 60)
398
+
399
+ const fileName = `${slug}.md`
400
+ const propPath = join(proposedDir, fileName)
401
+ const isNew = !existsSync(propPath)
402
+
403
+ const content = [
404
+ '---',
405
+ `proposed_at: ${new Date().toISOString()}`,
406
+ `category: ${category}`,
407
+ ...(from ? [`source: ${from}`] : []),
408
+ 'status: pending_review',
409
+ '---',
410
+ '',
411
+ `# ${title}`,
412
+ '',
413
+ body || '(no body provided)',
414
+ '',
415
+ '---',
416
+ '> This is a proposed knowledge entry. Review and merge into manual/ or generated/.',
417
+ ].join('\n')
418
+
419
+ writeFileSync(propPath, content)
420
+
421
+ output(true, {
422
+ id: `proposed/${slug}`,
423
+ path: `knowledge/proposed/${fileName}`,
424
+ title,
425
+ category,
426
+ new: isNew,
427
+ action: isNew ? 'created' : 'updated',
428
+ })
429
+ }
430
+
431
+ // ── 辅助函数 ──
432
+
433
+ function scanMdFiles(baseDir, prefix) {
434
+ const results = []
435
+ const items = readdirSync(baseDir, { withFileTypes: true })
436
+ for (const item of items) {
437
+ const rel = prefix ? `${prefix}/${item.name}` : item.name
438
+ if (item.isDirectory()) {
439
+ results.push(...scanMdFiles(join(baseDir, item.name), rel))
440
+ } else if (item.name.endsWith('.md')) {
441
+ results.push(rel)
442
+ }
443
+ }
444
+ return results
445
+ }
446
+
447
+ function extractSections(content) {
448
+ const lines = content.split('\n')
449
+ const sections = []
450
+ let currentHeading = null
451
+ let currentLines = []
452
+ let currentBody = []
453
+
454
+ for (const line of lines) {
455
+ if (line.startsWith('## ')) {
456
+ if (currentHeading) {
457
+ sections.push({
458
+ heading: currentHeading,
459
+ body: currentBody.join('\n').trim(),
460
+ lines: currentLines.length,
461
+ })
462
+ }
463
+ currentHeading = line.slice(3).trim()
464
+ currentLines = [line]
465
+ currentBody = []
466
+ } else if (currentHeading) {
467
+ currentLines.push(line)
468
+ // 跳过 frontmatter 和标题行
469
+ if (!line.startsWith('---') && !line.startsWith('#')) {
470
+ currentBody.push(line)
471
+ }
472
+ }
473
+ }
474
+
475
+ if (currentHeading) {
476
+ sections.push({
477
+ heading: currentHeading,
478
+ body: currentBody.join('\n').trim(),
479
+ lines: currentLines.length,
480
+ })
481
+ }
482
+
483
+ return sections.filter(s => s.lines >= 3)
484
+ }
485
+
486
+ // ── 入口路由 ──
487
+
488
+ /**
489
+ * @param {string[]} args - filteredArgs.slice(1)(去掉 'knowledge')
490
+ * @param {string} dir - 项目根目录
491
+ * @param {object} opts - { specDir }
492
+ */
493
+ export async function cmdKnowledge(args, dir, opts = {}) {
494
+ const subCommand = args[0] || ''
495
+
496
+ switch (subCommand) {
497
+ case 'search':
498
+ return cmdSearch(dir, args.slice(1), opts)
499
+ case 'inspect':
500
+ return cmdInspect(dir, args.slice(1), opts)
501
+ case 'validate':
502
+ return cmdValidate(dir, args.slice(1), opts)
503
+ case 'refresh':
504
+ return cmdRefresh(dir, args.slice(1), opts)
505
+ case 'propose':
506
+ return cmdPropose(dir, args.slice(1), opts)
507
+ default:
508
+ output(false, {}, {
509
+ code: 'unknown_subcommand',
510
+ subcommand: subCommand,
511
+ available: ['search', 'inspect', 'validate', 'refresh', 'propose'],
512
+ })
513
+ }
514
+ }