@jokerized/getresearchdone 0.4.1

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 (711) hide show
  1. package/.claude-plugin/plugin.json +103 -0
  2. package/README.md +211 -0
  3. package/agents/grd-baseline-assessor.md +684 -0
  4. package/agents/grd-code-reviewer.md +300 -0
  5. package/agents/grd-codebase-mapper.md +355 -0
  6. package/agents/grd-critique-agent.md +119 -0
  7. package/agents/grd-debugger.md +519 -0
  8. package/agents/grd-deep-diver.md +737 -0
  9. package/agents/grd-eval-planner.md +913 -0
  10. package/agents/grd-eval-reporter.md +717 -0
  11. package/agents/grd-executor.md +683 -0
  12. package/agents/grd-feasibility-analyst.md +624 -0
  13. package/agents/grd-integration-checker.md +367 -0
  14. package/agents/grd-knowledge-miner.md +81 -0
  15. package/agents/grd-migrator.md +88 -0
  16. package/agents/grd-phase-researcher.md +697 -0
  17. package/agents/grd-plan-checker.md +443 -0
  18. package/agents/grd-planner.md +1532 -0
  19. package/agents/grd-product-owner.md +562 -0
  20. package/agents/grd-project-researcher.md +513 -0
  21. package/agents/grd-research-synthesizer.md +273 -0
  22. package/agents/grd-roadmapper.md +798 -0
  23. package/agents/grd-surveyor.md +566 -0
  24. package/agents/grd-verifier.md +893 -0
  25. package/bin/gd.js +4 -0
  26. package/bin/gd.ts +227 -0
  27. package/bin/grd-manifest.js +4 -0
  28. package/bin/grd-manifest.ts +286 -0
  29. package/bin/grd-mcp-server.js +4 -0
  30. package/bin/grd-mcp-server.ts +124 -0
  31. package/bin/grd-tools.js +4 -0
  32. package/bin/grd-tools.ts +2471 -0
  33. package/bin/postinstall.js +4 -0
  34. package/bin/postinstall.ts +80 -0
  35. package/commands/add-phase.md +123 -0
  36. package/commands/add-todo.md +87 -0
  37. package/commands/assess-baseline.md +289 -0
  38. package/commands/autopilot.md +100 -0
  39. package/commands/autoplan.md +55 -0
  40. package/commands/check-todos.md +87 -0
  41. package/commands/compare-methods.md +262 -0
  42. package/commands/complete-milestone.md +225 -0
  43. package/commands/debug.md +372 -0
  44. package/commands/deep-dive.md +288 -0
  45. package/commands/discover.md +281 -0
  46. package/commands/discuss-phase.md +188 -0
  47. package/commands/discuss.md +55 -0
  48. package/commands/eval-report.md +310 -0
  49. package/commands/evolve.md +79 -0
  50. package/commands/execute-phase.md +1017 -0
  51. package/commands/feasibility.md +292 -0
  52. package/commands/help.md +407 -0
  53. package/commands/init.md +1508 -0
  54. package/commands/insert-phase.md +113 -0
  55. package/commands/iterate.md +327 -0
  56. package/commands/list-phase-assumptions.md +217 -0
  57. package/commands/long-term-roadmap.md +202 -0
  58. package/commands/map-codebase.md +111 -0
  59. package/commands/migrate.md +159 -0
  60. package/commands/new-milestone.md +169 -0
  61. package/commands/pause-work.md +83 -0
  62. package/commands/plan-milestone-gaps.md +373 -0
  63. package/commands/plan-phase.md +655 -0
  64. package/commands/principles.md +328 -0
  65. package/commands/product-plan.md +319 -0
  66. package/commands/progress.md +481 -0
  67. package/commands/quick.md +167 -0
  68. package/commands/reapply-patches.md +154 -0
  69. package/commands/remove-phase.md +97 -0
  70. package/commands/requirement.md +96 -0
  71. package/commands/resume-project.md +113 -0
  72. package/commands/settings.md +1144 -0
  73. package/commands/survey.md +242 -0
  74. package/commands/sync.md +246 -0
  75. package/commands/tracker-setup.md +322 -0
  76. package/commands/update.md +202 -0
  77. package/commands/verify-phase.md +335 -0
  78. package/commands/verify-work.md +701 -0
  79. package/commands/wireup.md +29 -0
  80. package/dist/bin/gd.d.ts +3 -0
  81. package/dist/bin/gd.d.ts.map +1 -0
  82. package/dist/bin/gd.js +178 -0
  83. package/dist/bin/gd.js.map +1 -0
  84. package/dist/bin/grd-manifest.d.ts +3 -0
  85. package/dist/bin/grd-manifest.d.ts.map +1 -0
  86. package/dist/bin/grd-manifest.js +202 -0
  87. package/dist/bin/grd-manifest.js.map +1 -0
  88. package/dist/bin/grd-mcp-server.d.ts +3 -0
  89. package/dist/bin/grd-mcp-server.d.ts.map +1 -0
  90. package/dist/bin/grd-mcp-server.js +71 -0
  91. package/dist/bin/grd-mcp-server.js.map +1 -0
  92. package/dist/bin/grd-tools.d.ts +3 -0
  93. package/dist/bin/grd-tools.d.ts.map +1 -0
  94. package/dist/bin/grd-tools.js +1680 -0
  95. package/dist/bin/grd-tools.js.map +1 -0
  96. package/dist/bin/postinstall.d.ts +3 -0
  97. package/dist/bin/postinstall.d.ts.map +1 -0
  98. package/dist/bin/postinstall.js +61 -0
  99. package/dist/bin/postinstall.js.map +1 -0
  100. package/dist/lib/autopilot-milestone.d.ts +2 -0
  101. package/dist/lib/autopilot-milestone.d.ts.map +1 -0
  102. package/dist/lib/autopilot-milestone.js +94 -0
  103. package/dist/lib/autopilot-milestone.js.map +1 -0
  104. package/dist/lib/autopilot-pipeline.d.ts +2 -0
  105. package/dist/lib/autopilot-pipeline.d.ts.map +1 -0
  106. package/dist/lib/autopilot-pipeline.js +830 -0
  107. package/dist/lib/autopilot-pipeline.js.map +1 -0
  108. package/dist/lib/autopilot-waves.d.ts +2 -0
  109. package/dist/lib/autopilot-waves.d.ts.map +1 -0
  110. package/dist/lib/autopilot-waves.js +266 -0
  111. package/dist/lib/autopilot-waves.js.map +1 -0
  112. package/dist/lib/autopilot.d.ts +2 -0
  113. package/dist/lib/autopilot.d.ts.map +1 -0
  114. package/dist/lib/autopilot.js +1314 -0
  115. package/dist/lib/autopilot.js.map +1 -0
  116. package/dist/lib/autoplan.d.ts +2 -0
  117. package/dist/lib/autoplan.d.ts.map +1 -0
  118. package/dist/lib/autoplan.js +198 -0
  119. package/dist/lib/autoplan.js.map +1 -0
  120. package/dist/lib/autoresearch.d.ts +2 -0
  121. package/dist/lib/autoresearch.d.ts.map +1 -0
  122. package/dist/lib/autoresearch.js +626 -0
  123. package/dist/lib/autoresearch.js.map +1 -0
  124. package/dist/lib/backend.d.ts +2 -0
  125. package/dist/lib/backend.d.ts.map +1 -0
  126. package/dist/lib/backend.js +1036 -0
  127. package/dist/lib/backend.js.map +1 -0
  128. package/dist/lib/benchmark.d.ts +99 -0
  129. package/dist/lib/benchmark.d.ts.map +1 -0
  130. package/dist/lib/benchmark.js +278 -0
  131. package/dist/lib/benchmark.js.map +1 -0
  132. package/dist/lib/citations.d.ts +2 -0
  133. package/dist/lib/citations.d.ts.map +1 -0
  134. package/dist/lib/citations.js +642 -0
  135. package/dist/lib/citations.js.map +1 -0
  136. package/dist/lib/cleanup.d.ts +2 -0
  137. package/dist/lib/cleanup.d.ts.map +1 -0
  138. package/dist/lib/cleanup.js +1222 -0
  139. package/dist/lib/cleanup.js.map +1 -0
  140. package/dist/lib/cli/adapters.d.ts +10 -0
  141. package/dist/lib/cli/adapters.d.ts.map +1 -0
  142. package/dist/lib/cli/adapters.js +27 -0
  143. package/dist/lib/cli/adapters.js.map +1 -0
  144. package/dist/lib/cli/agent.d.ts +17 -0
  145. package/dist/lib/cli/agent.d.ts.map +1 -0
  146. package/dist/lib/cli/agent.js +53 -0
  147. package/dist/lib/cli/agent.js.map +1 -0
  148. package/dist/lib/cli/index.d.ts +21 -0
  149. package/dist/lib/cli/index.d.ts.map +1 -0
  150. package/dist/lib/cli/index.js +264 -0
  151. package/dist/lib/cli/index.js.map +1 -0
  152. package/dist/lib/cli/output.d.ts +20 -0
  153. package/dist/lib/cli/output.d.ts.map +1 -0
  154. package/dist/lib/cli/output.js +22 -0
  155. package/dist/lib/cli/output.js.map +1 -0
  156. package/dist/lib/cli/scan-dispatch.d.ts +9 -0
  157. package/dist/lib/cli/scan-dispatch.d.ts.map +1 -0
  158. package/dist/lib/cli/scan-dispatch.js +107 -0
  159. package/dist/lib/cli/scan-dispatch.js.map +1 -0
  160. package/dist/lib/cli/tools.d.ts +16 -0
  161. package/dist/lib/cli/tools.d.ts.map +1 -0
  162. package/dist/lib/cli/tools.js +168 -0
  163. package/dist/lib/cli/tools.js.map +1 -0
  164. package/dist/lib/commands/_dashboard-parsers.d.ts +2 -0
  165. package/dist/lib/commands/_dashboard-parsers.d.ts.map +1 -0
  166. package/dist/lib/commands/_dashboard-parsers.js +192 -0
  167. package/dist/lib/commands/_dashboard-parsers.js.map +1 -0
  168. package/dist/lib/commands/analysis.d.ts +2 -0
  169. package/dist/lib/commands/analysis.d.ts.map +1 -0
  170. package/dist/lib/commands/analysis.js +1418 -0
  171. package/dist/lib/commands/analysis.js.map +1 -0
  172. package/dist/lib/commands/assumptions.d.ts +2 -0
  173. package/dist/lib/commands/assumptions.d.ts.map +1 -0
  174. package/dist/lib/commands/assumptions.js +166 -0
  175. package/dist/lib/commands/assumptions.js.map +1 -0
  176. package/dist/lib/commands/blame.d.ts +2 -0
  177. package/dist/lib/commands/blame.d.ts.map +1 -0
  178. package/dist/lib/commands/blame.js +133 -0
  179. package/dist/lib/commands/blame.js.map +1 -0
  180. package/dist/lib/commands/budget.d.ts +2 -0
  181. package/dist/lib/commands/budget.d.ts.map +1 -0
  182. package/dist/lib/commands/budget.js +100 -0
  183. package/dist/lib/commands/budget.js.map +1 -0
  184. package/dist/lib/commands/check-plans.d.ts +2 -0
  185. package/dist/lib/commands/check-plans.d.ts.map +1 -0
  186. package/dist/lib/commands/check-plans.js +190 -0
  187. package/dist/lib/commands/check-plans.js.map +1 -0
  188. package/dist/lib/commands/config.d.ts +2 -0
  189. package/dist/lib/commands/config.d.ts.map +1 -0
  190. package/dist/lib/commands/config.js +188 -0
  191. package/dist/lib/commands/config.js.map +1 -0
  192. package/dist/lib/commands/dashboard.d.ts +2 -0
  193. package/dist/lib/commands/dashboard.d.ts.map +1 -0
  194. package/dist/lib/commands/dashboard.js +466 -0
  195. package/dist/lib/commands/dashboard.js.map +1 -0
  196. package/dist/lib/commands/estimate.d.ts +2 -0
  197. package/dist/lib/commands/estimate.d.ts.map +1 -0
  198. package/dist/lib/commands/estimate.js +148 -0
  199. package/dist/lib/commands/estimate.js.map +1 -0
  200. package/dist/lib/commands/eval-diff.d.ts +2 -0
  201. package/dist/lib/commands/eval-diff.d.ts.map +1 -0
  202. package/dist/lib/commands/eval-diff.js +213 -0
  203. package/dist/lib/commands/eval-diff.js.map +1 -0
  204. package/dist/lib/commands/freshness.d.ts +2 -0
  205. package/dist/lib/commands/freshness.d.ts.map +1 -0
  206. package/dist/lib/commands/freshness.js +163 -0
  207. package/dist/lib/commands/freshness.js.map +1 -0
  208. package/dist/lib/commands/health.d.ts +2 -0
  209. package/dist/lib/commands/health.d.ts.map +1 -0
  210. package/dist/lib/commands/health.js +435 -0
  211. package/dist/lib/commands/health.js.map +1 -0
  212. package/dist/lib/commands/index.d.ts +2 -0
  213. package/dist/lib/commands/index.d.ts.map +1 -0
  214. package/dist/lib/commands/index.js +128 -0
  215. package/dist/lib/commands/index.js.map +1 -0
  216. package/dist/lib/commands/install.d.ts +56 -0
  217. package/dist/lib/commands/install.d.ts.map +1 -0
  218. package/dist/lib/commands/install.js +214 -0
  219. package/dist/lib/commands/install.js.map +1 -0
  220. package/dist/lib/commands/knowhow-aggregator.d.ts +2 -0
  221. package/dist/lib/commands/knowhow-aggregator.d.ts.map +1 -0
  222. package/dist/lib/commands/knowhow-aggregator.js +279 -0
  223. package/dist/lib/commands/knowhow-aggregator.js.map +1 -0
  224. package/dist/lib/commands/knowledge-search.d.ts +2 -0
  225. package/dist/lib/commands/knowledge-search.d.ts.map +1 -0
  226. package/dist/lib/commands/knowledge-search.js +113 -0
  227. package/dist/lib/commands/knowledge-search.js.map +1 -0
  228. package/dist/lib/commands/long-term-roadmap.d.ts +2 -0
  229. package/dist/lib/commands/long-term-roadmap.d.ts.map +1 -0
  230. package/dist/lib/commands/long-term-roadmap.js +272 -0
  231. package/dist/lib/commands/long-term-roadmap.js.map +1 -0
  232. package/dist/lib/commands/patterns.d.ts +91 -0
  233. package/dist/lib/commands/patterns.d.ts.map +1 -0
  234. package/dist/lib/commands/patterns.js +391 -0
  235. package/dist/lib/commands/patterns.js.map +1 -0
  236. package/dist/lib/commands/phase-info.d.ts +2 -0
  237. package/dist/lib/commands/phase-info.d.ts.map +1 -0
  238. package/dist/lib/commands/phase-info.js +509 -0
  239. package/dist/lib/commands/phase-info.js.map +1 -0
  240. package/dist/lib/commands/plan-lint.d.ts +56 -0
  241. package/dist/lib/commands/plan-lint.d.ts.map +1 -0
  242. package/dist/lib/commands/plan-lint.js +481 -0
  243. package/dist/lib/commands/plan-lint.js.map +1 -0
  244. package/dist/lib/commands/plan-phase.d.ts +53 -0
  245. package/dist/lib/commands/plan-phase.d.ts.map +1 -0
  246. package/dist/lib/commands/plan-phase.js +288 -0
  247. package/dist/lib/commands/plan-phase.js.map +1 -0
  248. package/dist/lib/commands/progress.d.ts +2 -0
  249. package/dist/lib/commands/progress.d.ts.map +1 -0
  250. package/dist/lib/commands/progress.js +266 -0
  251. package/dist/lib/commands/progress.js.map +1 -0
  252. package/dist/lib/commands/quality.d.ts +2 -0
  253. package/dist/lib/commands/quality.d.ts.map +1 -0
  254. package/dist/lib/commands/quality.js +80 -0
  255. package/dist/lib/commands/quality.js.map +1 -0
  256. package/dist/lib/commands/rollback.d.ts +2 -0
  257. package/dist/lib/commands/rollback.d.ts.map +1 -0
  258. package/dist/lib/commands/rollback.js +145 -0
  259. package/dist/lib/commands/rollback.js.map +1 -0
  260. package/dist/lib/commands/scan.d.ts +25 -0
  261. package/dist/lib/commands/scan.d.ts.map +1 -0
  262. package/dist/lib/commands/scan.js +28 -0
  263. package/dist/lib/commands/scan.js.map +1 -0
  264. package/dist/lib/commands/search.d.ts +2 -0
  265. package/dist/lib/commands/search.d.ts.map +1 -0
  266. package/dist/lib/commands/search.js +212 -0
  267. package/dist/lib/commands/search.js.map +1 -0
  268. package/dist/lib/commands/select-candidate.d.ts +128 -0
  269. package/dist/lib/commands/select-candidate.d.ts.map +1 -0
  270. package/dist/lib/commands/select-candidate.js +518 -0
  271. package/dist/lib/commands/select-candidate.js.map +1 -0
  272. package/dist/lib/commands/singularity.d.ts +2 -0
  273. package/dist/lib/commands/singularity.d.ts.map +1 -0
  274. package/dist/lib/commands/singularity.js +185 -0
  275. package/dist/lib/commands/singularity.js.map +1 -0
  276. package/dist/lib/commands/slug-timestamp.d.ts +2 -0
  277. package/dist/lib/commands/slug-timestamp.d.ts.map +1 -0
  278. package/dist/lib/commands/slug-timestamp.js +54 -0
  279. package/dist/lib/commands/slug-timestamp.js.map +1 -0
  280. package/dist/lib/commands/tail.d.ts +2 -0
  281. package/dist/lib/commands/tail.d.ts.map +1 -0
  282. package/dist/lib/commands/tail.js +100 -0
  283. package/dist/lib/commands/tail.js.map +1 -0
  284. package/dist/lib/commands/todo.d.ts +2 -0
  285. package/dist/lib/commands/todo.d.ts.map +1 -0
  286. package/dist/lib/commands/todo.js +200 -0
  287. package/dist/lib/commands/todo.js.map +1 -0
  288. package/dist/lib/commands/watch.d.ts +2 -0
  289. package/dist/lib/commands/watch.d.ts.map +1 -0
  290. package/dist/lib/commands/watch.js +72 -0
  291. package/dist/lib/commands/watch.js.map +1 -0
  292. package/dist/lib/complexity.d.ts +55 -0
  293. package/dist/lib/complexity.d.ts.map +1 -0
  294. package/dist/lib/complexity.js +80 -0
  295. package/dist/lib/complexity.js.map +1 -0
  296. package/dist/lib/context/agents.d.ts +2 -0
  297. package/dist/lib/context/agents.d.ts.map +1 -0
  298. package/dist/lib/context/agents.js +344 -0
  299. package/dist/lib/context/agents.js.map +1 -0
  300. package/dist/lib/context/base.d.ts +2 -0
  301. package/dist/lib/context/base.d.ts.map +1 -0
  302. package/dist/lib/context/base.js +81 -0
  303. package/dist/lib/context/base.js.map +1 -0
  304. package/dist/lib/context/execute.d.ts +2 -0
  305. package/dist/lib/context/execute.d.ts.map +1 -0
  306. package/dist/lib/context/execute.js +753 -0
  307. package/dist/lib/context/execute.js.map +1 -0
  308. package/dist/lib/context/index.d.ts +2 -0
  309. package/dist/lib/context/index.d.ts.map +1 -0
  310. package/dist/lib/context/index.js +88 -0
  311. package/dist/lib/context/index.js.map +1 -0
  312. package/dist/lib/context/progress.d.ts +2 -0
  313. package/dist/lib/context/progress.d.ts.map +1 -0
  314. package/dist/lib/context/progress.js +178 -0
  315. package/dist/lib/context/progress.js.map +1 -0
  316. package/dist/lib/context/project.d.ts +2 -0
  317. package/dist/lib/context/project.d.ts.map +1 -0
  318. package/dist/lib/context/project.js +413 -0
  319. package/dist/lib/context/project.js.map +1 -0
  320. package/dist/lib/context/research.d.ts +2 -0
  321. package/dist/lib/context/research.d.ts.map +1 -0
  322. package/dist/lib/context/research.js +466 -0
  323. package/dist/lib/context/research.js.map +1 -0
  324. package/dist/lib/dead-ends.d.ts +28 -0
  325. package/dist/lib/dead-ends.d.ts.map +1 -0
  326. package/dist/lib/dead-ends.js +451 -0
  327. package/dist/lib/dead-ends.js.map +1 -0
  328. package/dist/lib/deps.d.ts +2 -0
  329. package/dist/lib/deps.d.ts.map +1 -0
  330. package/dist/lib/deps.js +630 -0
  331. package/dist/lib/deps.js.map +1 -0
  332. package/dist/lib/discussion.d.ts +2 -0
  333. package/dist/lib/discussion.d.ts.map +1 -0
  334. package/dist/lib/discussion.js +1041 -0
  335. package/dist/lib/discussion.js.map +1 -0
  336. package/dist/lib/drift.d.ts +36 -0
  337. package/dist/lib/drift.d.ts.map +1 -0
  338. package/dist/lib/drift.js +481 -0
  339. package/dist/lib/drift.js.map +1 -0
  340. package/dist/lib/evolve/_dimensions-features.d.ts +2 -0
  341. package/dist/lib/evolve/_dimensions-features.d.ts.map +1 -0
  342. package/dist/lib/evolve/_dimensions-features.js +369 -0
  343. package/dist/lib/evolve/_dimensions-features.js.map +1 -0
  344. package/dist/lib/evolve/_dimensions.d.ts +2 -0
  345. package/dist/lib/evolve/_dimensions.d.ts.map +1 -0
  346. package/dist/lib/evolve/_dimensions.js +358 -0
  347. package/dist/lib/evolve/_dimensions.js.map +1 -0
  348. package/dist/lib/evolve/_product-ideation.d.ts +2 -0
  349. package/dist/lib/evolve/_product-ideation.d.ts.map +1 -0
  350. package/dist/lib/evolve/_product-ideation.js +281 -0
  351. package/dist/lib/evolve/_product-ideation.js.map +1 -0
  352. package/dist/lib/evolve/_prompts.d.ts +2 -0
  353. package/dist/lib/evolve/_prompts.d.ts.map +1 -0
  354. package/dist/lib/evolve/_prompts.js +153 -0
  355. package/dist/lib/evolve/_prompts.js.map +1 -0
  356. package/dist/lib/evolve/cli.d.ts +2 -0
  357. package/dist/lib/evolve/cli.d.ts.map +1 -0
  358. package/dist/lib/evolve/cli.js +224 -0
  359. package/dist/lib/evolve/cli.js.map +1 -0
  360. package/dist/lib/evolve/discovery.d.ts +2 -0
  361. package/dist/lib/evolve/discovery.d.ts.map +1 -0
  362. package/dist/lib/evolve/discovery.js +391 -0
  363. package/dist/lib/evolve/discovery.js.map +1 -0
  364. package/dist/lib/evolve/index.d.ts +2 -0
  365. package/dist/lib/evolve/index.d.ts.map +1 -0
  366. package/dist/lib/evolve/index.js +88 -0
  367. package/dist/lib/evolve/index.js.map +1 -0
  368. package/dist/lib/evolve/orchestrator.d.ts +2 -0
  369. package/dist/lib/evolve/orchestrator.d.ts.map +1 -0
  370. package/dist/lib/evolve/orchestrator.js +851 -0
  371. package/dist/lib/evolve/orchestrator.js.map +1 -0
  372. package/dist/lib/evolve/scoring.d.ts +2 -0
  373. package/dist/lib/evolve/scoring.d.ts.map +1 -0
  374. package/dist/lib/evolve/scoring.js +118 -0
  375. package/dist/lib/evolve/scoring.js.map +1 -0
  376. package/dist/lib/evolve/state.d.ts +2 -0
  377. package/dist/lib/evolve/state.d.ts.map +1 -0
  378. package/dist/lib/evolve/state.js +264 -0
  379. package/dist/lib/evolve/state.js.map +1 -0
  380. package/dist/lib/evolve/types.d.ts +249 -0
  381. package/dist/lib/evolve/types.d.ts.map +1 -0
  382. package/dist/lib/evolve/types.js +3 -0
  383. package/dist/lib/evolve/types.js.map +1 -0
  384. package/dist/lib/frontmatter.d.ts +2 -0
  385. package/dist/lib/frontmatter.d.ts.map +1 -0
  386. package/dist/lib/frontmatter.js +513 -0
  387. package/dist/lib/frontmatter.js.map +1 -0
  388. package/dist/lib/gates.d.ts +2 -0
  389. package/dist/lib/gates.d.ts.map +1 -0
  390. package/dist/lib/gates.js +578 -0
  391. package/dist/lib/gates.js.map +1 -0
  392. package/dist/lib/genome.d.ts +10 -0
  393. package/dist/lib/genome.d.ts.map +1 -0
  394. package/dist/lib/genome.js +368 -0
  395. package/dist/lib/genome.js.map +1 -0
  396. package/dist/lib/got.d.ts +2 -0
  397. package/dist/lib/got.d.ts.map +1 -0
  398. package/dist/lib/got.js +280 -0
  399. package/dist/lib/got.js.map +1 -0
  400. package/dist/lib/invariants.d.ts +2 -0
  401. package/dist/lib/invariants.d.ts.map +1 -0
  402. package/dist/lib/invariants.js +298 -0
  403. package/dist/lib/invariants.js.map +1 -0
  404. package/dist/lib/knowledge.d.ts +2 -0
  405. package/dist/lib/knowledge.d.ts.map +1 -0
  406. package/dist/lib/knowledge.js +658 -0
  407. package/dist/lib/knowledge.js.map +1 -0
  408. package/dist/lib/long-term-roadmap.d.ts +2 -0
  409. package/dist/lib/long-term-roadmap.d.ts.map +1 -0
  410. package/dist/lib/long-term-roadmap.js +602 -0
  411. package/dist/lib/long-term-roadmap.js.map +1 -0
  412. package/dist/lib/markdown-split.d.ts +2 -0
  413. package/dist/lib/markdown-split.d.ts.map +1 -0
  414. package/dist/lib/markdown-split.js +199 -0
  415. package/dist/lib/markdown-split.js.map +1 -0
  416. package/dist/lib/mcp-server.d.ts +2 -0
  417. package/dist/lib/mcp-server.d.ts.map +1 -0
  418. package/dist/lib/mcp-server.js +2424 -0
  419. package/dist/lib/mcp-server.js.map +1 -0
  420. package/dist/lib/metrics.d.ts +16 -0
  421. package/dist/lib/metrics.d.ts.map +1 -0
  422. package/dist/lib/metrics.js +48 -0
  423. package/dist/lib/metrics.js.map +1 -0
  424. package/dist/lib/overstory.d.ts +2 -0
  425. package/dist/lib/overstory.d.ts.map +1 -0
  426. package/dist/lib/overstory.js +211 -0
  427. package/dist/lib/overstory.js.map +1 -0
  428. package/dist/lib/parallel.d.ts +2 -0
  429. package/dist/lib/parallel.d.ts.map +1 -0
  430. package/dist/lib/parallel.js +349 -0
  431. package/dist/lib/parallel.js.map +1 -0
  432. package/dist/lib/paths.d.ts +2 -0
  433. package/dist/lib/paths.d.ts.map +1 -0
  434. package/dist/lib/paths.js +254 -0
  435. package/dist/lib/paths.js.map +1 -0
  436. package/dist/lib/phase-complete-llm.d.ts +22 -0
  437. package/dist/lib/phase-complete-llm.d.ts.map +1 -0
  438. package/dist/lib/phase-complete-llm.js +331 -0
  439. package/dist/lib/phase-complete-llm.js.map +1 -0
  440. package/dist/lib/phase-complete.d.ts +46 -0
  441. package/dist/lib/phase-complete.d.ts.map +1 -0
  442. package/dist/lib/phase-complete.js +278 -0
  443. package/dist/lib/phase-complete.js.map +1 -0
  444. package/dist/lib/phase-io.d.ts +2 -0
  445. package/dist/lib/phase-io.d.ts.map +1 -0
  446. package/dist/lib/phase-io.js +126 -0
  447. package/dist/lib/phase-io.js.map +1 -0
  448. package/dist/lib/phase.d.ts +2 -0
  449. package/dist/lib/phase.d.ts.map +1 -0
  450. package/dist/lib/phase.js +1344 -0
  451. package/dist/lib/phase.js.map +1 -0
  452. package/dist/lib/plan-tournament.d.ts +63 -0
  453. package/dist/lib/plan-tournament.d.ts.map +1 -0
  454. package/dist/lib/plan-tournament.js +353 -0
  455. package/dist/lib/plan-tournament.js.map +1 -0
  456. package/dist/lib/refinement.d.ts +74 -0
  457. package/dist/lib/refinement.d.ts.map +1 -0
  458. package/dist/lib/refinement.js +283 -0
  459. package/dist/lib/refinement.js.map +1 -0
  460. package/dist/lib/requirements.d.ts +2 -0
  461. package/dist/lib/requirements.d.ts.map +1 -0
  462. package/dist/lib/requirements.js +355 -0
  463. package/dist/lib/requirements.js.map +1 -0
  464. package/dist/lib/research-bundle.d.ts +2 -0
  465. package/dist/lib/research-bundle.d.ts.map +1 -0
  466. package/dist/lib/research-bundle.js +246 -0
  467. package/dist/lib/research-bundle.js.map +1 -0
  468. package/dist/lib/roadmap.d.ts +2 -0
  469. package/dist/lib/roadmap.d.ts.map +1 -0
  470. package/dist/lib/roadmap.js +541 -0
  471. package/dist/lib/roadmap.js.map +1 -0
  472. package/dist/lib/sample.d.ts +16 -0
  473. package/dist/lib/sample.d.ts.map +1 -0
  474. package/dist/lib/sample.js +20 -0
  475. package/dist/lib/sample.js.map +1 -0
  476. package/dist/lib/scaffold.d.ts +2 -0
  477. package/dist/lib/scaffold.d.ts.map +1 -0
  478. package/dist/lib/scaffold.js +355 -0
  479. package/dist/lib/scaffold.js.map +1 -0
  480. package/dist/lib/scan/_utils.d.ts +11 -0
  481. package/dist/lib/scan/_utils.d.ts.map +1 -0
  482. package/dist/lib/scan/_utils.js +36 -0
  483. package/dist/lib/scan/_utils.js.map +1 -0
  484. package/dist/lib/scan/base64.d.ts +15 -0
  485. package/dist/lib/scan/base64.d.ts.map +1 -0
  486. package/dist/lib/scan/base64.js +66 -0
  487. package/dist/lib/scan/base64.js.map +1 -0
  488. package/dist/lib/scan/ignorefile.d.ts +30 -0
  489. package/dist/lib/scan/ignorefile.d.ts.map +1 -0
  490. package/dist/lib/scan/ignorefile.js +101 -0
  491. package/dist/lib/scan/ignorefile.js.map +1 -0
  492. package/dist/lib/scan/injection.d.ts +14 -0
  493. package/dist/lib/scan/injection.d.ts.map +1 -0
  494. package/dist/lib/scan/injection.js +39 -0
  495. package/dist/lib/scan/injection.js.map +1 -0
  496. package/dist/lib/scan/patterns.d.ts +17 -0
  497. package/dist/lib/scan/patterns.d.ts.map +1 -0
  498. package/dist/lib/scan/patterns.js +123 -0
  499. package/dist/lib/scan/patterns.js.map +1 -0
  500. package/dist/lib/scan/strip-markdown.d.ts +7 -0
  501. package/dist/lib/scan/strip-markdown.d.ts.map +1 -0
  502. package/dist/lib/scan/strip-markdown.js +38 -0
  503. package/dist/lib/scan/strip-markdown.js.map +1 -0
  504. package/dist/lib/scan/types.d.ts +23 -0
  505. package/dist/lib/scan/types.d.ts.map +1 -0
  506. package/dist/lib/scan/types.js +3 -0
  507. package/dist/lib/scan/types.js.map +1 -0
  508. package/dist/lib/scheduler-wait.d.ts +2 -0
  509. package/dist/lib/scheduler-wait.d.ts.map +1 -0
  510. package/dist/lib/scheduler-wait.js +59 -0
  511. package/dist/lib/scheduler-wait.js.map +1 -0
  512. package/dist/lib/scheduler.d.ts +254 -0
  513. package/dist/lib/scheduler.d.ts.map +1 -0
  514. package/dist/lib/scheduler.js +1147 -0
  515. package/dist/lib/scheduler.js.map +1 -0
  516. package/dist/lib/state.d.ts +2 -0
  517. package/dist/lib/state.d.ts.map +1 -0
  518. package/dist/lib/state.js +744 -0
  519. package/dist/lib/state.js.map +1 -0
  520. package/dist/lib/think.d.ts +18 -0
  521. package/dist/lib/think.d.ts.map +1 -0
  522. package/dist/lib/think.js +317 -0
  523. package/dist/lib/think.js.map +1 -0
  524. package/dist/lib/tracker.d.ts +2 -0
  525. package/dist/lib/tracker.d.ts.map +1 -0
  526. package/dist/lib/tracker.js +1121 -0
  527. package/dist/lib/tracker.js.map +1 -0
  528. package/dist/lib/types.d.ts +1514 -0
  529. package/dist/lib/types.d.ts.map +1 -0
  530. package/dist/lib/types.js +4 -0
  531. package/dist/lib/types.js.map +1 -0
  532. package/dist/lib/utils.d.ts +2 -0
  533. package/dist/lib/utils.d.ts.map +1 -0
  534. package/dist/lib/utils.js +1363 -0
  535. package/dist/lib/utils.js.map +1 -0
  536. package/dist/lib/verify.d.ts +2 -0
  537. package/dist/lib/verify.d.ts.map +1 -0
  538. package/dist/lib/verify.js +1153 -0
  539. package/dist/lib/verify.js.map +1 -0
  540. package/dist/lib/wireup/autofix.d.ts +2 -0
  541. package/dist/lib/wireup/autofix.d.ts.map +1 -0
  542. package/dist/lib/wireup/autofix.js +188 -0
  543. package/dist/lib/wireup/autofix.js.map +1 -0
  544. package/dist/lib/wireup/cli.d.ts +2 -0
  545. package/dist/lib/wireup/cli.d.ts.map +1 -0
  546. package/dist/lib/wireup/cli.js +194 -0
  547. package/dist/lib/wireup/cli.js.map +1 -0
  548. package/dist/lib/wireup/detection.d.ts +47 -0
  549. package/dist/lib/wireup/detection.d.ts.map +1 -0
  550. package/dist/lib/wireup/detection.js +410 -0
  551. package/dist/lib/wireup/detection.js.map +1 -0
  552. package/dist/lib/wireup/discovery.d.ts +2 -0
  553. package/dist/lib/wireup/discovery.d.ts.map +1 -0
  554. package/dist/lib/wireup/discovery.js +934 -0
  555. package/dist/lib/wireup/discovery.js.map +1 -0
  556. package/dist/lib/wireup/execution.d.ts +2 -0
  557. package/dist/lib/wireup/execution.d.ts.map +1 -0
  558. package/dist/lib/wireup/execution.js +573 -0
  559. package/dist/lib/wireup/execution.js.map +1 -0
  560. package/dist/lib/wireup/index.d.ts +2 -0
  561. package/dist/lib/wireup/index.d.ts.map +1 -0
  562. package/dist/lib/wireup/index.js +85 -0
  563. package/dist/lib/wireup/index.js.map +1 -0
  564. package/dist/lib/wireup/orchestrator.d.ts +2 -0
  565. package/dist/lib/wireup/orchestrator.d.ts.map +1 -0
  566. package/dist/lib/wireup/orchestrator.js +366 -0
  567. package/dist/lib/wireup/orchestrator.js.map +1 -0
  568. package/dist/lib/wireup/report.d.ts +47 -0
  569. package/dist/lib/wireup/report.d.ts.map +1 -0
  570. package/dist/lib/wireup/report.js +201 -0
  571. package/dist/lib/wireup/report.js.map +1 -0
  572. package/dist/lib/wireup/scenarios.d.ts +2 -0
  573. package/dist/lib/wireup/scenarios.d.ts.map +1 -0
  574. package/dist/lib/wireup/scenarios.js +516 -0
  575. package/dist/lib/wireup/scenarios.js.map +1 -0
  576. package/dist/lib/wireup/state.d.ts +2 -0
  577. package/dist/lib/wireup/state.d.ts.map +1 -0
  578. package/dist/lib/wireup/state.js +102 -0
  579. package/dist/lib/wireup/state.js.map +1 -0
  580. package/dist/lib/wireup/types.d.ts +376 -0
  581. package/dist/lib/wireup/types.d.ts.map +1 -0
  582. package/dist/lib/wireup/types.js +3 -0
  583. package/dist/lib/wireup/types.js.map +1 -0
  584. package/dist/lib/worktree.d.ts +2 -0
  585. package/dist/lib/worktree.d.ts.map +1 -0
  586. package/dist/lib/worktree.js +999 -0
  587. package/dist/lib/worktree.js.map +1 -0
  588. package/lib/autopilot-milestone.ts +136 -0
  589. package/lib/autopilot-pipeline.ts +1179 -0
  590. package/lib/autopilot-waves.ts +361 -0
  591. package/lib/autopilot.ts +1874 -0
  592. package/lib/autoplan.ts +280 -0
  593. package/lib/autoresearch.js +4 -0
  594. package/lib/autoresearch.ts +886 -0
  595. package/lib/backend.ts +1252 -0
  596. package/lib/benchmark.ts +341 -0
  597. package/lib/citations.ts +760 -0
  598. package/lib/cleanup.ts +1588 -0
  599. package/lib/cli/adapters.ts +41 -0
  600. package/lib/cli/agent.ts +83 -0
  601. package/lib/cli/index.ts +273 -0
  602. package/lib/cli/output.ts +33 -0
  603. package/lib/cli/scan-dispatch.ts +130 -0
  604. package/lib/cli/tools.ts +198 -0
  605. package/lib/commands/_dashboard-parsers.ts +275 -0
  606. package/lib/commands/analysis.ts +1851 -0
  607. package/lib/commands/assumptions.ts +232 -0
  608. package/lib/commands/blame.ts +174 -0
  609. package/lib/commands/budget.ts +148 -0
  610. package/lib/commands/check-plans.ts +233 -0
  611. package/lib/commands/config.ts +287 -0
  612. package/lib/commands/dashboard.ts +680 -0
  613. package/lib/commands/estimate.ts +204 -0
  614. package/lib/commands/eval-diff.ts +252 -0
  615. package/lib/commands/freshness.ts +213 -0
  616. package/lib/commands/health.ts +607 -0
  617. package/lib/commands/index.ts +266 -0
  618. package/lib/commands/install.ts +307 -0
  619. package/lib/commands/knowhow-aggregator.ts +345 -0
  620. package/lib/commands/knowledge-search.ts +153 -0
  621. package/lib/commands/long-term-roadmap.ts +390 -0
  622. package/lib/commands/patterns.ts +465 -0
  623. package/lib/commands/phase-info.ts +698 -0
  624. package/lib/commands/plan-lint.ts +546 -0
  625. package/lib/commands/plan-phase.ts +375 -0
  626. package/lib/commands/progress.ts +319 -0
  627. package/lib/commands/quality.ts +138 -0
  628. package/lib/commands/rollback.ts +195 -0
  629. package/lib/commands/scan.ts +72 -0
  630. package/lib/commands/search.ts +300 -0
  631. package/lib/commands/select-candidate.ts +687 -0
  632. package/lib/commands/singularity.ts +222 -0
  633. package/lib/commands/slug-timestamp.ts +74 -0
  634. package/lib/commands/tail.ts +129 -0
  635. package/lib/commands/todo.ts +273 -0
  636. package/lib/commands/watch.ts +80 -0
  637. package/lib/complexity.ts +117 -0
  638. package/lib/context/agents.ts +505 -0
  639. package/lib/context/base.ts +123 -0
  640. package/lib/context/execute.ts +977 -0
  641. package/lib/context/index.ts +110 -0
  642. package/lib/context/progress.ts +278 -0
  643. package/lib/context/project.ts +531 -0
  644. package/lib/context/research.ts +646 -0
  645. package/lib/dead-ends.ts +506 -0
  646. package/lib/deps.ts +773 -0
  647. package/lib/discussion.ts +1275 -0
  648. package/lib/drift.ts +519 -0
  649. package/lib/evolve/_dimensions-features.ts +525 -0
  650. package/lib/evolve/_dimensions.ts +511 -0
  651. package/lib/evolve/_product-ideation.ts +405 -0
  652. package/lib/evolve/_prompts.ts +178 -0
  653. package/lib/evolve/cli.ts +330 -0
  654. package/lib/evolve/discovery.ts +571 -0
  655. package/lib/evolve/index.ts +105 -0
  656. package/lib/evolve/orchestrator.ts +1139 -0
  657. package/lib/evolve/scoring.ts +167 -0
  658. package/lib/evolve/state.ts +330 -0
  659. package/lib/evolve/types.ts +290 -0
  660. package/lib/frontmatter.ts +615 -0
  661. package/lib/gates.ts +695 -0
  662. package/lib/genome.ts +402 -0
  663. package/lib/got.js +4 -0
  664. package/lib/got.ts +361 -0
  665. package/lib/invariants.ts +378 -0
  666. package/lib/knowledge.ts +768 -0
  667. package/lib/long-term-roadmap.ts +806 -0
  668. package/lib/markdown-split.ts +273 -0
  669. package/lib/mcp-server.ts +3292 -0
  670. package/lib/metrics.ts +49 -0
  671. package/lib/overstory.ts +270 -0
  672. package/lib/parallel.ts +570 -0
  673. package/lib/paths.ts +293 -0
  674. package/lib/phase-complete-llm.ts +376 -0
  675. package/lib/phase-complete.ts +366 -0
  676. package/lib/phase-io.ts +101 -0
  677. package/lib/phase.ts +1981 -0
  678. package/lib/plan-tournament.ts +426 -0
  679. package/lib/refinement.ts +349 -0
  680. package/lib/requirements.ts +469 -0
  681. package/lib/research-bundle.ts +300 -0
  682. package/lib/roadmap.ts +775 -0
  683. package/lib/scaffold.ts +480 -0
  684. package/lib/scan/_utils.ts +37 -0
  685. package/lib/scan/base64.ts +90 -0
  686. package/lib/scan/ignorefile.ts +109 -0
  687. package/lib/scan/injection.ts +67 -0
  688. package/lib/scan/patterns.ts +139 -0
  689. package/lib/scan/strip-markdown.ts +39 -0
  690. package/lib/scan/types.ts +28 -0
  691. package/lib/scheduler-wait.ts +58 -0
  692. package/lib/scheduler.ts +1370 -0
  693. package/lib/state.ts +1000 -0
  694. package/lib/think.ts +365 -0
  695. package/lib/tracker.ts +1591 -0
  696. package/lib/types.ts +1663 -0
  697. package/lib/utils.ts +1479 -0
  698. package/lib/verify.ts +1434 -0
  699. package/lib/wireup/autofix.ts +241 -0
  700. package/lib/wireup/cli.ts +278 -0
  701. package/lib/wireup/detection.ts +542 -0
  702. package/lib/wireup/discovery.ts +1063 -0
  703. package/lib/wireup/execution.ts +686 -0
  704. package/lib/wireup/index.ts +117 -0
  705. package/lib/wireup/orchestrator.ts +519 -0
  706. package/lib/wireup/report.ts +286 -0
  707. package/lib/wireup/scenarios.ts +616 -0
  708. package/lib/wireup/state.ts +139 -0
  709. package/lib/wireup/types.ts +436 -0
  710. package/lib/worktree.ts +1309 -0
  711. package/package.json +67 -0
@@ -0,0 +1,768 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * GRD Knowledge Module -- KNOWHOW.md parsing, formatting, selection, and persistence.
5
+ *
6
+ * Provides four functions for managing structured knowledge entries mined from
7
+ * phase execution output. Entries are stored in KNOWHOW.md and injected into
8
+ * planning/execution prompts to compound improvements across phases.
9
+ *
10
+ * REQ-191: KNOWHOW.md Storage
11
+ *
12
+ * @module knowledge
13
+ */
14
+
15
+ import type { KnowhowEntry } from './types';
16
+
17
+ const fs = require('fs') as typeof import('fs');
18
+ const path = require('path') as typeof import('path');
19
+ const { safeReadFile, output } = require('./utils') as {
20
+ safeReadFile: (p: string) => string | null;
21
+ output: (result: unknown, raw: boolean, rawValue?: unknown) => never;
22
+ };
23
+
24
+ const KNOWHOW_HEADER = '# KNOWHOW\n\n';
25
+
26
+ // Module-level cache: maps knowhowPath → parsed entries, invalidated on write.
27
+ const _knowhowCache = new Map<string, { entries: KnowhowEntry[]; mtime: number }>();
28
+
29
+ function _cachedParseKnowhow(knowhowPath: string): KnowhowEntry[] {
30
+ try {
31
+ const stat = fs.statSync(knowhowPath) as { mtimeMs: number };
32
+ const cached = _knowhowCache.get(knowhowPath);
33
+ if (cached && cached.mtime === stat.mtimeMs) return cached.entries;
34
+ const content = (fs.readFileSync(knowhowPath, 'utf8') as string) ?? '';
35
+ const entries = parseKnowhowEntries(content);
36
+ _knowhowCache.set(knowhowPath, { entries, mtime: stat.mtimeMs });
37
+ return entries;
38
+ } catch {
39
+ return [];
40
+ }
41
+ }
42
+
43
+ /** Serialize a KnowhowEntry to a markdown level-3 heading block. */
44
+ function formatKnowhowEntry(entry: KnowhowEntry): string {
45
+ return (
46
+ `### ${entry.pattern_name}\n\n` +
47
+ `- **source:** ${entry.source}\n` +
48
+ `- **applicability:** ${entry.applicability}\n` +
49
+ `- **code_snippet:** ${entry.code_snippet}\n` +
50
+ `- **phase_number:** ${entry.phase_number}\n` +
51
+ `- **created_at:** ${entry.created_at}\n`
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Parse KNOWHOW.md content into an array of KnowhowEntry objects.
57
+ *
58
+ * Splits on `### ` level-3 headings. For each block, extracts pattern_name from
59
+ * the heading text and parses structured `- **field:** value` lines.
60
+ * Returns empty array for empty/missing content.
61
+ *
62
+ * Roundtrip guarantee: parseKnowhowEntries(formatKnowhowEntry(entry)) produces
63
+ * an equivalent entry (lossless).
64
+ */
65
+ function parseKnowhowEntries(content: string): KnowhowEntry[] {
66
+ if (!content || !content.trim()) {
67
+ return [];
68
+ }
69
+
70
+ const entries: KnowhowEntry[] = [];
71
+
72
+ const blocks = content.split(/(?=^### )/m);
73
+
74
+ for (const block of blocks) {
75
+ const trimmed = block.trim();
76
+ if (!trimmed.startsWith('### ')) {
77
+ continue;
78
+ }
79
+
80
+ const lines = trimmed.split('\n');
81
+ const headingLine = lines[0];
82
+ const pattern_name = headingLine.replace(/^### /, '').trim();
83
+
84
+ if (!pattern_name) {
85
+ continue;
86
+ }
87
+
88
+ const fieldPattern = /^- \*\*(\w+):\*\* (.*)$/;
89
+ const fields: Record<string, string> = {};
90
+
91
+ for (const line of lines.slice(1)) {
92
+ const match = line.match(fieldPattern);
93
+ if (match) {
94
+ fields[match[1]] = match[2].trim();
95
+ }
96
+ }
97
+
98
+ const REQUIRED_FIELDS = ['source', 'applicability', 'code_snippet', 'phase_number', 'created_at'] as const;
99
+ if (REQUIRED_FIELDS.every((k) => k in fields)) {
100
+ const phase_number = parseInt(fields['phase_number'], 10);
101
+ if (Number.isNaN(phase_number)) {
102
+ continue;
103
+ }
104
+ entries.push({
105
+ pattern_name,
106
+ source: fields['source'],
107
+ applicability: fields['applicability'],
108
+ code_snippet: fields['code_snippet'],
109
+ phase_number,
110
+ created_at: fields['created_at'],
111
+ });
112
+ }
113
+ }
114
+
115
+ return entries;
116
+ }
117
+
118
+ /**
119
+ * Read existing KNOWHOW.md at knowhowPath, merge new entries (deduplicating by
120
+ * pattern_name, keeping higher phase_number), and write back.
121
+ *
122
+ * - If the file does not exist, starts with an empty entry list.
123
+ * - Deduplication: when a new entry shares a pattern_name with an existing one,
124
+ * the entry with the higher phase_number is kept.
125
+ * - File always starts with `# KNOWHOW\n\n` header.
126
+ * - Parent directories are created if needed.
127
+ */
128
+ function appendKnowhowEntries(knowhowPath: string, entries: KnowhowEntry[]): void {
129
+ if (entries.length === 0) return;
130
+
131
+ const existing = _cachedParseKnowhow(knowhowPath);
132
+
133
+ const byName = new Map<string, KnowhowEntry>();
134
+
135
+ for (const e of existing) {
136
+ byName.set(e.pattern_name, e);
137
+ }
138
+
139
+ const total = entries.length;
140
+ for (let i = 0; i < total; i++) {
141
+ const e = entries[i];
142
+ if (total > 50) {
143
+ process.stderr.write(`[knowledge] merging entry ${i + 1}/${total}: ${e.pattern_name}\n`);
144
+ }
145
+ const current = byName.get(e.pattern_name);
146
+ if (!current || e.phase_number >= current.phase_number) {
147
+ byName.set(e.pattern_name, e);
148
+ }
149
+ }
150
+
151
+ const merged = Array.from(byName.values());
152
+
153
+ merged.sort((a, b) => b.phase_number - a.phase_number);
154
+
155
+ const body = merged.map(formatKnowhowEntry).join('\n');
156
+ const fileContent = KNOWHOW_HEADER + body;
157
+
158
+ const dir = path.dirname(knowhowPath);
159
+ fs.mkdirSync(dir, { recursive: true });
160
+
161
+ fs.writeFileSync(knowhowPath, fileContent, 'utf8');
162
+ _knowhowCache.delete(knowhowPath);
163
+ }
164
+
165
+ /**
166
+ * Return top-N entries from the input array sorted by recency.
167
+ *
168
+ * - Primary sort: phase_number descending (most recent first).
169
+ * - If moduleHints provided: entries whose source or applicability mentions any
170
+ * hint string are sorted first within each phase_number bucket.
171
+ * - Tertiary sort: when currentPhase is provided, entries closer to the current
172
+ * phase rank higher within the same phase_number bucket (proximity scoring).
173
+ * - Returns at most n entries.
174
+ * - If entries.length <= n, returns all entries sorted.
175
+ */
176
+ function selectTopEntries(
177
+ entries: KnowhowEntry[],
178
+ n: number,
179
+ moduleHints?: string[],
180
+ currentPhase?: number,
181
+ ): KnowhowEntry[] {
182
+ if (entries.length === 0 || n <= 0) {
183
+ return [];
184
+ }
185
+
186
+ const lowerHints = moduleHints?.map((h) => h.toLowerCase()) ?? [];
187
+ const hintMatches = new Set<KnowhowEntry>();
188
+ if (lowerHints.length > 0) {
189
+ for (const entry of entries) {
190
+ const combined = `${entry.source} ${entry.applicability}`.toLowerCase();
191
+ if (lowerHints.some((hint) => combined.includes(hint))) {
192
+ hintMatches.add(entry);
193
+ }
194
+ }
195
+ }
196
+
197
+ const scoreEntry = (e: KnowhowEntry): number =>
198
+ e.phase_number * 1000 +
199
+ (hintMatches.has(e) ? 100 : 0) -
200
+ (currentPhase !== undefined ? Math.abs(currentPhase - e.phase_number) : 0);
201
+ const sorted = [...entries].sort((a, b) => scoreEntry(b) - scoreEntry(a));
202
+
203
+ return sorted.slice(0, n);
204
+ }
205
+
206
+ // ─── Knowledge Stats Tracking ─────────────────────────────────────────────────
207
+
208
+ interface KnowhowStat {
209
+ hit_count: number;
210
+ last_used: string;
211
+ }
212
+
213
+ function _loadKnowledgeStats(statsPath: string): Record<string, KnowhowStat> {
214
+ try {
215
+ const raw = fs.readFileSync(statsPath, 'utf8') as string;
216
+ return JSON.parse(raw) as Record<string, KnowhowStat>;
217
+ } catch {
218
+ return {};
219
+ }
220
+ }
221
+
222
+ function _saveKnowledgeStats(statsPath: string, stats: Record<string, KnowhowStat>): void {
223
+ try {
224
+ fs.mkdirSync(path.dirname(statsPath), { recursive: true });
225
+ fs.writeFileSync(statsPath, JSON.stringify(stats, null, 2), 'utf8');
226
+ } catch {
227
+ /* stats are best-effort; never crash injection on write failure */
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Build a structured knowledge injection block from KNOWHOW.md for prompt injection.
233
+ *
234
+ * Reads KNOWHOW.md from path.join(cwd, 'KNOWHOW.md'), selects top 5 entries
235
+ * using selectTopEntries, and wraps them in <knowhow_context> XML tags.
236
+ * Increments hit_count and last_used in .planning/knowledge-stats.json after each injection.
237
+ *
238
+ * @param cwd - Project root directory
239
+ * @param _phaseNum - Current phase number (reserved for future phase-proximity scoring)
240
+ * @param moduleHints - Optional module name hints to boost relevant entries
241
+ * @returns Formatted injection block string, or '' if no entries
242
+ */
243
+ function buildKnowledgeInjectionBlock(cwd: string, _phaseNum: string, moduleHints?: string[]): string {
244
+ const knowhowPath = path.join(cwd, 'KNOWHOW.md');
245
+ const entries = _cachedParseKnowhow(knowhowPath);
246
+ if (entries.length === 0) {
247
+ return '';
248
+ }
249
+
250
+ const parsedPhase = parseInt(_phaseNum, 10);
251
+ const currentPhase = Number.isNaN(parsedPhase) ? undefined : parsedPhase;
252
+ const top = selectTopEntries(entries, 5, moduleHints, currentPhase);
253
+ if (top.length === 0) {
254
+ return '';
255
+ }
256
+
257
+ // Track which entries were injected
258
+ const statsPath = path.join(cwd, '.planning', 'knowledge-stats.json');
259
+ const stats = _loadKnowledgeStats(statsPath);
260
+ const now = new Date().toISOString();
261
+ for (const entry of top) {
262
+ const existing = stats[entry.pattern_name];
263
+ stats[entry.pattern_name] = {
264
+ hit_count: (existing?.hit_count ?? 0) + 1,
265
+ last_used: now,
266
+ };
267
+ }
268
+ _saveKnowledgeStats(statsPath, stats);
269
+
270
+ const formatted = top.map(formatKnowhowEntry).join('\n');
271
+ return `<knowhow_context>\n${formatted}\n</knowhow_context>`;
272
+ }
273
+
274
+ /**
275
+ * Extract module hints from PLAN.md frontmatter files_modified fields.
276
+ *
277
+ * Reads all *-PLAN.md files in phaseDir, extracts files_modified from YAML
278
+ * frontmatter, and returns unique basenames (without extensions).
279
+ *
280
+ * @param phaseDir - Path to phase directory containing PLAN.md files
281
+ * @returns Array of unique module basenames
282
+ */
283
+ function extractModuleHints(phaseDir: string): string[] {
284
+ if (!fs.existsSync(phaseDir)) {
285
+ return [];
286
+ }
287
+
288
+ let files: string[];
289
+ try {
290
+ files = (fs.readdirSync(phaseDir) as string[]).filter(
291
+ (f: string) => f.endsWith('-PLAN.md') || f === 'PLAN.md'
292
+ );
293
+ } catch {
294
+ return [];
295
+ }
296
+
297
+ if (files.length === 0) {
298
+ return [];
299
+ }
300
+
301
+ const hints = new Set<string>();
302
+
303
+ for (const file of files) {
304
+ const filePath = path.join(phaseDir, file);
305
+ const content = safeReadFile(filePath);
306
+ if (!content) continue;
307
+
308
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
309
+ if (!fmMatch) continue;
310
+
311
+ const fmContent = fmMatch[1];
312
+ const filesMatch = fmContent.match(/files_modified:\s*\[([^\]]*)\]/);
313
+ if (!filesMatch) continue;
314
+
315
+ const filesList = filesMatch[1].split(',').map((f: string) => f.trim()).filter(Boolean);
316
+ for (const f of filesList) {
317
+ const basename = path.basename(f).split('.')[0];
318
+ if (basename) {
319
+ hints.add(basename);
320
+ }
321
+ }
322
+ }
323
+
324
+ return Array.from(hints);
325
+ }
326
+
327
+ // ─── Knowhow Audit ──────────────────────────────────────────────────────────
328
+
329
+ /** A stale or conflicting entry flagged by the auditor. */
330
+ interface KnowhowAuditFlag {
331
+ pattern_name: string;
332
+ source_file: string;
333
+ issue: 'broken_ref' | 'contradicts';
334
+ detail: string;
335
+ }
336
+
337
+ /** Result of the KNOWHOW.md audit command. */
338
+ interface KnowhowAuditResult {
339
+ total_entries: number;
340
+ stale_count: number;
341
+ contradiction_count: number;
342
+ flags: KnowhowAuditFlag[];
343
+ knowhow_files_scanned: number;
344
+ }
345
+
346
+ /**
347
+ * CLI command: Audit all KNOWHOW.md files for stale references and contradictions.
348
+ *
349
+ * Scans all KNOWHOW.md files under .planning/milestones/ and the root research dir.
350
+ * For each entry:
351
+ * - Extracts file paths referenced in the source field and checks they exist.
352
+ * - Detects entries with the same pattern_name but different applicability advice.
353
+ *
354
+ * @param cwd - Project working directory
355
+ * @param raw - Output raw text instead of JSON
356
+ */
357
+ function cmdKnowhowAudit(cwd: string, raw: boolean): void {
358
+ const milestonesBase = path.join(cwd, '.planning', 'milestones');
359
+ const flags: KnowhowAuditFlag[] = [];
360
+
361
+ // Collect all KNOWHOW.md paths
362
+ const knowhowPaths: string[] = [];
363
+ try {
364
+ const msDirs = (fs.readdirSync(milestonesBase) as string[]).filter((d) => {
365
+ try {
366
+ return fs.statSync(path.join(milestonesBase, d)).isDirectory();
367
+ } catch {
368
+ return false;
369
+ }
370
+ });
371
+ for (const ms of msDirs) {
372
+ const msKnowhow = path.join(milestonesBase, ms, 'KNOWHOW.md');
373
+ if (fs.existsSync(msKnowhow)) knowhowPaths.push(msKnowhow);
374
+ const resKnowhow = path.join(milestonesBase, ms, 'research', 'KNOWHOW.md');
375
+ if (fs.existsSync(resKnowhow)) knowhowPaths.push(resKnowhow);
376
+ // Codex r25 P2: per-phase KNOWHOW.md files are where the knowledge
377
+ // miner writes new entries; audit/dedup must scan them or they
378
+ // miss the common case entirely.
379
+ const phasesBase = path.join(milestonesBase, ms, 'phases');
380
+ try {
381
+ for (const ph of fs.readdirSync(phasesBase) as string[]) {
382
+ const phKnowhow = path.join(phasesBase, ph, 'KNOWHOW.md');
383
+ if (fs.existsSync(phKnowhow)) knowhowPaths.push(phKnowhow);
384
+ }
385
+ } catch { /* skip */ }
386
+ }
387
+ } catch {
388
+ // milestones dir doesn't exist
389
+ }
390
+ // Also check root planning research dir + project-root KNOWHOW.md
391
+ const rootResearchKnowhow = path.join(cwd, '.planning', 'research', 'KNOWHOW.md');
392
+ if (fs.existsSync(rootResearchKnowhow)) knowhowPaths.push(rootResearchKnowhow);
393
+ const rootKnowhow = path.join(cwd, '.planning', 'KNOWHOW.md');
394
+ if (fs.existsSync(rootKnowhow)) knowhowPaths.push(rootKnowhow);
395
+ const projectRootKnowhow = path.join(cwd, 'KNOWHOW.md');
396
+ if (fs.existsSync(projectRootKnowhow)) knowhowPaths.push(projectRootKnowhow);
397
+
398
+ let totalEntries = 0;
399
+ // Track all entries across files for contradiction detection (by pattern_name)
400
+ const allByName = new Map<string, { entry: KnowhowEntry; file: string }[]>();
401
+
402
+ for (const kPath of knowhowPaths) {
403
+ const content = safeReadFile(kPath);
404
+ if (!content) continue;
405
+ const entries = parseKnowhowEntries(content);
406
+ totalEntries += entries.length;
407
+
408
+ for (const entry of entries) {
409
+ // Check if source field references a real file path
410
+ const sourceRef = entry.source.split(':')[0].trim(); // strip line numbers
411
+ if (sourceRef && sourceRef.includes('/') && !sourceRef.startsWith('http')) {
412
+ const absRef = path.isAbsolute(sourceRef)
413
+ ? sourceRef
414
+ : path.join(cwd, sourceRef);
415
+ if (!fs.existsSync(absRef)) {
416
+ flags.push({
417
+ pattern_name: entry.pattern_name,
418
+ source_file: path.relative(cwd, kPath),
419
+ issue: 'broken_ref',
420
+ detail: `Referenced source "${sourceRef}" does not exist`,
421
+ });
422
+ }
423
+ }
424
+
425
+ // Accumulate for contradiction detection
426
+ const existing = allByName.get(entry.pattern_name) ?? [];
427
+ existing.push({ entry, file: path.relative(cwd, kPath) });
428
+ allByName.set(entry.pattern_name, existing);
429
+ }
430
+ }
431
+
432
+ // Detect contradictions: same pattern_name, significantly different applicability
433
+ let contradictionCount = 0;
434
+ for (const [name, items] of allByName) {
435
+ if (items.length < 2) continue;
436
+ const applicabilities = items.map((i) => i.entry.applicability.toLowerCase());
437
+ const first = applicabilities[0];
438
+ // Heuristic: if one says "always/use" and another says "never/avoid", flag it
439
+ const hasPositive = applicabilities.some((a) => /\b(always|use|prefer|do)\b/.test(a));
440
+ const hasNegative = applicabilities.some((a) => /\b(never|avoid|don't|do not)\b/.test(a));
441
+ if (hasPositive && hasNegative) {
442
+ contradictionCount++;
443
+ flags.push({
444
+ pattern_name: name,
445
+ source_file: items.map((i) => i.file).join(', '),
446
+ issue: 'contradicts',
447
+ detail: `"${first.slice(0, 80)}" vs "${applicabilities.slice(1).join(' / ').slice(0, 80)}"`,
448
+ });
449
+ }
450
+ }
451
+
452
+ const staleCount = flags.filter((f) => f.issue === 'broken_ref').length;
453
+ const result: KnowhowAuditResult = {
454
+ total_entries: totalEntries,
455
+ stale_count: staleCount,
456
+ contradiction_count: contradictionCount,
457
+ flags,
458
+ knowhow_files_scanned: knowhowPaths.length,
459
+ };
460
+
461
+ const summary = `${knowhowPaths.length} files, ${totalEntries} entries: ${staleCount} stale refs, ${contradictionCount} contradictions`;
462
+ output(result, raw, summary);
463
+ }
464
+
465
+ // ─── Knowhow Dedup ──────────────────────────────────────────────────────────
466
+
467
+ /** A candidate merge pair from the dedup analysis. */
468
+ interface KnowhowDedupPair {
469
+ entry_a: string;
470
+ entry_b: string;
471
+ source_a: string;
472
+ source_b: string;
473
+ similarity: number;
474
+ suggested_merge: string;
475
+ }
476
+
477
+ /** Result of the dedup command. */
478
+ interface KnowhowDedupResult {
479
+ files_scanned: number;
480
+ entries_total: number;
481
+ pairs_above_threshold: number;
482
+ pairs: KnowhowDedupPair[];
483
+ report_path: string | null;
484
+ }
485
+
486
+ /** Compute trigram set from text for Jaccard similarity. */
487
+ function _trigrams(text: string): Set<string> {
488
+ const normalized = text.toLowerCase().replace(/[^a-z0-9 ]/g, ' ').replace(/\s+/g, ' ').trim();
489
+ const set = new Set<string>();
490
+ for (let i = 0; i + 2 < normalized.length; i++) {
491
+ set.add(normalized.slice(i, i + 3));
492
+ }
493
+ return set;
494
+ }
495
+
496
+ /** Compute Jaccard similarity between two trigram sets. */
497
+ function _jaccard(a: Set<string>, b: Set<string>): number {
498
+ if (a.size === 0 && b.size === 0) return 1;
499
+ let intersection = 0;
500
+ for (const t of a) {
501
+ if (b.has(t)) intersection++;
502
+ }
503
+ const union = a.size + b.size - intersection;
504
+ return union === 0 ? 0 : intersection / union;
505
+ }
506
+
507
+ /**
508
+ * CLI command: Find near-duplicate entries across all KNOWHOW.md files.
509
+ *
510
+ * Scans all KNOWHOW.md files under .planning/milestones/ and the root research dir.
511
+ * Computes pairwise trigram-Jaccard similarity on entry title + first 3 body lines.
512
+ * Writes a report to .planning/KNOWHOW-DEDUP.md listing pairs with similarity > threshold (default 0.75).
513
+ *
514
+ * @param cwd - Project working directory
515
+ * @param raw - Output raw text instead of JSON
516
+ * @param threshold - Similarity threshold (default 0.75)
517
+ */
518
+ function cmdKnowhowDedup(cwd: string, raw: boolean, threshold = 0.75): void {
519
+ const milestonesBase = path.join(cwd, '.planning', 'milestones');
520
+
521
+ // Collect all KNOWHOW.md paths
522
+ const knowhowPaths: string[] = [];
523
+ try {
524
+ const msDirs = (fs.readdirSync(milestonesBase) as string[]).filter((d) => {
525
+ try { return fs.statSync(path.join(milestonesBase, d)).isDirectory(); } catch { return false; }
526
+ });
527
+ for (const ms of msDirs) {
528
+ const msKnowhow = path.join(milestonesBase, ms, 'KNOWHOW.md');
529
+ if (fs.existsSync(msKnowhow)) knowhowPaths.push(msKnowhow);
530
+ const resKnowhow = path.join(milestonesBase, ms, 'research', 'KNOWHOW.md');
531
+ if (fs.existsSync(resKnowhow)) knowhowPaths.push(resKnowhow);
532
+ // Codex r25 P2: include per-phase KNOWHOW.md — that's where the
533
+ // knowledge miner writes the entries that most often dup.
534
+ const phasesBase = path.join(milestonesBase, ms, 'phases');
535
+ try {
536
+ for (const ph of fs.readdirSync(phasesBase) as string[]) {
537
+ const phKnowhow = path.join(phasesBase, ph, 'KNOWHOW.md');
538
+ if (fs.existsSync(phKnowhow)) knowhowPaths.push(phKnowhow);
539
+ }
540
+ } catch { /* skip */ }
541
+ }
542
+ } catch {
543
+ // milestones dir doesn't exist
544
+ }
545
+ const rootResearchKnowhow = path.join(cwd, '.planning', 'research', 'KNOWHOW.md');
546
+ if (fs.existsSync(rootResearchKnowhow)) knowhowPaths.push(rootResearchKnowhow);
547
+ const rootKnowhow = path.join(cwd, '.planning', 'KNOWHOW.md');
548
+ if (fs.existsSync(rootKnowhow)) knowhowPaths.push(rootKnowhow);
549
+ const projectRootKnowhow = path.join(cwd, 'KNOWHOW.md');
550
+ if (fs.existsSync(projectRootKnowhow)) knowhowPaths.push(projectRootKnowhow);
551
+
552
+ // Load all entries with source file info
553
+ const allEntries: { entry: KnowhowEntry; file: string; fingerprint: string; trigrams: Set<string> }[] = [];
554
+ for (const kPath of knowhowPaths) {
555
+ const content = safeReadFile(kPath);
556
+ if (!content) continue;
557
+ const entries = parseKnowhowEntries(content);
558
+ for (const entry of entries) {
559
+ // Fingerprint: title + first 3 lines of applicability
560
+ const bodyLines = entry.applicability.split('\n').slice(0, 3).join(' ');
561
+ const fingerprint = `${entry.pattern_name} ${bodyLines}`;
562
+ allEntries.push({
563
+ entry,
564
+ file: path.relative(cwd, kPath),
565
+ fingerprint,
566
+ trigrams: _trigrams(fingerprint),
567
+ });
568
+ }
569
+ }
570
+
571
+ // Pairwise similarity (O(n^2), acceptable for typical KNOWHOW sizes <500 entries)
572
+ const pairs: KnowhowDedupPair[] = [];
573
+ const totalEntryCount = allEntries.length;
574
+ for (let i = 0; i < totalEntryCount; i++) {
575
+ if (totalEntryCount > 20 && i % Math.max(1, Math.floor(totalEntryCount / 20)) === 0) {
576
+ process.stderr.write(`[knowledge:dedup] scanning entry ${i + 1}/${totalEntryCount}\n`);
577
+ }
578
+ for (let j = i + 1; j < totalEntryCount; j++) {
579
+ const sim = _jaccard(allEntries[i].trigrams, allEntries[j].trigrams);
580
+ if (sim >= threshold) {
581
+ pairs.push({
582
+ entry_a: allEntries[i].entry.pattern_name,
583
+ entry_b: allEntries[j].entry.pattern_name,
584
+ source_a: allEntries[i].file,
585
+ source_b: allEntries[j].file,
586
+ similarity: Math.round(sim * 100) / 100,
587
+ suggested_merge: `Keep: "${allEntries[i].entry.pattern_name}" (phase ${allEntries[i].entry.phase_number} ≥ ${allEntries[j].entry.phase_number} ? A : B)`,
588
+ });
589
+ }
590
+ }
591
+ }
592
+
593
+ // Sort by similarity descending
594
+ pairs.sort((a, b) => b.similarity - a.similarity);
595
+
596
+ // Write report
597
+ let reportPath: string | null = null;
598
+ const reportDir = path.join(cwd, '.planning');
599
+ const reportFile = path.join(reportDir, 'KNOWHOW-DEDUP.md');
600
+ try {
601
+ const lines = [
602
+ `# KNOWHOW Deduplication Report`,
603
+ ``,
604
+ `Generated: ${new Date().toISOString().split('T')[0]}`,
605
+ `Files scanned: ${knowhowPaths.length}`,
606
+ `Entries total: ${allEntries.length}`,
607
+ `Threshold: ${threshold}`,
608
+ `Pairs above threshold: ${pairs.length}`,
609
+ ``,
610
+ ];
611
+ if (pairs.length === 0) {
612
+ lines.push('No near-duplicate entries found.');
613
+ } else {
614
+ lines.push('## Merge Candidates\n');
615
+ for (const p of pairs) {
616
+ lines.push(`### Similarity ${p.similarity}`);
617
+ lines.push(`- **A**: \`${p.entry_a}\` (${p.source_a})`);
618
+ lines.push(`- **B**: \`${p.entry_b}\` (${p.source_b})`);
619
+ lines.push(`- **Suggested**: ${p.suggested_merge}`);
620
+ lines.push('');
621
+ }
622
+ }
623
+ fs.mkdirSync(reportDir, { recursive: true });
624
+ fs.writeFileSync(reportFile, lines.join('\n'), 'utf-8');
625
+ reportPath = path.relative(cwd, reportFile);
626
+ } catch {
627
+ // Non-fatal
628
+ }
629
+
630
+ const result: KnowhowDedupResult = {
631
+ files_scanned: knowhowPaths.length,
632
+ entries_total: allEntries.length,
633
+ pairs_above_threshold: pairs.length,
634
+ pairs,
635
+ report_path: reportPath,
636
+ };
637
+
638
+ output(
639
+ result,
640
+ raw,
641
+ `${allEntries.length} entries, ${pairs.length} duplicate pairs (threshold=${threshold}) → ${reportPath ?? 'report not written'}`
642
+ );
643
+ }
644
+
645
+ // ─── TF-IDF Relevance Ranking ────────────────────────────────────────────────
646
+
647
+ const STOPWORDS = new Set([
648
+ 'a','an','the','and','or','but','in','on','at','to','for','of','with',
649
+ 'is','are','was','were','be','been','being','have','has','had','do','does',
650
+ 'did','will','would','could','should','may','might','it','its','this',
651
+ 'that','these','those','from','by','as','if','when','where','which','who',
652
+ ]);
653
+
654
+ /** Tokenize text into lowercase words, removing stopwords and punctuation. */
655
+ function _tokenize(text: string): string[] {
656
+ return text
657
+ .toLowerCase()
658
+ .replace(/[^a-z0-9 ]/g, ' ')
659
+ .split(/\s+/)
660
+ .filter((t) => t.length > 2 && !STOPWORDS.has(t));
661
+ }
662
+
663
+ /**
664
+ * Rank knowhow entries by TF-IDF relevance to a phase goal string.
665
+ *
666
+ * Tokenizes the goal and each entry's problem/solution text, computes IDF across
667
+ * all entries, then scores each entry by the sum of TF-IDF for query tokens.
668
+ * Returns at most topN entries sorted by descending relevance score.
669
+ *
670
+ * @param goal - Phase goal string to rank against
671
+ * @param entries - Array of KnowhowEntry to rank
672
+ * @param topN - Number of entries to return (default 5)
673
+ */
674
+ function rankKnowhowByPhaseGoal(goal: string, entries: KnowhowEntry[], topN = 5): KnowhowEntry[] {
675
+ if (entries.length === 0 || !goal.trim()) return [];
676
+
677
+ const queryTokens = new Set(_tokenize(goal));
678
+ if (queryTokens.size === 0) return entries.slice(0, topN);
679
+
680
+ // Build per-entry token lists from pattern_name + applicability (proxy for Problem+Solution)
681
+ const entryTexts = entries.map((e) =>
682
+ _tokenize(`${e.pattern_name} ${e.applicability} ${e.source}`)
683
+ );
684
+
685
+ // Compute IDF for each query token
686
+ const idf = new Map<string, number>();
687
+ for (const token of queryTokens) {
688
+ const docsWithToken = entryTexts.filter((tokens) => tokens.includes(token)).length;
689
+ idf.set(token, Math.log((entries.length + 1) / (docsWithToken + 1)) + 1);
690
+ }
691
+
692
+ // Score each entry
693
+ const scored = entries.map((entry, i) => {
694
+ const tokens = entryTexts[i];
695
+ const tf = new Map<string, number>();
696
+ for (const t of tokens) {
697
+ tf.set(t, (tf.get(t) ?? 0) + 1);
698
+ }
699
+ let score = 0;
700
+ for (const token of queryTokens) {
701
+ const termFreq = (tf.get(token) ?? 0) / Math.max(tokens.length, 1);
702
+ score += termFreq * (idf.get(token) ?? 1);
703
+ }
704
+ return { entry, score };
705
+ });
706
+
707
+ scored.sort((a, b) => b.score - a.score);
708
+ return scored.slice(0, topN).map((s) => s.entry);
709
+ }
710
+
711
+ /**
712
+ * CLI command: Rank KNOWHOW entries by relevance to a query string using TF-IDF.
713
+ *
714
+ * @param cwd - Project working directory
715
+ * @param query - Query string to rank against
716
+ * @param topN - Number of top entries to return (default 5)
717
+ * @param raw - Output raw text instead of JSON
718
+ */
719
+ function cmdKnowhowRank(cwd: string, query: string, topN: number, raw: boolean): void {
720
+ // Codex r21 P2: KNOWHOW lives in milestone/research dirs and per-phase
721
+ // dirs, not the project root. Match the multi-location scan from
722
+ // r18 (lib/context/agents.ts knowhow_block + lib/commands/knowledge-search.ts).
723
+ const fs = require('fs') as typeof import('fs');
724
+ const candidates: string[] = [
725
+ path.join(cwd, '.planning', 'KNOWHOW.md'),
726
+ path.join(cwd, 'KNOWHOW.md'),
727
+ ];
728
+ const milestonesBase = path.join(cwd, '.planning', 'milestones');
729
+ try {
730
+ for (const ms of fs.readdirSync(milestonesBase) as string[]) {
731
+ candidates.push(path.join(milestonesBase, ms, 'KNOWHOW.md'));
732
+ candidates.push(path.join(milestonesBase, ms, 'research', 'KNOWHOW.md'));
733
+ const phasesBase = path.join(milestonesBase, ms, 'phases');
734
+ try {
735
+ for (const ph of fs.readdirSync(phasesBase) as string[]) {
736
+ candidates.push(path.join(phasesBase, ph, 'KNOWHOW.md'));
737
+ }
738
+ } catch { /* skip */ }
739
+ }
740
+ } catch { /* skip */ }
741
+ const entries: ReturnType<typeof _cachedParseKnowhow> = [];
742
+ for (const p of candidates) entries.push(..._cachedParseKnowhow(p));
743
+ if (entries.length === 0) {
744
+ output({ query, top_n: topN, entries: [], message: 'KNOWHOW.md not found or empty' }, raw, 'KNOWHOW.md not found');
745
+ return;
746
+ }
747
+ const ranked = rankKnowhowByPhaseGoal(query, entries, topN);
748
+ const summaries = ranked.map((e) => ({
749
+ pattern_name: e.pattern_name,
750
+ phase_number: e.phase_number,
751
+ applicability: e.applicability.slice(0, 100),
752
+ }));
753
+ output({ query, top_n: topN, total: entries.length, entries: summaries }, raw,
754
+ ranked.map((e, i) => `${i + 1}. ${e.pattern_name} (phase ${e.phase_number})`).join('\n') || 'No entries');
755
+ }
756
+
757
+ module.exports = {
758
+ formatKnowhowEntry,
759
+ parseKnowhowEntries,
760
+ appendKnowhowEntries,
761
+ selectTopEntries,
762
+ buildKnowledgeInjectionBlock,
763
+ extractModuleHints,
764
+ rankKnowhowByPhaseGoal,
765
+ cmdKnowhowAudit,
766
+ cmdKnowhowDedup,
767
+ cmdKnowhowRank,
768
+ };