@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,1222 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execFileSync } = require('child_process');
6
+ const { planningDir: getPlanningDir, phasesDir: getPhasesDirPath } = require('./paths');
7
+ const { safeReadFile, safeReadJSON, createRunCache, walkJsFiles } = require('./utils');
8
+ // ─── File Content Cache ───────────────────────────────────────────────────────
9
+ const _cleanupCache = createRunCache();
10
+ function _cachedRead(absPath) {
11
+ return _cleanupCache.get(absPath, safeReadFile);
12
+ }
13
+ /**
14
+ * Reset the cleanup file content cache.
15
+ * Useful for tests that need to ensure a clean state between runs.
16
+ */
17
+ function resetCleanupCache() {
18
+ _cleanupCache.reset();
19
+ }
20
+ // ─── Config ──────────────────────────────────────────────────────────────────
21
+ const CLEANUP_DEFAULTS = {
22
+ enabled: false,
23
+ refactoring: false,
24
+ doc_sync: false,
25
+ test_coverage: false,
26
+ export_consistency: false,
27
+ doc_staleness: false,
28
+ config_schema: false,
29
+ cleanup_threshold: 5,
30
+ };
31
+ /**
32
+ * Read the `phase_cleanup` section from `.planning/config.json` and return
33
+ * a merged config object with defaults for any missing fields.
34
+ */
35
+ function getCleanupConfig(cwd) {
36
+ const configPath = path.join(cwd, '.planning', 'config.json');
37
+ const parsed = safeReadJSON(configPath, {});
38
+ const phaseCleanup = (parsed.phase_cleanup || {});
39
+ return { ...CLEANUP_DEFAULTS, ...phaseCleanup };
40
+ }
41
+ // ─── Complexity Analysis ─────────────────────────────────────────────────────
42
+ /** Module-level cache for ESLint complexity results: key = `${threshold}:${files.join(',')}` */
43
+ const _complexityCache = new Map();
44
+ /**
45
+ * Run ESLint complexity analysis on the specified files and return violations.
46
+ * Results are memoized per unique (files, threshold) combination within a process lifetime.
47
+ */
48
+ function analyzeComplexity(cwd, files, options = {}) {
49
+ if (!files || files.length === 0)
50
+ return [];
51
+ const threshold = options.threshold || 10;
52
+ const onProgress = options.onProgress;
53
+ // Filter to existing files only
54
+ const existingFiles = files.filter((f) => {
55
+ const absPath = path.resolve(cwd, f);
56
+ try {
57
+ fs.statSync(absPath);
58
+ return true;
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ });
64
+ if (existingFiles.length === 0)
65
+ return [];
66
+ // Check memoization cache (skip for calls with progress callbacks since they need events)
67
+ const cacheKey = `${threshold}:${existingFiles.join(',')}`;
68
+ if (!onProgress && _complexityCache.has(cacheKey)) {
69
+ return _complexityCache.get(cacheKey);
70
+ }
71
+ if (onProgress) {
72
+ onProgress({ event: 'started', file_count: existingFiles.length });
73
+ }
74
+ try {
75
+ // Run ESLint with complexity rule only, JSON output
76
+ // Use execFileSync with args array to avoid shell quoting issues
77
+ // Use relative paths with -- separator to avoid "outside base path" errors
78
+ const args = [
79
+ 'eslint',
80
+ '--no-config-lookup',
81
+ '--rule',
82
+ `complexity: ["warn", ${threshold}]`,
83
+ '--format',
84
+ 'json',
85
+ '--',
86
+ ...existingFiles,
87
+ ];
88
+ const result = execFileSync('npx', args, {
89
+ cwd,
90
+ encoding: 'utf-8',
91
+ stdio: ['pipe', 'pipe', 'pipe'],
92
+ });
93
+ const violations = parseEslintComplexityResults(cwd, result);
94
+ if (!onProgress)
95
+ _complexityCache.set(cacheKey, violations);
96
+ if (onProgress) {
97
+ onProgress({ event: 'completed', violation_count: violations.length });
98
+ }
99
+ return violations;
100
+ }
101
+ catch (err) {
102
+ // ESLint exits with code 1 when there are warnings/errors; stdout still has JSON
103
+ const execErr = err;
104
+ if (execErr.stdout) {
105
+ try {
106
+ const violations = parseEslintComplexityResults(cwd, execErr.stdout);
107
+ if (!onProgress)
108
+ _complexityCache.set(cacheKey, violations);
109
+ if (onProgress) {
110
+ onProgress({ event: 'completed', violation_count: violations.length });
111
+ }
112
+ return violations;
113
+ }
114
+ catch {
115
+ process.stderr.write('[cleanup] ESLint complexity analysis failed to parse output\n');
116
+ return [];
117
+ }
118
+ }
119
+ process.stderr.write('[cleanup] ESLint complexity analysis failed: ' + (execErr.message || 'unknown error') + '\n');
120
+ return [];
121
+ }
122
+ }
123
+ /**
124
+ * Parse ESLint JSON output for complexity violations.
125
+ */
126
+ function parseEslintComplexityResults(cwd, jsonOutput) {
127
+ const results = JSON.parse(jsonOutput);
128
+ const violations = [];
129
+ // Resolve cwd to real path for consistent path.relative calculation
130
+ // (handles macOS /var -> /private/var symlink)
131
+ const realCwd = fs.realpathSync(cwd);
132
+ for (const fileResult of results) {
133
+ for (const msg of fileResult.messages || []) {
134
+ if (msg.ruleId !== 'complexity')
135
+ continue;
136
+ // Extract function name and complexity from message text
137
+ // Format: "Function 'name' has a complexity of N. Maximum allowed is M."
138
+ // or: "Arrow function has a complexity of N. Maximum allowed is M."
139
+ const funcMatch = msg.message.match(/(?:Function '(\w+)'|(\w+ function))/);
140
+ const complexityMatch = msg.message.match(/complexity of (\d+)/);
141
+ if (complexityMatch) {
142
+ violations.push({
143
+ file: path.relative(realCwd, fileResult.filePath),
144
+ line: msg.line,
145
+ functionName: funcMatch ? funcMatch[1] || funcMatch[2] : 'anonymous',
146
+ complexity: parseInt(complexityMatch[1], 10),
147
+ });
148
+ }
149
+ }
150
+ }
151
+ return violations;
152
+ }
153
+ // ─── Dead Export Detection ────────────────────────────────────────────────────
154
+ /**
155
+ * Detect unused exports by scanning `module.exports` declarations and searching
156
+ * for corresponding `require()` imports across the codebase.
157
+ */
158
+ function analyzeDeadExports(cwd, files, options = {}) {
159
+ if (!files || files.length === 0)
160
+ return [];
161
+ const excludePatterns = options.excludePatterns || [];
162
+ const deadExports = [];
163
+ for (const file of files) {
164
+ const absPath = path.resolve(cwd, file);
165
+ const content = _cachedRead(absPath);
166
+ if (!content)
167
+ continue;
168
+ const exportNames = extractExportNames(content);
169
+ if (exportNames.length === 0)
170
+ continue;
171
+ const allJsFiles = findJsFiles(cwd, excludePatterns);
172
+ for (const exportName of exportNames) {
173
+ const hasConsumer = allJsFiles.some((jsFile) => {
174
+ if (path.resolve(cwd, jsFile) === absPath)
175
+ return false;
176
+ const jsContent = safeReadFile(path.resolve(cwd, jsFile));
177
+ if (!jsContent)
178
+ return false;
179
+ // Check for destructured import: { exportName } = require(...)
180
+ // or property access: someVar.exportName
181
+ const patterns = [
182
+ new RegExp(`\\b${exportName}\\b.*require`, 'g'),
183
+ new RegExp(`require.*\\b${exportName}\\b`, 'g'),
184
+ new RegExp(`\\.${exportName}\\b`, 'g'),
185
+ ];
186
+ return patterns.some((p) => p.test(jsContent));
187
+ });
188
+ if (!hasConsumer) {
189
+ // Find the line number where this name is exported
190
+ const exportLine = findExportLine(content, exportName);
191
+ deadExports.push({
192
+ file,
193
+ exportName,
194
+ line: exportLine,
195
+ });
196
+ }
197
+ }
198
+ }
199
+ return deadExports;
200
+ }
201
+ /**
202
+ * Extract exported names from a JS file content.
203
+ * Handles `module.exports = { a, b, c }` and `exports.name = ...` patterns.
204
+ */
205
+ function extractExportNames(content) {
206
+ const names = [];
207
+ // Pattern 1: module.exports = { name1, name2, ... }
208
+ // Handle multiline exports blocks
209
+ const moduleExportsMatch = content.match(/module\.exports\s*=\s*\{([^}]+)\}/s);
210
+ if (moduleExportsMatch) {
211
+ const block = moduleExportsMatch[1];
212
+ // Split on commas, extract name (handle `name: value` and plain `name`)
213
+ const entries = block.split(',');
214
+ for (const entry of entries) {
215
+ const trimmed = entry.trim();
216
+ if (!trimmed)
217
+ continue;
218
+ // Could be "name" or "name: value" or "name: someFunction"
219
+ const nameMatch = trimmed.match(/^(\w+)/);
220
+ if (nameMatch) {
221
+ names.push(nameMatch[1]);
222
+ }
223
+ }
224
+ }
225
+ // Pattern 2: exports.funcName = ...
226
+ const exportsPattern = /exports\.(\w+)\s*=/g;
227
+ let match;
228
+ while ((match = exportsPattern.exec(content)) !== null) {
229
+ if (!names.includes(match[1])) {
230
+ names.push(match[1]);
231
+ }
232
+ }
233
+ return names;
234
+ }
235
+ /**
236
+ * Find the line number where an export name is defined or exported.
237
+ */
238
+ function findExportLine(content, exportName) {
239
+ const lines = content.split('\n');
240
+ for (let i = 0; i < lines.length; i++) {
241
+ if (lines[i].includes(exportName)) {
242
+ return i + 1;
243
+ }
244
+ }
245
+ return 0;
246
+ }
247
+ /**
248
+ * Recursively find all .js files under cwd, excluding node_modules and
249
+ * files matching excludePatterns. Delegates to the shared walkJsFiles utility.
250
+ */
251
+ function findJsFiles(cwd, excludePatterns = []) {
252
+ return walkJsFiles(cwd, excludePatterns);
253
+ }
254
+ // ─── File Size Analysis ──────────────────────────────────────────────────────
255
+ /**
256
+ * Check files against configurable line-count thresholds.
257
+ */
258
+ function analyzeFileSize(cwd, files, thresholds = {}) {
259
+ if (!files || files.length === 0)
260
+ return [];
261
+ const maxLines = thresholds.maxLines || 500;
262
+ const violations = [];
263
+ for (const file of files) {
264
+ const absPath = path.resolve(cwd, file);
265
+ const content = _cachedRead(absPath);
266
+ if (!content)
267
+ continue;
268
+ const lines = content.split('\n').length - (content.endsWith('\n') ? 1 : 0);
269
+ if (lines > maxLines) {
270
+ violations.push({
271
+ file,
272
+ lines,
273
+ threshold: maxLines,
274
+ });
275
+ }
276
+ }
277
+ return violations;
278
+ }
279
+ // ─── Doc Drift Detection ─────────────────────────────────────────────────────
280
+ /**
281
+ * Detect stale CHANGELOG.md by comparing its mtime to the newest SUMMARY.md.
282
+ */
283
+ function analyzeChangelogDrift(cwd) {
284
+ const changelogPath = path.join(cwd, 'CHANGELOG.md');
285
+ try {
286
+ fs.statSync(changelogPath);
287
+ }
288
+ catch {
289
+ return []; // No CHANGELOG.md — graceful skip
290
+ }
291
+ // Find all *-SUMMARY.md files under .planning/phases/
292
+ const phasesDir = getPhasesDirPath(cwd);
293
+ const summaryFiles = _findSummaryFiles(phasesDir);
294
+ if (summaryFiles.length === 0)
295
+ return []; // Nothing to compare
296
+ // Get mtimes
297
+ const changelogMtime = fs.statSync(changelogPath).mtime;
298
+ let newestSummaryMtime = new Date(0);
299
+ for (const sf of summaryFiles) {
300
+ const mtime = fs.statSync(sf).mtime;
301
+ if (mtime > newestSummaryMtime) {
302
+ newestSummaryMtime = mtime;
303
+ }
304
+ }
305
+ if (changelogMtime < newestSummaryMtime) {
306
+ return [
307
+ {
308
+ file: 'CHANGELOG.md',
309
+ reason: 'Not updated since last plan completion',
310
+ last_modified: changelogMtime.toISOString(),
311
+ latest_summary: newestSummaryMtime.toISOString(),
312
+ },
313
+ ];
314
+ }
315
+ return [];
316
+ }
317
+ /**
318
+ * Recursively find all *-SUMMARY.md files under a directory.
319
+ */
320
+ function _findSummaryFiles(dir) {
321
+ const results = [];
322
+ try {
323
+ const entries = fs.readdirSync(dir, {
324
+ withFileTypes: true,
325
+ });
326
+ for (const entry of entries) {
327
+ const fullPath = path.join(dir, entry.name);
328
+ if (entry.isDirectory()) {
329
+ results.push(..._findSummaryFiles(fullPath));
330
+ }
331
+ else if (entry.isFile() && entry.name.endsWith('-SUMMARY.md')) {
332
+ results.push(fullPath);
333
+ }
334
+ }
335
+ }
336
+ catch {
337
+ // Directory doesn't exist — return empty
338
+ }
339
+ return results;
340
+ }
341
+ /**
342
+ * Detect broken internal file references in README.md markdown links.
343
+ */
344
+ function analyzeReadmeLinks(cwd) {
345
+ const readmePath = path.join(cwd, 'README.md');
346
+ const content = safeReadFile(readmePath);
347
+ if (!content)
348
+ return [];
349
+ const broken = [];
350
+ const lines = content.split('\n');
351
+ const linkRegex = /\[([^\]]*)\]\(([^)"\s]+)(?:\s+"[^"]*")?\)/g;
352
+ for (let i = 0; i < lines.length; i++) {
353
+ let match;
354
+ // Reset lastIndex for each line since we reuse the regex
355
+ linkRegex.lastIndex = 0;
356
+ while ((match = linkRegex.exec(lines[i])) !== null) {
357
+ const linkPath = match[2];
358
+ // Skip external links and anchor-only links
359
+ if (linkPath.startsWith('http://') ||
360
+ linkPath.startsWith('https://') ||
361
+ linkPath.startsWith('#')) {
362
+ continue;
363
+ }
364
+ // Resolve relative path against cwd
365
+ const resolved = path.resolve(cwd, linkPath);
366
+ if (!fs.existsSync(resolved)) {
367
+ broken.push({
368
+ file: 'README.md',
369
+ link: linkPath,
370
+ line: i + 1,
371
+ });
372
+ }
373
+ }
374
+ }
375
+ return broken;
376
+ }
377
+ /**
378
+ * Detect JSDoc @param annotations that do not match actual function parameter names.
379
+ */
380
+ // Compiled once at module level to avoid repeated RegExp construction in loops
381
+ const _JSDOC_BLOCK_RE_SRC = '\\/\\*\\*[\\s\\S]*?\\*\\/';
382
+ const _JSDOC_PARAM_RE_SRC = '@param\\s+(?:\\{[^}]*\\}\\s+)?(\\w+)';
383
+ const _FUNC_PATTERNS = [
384
+ /function\s+(\w+)\s*\(([^)]*)\)/,
385
+ /(?:const|let|var)\s+(\w+)\s*=\s*\(([^)]*)\)\s*=>/,
386
+ /(?:const|let|var)\s+(\w+)\s*=\s*(\w+)\s*=>/,
387
+ /(\w+)\s*\(([^)]*)\)\s*\{/,
388
+ ];
389
+ /**
390
+ * Extract @param names from a JSDoc comment block string.
391
+ */
392
+ function _extractJsdocParams(block) {
393
+ const params = [];
394
+ const re = new RegExp(_JSDOC_PARAM_RE_SRC, 'g');
395
+ let m;
396
+ while ((m = re.exec(block)) !== null) {
397
+ params.push(m[1]);
398
+ }
399
+ return params;
400
+ }
401
+ /**
402
+ * Find the function name and parameter string immediately following a JSDoc block.
403
+ */
404
+ function _parseFunctionAfterJsdoc(contentAfterBlock) {
405
+ const nextLines = contentAfterBlock.split('\n').slice(0, 5).join('\n');
406
+ for (const pattern of _FUNC_PATTERNS) {
407
+ const m = nextLines.match(pattern);
408
+ if (m)
409
+ return { funcName: m[1], paramsStr: m[2] };
410
+ }
411
+ return { funcName: null, paramsStr: null };
412
+ }
413
+ function analyzeJsdocDrift(cwd, files) {
414
+ if (!files || files.length === 0)
415
+ return [];
416
+ const issues = [];
417
+ for (const file of files) {
418
+ const absPath = path.resolve(cwd, file);
419
+ const content = _cachedRead(absPath);
420
+ if (!content)
421
+ continue;
422
+ const blockRe = new RegExp(_JSDOC_BLOCK_RE_SRC, 'g');
423
+ let blockMatch;
424
+ while ((blockMatch = blockRe.exec(content)) !== null) {
425
+ const blockEnd = blockMatch.index + blockMatch[0].length;
426
+ const blockStartLine = content.substring(0, blockMatch.index).split('\n').length;
427
+ const docParams = _extractJsdocParams(blockMatch[0]);
428
+ if (docParams.length === 0)
429
+ continue; // No @param annotations, skip
430
+ const { funcName, paramsStr } = _parseFunctionAfterJsdoc(content.substring(blockEnd));
431
+ if (!funcName || paramsStr === null || paramsStr === undefined)
432
+ continue;
433
+ const actualParams = _extractParamNames(paramsStr);
434
+ for (const dp of docParams) {
435
+ if (!actualParams.includes(dp)) {
436
+ issues.push({
437
+ file,
438
+ line: blockStartLine,
439
+ functionName: funcName,
440
+ issue: `extra @param: ${dp}`,
441
+ });
442
+ }
443
+ }
444
+ for (const ap of actualParams) {
445
+ if (!docParams.includes(ap)) {
446
+ issues.push({
447
+ file,
448
+ line: blockStartLine,
449
+ functionName: funcName,
450
+ issue: `missing @param: ${ap}`,
451
+ });
452
+ }
453
+ }
454
+ }
455
+ }
456
+ return issues;
457
+ }
458
+ /**
459
+ * Extract parameter names from a function signature string.
460
+ * Handles default values (x = 1), destructured params ({a, b}), and rest params (...args).
461
+ */
462
+ function _extractParamNames(paramsStr) {
463
+ if (!paramsStr || !paramsStr.trim())
464
+ return [];
465
+ const params = [];
466
+ // Split by commas, but be careful of nested braces/brackets
467
+ let depth = 0;
468
+ let current = '';
469
+ for (const ch of paramsStr) {
470
+ if (ch === '{' || ch === '[' || ch === '(')
471
+ depth++;
472
+ else if (ch === '}' || ch === ']' || ch === ')')
473
+ depth--;
474
+ else if (ch === ',' && depth === 0) {
475
+ params.push(current.trim());
476
+ current = '';
477
+ continue;
478
+ }
479
+ current += ch;
480
+ }
481
+ if (current.trim())
482
+ params.push(current.trim());
483
+ return params
484
+ .map((p) => {
485
+ // Remove rest operator
486
+ let cleaned = p.replace(/^\.\.\./, '');
487
+ // Remove default value
488
+ cleaned = cleaned.split('=')[0].trim();
489
+ // If it's a destructured param ({...}), skip — can't match by name
490
+ if (cleaned.startsWith('{') || cleaned.startsWith('['))
491
+ return null;
492
+ // Extract just the identifier
493
+ const nameMatch = cleaned.match(/^(\w+)/);
494
+ return nameMatch ? nameMatch[1] : null;
495
+ })
496
+ .filter((n) => n !== null);
497
+ }
498
+ // ─── Test Coverage Gap Detection ──────────────────────────────────────────────
499
+ /**
500
+ * Detect exported functions/values with no corresponding mention in test files.
501
+ * For each lib/foo.js, checks tests/unit/foo.test.js for references to each export.
502
+ */
503
+ function analyzeTestCoverageGaps(cwd, files) {
504
+ if (!files || files.length === 0)
505
+ return [];
506
+ const gaps = [];
507
+ for (const file of files) {
508
+ const absPath = path.resolve(cwd, file);
509
+ const content = _cachedRead(absPath);
510
+ if (!content)
511
+ continue;
512
+ const exportNames = extractExportNames(content);
513
+ if (exportNames.length === 0)
514
+ continue;
515
+ const basename = path.basename(file, '.js');
516
+ const testFile = path.join('tests', 'unit', `${basename}.test.js`);
517
+ const testContent = safeReadFile(path.resolve(cwd, testFile));
518
+ if (!testContent) {
519
+ for (const exportName of exportNames) {
520
+ gaps.push({
521
+ file,
522
+ exportName,
523
+ testFile,
524
+ line: findExportLine(content, exportName),
525
+ });
526
+ }
527
+ continue;
528
+ }
529
+ for (const exportName of exportNames) {
530
+ if (!testContent.includes(exportName)) {
531
+ gaps.push({
532
+ file,
533
+ exportName,
534
+ testFile,
535
+ line: findExportLine(content, exportName),
536
+ });
537
+ }
538
+ }
539
+ }
540
+ return gaps;
541
+ }
542
+ // ─── Export Consistency Detection ──────────────────────────────────────────────
543
+ /**
544
+ * Detect stale imports where a destructured require references a name no longer
545
+ * exported by the target module.
546
+ */
547
+ function analyzeExportConsistency(cwd, files) {
548
+ if (!files || files.length === 0)
549
+ return [];
550
+ const issues = [];
551
+ for (const file of files) {
552
+ const absPath = path.resolve(cwd, file);
553
+ const content = _cachedRead(absPath);
554
+ if (!content)
555
+ continue;
556
+ const lines = content.split('\n');
557
+ const requirePattern = /const\s+\{([^}]+)\}\s*=\s*require\(['"]([^'"]+)['"]\)/;
558
+ for (let i = 0; i < lines.length; i++) {
559
+ const match = lines[i].match(requirePattern);
560
+ if (!match)
561
+ continue;
562
+ const importedNames = match[1]
563
+ .split(',')
564
+ .map((n) => n.trim())
565
+ .filter(Boolean);
566
+ const requirePath = match[2];
567
+ if (!requirePath.startsWith('.'))
568
+ continue;
569
+ let sourcePath = path.resolve(path.dirname(absPath), requirePath);
570
+ if (!sourcePath.endsWith('.js'))
571
+ sourcePath += '.js';
572
+ const sourceContent = safeReadFile(sourcePath);
573
+ if (!sourceContent)
574
+ continue;
575
+ const sourceExports = extractExportNames(sourceContent);
576
+ const sourceModule = path.relative(cwd, sourcePath);
577
+ for (const name of importedNames) {
578
+ const cleanName = name.split(':')[0].trim();
579
+ if (!cleanName)
580
+ continue;
581
+ if (!sourceExports.includes(cleanName)) {
582
+ issues.push({
583
+ file,
584
+ importedName: cleanName,
585
+ sourceModule,
586
+ line: i + 1,
587
+ });
588
+ }
589
+ }
590
+ }
591
+ }
592
+ return issues;
593
+ }
594
+ // ─── Doc Staleness Detection ──────────────────────────────────────────────────
595
+ /**
596
+ * Cross-reference CLAUDE.md CLI Tooling documentation with mcp-server.js
597
+ * COMMAND_DESCRIPTORS to detect documentation gaps.
598
+ */
599
+ function analyzeDocStaleness(cwd) {
600
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
601
+ const claudeContent = safeReadFile(claudeMdPath);
602
+ if (!claudeContent)
603
+ return [];
604
+ const mcpPath = path.join(cwd, 'lib', 'mcp-server.js');
605
+ const mcpContent = safeReadFile(mcpPath);
606
+ if (!mcpContent)
607
+ return [];
608
+ const issues = [];
609
+ const documentedCommands = _extractDocumentedCommands(claudeContent);
610
+ const actualTools = _extractToolNames(mcpContent);
611
+ // Check documented but not implemented
612
+ for (const cmd of documentedCommands) {
613
+ const hasMatch = cmd.possibleNames.some((n) => actualTools.has(n));
614
+ if (!hasMatch) {
615
+ issues.push({
616
+ file: 'CLAUDE.md',
617
+ issue: 'documented-but-not-implemented',
618
+ detail: `Command "${cmd.raw}" not found in COMMAND_DESCRIPTORS`,
619
+ line: cmd.line,
620
+ });
621
+ }
622
+ }
623
+ // Check implemented but not documented
624
+ const allDocumentedNames = new Set();
625
+ for (const cmd of documentedCommands) {
626
+ for (const n of cmd.possibleNames) {
627
+ allDocumentedNames.add(n);
628
+ }
629
+ }
630
+ for (const tool of actualTools) {
631
+ if (!allDocumentedNames.has(tool)) {
632
+ issues.push({
633
+ file: 'lib/mcp-server.js',
634
+ issue: 'implemented-but-not-documented',
635
+ detail: `Tool "${tool}" not documented in CLAUDE.md CLI Tooling section`,
636
+ line: 0,
637
+ });
638
+ }
639
+ }
640
+ return issues;
641
+ }
642
+ /**
643
+ * Extract documented CLI commands from the "CLI Tooling" section of CLAUDE.md.
644
+ */
645
+ function _extractDocumentedCommands(content) {
646
+ const commands = [];
647
+ const lines = content.split('\n');
648
+ let inSection = false;
649
+ for (let i = 0; i < lines.length; i++) {
650
+ const line = lines[i];
651
+ if (/^## CLI Tooling/.test(line)) {
652
+ inSection = true;
653
+ continue;
654
+ }
655
+ if (inSection && /^## /.test(line))
656
+ break;
657
+ if (!inSection)
658
+ continue;
659
+ const cmdMatch = line.match(/^- `([^`]+)`/);
660
+ if (!cmdMatch)
661
+ continue;
662
+ const rawCmd = cmdMatch[1];
663
+ const cleaned = rawCmd
664
+ .replace(/\[[^\]]*\]/g, '')
665
+ .replace(/<[^>]*>/g, '')
666
+ .replace(/--\S+(\s+"[^"]*"|\s+\S+)?/g, '')
667
+ .replace(/\.\.\./g, '')
668
+ .trim()
669
+ .replace(/\s+/g, ' ');
670
+ if (!cleaned)
671
+ continue;
672
+ const possibleNames = _generateToolNames(cleaned);
673
+ if (possibleNames.length > 0) {
674
+ commands.push({ raw: rawCmd, possibleNames, line: i + 1 });
675
+ }
676
+ }
677
+ return commands;
678
+ }
679
+ /**
680
+ * Generate possible MCP tool names from a cleaned CLI command string.
681
+ * Handles slash-separated subcommands and " / " alternatives.
682
+ */
683
+ function _generateToolNames(cleaned) {
684
+ const names = [];
685
+ // Handle " / " pattern: "state add-blocker / resolve-blocker"
686
+ if (cleaned.includes(' / ')) {
687
+ const parts = cleaned.split(' / ').map((p) => p.trim());
688
+ const firstParts = parts[0].split(/\s+/);
689
+ if (firstParts.length >= 2) {
690
+ const base = firstParts.slice(0, -1).join('_').replace(/-/g, '_');
691
+ names.push('grd_' + base + '_' + firstParts[firstParts.length - 1].replace(/-/g, '_'));
692
+ for (let j = 1; j < parts.length; j++) {
693
+ names.push('grd_' + base + '_' + parts[j].replace(/-/g, '_'));
694
+ }
695
+ }
696
+ return names;
697
+ }
698
+ const words = cleaned.split(/\s+/).filter(Boolean);
699
+ const lastWord = words[words.length - 1];
700
+ // Handle slash-separated in last word
701
+ if (lastWord && lastWord.includes('/')) {
702
+ const base = words.slice(0, -1).join('_').replace(/-/g, '_');
703
+ const subs = lastWord.split('/');
704
+ // Add base-only version (for parameterized tools like scaffold)
705
+ if (base)
706
+ names.push('grd_' + base);
707
+ // Add expanded versions
708
+ for (const sub of subs) {
709
+ const subNorm = sub.replace(/-/g, '_');
710
+ names.push(base ? 'grd_' + base + '_' + subNorm : 'grd_' + subNorm);
711
+ }
712
+ return names;
713
+ }
714
+ // Simple command
715
+ names.push('grd_' + cleaned.replace(/[\s-]+/g, '_'));
716
+ return names;
717
+ }
718
+ /**
719
+ * Extract tool names from mcp-server.js COMMAND_DESCRIPTORS.
720
+ */
721
+ function _extractToolNames(content) {
722
+ const names = new Set();
723
+ const namePattern = /name:\s*'(grd_[^']+)'/g;
724
+ let match;
725
+ while ((match = namePattern.exec(content)) !== null) {
726
+ names.add(match[1]);
727
+ }
728
+ return names;
729
+ }
730
+ // ─── Config Schema Drift Detection ───────────────────────────────────────────
731
+ /**
732
+ * Detect drift between documented config keys in CLAUDE.md and actual
733
+ * config.json keys, and verify COMMAND_DESCRIPTORS execute references.
734
+ */
735
+ function analyzeConfigSchemaDrift(cwd) {
736
+ const issues = [];
737
+ // 1. Parse CLAUDE.md Configuration section for documented config keys
738
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
739
+ const claudeContent = safeReadFile(claudeMdPath);
740
+ if (!claudeContent)
741
+ return [];
742
+ const documentedKeys = _extractDocumentedConfigKeys(claudeContent);
743
+ // 2. Read actual config.json
744
+ const configPath = path.join(cwd, '.planning', 'config.json');
745
+ const parsedConfig = safeReadJSON(configPath);
746
+ const actualKeys = parsedConfig
747
+ ? Object.keys(parsedConfig).filter((k) => !k.startsWith('_'))
748
+ : null;
749
+ if (actualKeys) {
750
+ for (const dk of documentedKeys) {
751
+ if (!actualKeys.includes(dk.key)) {
752
+ issues.push({
753
+ file: 'CLAUDE.md',
754
+ issue: 'documented-key-not-in-config',
755
+ detail: `Config key "${dk.key}" documented but not found in config.json`,
756
+ line: dk.line,
757
+ });
758
+ }
759
+ }
760
+ const documentedKeySet = new Set(documentedKeys.map((dk) => dk.key));
761
+ for (const key of actualKeys) {
762
+ if (!documentedKeySet.has(key)) {
763
+ issues.push({
764
+ file: path.relative(cwd, path.join(getPlanningDir(cwd), 'config.json')),
765
+ issue: 'config-key-not-documented',
766
+ detail: `Config key "${key}" present but not documented in CLAUDE.md`,
767
+ line: 0,
768
+ });
769
+ }
770
+ }
771
+ }
772
+ // 3. Check COMMAND_DESCRIPTORS execute references
773
+ const mcpPath = path.join(cwd, 'lib', 'mcp-server.js');
774
+ const mcpContent = safeReadFile(mcpPath);
775
+ if (!mcpContent)
776
+ return issues;
777
+ const executePattern = /execute:\s*\([^)]*\)\s*=>\s*(\w+)\(/g;
778
+ const executeFunctions = new Set();
779
+ let execMatch;
780
+ while ((execMatch = executePattern.exec(mcpContent)) !== null) {
781
+ executeFunctions.add(execMatch[1]);
782
+ }
783
+ const preamble = mcpContent.split('const COMMAND_DESCRIPTORS')[0] || '';
784
+ for (const funcName of executeFunctions) {
785
+ if (!preamble.includes(funcName)) {
786
+ issues.push({
787
+ file: 'lib/mcp-server.js',
788
+ issue: 'execute-function-not-imported',
789
+ detail: `Function "${funcName}" referenced in execute but not imported`,
790
+ line: 0,
791
+ });
792
+ }
793
+ }
794
+ return issues;
795
+ }
796
+ /**
797
+ * Extract documented configuration keys from the "Configuration" section of CLAUDE.md.
798
+ */
799
+ function _extractDocumentedConfigKeys(content) {
800
+ const keys = [];
801
+ const lines = content.split('\n');
802
+ let inSection = false;
803
+ for (let i = 0; i < lines.length; i++) {
804
+ const line = lines[i];
805
+ if (/^## Configuration/.test(line)) {
806
+ inSection = true;
807
+ continue;
808
+ }
809
+ if (inSection && /^## /.test(line))
810
+ break;
811
+ if (!inSection)
812
+ continue;
813
+ const keyMatch = line.match(/^- `(\w+)`/);
814
+ if (keyMatch) {
815
+ keys.push({ key: keyMatch[1], line: i + 1 });
816
+ }
817
+ }
818
+ return keys;
819
+ }
820
+ // ─── Quality Analysis Orchestrator ───────────────────────────────────────────
821
+ /**
822
+ * Orchestrate all quality checks (complexity, dead exports, file size, doc drift)
823
+ * and return a structured quality report.
824
+ */
825
+ function runQualityAnalysis(cwd, phaseNum) {
826
+ const config = getCleanupConfig(cwd);
827
+ if (!config.enabled) {
828
+ return { skipped: true, reason: 'phase_cleanup not enabled' };
829
+ }
830
+ _cleanupCache.init();
831
+ try {
832
+ // Find files to analyze: scan lib/*.js as default
833
+ const jsFiles = findAnalysisFiles(cwd, phaseNum);
834
+ // Run core analyses
835
+ const complexityResults = analyzeComplexity(cwd, jsFiles);
836
+ const deadExportResults = analyzeDeadExports(cwd, jsFiles);
837
+ const fileSizeResults = analyzeFileSize(cwd, jsFiles);
838
+ const baseIssues = complexityResults.length + deadExportResults.length + fileSizeResults.length;
839
+ const summary = {
840
+ total_issues: baseIssues,
841
+ complexity_violations: complexityResults.length,
842
+ dead_exports: deadExportResults.length,
843
+ oversized_files: fileSizeResults.length,
844
+ };
845
+ const details = {
846
+ complexity: complexityResults,
847
+ dead_exports: deadExportResults,
848
+ file_size: fileSizeResults,
849
+ };
850
+ // Run doc drift checks when doc_sync is enabled
851
+ if (config.doc_sync) {
852
+ const changelogResults = analyzeChangelogDrift(cwd);
853
+ const readmeResults = analyzeReadmeLinks(cwd);
854
+ const jsdocResults = analyzeJsdocDrift(cwd, jsFiles);
855
+ const docDriftCount = changelogResults.length + readmeResults.length + jsdocResults.length;
856
+ summary.doc_drift_issues = docDriftCount;
857
+ summary.total_issues += docDriftCount;
858
+ details.doc_drift = {
859
+ changelog: changelogResults,
860
+ readme_links: readmeResults,
861
+ jsdoc: jsdocResults,
862
+ };
863
+ }
864
+ // Run test coverage gap analysis when test_coverage is enabled
865
+ if (config.test_coverage) {
866
+ const testCoverageResults = analyzeTestCoverageGaps(cwd, jsFiles);
867
+ summary.test_coverage_gaps = testCoverageResults.length;
868
+ summary.total_issues += testCoverageResults.length;
869
+ details.test_coverage = testCoverageResults;
870
+ }
871
+ // Run export consistency analysis when export_consistency is enabled
872
+ if (config.export_consistency) {
873
+ const exportConsistencyResults = analyzeExportConsistency(cwd, jsFiles);
874
+ summary.stale_imports = exportConsistencyResults.length;
875
+ summary.total_issues += exportConsistencyResults.length;
876
+ details.export_consistency = exportConsistencyResults;
877
+ }
878
+ // Run doc staleness analysis when doc_staleness is enabled
879
+ if (config.doc_staleness) {
880
+ const docStalenessResults = analyzeDocStaleness(cwd);
881
+ summary.doc_staleness_issues = docStalenessResults.length;
882
+ summary.total_issues += docStalenessResults.length;
883
+ details.doc_staleness = docStalenessResults;
884
+ }
885
+ // Run config schema drift analysis when config_schema is enabled
886
+ if (config.config_schema) {
887
+ const configSchemaResults = analyzeConfigSchemaDrift(cwd);
888
+ summary.config_schema_issues = configSchemaResults.length;
889
+ summary.total_issues += configSchemaResults.length;
890
+ details.config_schema = configSchemaResults;
891
+ }
892
+ // Compute trends against previous phase if history exists
893
+ const history = loadQualityHistory(cwd);
894
+ let trends = null;
895
+ const prevPhase = String(parseInt(phaseNum, 10) - 1);
896
+ if (history[prevPhase]) {
897
+ trends = computeTrends(summary, history[prevPhase], prevPhase);
898
+ }
899
+ return {
900
+ phase: phaseNum,
901
+ timestamp: new Date().toISOString().split('T')[0],
902
+ summary,
903
+ details,
904
+ trends,
905
+ };
906
+ }
907
+ finally {
908
+ _cleanupCache.reset();
909
+ }
910
+ }
911
+ /**
912
+ * Find files to analyze for a given phase. Scans lib/*.js as fallback.
913
+ */
914
+ function findAnalysisFiles(cwd, _phaseNum) {
915
+ const libDir = path.join(cwd, 'lib');
916
+ try {
917
+ const entries = fs.readdirSync(libDir, {
918
+ withFileTypes: true,
919
+ });
920
+ return entries
921
+ .filter((e) => e.isFile() && e.name.endsWith('.js'))
922
+ .map((e) => path.join('lib', e.name));
923
+ }
924
+ catch {
925
+ return [];
926
+ }
927
+ }
928
+ // ─── Cleanup Plan Generation ──────────────────────────────────────────────────
929
+ /**
930
+ * Auto-generate a cleanup PLAN.md when quality issues exceed a configurable threshold.
931
+ * Scans existing plan files in the phase directory to determine the next plan number,
932
+ * then writes a standard-format PLAN.md with tasks derived from the quality report.
933
+ */
934
+ function generateCleanupPlan(cwd, phaseNum, qualityReport) {
935
+ const config = getCleanupConfig(cwd);
936
+ const threshold = config.cleanup_threshold;
937
+ // No plan needed if issues are at or below threshold
938
+ if (!qualityReport || !qualityReport.summary || qualityReport.summary.total_issues <= threshold) {
939
+ return null;
940
+ }
941
+ // Find phase directory
942
+ const phasesDir = getPhasesDirPath(cwd);
943
+ let phaseDir = null;
944
+ let phaseDirName = null;
945
+ try {
946
+ const entries = fs.readdirSync(phasesDir, {
947
+ withFileTypes: true,
948
+ });
949
+ const dirs = entries
950
+ .filter((e) => e.isDirectory())
951
+ .map((e) => e.name);
952
+ const normalized = String(phaseNum).padStart(2, '0');
953
+ const match = dirs.find((d) => d.startsWith(normalized + '-') || d === normalized);
954
+ if (match) {
955
+ phaseDir = path.join(phasesDir, match);
956
+ phaseDirName = match;
957
+ }
958
+ }
959
+ catch {
960
+ // phases directory doesn't exist
961
+ }
962
+ if (!phaseDir || !phaseDirName)
963
+ return null;
964
+ // Find next plan number
965
+ let nextPlanNum = 1;
966
+ try {
967
+ const files = fs.readdirSync(phaseDir);
968
+ const normalized = String(phaseNum).padStart(2, '0');
969
+ const planFiles = files.filter((f) => {
970
+ const pattern = new RegExp(`^${normalized}-(\\d{2})-PLAN\\.md$`);
971
+ return pattern.test(f);
972
+ });
973
+ if (planFiles.length > 0) {
974
+ const planNums = planFiles.map((f) => {
975
+ const m = f.match(/(\d{2})-PLAN\.md$/);
976
+ return m ? parseInt(m[1], 10) : 0;
977
+ });
978
+ nextPlanNum = Math.max(...planNums) + 1;
979
+ }
980
+ }
981
+ catch {
982
+ // directory read error
983
+ }
984
+ const paddedPlan = String(nextPlanNum).padStart(2, '0');
985
+ const phaseSlug = phaseDirName.replace(/^\d+(?:\.\d+)?-?/, '');
986
+ // Collect unique files from quality issues
987
+ const filesSet = new Set();
988
+ const { details } = qualityReport;
989
+ if (details) {
990
+ if (details.complexity) {
991
+ details.complexity.forEach((v) => filesSet.add(v.file));
992
+ }
993
+ if (details.dead_exports) {
994
+ details.dead_exports.forEach((v) => filesSet.add(v.file));
995
+ }
996
+ if (details.file_size) {
997
+ details.file_size.forEach((v) => filesSet.add(v.file));
998
+ }
999
+ if (details.doc_drift) {
1000
+ if (details.doc_drift.changelog) {
1001
+ details.doc_drift.changelog.forEach((v) => filesSet.add(v.file));
1002
+ }
1003
+ if (details.doc_drift.readme_links) {
1004
+ details.doc_drift.readme_links.forEach((v) => filesSet.add(v.file));
1005
+ }
1006
+ if (details.doc_drift.jsdoc) {
1007
+ details.doc_drift.jsdoc.forEach((v) => filesSet.add(v.file));
1008
+ }
1009
+ }
1010
+ if (details.test_coverage) {
1011
+ details.test_coverage.forEach((v) => filesSet.add(v.file));
1012
+ }
1013
+ if (details.export_consistency) {
1014
+ details.export_consistency.forEach((v) => filesSet.add(v.file));
1015
+ }
1016
+ if (details.doc_staleness) {
1017
+ details.doc_staleness.forEach((v) => filesSet.add(v.file));
1018
+ }
1019
+ if (details.config_schema) {
1020
+ details.config_schema.forEach((v) => filesSet.add(v.file));
1021
+ }
1022
+ }
1023
+ const filesModified = [...filesSet];
1024
+ // Build tasks from quality report
1025
+ const tasks = [];
1026
+ // Task 1: Code quality issues (complexity, dead exports, file size)
1027
+ const codeIssues = [];
1028
+ if (details && details.complexity && details.complexity.length > 0) {
1029
+ codeIssues.push(`- Refactor ${details.complexity.length} high-complexity function(s): ${details.complexity.map((v) => `${v.functionName} in ${v.file}`).join(', ')}`);
1030
+ }
1031
+ if (details && details.dead_exports && details.dead_exports.length > 0) {
1032
+ codeIssues.push(`- Remove or document ${details.dead_exports.length} dead export(s): ${details.dead_exports.map((v) => `${v.exportName} in ${v.file}`).join(', ')}`);
1033
+ }
1034
+ if (details && details.file_size && details.file_size.length > 0) {
1035
+ codeIssues.push(`- Split ${details.file_size.length} oversized file(s): ${details.file_size.map((v) => `${v.file} (${v.lines} lines)`).join(', ')}`);
1036
+ }
1037
+ if (codeIssues.length > 0) {
1038
+ tasks.push({
1039
+ name: 'Resolve code quality issues',
1040
+ items: codeIssues,
1041
+ });
1042
+ }
1043
+ // Task 2: Doc drift issues
1044
+ const docIssues = [];
1045
+ if (details && details.doc_drift) {
1046
+ if (details.doc_drift.changelog && details.doc_drift.changelog.length > 0) {
1047
+ docIssues.push(`- Update stale CHANGELOG.md`);
1048
+ }
1049
+ if (details.doc_drift.readme_links && details.doc_drift.readme_links.length > 0) {
1050
+ docIssues.push(`- Fix ${details.doc_drift.readme_links.length} broken README link(s): ${details.doc_drift.readme_links.map((v) => v.link).join(', ')}`);
1051
+ }
1052
+ if (details.doc_drift.jsdoc && details.doc_drift.jsdoc.length > 0) {
1053
+ docIssues.push(`- Fix ${details.doc_drift.jsdoc.length} JSDoc mismatch(es): ${details.doc_drift.jsdoc.map((v) => `${v.functionName} in ${v.file}`).join(', ')}`);
1054
+ }
1055
+ }
1056
+ if (docIssues.length > 0) {
1057
+ tasks.push({
1058
+ name: 'Update stale documentation',
1059
+ items: docIssues,
1060
+ });
1061
+ }
1062
+ // Task: Test coverage gaps
1063
+ if (details && details.test_coverage && details.test_coverage.length > 0) {
1064
+ tasks.push({
1065
+ name: 'Close test coverage gaps',
1066
+ items: details.test_coverage.map((v) => `- Add tests for ${v.exportName} from ${v.file} in ${v.testFile}`),
1067
+ });
1068
+ }
1069
+ // Task: Consistency and schema issues
1070
+ const consistencyIssues = [];
1071
+ if (details && details.export_consistency && details.export_consistency.length > 0) {
1072
+ consistencyIssues.push(`- Fix ${details.export_consistency.length} stale import(s): ${details.export_consistency.map((v) => `${v.importedName} in ${v.file}`).join(', ')}`);
1073
+ }
1074
+ if (details && details.doc_staleness && details.doc_staleness.length > 0) {
1075
+ consistencyIssues.push(`- Resolve ${details.doc_staleness.length} doc staleness issue(s)`);
1076
+ }
1077
+ if (details && details.config_schema && details.config_schema.length > 0) {
1078
+ consistencyIssues.push(`- Fix ${details.config_schema.length} config schema drift(s)`);
1079
+ }
1080
+ if (consistencyIssues.length > 0) {
1081
+ tasks.push({
1082
+ name: 'Fix consistency and schema issues',
1083
+ items: consistencyIssues,
1084
+ });
1085
+ }
1086
+ // If no tasks were generated (shouldn't happen if total_issues > threshold), create a generic one
1087
+ if (tasks.length === 0) {
1088
+ tasks.push({
1089
+ name: 'Resolve quality issues',
1090
+ items: [
1091
+ `- Address ${qualityReport.summary.total_issues} quality issue(s) found during analysis`,
1092
+ ],
1093
+ });
1094
+ }
1095
+ // Build PLAN.md content
1096
+ const filesModifiedYaml = filesModified.map((f) => ` - "${f}"`).join('\n');
1097
+ const taskBlocks = tasks
1098
+ .map((t, i) => {
1099
+ return `<task type="auto">
1100
+ <name>Task ${i + 1}: ${t.name}</name>
1101
+ <files>${filesModified.join(', ')}</files>
1102
+ <action>
1103
+ ${t.items.join('\n')}
1104
+ </action>
1105
+ <verify>Run tests and verify issues are resolved.</verify>
1106
+ <done>${t.name} complete.</done>
1107
+ </task>`;
1108
+ })
1109
+ .join('\n\n');
1110
+ const planContent = `---
1111
+ phase: ${phaseSlug}
1112
+ plan: ${paddedPlan}
1113
+ type: execute
1114
+ wave: 1
1115
+ depends_on: []
1116
+ files_modified:
1117
+ ${filesModifiedYaml}
1118
+ autonomous: true
1119
+ verification_level: sanity
1120
+ cleanup_generated: true
1121
+ must_haves:
1122
+ truths:
1123
+ - "All auto-detected quality issues from phase ${phaseNum} completion are resolved"
1124
+ artifacts: []
1125
+ key_links: []
1126
+ ---
1127
+
1128
+ <objective>
1129
+ Auto-generated cleanup plan for ${qualityReport.summary.total_issues} quality issue(s) detected during phase ${phaseNum} completion.
1130
+ </objective>
1131
+
1132
+ <tasks>
1133
+
1134
+ ${taskBlocks}
1135
+
1136
+ </tasks>
1137
+
1138
+ <success_criteria>
1139
+ All quality issues from phase ${phaseNum} completion resolved.
1140
+ </success_criteria>
1141
+ `;
1142
+ // Write the plan file
1143
+ const normalized = String(phaseNum).padStart(2, '0');
1144
+ const planFileName = `${normalized}-${paddedPlan}-PLAN.md`;
1145
+ const planPath = path.join(phaseDir, planFileName);
1146
+ fs.writeFileSync(planPath, planContent, 'utf-8');
1147
+ return {
1148
+ path: path.relative(cwd, planPath),
1149
+ plan_number: paddedPlan,
1150
+ issues_addressed: qualityReport.summary.total_issues,
1151
+ };
1152
+ }
1153
+ // ─── Quality History & Trends ─────────────────────────────────────────────────
1154
+ const QUALITY_HISTORY_FILE = '.quality-history.json';
1155
+ /**
1156
+ * Load quality history from .planning/.quality-history.json.
1157
+ */
1158
+ function loadQualityHistory(cwd) {
1159
+ const historyPath = path.join(cwd, '.planning', QUALITY_HISTORY_FILE);
1160
+ try {
1161
+ const content = fs.readFileSync(historyPath, 'utf-8');
1162
+ return JSON.parse(content);
1163
+ }
1164
+ catch {
1165
+ return {};
1166
+ }
1167
+ }
1168
+ /**
1169
+ * Save quality metrics for a phase into .planning/.quality-history.json.
1170
+ * Accumulates entries across phases.
1171
+ */
1172
+ function saveQualityMetrics(cwd, phase, summary) {
1173
+ const history = loadQualityHistory(cwd);
1174
+ history[phase] = summary;
1175
+ const historyPath = path.join(cwd, '.planning', QUALITY_HISTORY_FILE);
1176
+ fs.writeFileSync(historyPath, JSON.stringify(history, null, 2), 'utf-8');
1177
+ }
1178
+ /**
1179
+ * Compute trends (deltas) between current and previous quality summaries.
1180
+ * Only compares numeric fields. Returns an object with delta and label for each field.
1181
+ */
1182
+ function computeTrends(current, previous, fromPhase) {
1183
+ const trends = {};
1184
+ for (const key of Object.keys(current)) {
1185
+ const currentVal = current[key];
1186
+ const previousVal = previous[key];
1187
+ if (typeof currentVal !== 'number' || typeof previousVal !== 'number')
1188
+ continue;
1189
+ const delta = currentVal - previousVal;
1190
+ let arrow = '';
1191
+ if (delta > 0)
1192
+ arrow = '\u2191'; // up arrow (regression for issues, improvement for scores)
1193
+ else if (delta < 0)
1194
+ arrow = '\u2193'; // down arrow
1195
+ trends[key] = {
1196
+ delta,
1197
+ label: `${arrow} ${delta >= 0 ? '+' : ''}${delta} from Phase ${fromPhase}`,
1198
+ };
1199
+ }
1200
+ return trends;
1201
+ }
1202
+ // ─── Exports ─────────────────────────────────────────────────────────────────
1203
+ module.exports = {
1204
+ getCleanupConfig,
1205
+ analyzeComplexity,
1206
+ analyzeDeadExports,
1207
+ analyzeFileSize,
1208
+ analyzeChangelogDrift,
1209
+ analyzeReadmeLinks,
1210
+ analyzeJsdocDrift,
1211
+ analyzeTestCoverageGaps,
1212
+ analyzeExportConsistency,
1213
+ analyzeDocStaleness,
1214
+ analyzeConfigSchemaDrift,
1215
+ runQualityAnalysis,
1216
+ generateCleanupPlan,
1217
+ resetCleanupCache,
1218
+ loadQualityHistory,
1219
+ saveQualityMetrics,
1220
+ computeTrends,
1221
+ };
1222
+ //# sourceMappingURL=cleanup.js.map