@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
package/lib/roadmap.ts ADDED
@@ -0,0 +1,775 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * GRD Roadmap Operations -- ROADMAP.md parsing, phase queries, schedule computation
5
+ *
6
+ * Extracted from bin/grd-tools.js during Phase 03 modularization.
7
+ * Depends on: lib/utils.ts (safeReadFile, normalizePhaseName, stripShippedSections, output, error)
8
+ * Depends on: lib/paths.ts (phasesDir)
9
+ * Depends on: lib/frontmatter.js (extractFrontmatter)
10
+ */
11
+
12
+
13
+ // Type-only import to establish module scope (no runtime effect)
14
+ import type {} from './types';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const {
19
+ safeReadFile,
20
+ safeReadMarkdown,
21
+ normalizePhaseName,
22
+ stripShippedSections,
23
+ output,
24
+ error,
25
+ } = require('./utils');
26
+ const { phasesDir: getPhasesDirPath } = require('./paths');
27
+
28
+ // ─── Types ──────────────────────────────────────────────────────────────────
29
+
30
+ /**
31
+ * Parsed milestone from ROADMAP.md with optional start/target dates.
32
+ */
33
+ interface ParsedMilestone {
34
+ version: string;
35
+ heading: string;
36
+ start: string | null;
37
+ target: string | null;
38
+ }
39
+
40
+ /**
41
+ * Internal milestone position for schedule computation.
42
+ */
43
+ interface MilestonePosition {
44
+ version: string;
45
+ heading: string;
46
+ index: number;
47
+ start: string | null;
48
+ }
49
+
50
+ /**
51
+ * A phase entry with schedule dates computed from milestone start + duration.
52
+ */
53
+ interface PhaseScheduleEntry {
54
+ number: string;
55
+ name: string;
56
+ duration_days: number;
57
+ milestone: string | null;
58
+ start_date: string | null;
59
+ due_date: string | null;
60
+ }
61
+
62
+ /**
63
+ * Internal phase parsed from ROADMAP.md before schedule computation.
64
+ */
65
+ interface ParsedPhase {
66
+ number: string;
67
+ name: string;
68
+ duration_days: number;
69
+ milestone: string | null;
70
+ start_date?: string | null;
71
+ due_date?: string | null;
72
+ }
73
+
74
+ /**
75
+ * Result of computeSchedule() with milestone and phase schedules.
76
+ */
77
+ interface ScheduleResult {
78
+ milestones: ParsedMilestone[];
79
+ phases: PhaseScheduleEntry[];
80
+ }
81
+
82
+ /**
83
+ * Milestone heading info returned by analyzeRoadmap.
84
+ */
85
+ interface AnalyzedMilestone {
86
+ heading: string;
87
+ version: string;
88
+ }
89
+
90
+ /**
91
+ * Phase analysis entry returned by analyzeRoadmap with disk status and metadata.
92
+ */
93
+ interface AnalyzedPhaseEntry {
94
+ number: string;
95
+ name: string;
96
+ goal: string | null;
97
+ depends_on: string | null;
98
+ plan_count: number;
99
+ summary_count: number;
100
+ has_context: boolean;
101
+ has_research: boolean;
102
+ disk_status: string;
103
+ roadmap_complete: boolean;
104
+ line: number;
105
+ warnings: string[];
106
+ duration_days: number;
107
+ start_date: string | null;
108
+ due_date: string | null;
109
+ _duration_days?: number;
110
+ _milestone?: string | null;
111
+ }
112
+
113
+ /**
114
+ * Full roadmap analysis result returned by analyzeRoadmap().
115
+ */
116
+ interface AnalyzedRoadmap {
117
+ error?: string;
118
+ milestones: AnalyzedMilestone[];
119
+ phases: AnalyzedPhaseEntry[];
120
+ phase_count: number;
121
+ completed_phases: number;
122
+ total_plans: number;
123
+ total_summaries: number;
124
+ progress_percent: number;
125
+ current_phase: string | null;
126
+ next_phase: string | null;
127
+ }
128
+
129
+ // ─── Schedule Helpers ───────────────────────────────────────────────────────
130
+
131
+ /**
132
+ * Format a Date object as a YYYY-MM-DD string.
133
+ * @param date - Date object to format
134
+ * @returns Date formatted as 'YYYY-MM-DD'
135
+ */
136
+ function formatScheduleDate(date: Date): string {
137
+ const y: number = date.getFullYear();
138
+ const m: string = String(date.getMonth() + 1).padStart(2, '0');
139
+ const d: string = String(date.getDate()).padStart(2, '0');
140
+ return `${y}-${m}-${d}`;
141
+ }
142
+
143
+ /**
144
+ * Add N days to a Date, returning a new Date object.
145
+ * @param date - Starting date
146
+ * @param days - Number of days to add
147
+ * @returns New Date object with the days added
148
+ */
149
+ function addDays(date: Date, days: number): Date {
150
+ const result = new Date(date);
151
+ result.setDate(result.getDate() + days);
152
+ return result;
153
+ }
154
+
155
+ /**
156
+ * Compute milestone and phase schedule from ROADMAP.md durations and start dates.
157
+ * @param cwd - Project working directory
158
+ * @returns Schedule with computed start/due dates per phase
159
+ */
160
+ function computeSchedule(cwd: string): ScheduleResult {
161
+ const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
162
+ const configPath: string = path.join(cwd, '.planning', 'config.json');
163
+ const roadmapContent: string | null = safeReadMarkdown(roadmapPath);
164
+ if (!roadmapContent) return { milestones: [], phases: [] };
165
+ const activeContent: string = stripShippedSections(roadmapContent);
166
+
167
+ // Read default_duration_days from config
168
+ let defaultDuration = 7;
169
+ const configRaw: string | null = safeReadFile(configPath);
170
+ if (configRaw) {
171
+ try {
172
+ const config = JSON.parse(configRaw) as Record<string, unknown>;
173
+ const tracker = config.tracker as Record<string, unknown> | undefined;
174
+ const mcp = tracker && (tracker.mcp_atlassian as Record<string, unknown> | undefined);
175
+ if (mcp && mcp.default_duration_days) {
176
+ defaultDuration = parseInt(String(mcp.default_duration_days), 10) || 7;
177
+ }
178
+ } catch {
179
+ // Invalid JSON config; use default duration
180
+ }
181
+ }
182
+
183
+ // Parse milestones with Start/Target dates
184
+ const milestoneRegex = /^##\s*(.*v(\d+\.\d+(?:\.\d+)?)[^(\n]*)/gim;
185
+ const milestones: ParsedMilestone[] = [];
186
+ const milestonePositions: MilestonePosition[] = [];
187
+ let mMatch: RegExpExecArray | null;
188
+ while ((mMatch = milestoneRegex.exec(activeContent)) !== null) {
189
+ const heading: string = mMatch[1].trim();
190
+ const version = 'v' + mMatch[2];
191
+ const afterHeading: string = activeContent.slice(mMatch.index, mMatch.index + 500);
192
+ const startMatch: RegExpMatchArray | null = afterHeading.match(
193
+ /\*\*Start:\*\*\s*(\d{4}-\d{2}-\d{2})/
194
+ );
195
+ const targetMatch: RegExpMatchArray | null = afterHeading.match(
196
+ /\*\*Target:\*\*\s*(\d{4}-\d{2}-\d{2})/
197
+ );
198
+ milestones.push({
199
+ version,
200
+ heading,
201
+ start: startMatch ? startMatch[1] : null,
202
+ target: targetMatch ? targetMatch[1] : null,
203
+ });
204
+ milestonePositions.push({
205
+ version,
206
+ heading,
207
+ index: mMatch.index,
208
+ start: startMatch ? startMatch[1] : null,
209
+ });
210
+ }
211
+
212
+ // Parse phases with Duration
213
+ const phaseRegex = /#{2,}\s*Phase\s+(\d+(?:\.\d+)?)\s*:\s*([^\n]+)/gi;
214
+ const phases: ParsedPhase[] = [];
215
+ let pMatch: RegExpExecArray | null;
216
+ while ((pMatch = phaseRegex.exec(activeContent)) !== null) {
217
+ const number: string = pMatch[1];
218
+ const name: string = pMatch[2].replace(/\(INSERTED\)/i, '').trim();
219
+ // Extract section text up to the next heading (or end of content).
220
+ // Use [ \t] instead of \s so we don't accidentally match \n##\n sequences.
221
+ const sectionStart: number = pMatch.index;
222
+ const restContent: string = activeContent.slice(sectionStart + pMatch[0].length);
223
+ const nextHeading: RegExpMatchArray | null = restContent.match(/\n#{2,}[ \t]/);
224
+ const sectionText: string = nextHeading
225
+ ? activeContent.slice(
226
+ sectionStart,
227
+ sectionStart + pMatch[0].length + (nextHeading.index as number)
228
+ )
229
+ : activeContent.slice(sectionStart);
230
+ const durationMatch: RegExpMatchArray | null = sectionText.match(/\*\*Duration:\*\*\s*(\d+)d/);
231
+ const durationDays: number = durationMatch ? parseInt(durationMatch[1], 10) : defaultDuration;
232
+
233
+ // Determine milestone
234
+ let milestone: string | null =
235
+ milestonePositions.length > 0 ? milestonePositions[0].version : null;
236
+ for (const ms of milestonePositions) {
237
+ if (pMatch.index > ms.index) milestone = ms.version;
238
+ }
239
+
240
+ phases.push({ number, name, duration_days: durationDays, milestone });
241
+ }
242
+
243
+ // Compute dates per milestone group
244
+ const milestoneStartMap: Record<string, string> = {};
245
+ for (const ms of milestonePositions) {
246
+ if (ms.start) milestoneStartMap[ms.version] = ms.start;
247
+ }
248
+
249
+ let currentDate: Date | null = null;
250
+ let currentMilestone: string | null = null;
251
+ for (const phase of phases) {
252
+ if (phase.milestone !== currentMilestone) {
253
+ currentMilestone = phase.milestone;
254
+ const msStart: string | undefined = currentMilestone
255
+ ? milestoneStartMap[currentMilestone]
256
+ : undefined;
257
+ currentDate = msStart ? new Date(msStart + 'T00:00:00') : null;
258
+ }
259
+ if (currentDate) {
260
+ phase.start_date = formatScheduleDate(currentDate);
261
+ const endDate: Date = addDays(currentDate, phase.duration_days - 1);
262
+ phase.due_date = formatScheduleDate(endDate);
263
+ currentDate = addDays(endDate, 1); // next phase starts day after
264
+ } else {
265
+ phase.start_date = null;
266
+ phase.due_date = null;
267
+ }
268
+ }
269
+
270
+ return {
271
+ milestones,
272
+ phases: phases as PhaseScheduleEntry[],
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Look up a phase schedule entry by phase number.
278
+ * @param schedule - Schedule object from computeSchedule
279
+ * @param phaseNum - Phase number to look up
280
+ * @returns Phase schedule entry with start_date, due_date, duration_days, or null
281
+ */
282
+ function getScheduleForPhase(
283
+ schedule: ScheduleResult,
284
+ phaseNum: string | number
285
+ ): PhaseScheduleEntry | null {
286
+ const num: string = String(phaseNum);
287
+ return schedule.phases.find((p: PhaseScheduleEntry) => p.number === num) || null;
288
+ }
289
+
290
+ /**
291
+ * Look up a milestone schedule entry by version string.
292
+ * @param schedule - Schedule object from computeSchedule
293
+ * @param version - Milestone version to look up (e.g., 'v1.0')
294
+ * @returns Milestone schedule entry with start and target dates, or null
295
+ */
296
+ function getScheduleForMilestone(
297
+ schedule: ScheduleResult,
298
+ version: string
299
+ ): ParsedMilestone | null {
300
+ return schedule.milestones.find((m: ParsedMilestone) => m.version === version) || null;
301
+ }
302
+
303
+ // ─── Roadmap Commands ───────────────────────────────────────────────────────
304
+
305
+ /**
306
+ * CLI command: Get phase info (name, goal, full section text) from ROADMAP.md.
307
+ * @param cwd - Project working directory
308
+ * @param phaseNum - Phase number to look up
309
+ * @param raw - Output raw section text instead of JSON
310
+ */
311
+ function cmdRoadmapGetPhase(cwd: string, phaseNum: string, raw: boolean): void {
312
+ const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
313
+
314
+ if (!fs.existsSync(roadmapPath)) {
315
+ output({ found: false, error: 'ROADMAP.md not found' }, raw, '');
316
+ return;
317
+ }
318
+
319
+ try {
320
+ const content: string | null = safeReadMarkdown(roadmapPath);
321
+ if (!content) {
322
+ output({ found: false, error: 'ROADMAP.md could not be read' }, raw, '');
323
+ return;
324
+ }
325
+ const activeContent: string = stripShippedSections(content);
326
+
327
+ // Escape special regex chars in phase number, handle decimal
328
+ const escapedPhase: string = phaseNum.replace(/\./g, '\\.');
329
+
330
+ // Match "## Phase X:" or "### Phase X.Y:" with optional name
331
+ const phasePattern = new RegExp(`#{2,}\\s*Phase\\s+${escapedPhase}:\\s*([^\\n]+)`, 'i');
332
+ const headerMatch: RegExpMatchArray | null = activeContent.match(phasePattern);
333
+
334
+ if (!headerMatch) {
335
+ output({ found: false, phase_number: phaseNum }, raw, '');
336
+ return;
337
+ }
338
+
339
+ const phaseName: string = headerMatch[1].trim();
340
+ const headerIndex: number = headerMatch.index as number;
341
+
342
+ // Find the end of this section (next ### or end of file)
343
+ const restOfContent: string = activeContent.slice(headerIndex);
344
+ const nextHeaderMatch: RegExpMatchArray | null = restOfContent.match(/\n#{2,}\s+Phase\s+\d/i);
345
+ const sectionEnd: number = nextHeaderMatch
346
+ ? headerIndex + (nextHeaderMatch.index as number)
347
+ : activeContent.length;
348
+
349
+ const section: string = activeContent.slice(headerIndex, sectionEnd).trim();
350
+
351
+ // Extract goal if present
352
+ const goalMatch: RegExpMatchArray | null = section.match(/\*\*Goal:?\*\*:?\s*([^\n]+)/i);
353
+ const goal: string | null = goalMatch ? goalMatch[1].trim() : null;
354
+
355
+ output(
356
+ {
357
+ found: true,
358
+ phase_number: phaseNum,
359
+ phase_name: phaseName,
360
+ goal,
361
+ section,
362
+ },
363
+ raw,
364
+ section
365
+ );
366
+ } catch (e: unknown) {
367
+ error('Failed to read ROADMAP.md: ' + (e as Error).message);
368
+ }
369
+ }
370
+
371
+ // ─── Phase Next Decimal ─────────────────────────────────────────────────────
372
+
373
+ /**
374
+ * CLI command: Compute the next available decimal phase number for insertion.
375
+ * @param cwd - Project working directory
376
+ * @param basePhase - Base phase number to find next decimal for (e.g., '06')
377
+ * @param raw - Output raw next decimal string instead of JSON
378
+ */
379
+ function cmdPhaseNextDecimal(cwd: string, basePhase: string, raw: boolean): void {
380
+ const phasesDir: string = getPhasesDirPath(cwd);
381
+ const normalized: string = normalizePhaseName(basePhase);
382
+
383
+ // Check if phases directory exists
384
+ if (!fs.existsSync(phasesDir)) {
385
+ output(
386
+ {
387
+ found: false,
388
+ base_phase: normalized,
389
+ next: `${normalized}.1`,
390
+ existing: [],
391
+ },
392
+ raw,
393
+ `${normalized}.1`
394
+ );
395
+ return;
396
+ }
397
+
398
+ try {
399
+ const entries: Array<{ isDirectory: () => boolean; name: string }> = fs.readdirSync(phasesDir, {
400
+ withFileTypes: true,
401
+ });
402
+ const dirs: string[] = entries
403
+ .filter((e: { isDirectory: () => boolean }) => e.isDirectory())
404
+ .map((e: { name: string }) => e.name);
405
+
406
+ // Check if base phase exists
407
+ const baseExists: boolean = dirs.some(
408
+ (d: string) => d.startsWith(normalized + '-') || d === normalized
409
+ );
410
+
411
+ // Find existing decimal phases for this base
412
+ const decimalPattern = new RegExp(`^${normalized}\\.(\\d+)`);
413
+ const existingDecimals: string[] = [];
414
+
415
+ for (const dir of dirs) {
416
+ const match: RegExpMatchArray | null = dir.match(decimalPattern);
417
+ if (match) {
418
+ existingDecimals.push(`${normalized}.${match[1]}`);
419
+ }
420
+ }
421
+
422
+ // Sort numerically
423
+ existingDecimals.sort((a: string, b: string) => {
424
+ const aNum: number = parseFloat(a);
425
+ const bNum: number = parseFloat(b);
426
+ return aNum - bNum;
427
+ });
428
+
429
+ // Calculate next decimal
430
+ let nextDecimal: string;
431
+ if (existingDecimals.length === 0) {
432
+ nextDecimal = `${normalized}.1`;
433
+ } else {
434
+ const lastDecimal: string = existingDecimals[existingDecimals.length - 1];
435
+ const lastNum: number = parseInt(lastDecimal.split('.')[1], 10);
436
+ nextDecimal = `${normalized}.${lastNum + 1}`;
437
+ }
438
+
439
+ output(
440
+ {
441
+ found: baseExists,
442
+ base_phase: normalized,
443
+ next: nextDecimal,
444
+ existing: existingDecimals,
445
+ },
446
+ raw,
447
+ nextDecimal
448
+ );
449
+ } catch (e: unknown) {
450
+ error('Failed to calculate next decimal phase: ' + (e as Error).message);
451
+ }
452
+ }
453
+
454
+ // ─── Roadmap Analyze ────────────────────────────────────────────────────────
455
+
456
+ /**
457
+ * Analyze the full roadmap structure with disk status, schedule, and progress.
458
+ * Returns the result object directly without calling output() or process.exit().
459
+ * Used internally by cmdRoadmapAnalyze and by dependency analysis (lib/deps.js).
460
+ * @param cwd - Project working directory
461
+ * @returns Roadmap analysis with milestones, phases, progress, etc.
462
+ */
463
+ function analyzeRoadmap(cwd: string): AnalyzedRoadmap {
464
+ const roadmapPath: string = path.join(cwd, '.planning', 'ROADMAP.md');
465
+
466
+ if (!fs.existsSync(roadmapPath)) {
467
+ return {
468
+ error: 'ROADMAP.md not found',
469
+ milestones: [],
470
+ phases: [],
471
+ phase_count: 0,
472
+ completed_phases: 0,
473
+ total_plans: 0,
474
+ total_summaries: 0,
475
+ progress_percent: 0,
476
+ current_phase: null,
477
+ next_phase: null,
478
+ };
479
+ }
480
+
481
+ const content: string | null = safeReadMarkdown(roadmapPath);
482
+ if (!content) {
483
+ return {
484
+ error: 'ROADMAP.md could not be read',
485
+ milestones: [],
486
+ phases: [],
487
+ phase_count: 0,
488
+ completed_phases: 0,
489
+ total_plans: 0,
490
+ total_summaries: 0,
491
+ progress_percent: 0,
492
+ current_phase: null,
493
+ next_phase: null,
494
+ };
495
+ }
496
+ const activeContent: string = stripShippedSections(content);
497
+ const phasesDir: string = getPhasesDirPath(cwd);
498
+
499
+ // Read default_duration_days from config (same logic as computeSchedule, no re-read needed).
500
+ let defaultDuration = 7;
501
+ const configPath: string = path.join(cwd, '.planning', 'config.json');
502
+ const configRaw: string | null = safeReadFile(configPath);
503
+ if (configRaw) {
504
+ try {
505
+ const config = JSON.parse(configRaw) as Record<string, unknown>;
506
+ const tracker = config.tracker as Record<string, unknown> | undefined;
507
+ const mcp = tracker && (tracker.mcp_atlassian as Record<string, unknown> | undefined);
508
+ if (mcp && mcp.default_duration_days) {
509
+ defaultDuration = parseInt(String(mcp.default_duration_days), 10) || 7;
510
+ }
511
+ } catch {
512
+ // Invalid JSON config; use default duration
513
+ }
514
+ }
515
+
516
+ // Parse milestone positions with Start dates from activeContent (already in memory).
517
+ const milestoneRegexLocal = /^##\s*(.*v(\d+\.\d+(?:\.\d+)?)[^(\n]*)/gim;
518
+ const milestonePositions: MilestonePosition[] = [];
519
+ let mMatchLocal: RegExpExecArray | null;
520
+ while ((mMatchLocal = milestoneRegexLocal.exec(activeContent)) !== null) {
521
+ const version = 'v' + mMatchLocal[2];
522
+ const heading: string = mMatchLocal[1].trim();
523
+ const afterHeading: string = activeContent.slice(mMatchLocal.index, mMatchLocal.index + 500);
524
+ const startMatch: RegExpMatchArray | null = afterHeading.match(
525
+ /\*\*Start:\*\*\s*(\d{4}-\d{2}-\d{2})/
526
+ );
527
+ milestonePositions.push({
528
+ version,
529
+ heading,
530
+ index: mMatchLocal.index,
531
+ start: startMatch ? startMatch[1] : null,
532
+ });
533
+ }
534
+
535
+ // Read phases directory once before the loop to avoid N repeated readdirSync calls.
536
+ let phasesDirNames: string[] = [];
537
+ try {
538
+ const phasesDirEntries: Array<{ isDirectory: () => boolean; name: string }> = fs.readdirSync(
539
+ phasesDir,
540
+ { withFileTypes: true }
541
+ );
542
+ phasesDirNames = phasesDirEntries
543
+ .filter((e: { isDirectory: () => boolean }) => e.isDirectory())
544
+ .map((e: { name: string }) => e.name);
545
+ } catch (dirErr: unknown) {
546
+ const err = dirErr as { code?: string; message?: string } | null;
547
+ if (err && err.code && err.code !== 'ENOENT') {
548
+ process.stderr.write(`[roadmap] phases directory read error (${err.code}): ${err.message}\n`);
549
+ }
550
+ }
551
+
552
+ // Extract all phase headings: ## Phase N: Name or ### Phase N: Name
553
+ const phasePattern = /#{2,}\s*Phase\s+(\d+(?:\.\d+)?)\s*:\s*([^\n]+)/gi;
554
+ const phases: AnalyzedPhaseEntry[] = [];
555
+ let match: RegExpExecArray | null;
556
+
557
+ while ((match = phasePattern.exec(activeContent)) !== null) {
558
+ const phaseNum: string = match[1];
559
+ const phaseName: string = match[2].replace(/\(INSERTED\)/i, '').trim();
560
+
561
+ // Compute line number of heading in ROADMAP.md
562
+ const lineNumber: number = activeContent.substring(0, match.index).split('\n').length;
563
+
564
+ // Extract goal from the section
565
+ const sectionStart: number = match.index;
566
+ const restOfContent: string = activeContent.slice(sectionStart);
567
+ const nextHeader: RegExpMatchArray | null = restOfContent.match(/\n#{2,}\s+Phase\s+\d/i);
568
+ const sectionEnd: number = nextHeader
569
+ ? sectionStart + (nextHeader.index as number)
570
+ : activeContent.length;
571
+ const section: string = activeContent.slice(sectionStart, sectionEnd);
572
+
573
+ const goalMatch: RegExpMatchArray | null = section.match(/\*\*Goal:?\*\*:?\s*([^\n]+)/i);
574
+ const goal: string | null = goalMatch ? goalMatch[1].trim() : null;
575
+
576
+ const dependsMatch: RegExpMatchArray | null = section.match(
577
+ /\*\*Depends on:?\*\*:?\s*([^\n]+)/i
578
+ );
579
+ const depends_on: string | null = dependsMatch ? dependsMatch[1].trim() : null;
580
+
581
+ // Extract duration for schedule computation (reuse the already-sliced section text).
582
+ const durationMatch: RegExpMatchArray | null = section.match(/\*\*Duration:\*\*\s*(\d+)d/);
583
+ const durationDays: number = durationMatch ? parseInt(durationMatch[1], 10) : defaultDuration;
584
+
585
+ // Determine which milestone this phase belongs to.
586
+ let phaseMilestone: string | null =
587
+ milestonePositions.length > 0 ? milestonePositions[0].version : null;
588
+ for (const ms of milestonePositions) {
589
+ if (match.index > ms.index) phaseMilestone = ms.version;
590
+ }
591
+
592
+ // Build warnings array
593
+ const warnings: string[] = [];
594
+ if (!goal) {
595
+ warnings.push(`Phase ${phaseNum} (line ${lineNumber}): missing goal`);
596
+ }
597
+
598
+ // Check completion on disk
599
+ const normalized: string = normalizePhaseName(phaseNum);
600
+ let diskStatus = 'no_directory';
601
+ let planCount = 0;
602
+ let summaryCount = 0;
603
+ let hasContext = false;
604
+ let hasResearch = false;
605
+
606
+ try {
607
+ const dirMatch: string | undefined = phasesDirNames.find(
608
+ (d: string) => d.startsWith(normalized + '-') || d === normalized
609
+ );
610
+
611
+ if (dirMatch) {
612
+ const phaseFiles: string[] = fs.readdirSync(path.join(phasesDir, dirMatch));
613
+ planCount = phaseFiles.filter(
614
+ (f: string) => f.endsWith('-PLAN.md') || f === 'PLAN.md'
615
+ ).length;
616
+ summaryCount = phaseFiles.filter(
617
+ (f: string) => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md'
618
+ ).length;
619
+ hasContext = phaseFiles.some(
620
+ (f: string) => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md'
621
+ );
622
+ hasResearch = phaseFiles.some(
623
+ (f: string) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md'
624
+ );
625
+
626
+ if (summaryCount >= planCount && planCount > 0) diskStatus = 'complete';
627
+ else if (summaryCount > 0) diskStatus = 'partial';
628
+ else if (planCount > 0) diskStatus = 'planned';
629
+ else if (hasResearch) diskStatus = 'researched';
630
+ else if (hasContext) diskStatus = 'discussed';
631
+ else diskStatus = 'empty';
632
+ }
633
+ } catch (scanErr: unknown) {
634
+ const err = scanErr as { code?: string; message?: string } | null;
635
+ if (err && err.code && err.code !== 'ENOENT') {
636
+ process.stderr.write(
637
+ `[roadmap] phase directory scan error (${err.code}): ${err.message}\n`
638
+ );
639
+ }
640
+ }
641
+
642
+ // Check ROADMAP checkbox status
643
+ const checkboxPattern = new RegExp(
644
+ `-\\s*\\[(x| )\\]\\s*.*Phase\\s+${phaseNum.replace('.', '\\.')}`,
645
+ 'i'
646
+ );
647
+ const checkboxMatch: RegExpMatchArray | null = activeContent.match(checkboxPattern);
648
+ const roadmapComplete: boolean = checkboxMatch ? checkboxMatch[1] === 'x' : false;
649
+
650
+ phases.push({
651
+ number: phaseNum,
652
+ name: phaseName,
653
+ goal,
654
+ depends_on,
655
+ plan_count: planCount,
656
+ summary_count: summaryCount,
657
+ has_context: hasContext,
658
+ has_research: hasResearch,
659
+ disk_status: diskStatus,
660
+ roadmap_complete: roadmapComplete,
661
+ line: lineNumber,
662
+ warnings,
663
+ _duration_days: durationDays,
664
+ _milestone: phaseMilestone,
665
+ duration_days: durationDays,
666
+ start_date: null,
667
+ due_date: null,
668
+ });
669
+ }
670
+
671
+ // Build milestones array from already-parsed positions -- no second regex pass needed.
672
+ // Only heading and version to preserve the original analyzeRoadmap output shape.
673
+ const milestones: AnalyzedMilestone[] = milestonePositions.map((ms: MilestonePosition) => ({
674
+ heading: ms.heading,
675
+ version: ms.version,
676
+ }));
677
+
678
+ // Compute dates inline using already-parsed milestone positions -- no second parse needed.
679
+ const milestoneStartMap: Record<string, string> = {};
680
+ for (const ms of milestonePositions) {
681
+ if (ms.start) milestoneStartMap[ms.version] = ms.start;
682
+ }
683
+ let currentDate: Date | null = null;
684
+ let currentMilestone: string | null = null;
685
+ for (const phase of phases) {
686
+ if (phase._milestone !== currentMilestone) {
687
+ currentMilestone = phase._milestone ?? null;
688
+ const msStart: string | undefined = currentMilestone
689
+ ? milestoneStartMap[currentMilestone]
690
+ : undefined;
691
+ currentDate = msStart ? new Date(msStart + 'T00:00:00') : null;
692
+ }
693
+ phase.duration_days = phase._duration_days as number;
694
+ if (currentDate) {
695
+ phase.start_date = formatScheduleDate(currentDate);
696
+ const endDate: Date = addDays(currentDate, phase._duration_days as number);
697
+ phase.due_date = formatScheduleDate(endDate);
698
+ currentDate = addDays(endDate, 1);
699
+ } else {
700
+ phase.start_date = null;
701
+ phase.due_date = null;
702
+ }
703
+ delete phase._duration_days;
704
+ delete phase._milestone;
705
+ }
706
+
707
+ // Find current and next phase
708
+ const currentPhaseEntry: AnalyzedPhaseEntry | undefined = phases.find(
709
+ (p: AnalyzedPhaseEntry) => p.disk_status === 'planned' || p.disk_status === 'partial'
710
+ );
711
+ const nextPhase: AnalyzedPhaseEntry | undefined = phases.find(
712
+ (p: AnalyzedPhaseEntry) =>
713
+ p.disk_status === 'empty' ||
714
+ p.disk_status === 'no_directory' ||
715
+ p.disk_status === 'discussed' ||
716
+ p.disk_status === 'researched'
717
+ );
718
+
719
+ // Aggregated stats
720
+ const totalPlans: number = phases.reduce(
721
+ (sum: number, p: AnalyzedPhaseEntry) => sum + p.plan_count,
722
+ 0
723
+ );
724
+ const totalSummaries: number = phases.reduce(
725
+ (sum: number, p: AnalyzedPhaseEntry) => sum + p.summary_count,
726
+ 0
727
+ );
728
+ const completedPhases: number = phases.filter(
729
+ (p: AnalyzedPhaseEntry) => p.disk_status === 'complete'
730
+ ).length;
731
+
732
+ return {
733
+ milestones,
734
+ phases,
735
+ phase_count: phases.length,
736
+ completed_phases: completedPhases,
737
+ total_plans: totalPlans,
738
+ total_summaries: totalSummaries,
739
+ progress_percent: totalPlans > 0 ? Math.round((totalSummaries / totalPlans) * 100) : 0,
740
+ current_phase: currentPhaseEntry ? currentPhaseEntry.number : null,
741
+ next_phase: nextPhase ? nextPhase.number : null,
742
+ };
743
+ }
744
+
745
+ /**
746
+ * CLI command: Analyze the full roadmap structure with disk status, schedule, and progress.
747
+ * Thin wrapper around analyzeRoadmap that outputs the result via output().
748
+ * @param cwd - Project working directory
749
+ * @param raw - Output raw text instead of JSON
750
+ */
751
+ function cmdRoadmapAnalyze(cwd: string, raw: boolean): void {
752
+ const result: AnalyzedRoadmap = analyzeRoadmap(cwd);
753
+ output(
754
+ result,
755
+ raw,
756
+ `${result.phase_count} phases, ${result.completed_phases} complete, ${result.progress_percent}% done`
757
+ );
758
+ }
759
+
760
+ // ─── Exports ────────────────────────────────────────────────────────────────
761
+
762
+ module.exports = {
763
+ // Schedule helpers (used by tracker code too)
764
+ formatScheduleDate,
765
+ addDays,
766
+ computeSchedule,
767
+ getScheduleForPhase,
768
+ getScheduleForMilestone,
769
+ // Roadmap commands
770
+ cmdRoadmapGetPhase,
771
+ cmdPhaseNextDecimal,
772
+ cmdRoadmapAnalyze,
773
+ // Internal (used by lib/deps.js)
774
+ analyzeRoadmap,
775
+ };