@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,1314 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const childProcess = require('child_process');
6
+ const { loadConfig, findPhaseInternal, output, getMilestoneInfo, MODEL_PROFILES, resolveModelForAgent, } = require('./utils');
7
+ const { detectBackend, getBackendCapabilities, getEffectiveTierForDispatch, } = require('./backend');
8
+ const { isOntologyConverged, } = require('./drift');
9
+ const { analyzeRoadmap, } = require('./roadmap');
10
+ const { parseLongTermRoadmap, } = require('./long-term-roadmap');
11
+ const { createScheduler, resolveAccount, } = require('./scheduler');
12
+ const { slingPlanAsync, loadOverstoryConfig, generateOverlay, } = require('./overstory');
13
+ const { worktreePath: getWorktreePath, worktreeBranch: getWorktreeBranch, ensureWorktreesDir, } = require('./worktree');
14
+ const { execGit, } = require('./utils');
15
+ const { buildKnowledgeInjectionBlock, } = require('./knowledge');
16
+ const { createMergeQueue, parseWriteIntent, compareWriteIntent, formatWriteIntentMismatch, buildWaves, buildWavesFromPlans, } = require('./autopilot-waves');
17
+ const { isMilestoneComplete, resolveNextMilestone, buildNewMilestonePrompt, buildMilestoneCompletePrompt, } = require('./autopilot-milestone');
18
+ const { selectCandidate, } = require('./commands/select-candidate');
19
+ const { toSpawnResult, spawnClaude, spawnClaudeAsync, writeStatusMarker, updateStateProgress, buildSimplifyPrompt, buildCodeReviewPrompt, buildConflictResolvePrompt, buildKnowledgeMiningPrompt, buildCritiqueAgentPrompt, runKnowledgeMining, runRefinementLoop, runPostPhasePipeline, finalizePhaseAfterPipeline, } = require('./autopilot-pipeline');
20
+ // ─── Default Constants ──────────────────────────────────────────────────────
21
+ const DEFAULT_TIMEOUT_MINUTES = 120;
22
+ const HEARTBEAT_INTERVAL_MS = 30000;
23
+ /**
24
+ * Codex r44 P1 #6: invoke handleSpinEvent when the scheduler detected a
25
+ * spinning subprocess. `spawnStep` (lib/autopilot-pipeline.ts) already
26
+ * does this for post-pipeline steps, but the main autopilot plan and
27
+ * execute calls go through `scheduler.spawn` directly and previously
28
+ * dropped the event. Helper de-duplicates the wiring so every direct
29
+ * scheduler.spawn caller surfaces SPIN-REPORT.md.
30
+ */
31
+ function _handleSpinIfDetected(cwd, phaseNum, result) {
32
+ if (!result.spinEvent || !result.spinEvent.detected)
33
+ return;
34
+ try {
35
+ const info = findPhaseInternal(cwd, phaseNum);
36
+ const phaseDir = info && info.found ? require('path').join(cwd, info.directory) : cwd;
37
+ handleSpinEvent(phaseDir, result.spinEvent, `phase-${phaseNum}`);
38
+ }
39
+ catch {
40
+ /* spin handling is best-effort */
41
+ }
42
+ }
43
+ // ─── Scheduler State Helpers ────────────────────────────────────────────────
44
+ /**
45
+ * Build a states map from the scheduler for use with resolveAccount().
46
+ * Enumerates all configured account state keys and queries the scheduler
47
+ * for each, collecting only those that exist.
48
+ */
49
+ function _getSchedulerStates(scheduler, schedulerConfig, superpowersConfig) {
50
+ const states = new Map();
51
+ const accounts = superpowersConfig.accounts;
52
+ const allBackends = new Set([
53
+ ...schedulerConfig.backend_priority,
54
+ schedulerConfig.free_fallback.backend,
55
+ ]);
56
+ for (const backend of allBackends) {
57
+ const backendAccounts = accounts[backend];
58
+ if (!backendAccounts || backendAccounts.length === 0)
59
+ continue;
60
+ for (const account of backendAccounts) {
61
+ const stateKey = `${backend}/${account.config_dir}`;
62
+ const state = scheduler.getState(stateKey);
63
+ if (state) {
64
+ states.set(stateKey, state);
65
+ }
66
+ }
67
+ }
68
+ // Also check the fallback backend with no config_dir
69
+ const fallbackState = scheduler.getState(schedulerConfig.free_fallback.backend);
70
+ if (fallbackState) {
71
+ states.set(schedulerConfig.free_fallback.backend, fallbackState);
72
+ }
73
+ // Check default_backend with no config_dir
74
+ const defaultBackend = superpowersConfig.default_backend;
75
+ const defaultState = scheduler.getState(defaultBackend);
76
+ if (defaultState) {
77
+ states.set(defaultBackend, defaultState);
78
+ }
79
+ return states;
80
+ }
81
+ // ─── Pure Helper Functions ──────────────────────────────────────────────────
82
+ /**
83
+ * Resolve the range of phases to process from ROADMAP.md.
84
+ */
85
+ function resolvePhaseRange(cwd, from, to) {
86
+ const analysis = analyzeRoadmap(cwd);
87
+ if (analysis.error) {
88
+ return { phases: [], error: analysis.error };
89
+ }
90
+ let phases = analysis.phases;
91
+ if (!phases || phases.length === 0) {
92
+ return { phases: [], error: 'No phases found in ROADMAP.md' };
93
+ }
94
+ // Filter to range
95
+ if (from) {
96
+ const fromNum = parseFloat(from);
97
+ phases = phases.filter((p) => parseFloat(p.number) >= fromNum);
98
+ }
99
+ if (to) {
100
+ const toNum = parseFloat(to);
101
+ phases = phases.filter((p) => parseFloat(p.number) <= toNum);
102
+ }
103
+ if (phases.length === 0) {
104
+ return { phases: [], error: `No phases found in range ${from || 'start'}..${to || 'end'}` };
105
+ }
106
+ return {
107
+ phases: phases.map((p) => ({
108
+ number: p.number,
109
+ name: p.name,
110
+ disk_status: p.disk_status || 'unknown',
111
+ depends_on: p.depends_on,
112
+ })),
113
+ error: null,
114
+ };
115
+ }
116
+ /**
117
+ * Check if a phase has been planned (used for auto-resume skip logic).
118
+ */
119
+ function isPhasePlanned(cwd, phaseNum) {
120
+ const info = findPhaseInternal(cwd, phaseNum);
121
+ if (!info)
122
+ return false;
123
+ return info.plans.length > 0;
124
+ }
125
+ /**
126
+ * Check if a phase has been fully executed (used for auto-resume skip logic).
127
+ */
128
+ function isPhaseExecuted(cwd, phaseNum) {
129
+ const info = findPhaseInternal(cwd, phaseNum);
130
+ if (!info)
131
+ return false;
132
+ return info.plans.length > 0 && info.incomplete_plans.length === 0;
133
+ }
134
+ /**
135
+ * v0.4 Phase 2 gate: detect when a phase has multiple PLAN candidates
136
+ * (PLAN-1.md ... PLAN-N.md) instead of a single resolved PLAN.md.
137
+ *
138
+ * Multi-candidate phases are NOT yet runnable by execute-phase — Phase 3's
139
+ * deterministic selector picks one and renames it to PLAN.md before
140
+ * execution can proceed. Until Phase 3 lands, this gate logs and skips
141
+ * execution; an operator must select manually.
142
+ */
143
+ function hasMultipleCandidates(cwd, phaseNum) {
144
+ const info = findPhaseInternal(cwd, phaseNum);
145
+ if (!info)
146
+ return false;
147
+ // Phase has PLAN-N.md candidates AND no resolved bare PLAN.md.
148
+ const candidateRe = /^PLAN-\d+\.md$/;
149
+ let candidateCount = 0;
150
+ let hasResolvedPlan = false;
151
+ for (const filename of info.plans) {
152
+ if (candidateRe.test(filename))
153
+ candidateCount++;
154
+ if (filename === 'PLAN.md')
155
+ hasResolvedPlan = true;
156
+ }
157
+ return candidateCount >= 2 && !hasResolvedPlan;
158
+ }
159
+ /**
160
+ * Prepend "ultrathink" keyword when the backend supports the effort capability.
161
+ */
162
+ function withUltrathink(prompt, backend) {
163
+ if (backend && getBackendCapabilities(backend).effort) {
164
+ return `ultrathink\n\n${prompt}`;
165
+ }
166
+ return prompt;
167
+ }
168
+ /**
169
+ * Build the prompt for planning a phase via `claude -p`.
170
+ */
171
+ function buildPlanPrompt(phaseNum, backend, cwd) {
172
+ const basePrompt = `Use the Skill tool to invoke skill "grd:plan-phase" with args "${phaseNum}" (i.e. plan-phase ${phaseNum}). Autonomous mode — make all decisions yourself, no questions. Complete all planning steps and write the PLAN.md files. Ensure each PLAN.md includes a \`files_modified:\` field in its YAML frontmatter listing the lib/ modules and other files the plan expects to modify. Each PLAN.md MUST also include \`provides: []\`, \`requires: []\`, and \`integration_points: []\` in YAML frontmatter. \`provides\` lists artifact identifiers this plan creates (format: "module:ExportName", e.g., "lib/deps.ts:buildArtifactDAG"). \`requires\` lists artifacts from other plans that must exist before this plan executes. \`integration_points\` lists artifacts this plan connects to but does not strictly depend on.`;
173
+ const knowhowBlock = cwd ? buildKnowledgeInjectionBlock(cwd, phaseNum) : '';
174
+ return withUltrathink(knowhowBlock ? `${knowhowBlock}\n\n${basePrompt}` : basePrompt, backend);
175
+ }
176
+ /**
177
+ * Build the prompt for executing a phase via `claude -p`.
178
+ */
179
+ function buildExecutePrompt(phaseNum, cwd) {
180
+ const basePrompt = `Use the Skill tool to invoke skill "grd:execute-phase" with args "${phaseNum}" (i.e. execute-phase ${phaseNum}). Autonomous mode — make all decisions yourself, no questions. After execution, merge locally. Do not push.`;
181
+ const knowhowBlock = cwd ? buildKnowledgeInjectionBlock(cwd, phaseNum) : '';
182
+ return knowhowBlock ? `${knowhowBlock}\n\n${basePrompt}` : basePrompt;
183
+ }
184
+ /** Wireup discovery after milestone completion. */
185
+ function buildWireupPrompt() {
186
+ return 'Use the Skill tool to invoke skill "grd:wireup" with no additional args. Autonomous mode — make all decisions yourself, no questions. Run wireup discovery (exported-but-uncalled, config-without-surface, endpoint-without-integration-test) and fix any findings.';
187
+ }
188
+ // ─── Main Loop ──────────────────────────────────────────────────────────────
189
+ /**
190
+ * Run the autopilot loop over a range of phases, grouped by dependency waves.
191
+ * Independent phases are planned in parallel; execution is always sequential.
192
+ */
193
+ async function runAutopilot(cwd, options = {}) {
194
+ const { phaseFrom = null, phaseTo = null, dryRun = false, skipPlan = false, skipExecute = false, skipPostPipeline = false, timeout, maxTurns, model, } = options;
195
+ const { phases, error: rangeError } = resolvePhaseRange(cwd, phaseFrom, phaseTo);
196
+ if (rangeError) {
197
+ return {
198
+ phases_attempted: 0,
199
+ phases_completed: 0,
200
+ stopped_at: rangeError,
201
+ converged_at: null,
202
+ waves: [],
203
+ results: [],
204
+ };
205
+ }
206
+ const waves = buildWaves(phases);
207
+ const timeoutMs = timeout ? timeout * 60 * 1000 : undefined;
208
+ const results = [];
209
+ let phasesAttempted = 0;
210
+ let phasesCompleted = 0;
211
+ let stoppedAt = null;
212
+ // Graceful early termination (Tier-3 #10). Separate from stoppedAt so
213
+ // existing callers (multi-milestone autopilot, evolve) do not classify
214
+ // convergence as a failure. codex r2 P2 on PR #40.
215
+ let convergedAt = null;
216
+ const config = loadConfig(cwd);
217
+ const backend = detectBackend(cwd);
218
+ const scheduler = createScheduler(config.scheduler, config.superpowers);
219
+ if (scheduler) {
220
+ scheduler.loadPersistedState(path.join(cwd, '.planning'));
221
+ }
222
+ // autopilot.log is project-scoped (.planning/autopilot/).
223
+ // Cross-project scheduler state (e.g., global phase timing stats,
224
+ // retry policies) could use CLAUDE_PLUGIN_DATA when available:
225
+ // const globalSchedulerDir = process.env.CLAUDE_PLUGIN_DATA
226
+ // ? path.join(process.env.CLAUDE_PLUGIN_DATA, 'grd', 'scheduler')
227
+ // : null;
228
+ const logFile = path.join(cwd, '.planning', 'autopilot', 'autopilot.log');
229
+ fs.mkdirSync(path.dirname(logFile), { recursive: true });
230
+ const log = (msg) => {
231
+ const line = `[${new Date().toISOString()}] ${msg}\n`;
232
+ process.stderr.write(`[autopilot] ${msg}\n`);
233
+ fs.appendFileSync(logFile, line);
234
+ };
235
+ log(`Starting autopilot: ${phases.length} phase(s) in ${waves.length} wave(s)`);
236
+ // Single merge queue shared across all waves — only the rebase+merge step
237
+ // is serialized; simplify/PR/review steps run concurrently per phase.
238
+ const mergeQueue = createMergeQueue();
239
+ for (let waveIdx = 0; waveIdx < waves.length; waveIdx++) {
240
+ const wave = waves[waveIdx];
241
+ if (stoppedAt || convergedAt)
242
+ break;
243
+ log(`Wave ${waveIdx + 1}/${waves.length}: phases [${wave.join(', ')}]`);
244
+ // ── Plan step: all phases in wave in parallel ──
245
+ if (!skipPlan) {
246
+ const planTasks = [];
247
+ for (const phaseNum of wave) {
248
+ phasesAttempted++;
249
+ if (isPhasePlanned(cwd, phaseNum)) {
250
+ results.push({
251
+ phase: phaseNum,
252
+ step: 'plan',
253
+ status: 'skipped',
254
+ reason: 'already planned',
255
+ });
256
+ planTasks.push({ phaseNum, skipped: true });
257
+ }
258
+ else if (dryRun) {
259
+ results.push({
260
+ phase: phaseNum,
261
+ step: 'plan',
262
+ status: 'dry-run',
263
+ prompt: buildPlanPrompt(phaseNum, backend, cwd),
264
+ });
265
+ planTasks.push({ phaseNum, skipped: true });
266
+ }
267
+ else {
268
+ log(`Phase ${phaseNum}: planning...`);
269
+ writeStatusMarker(cwd, phaseNum, 'plan', 'started');
270
+ updateStateProgress(cwd, phaseNum, 'planning');
271
+ // Compute the plan prompt once so we can pass it to both the adaptive
272
+ // tier helper (for promptLength) and the actual dispatch.
273
+ const planPrompt = buildPlanPrompt(phaseNum, backend, cwd);
274
+ // Resolve the effective model for this dispatch. When the caller
275
+ // passed an explicit --model flag we honour it; otherwise the Spec 4
276
+ // chain (complexity → pressure → tier) picks the right model.
277
+ const planTier = getEffectiveTierForDispatch({
278
+ agentType: 'grd-planner',
279
+ prompt: planPrompt,
280
+ config,
281
+ scheduler,
282
+ schedulerConfig: config.scheduler,
283
+ superpowersConfig: config.superpowers,
284
+ modelProfiles: MODEL_PROFILES,
285
+ });
286
+ const planModel = model
287
+ ? model
288
+ : resolveModelForAgent(config, 'grd-planner', cwd, {
289
+ effectiveTierOverride: planTier,
290
+ });
291
+ // Check for overstory sling path: parallel wave + account rotation + native worktree isolation
292
+ let promise;
293
+ if (config.superpowers?.account_rotation && scheduler && config.scheduler) {
294
+ const resolution = resolveAccount(config.superpowers, config.scheduler, _getSchedulerStates(scheduler, config.scheduler, config.superpowers), config.scheduler.prediction.safety_margin_tasks);
295
+ const caps = getBackendCapabilities(resolution.backend);
296
+ if (caps.native_worktree_isolation) {
297
+ // Overstory sling path: bypass scheduler.spawn() for parallel wave planning
298
+ const ovConfig = loadOverstoryConfig(cwd);
299
+ const milestoneInfo = getMilestoneInfo(cwd);
300
+ const phaseInfo = findPhaseInternal(cwd, phaseNum);
301
+ const phaseDir = phaseInfo?.directory ||
302
+ path.join(cwd, '.planning', 'milestones', milestoneInfo.version, 'phases', `phase-${phaseNum}`);
303
+ const planId = `phase-${phaseNum}-plan`;
304
+ const overlayContent = generateOverlay(planPrompt, {
305
+ phase_number: phaseNum,
306
+ plan_id: planId,
307
+ milestone: milestoneInfo.version,
308
+ phase_dir: phaseDir,
309
+ });
310
+ const overlayDir = path.join(cwd, '.planning', 'autopilot', 'overlays');
311
+ fs.mkdirSync(overlayDir, { recursive: true });
312
+ const overlayPath = path.join(overlayDir, `overlay-${phaseNum}.md`);
313
+ fs.writeFileSync(overlayPath, overlayContent);
314
+ const slingOpts = {
315
+ plan_path: phaseDir,
316
+ overlay_path: overlayPath,
317
+ runtime: ovConfig.runtime,
318
+ model: planModel || 'default',
319
+ phase_number: phaseNum,
320
+ plan_id: planId,
321
+ milestone: milestoneInfo.version,
322
+ timeout_minutes: timeout || DEFAULT_TIMEOUT_MINUTES,
323
+ };
324
+ log(`Phase ${phaseNum}: using overstory sling path (backend: ${resolution.backend})`);
325
+ promise = slingPlanAsync(cwd, slingOpts, ovConfig.poll_interval_ms, ovConfig.merge_strategy).then((slingResult) => {
326
+ // Record the sample back to the scheduler
327
+ const sample = {
328
+ backend: resolution.backend,
329
+ stateKey: resolution.stateKey,
330
+ timestamp: Date.now(),
331
+ duration: slingResult.duration,
332
+ tokenEstimate: Math.round(slingResult.duration * 10), // fallback estimate
333
+ exitCode: slingResult.exitCode,
334
+ workItemId: `phase-${phaseNum}-plan`,
335
+ };
336
+ scheduler.recordExternalSample(resolution.stateKey, sample);
337
+ return { exitCode: slingResult.exitCode, timedOut: false };
338
+ });
339
+ }
340
+ else {
341
+ // Non-overstory backend with account rotation: use scheduler.spawn
342
+ promise = scheduler
343
+ .spawn(planPrompt, {
344
+ timeout: timeoutMs,
345
+ maxTurns,
346
+ model: planModel,
347
+ cwd,
348
+ workItemId: `phase-${phaseNum}-plan`,
349
+ agentType: 'grd-planner',
350
+ })
351
+ .then((sr) => {
352
+ _handleSpinIfDetected(cwd, phaseNum, sr);
353
+ return toSpawnResult(sr);
354
+ });
355
+ }
356
+ }
357
+ else {
358
+ promise = scheduler
359
+ ? scheduler
360
+ .spawn(planPrompt, {
361
+ timeout: timeoutMs,
362
+ maxTurns,
363
+ model: planModel,
364
+ cwd,
365
+ workItemId: `phase-${phaseNum}-plan`,
366
+ agentType: 'grd-planner',
367
+ })
368
+ .then((sr) => {
369
+ _handleSpinIfDetected(cwd, phaseNum, sr);
370
+ return toSpawnResult(sr);
371
+ })
372
+ : spawnClaudeAsync(cwd, planPrompt, {
373
+ timeout: timeoutMs,
374
+ maxTurns,
375
+ model: planModel,
376
+ });
377
+ }
378
+ planTasks.push({ phaseNum, skipped: false, promise });
379
+ }
380
+ }
381
+ // Await all parallel plan spawns
382
+ for (const task of planTasks) {
383
+ if (task.skipped)
384
+ continue;
385
+ const planResult = await task.promise;
386
+ if (planResult.exitCode !== 0) {
387
+ const reason = planResult.timedOut
388
+ ? 'timeout'
389
+ : `exit code ${planResult.exitCode}`;
390
+ log(`Phase ${task.phaseNum}: plan FAILED (${reason})`);
391
+ writeStatusMarker(cwd, task.phaseNum, 'plan', 'failed');
392
+ results.push({ phase: task.phaseNum, step: 'plan', status: 'failed', reason });
393
+ stoppedAt = `Phase ${task.phaseNum} plan failed: ${reason}`;
394
+ continue;
395
+ }
396
+ log(`Phase ${task.phaseNum}: plan completed`);
397
+ writeStatusMarker(cwd, task.phaseNum, 'plan', 'completed');
398
+ results.push({ phase: task.phaseNum, step: 'plan', status: 'completed' });
399
+ }
400
+ if (stoppedAt)
401
+ break;
402
+ // If skipExecute, count only planned phases (not yet counted above for non-skipPlan path)
403
+ if (skipExecute) {
404
+ phasesCompleted += wave.length;
405
+ continue;
406
+ }
407
+ }
408
+ else {
409
+ // skipPlan: still need to count attempts
410
+ phasesAttempted += wave.length;
411
+ if (skipExecute) {
412
+ phasesCompleted += wave.length;
413
+ continue;
414
+ }
415
+ }
416
+ // ── Execute step: parallel within wave using worktrees ──
417
+ // Track which phases failed planning so we skip them during execution
418
+ const failedPlanPhases = new Set(results.filter((r) => r.step === 'plan' && r.status === 'failed').map((r) => r.phase));
419
+ if (!skipExecute) {
420
+ const milestoneInfo = getMilestoneInfo(cwd);
421
+ ensureWorktreesDir(cwd);
422
+ // Build execution tasks for all phases in the wave
423
+ const execTasks = [];
424
+ for (const phaseNum of wave) {
425
+ if (failedPlanPhases.has(phaseNum)) {
426
+ log(`Phase ${phaseNum}: skipping execution (planning failed)`);
427
+ results.push({
428
+ phase: phaseNum,
429
+ step: 'execute',
430
+ status: 'skipped',
431
+ reason: 'planning failed',
432
+ });
433
+ execTasks.push({ phaseNum, skipped: true });
434
+ continue;
435
+ }
436
+ if (isPhaseExecuted(cwd, phaseNum)) {
437
+ results.push({
438
+ phase: phaseNum,
439
+ step: 'execute',
440
+ status: 'skipped',
441
+ reason: 'already executed',
442
+ });
443
+ execTasks.push({ phaseNum, skipped: true });
444
+ continue;
445
+ }
446
+ // v0.4 Phase 3: when multiple PLAN candidates exist and none has been
447
+ // promoted to PLAN.md yet, run the deterministic selector. It scores
448
+ // each candidate, hard-fails DEAD-ENDS violators, picks the highest
449
+ // survivor, promotes it to PLAN.md, and writes PLAN-SELECTION.json.
450
+ if (hasMultipleCandidates(cwd, phaseNum)) {
451
+ if (dryRun) {
452
+ log(`Phase ${phaseNum}: [dry-run] would run deterministic selector over candidates`);
453
+ }
454
+ else {
455
+ const selection = selectCandidate(cwd, phaseNum);
456
+ if (!selection.winner) {
457
+ log(`Phase ${phaseNum}: all PLAN candidates hard-failed DEAD-ENDS checks — cannot select`);
458
+ failedPlanPhases.add(phaseNum);
459
+ results.push({
460
+ phase: phaseNum,
461
+ step: 'execute',
462
+ status: 'skipped',
463
+ reason: 'all candidates hard-failed DEAD-ENDS; no viable plan to execute',
464
+ });
465
+ execTasks.push({ phaseNum, skipped: true });
466
+ continue;
467
+ }
468
+ log(`Phase ${phaseNum}: selected ${selection.winner.relPath} (score ${selection.winner.total_score.toFixed(3)}) → promoted to PLAN.md`);
469
+ }
470
+ }
471
+ if (dryRun) {
472
+ results.push({
473
+ phase: phaseNum,
474
+ step: 'execute',
475
+ status: 'dry-run',
476
+ prompt: buildExecutePrompt(phaseNum, cwd),
477
+ });
478
+ execTasks.push({ phaseNum, skipped: true });
479
+ continue;
480
+ }
481
+ // Create worktree for this phase
482
+ const wtPath = getWorktreePath(cwd, milestoneInfo.version, phaseNum);
483
+ const branch = getWorktreeBranch(cwd, milestoneInfo.version, phaseNum, phaseNum);
484
+ // Remove stale worktree if it exists
485
+ // Remove stale worktree if present (no existence check — idempotent)
486
+ execGit(cwd, ['worktree', 'remove', wtPath, '--force'], { allowBlocked: true });
487
+ execGit(cwd, ['worktree', 'prune']);
488
+ // Remove stale branch if it exists
489
+ execGit(cwd, ['branch', '-D', branch]);
490
+ const wtResult = execGit(cwd, ['worktree', 'add', '-b', branch, wtPath]);
491
+ if (wtResult.exitCode !== 0) {
492
+ log(`Phase ${phaseNum}: failed to create worktree: ${wtResult.stderr}`);
493
+ results.push({
494
+ phase: phaseNum,
495
+ step: 'execute',
496
+ status: 'failed',
497
+ reason: `worktree creation failed: ${wtResult.stderr}`,
498
+ });
499
+ execTasks.push({ phaseNum, skipped: true });
500
+ continue;
501
+ }
502
+ log(`Phase ${phaseNum}: executing in worktree ${wtPath}...`);
503
+ writeStatusMarker(cwd, phaseNum, 'execute', 'started');
504
+ updateStateProgress(cwd, phaseNum, 'executing');
505
+ // Compute execute prompt once to share between tier computation and dispatch.
506
+ const executePrompt = buildExecutePrompt(phaseNum, wtPath);
507
+ // Resolve effective model for execution dispatch via the Spec 4 chain.
508
+ const executeTier = getEffectiveTierForDispatch({
509
+ agentType: 'grd-executor',
510
+ prompt: executePrompt,
511
+ config,
512
+ scheduler,
513
+ schedulerConfig: config.scheduler,
514
+ superpowersConfig: config.superpowers,
515
+ modelProfiles: MODEL_PROFILES,
516
+ });
517
+ const executeModel = model
518
+ ? model
519
+ : resolveModelForAgent(config, 'grd-executor', cwd, {
520
+ effectiveTierOverride: executeTier,
521
+ });
522
+ const promise = (async () => {
523
+ let execResult;
524
+ if (scheduler) {
525
+ const sr = await scheduler.spawn(executePrompt, {
526
+ timeout: timeoutMs,
527
+ maxTurns,
528
+ model: executeModel,
529
+ cwd: wtPath,
530
+ workItemId: `phase-${phaseNum}-execute`,
531
+ agentType: 'grd-executor',
532
+ });
533
+ _handleSpinIfDetected(cwd, phaseNum, sr);
534
+ execResult = toSpawnResult(sr);
535
+ }
536
+ else {
537
+ execResult = await spawnClaudeAsync(wtPath, executePrompt, {
538
+ timeout: timeoutMs,
539
+ maxTurns,
540
+ model: executeModel,
541
+ });
542
+ }
543
+ return { execResult, wtPath };
544
+ })();
545
+ execTasks.push({ phaseNum, skipped: false, promise, wtPath });
546
+ }
547
+ // Await all parallel execution spawns and collect successful phases for pipelines
548
+ const pipelineTasks = [];
549
+ for (const task of execTasks) {
550
+ if (task.skipped)
551
+ continue;
552
+ const { execResult, wtPath } = await task.promise;
553
+ if (execResult.exitCode !== 0) {
554
+ const reason = execResult.timedOut
555
+ ? 'timeout'
556
+ : `exit code ${execResult.exitCode}`;
557
+ log(`Phase ${task.phaseNum}: execute FAILED (${reason})`);
558
+ writeStatusMarker(cwd, task.phaseNum, 'execute', 'failed');
559
+ results.push({ phase: task.phaseNum, step: 'execute', status: 'failed', reason });
560
+ stoppedAt = `Phase ${task.phaseNum} execute failed: ${reason}`;
561
+ // Clean up worktree on failure
562
+ execGit(cwd, ['worktree', 'remove', wtPath, '--force'], { allowBlocked: true });
563
+ execGit(cwd, ['worktree', 'prune']);
564
+ continue;
565
+ }
566
+ log(`Phase ${task.phaseNum}: execute completed`);
567
+ writeStatusMarker(cwd, task.phaseNum, 'execute', 'completed');
568
+ results.push({ phase: task.phaseNum, step: 'execute', status: 'completed' });
569
+ // Knowledge mining (non-blocking — runKnowledgeMining never rejects)
570
+ await runKnowledgeMining(cwd, task.phaseNum, { scheduler, log });
571
+ // Refinement loop (non-blocking — runRefinementLoop never rejects).
572
+ // Codex r43 P1 #2: pass wtPath so critique-agent edits land in
573
+ // the phase worktree the post-pipeline merges.
574
+ await runRefinementLoop(cwd, task.phaseNum, { scheduler, log, workCwd: wtPath });
575
+ // Launch post-phase pipeline concurrently (Steps 1-3 run in parallel across
576
+ // phases; Step 4 rebase+merge is serialized via the shared mergeQueue).
577
+ if (!skipPostPipeline) {
578
+ const phaseNumCapture = task.phaseNum;
579
+ const wtPathCapture = wtPath;
580
+ log(`Phase ${phaseNumCapture}: starting post-phase pipeline`);
581
+ writeStatusMarker(cwd, phaseNumCapture, 'post-pipeline', 'started');
582
+ const pipelinePromise = runPostPhasePipeline(cwd, phaseNumCapture, wtPathCapture, {
583
+ timeout,
584
+ maxTurns,
585
+ model,
586
+ scheduler,
587
+ log,
588
+ mergeQueue,
589
+ }).then((result) => ({ phaseNum: phaseNumCapture, result }));
590
+ pipelineTasks.push({
591
+ phaseNum: phaseNumCapture,
592
+ wtPath: wtPathCapture,
593
+ promise: pipelinePromise,
594
+ });
595
+ }
596
+ else {
597
+ // No pipeline — clean up worktree immediately
598
+ execGit(cwd, ['worktree', 'remove', wtPath, '--force'], { allowBlocked: true });
599
+ execGit(cwd, ['worktree', 'prune']);
600
+ }
601
+ }
602
+ // Await all concurrent post-phase pipelines
603
+ if (pipelineTasks.length > 0) {
604
+ const pipelineResults = await Promise.all(pipelineTasks.map((t) => t.promise));
605
+ for (const { phaseNum: pNum, result: pipelineResult } of pipelineResults) {
606
+ const taskEntry = pipelineTasks.find((t) => t.phaseNum === pNum);
607
+ if (pipelineResult.status === 'failed') {
608
+ log(`Phase ${pNum}: post-pipeline FAILED at ${pipelineResult.failedStep}: ${pipelineResult.reason}`);
609
+ writeStatusMarker(cwd, pNum, 'post-pipeline', 'failed');
610
+ results.push({
611
+ phase: pNum,
612
+ step: 'post-pipeline',
613
+ status: 'failed',
614
+ reason: `${pipelineResult.failedStep}: ${pipelineResult.reason}`,
615
+ });
616
+ if (!stoppedAt) {
617
+ stoppedAt = `Phase ${pNum} post-pipeline failed at ${pipelineResult.failedStep}`;
618
+ }
619
+ }
620
+ else {
621
+ log(`Phase ${pNum}: post-pipeline completed`);
622
+ writeStatusMarker(cwd, pNum, 'post-pipeline', 'completed');
623
+ results.push({ phase: pNum, step: 'post-pipeline', status: 'completed' });
624
+ // Spec 3: mechanical phase finalization. On a successful post-pipeline,
625
+ // fold in phase complete (ROADMAP + STATE + quality analysis) instead
626
+ // of leaving it for the user to run manually.
627
+ const finalizeResult = await finalizePhaseAfterPipeline(cwd, pNum, scheduler, log);
628
+ if (finalizeResult) {
629
+ results.push({ phase: pNum, step: 'phase-finalize', status: 'completed' });
630
+ }
631
+ else {
632
+ results.push({
633
+ phase: pNum,
634
+ step: 'phase-finalize',
635
+ status: 'failed',
636
+ reason: 'phase complete failed — see logs for details',
637
+ });
638
+ }
639
+ }
640
+ // Clean up worktree after pipeline completes (success or failure)
641
+ execGit(cwd, ['worktree', 'remove', taskEntry.wtPath, '--force'], { allowBlocked: true });
642
+ execGit(cwd, ['worktree', 'prune']);
643
+ }
644
+ }
645
+ if (stoppedAt)
646
+ break;
647
+ // Count phases where execution didn't fail
648
+ for (const phaseNum of wave) {
649
+ const hasFailed = results.some((r) => r.phase === phaseNum && r.status === 'failed');
650
+ if (!hasFailed)
651
+ phasesCompleted++;
652
+ }
653
+ // Tier-3 #10: ontology-convergence termination. Opt-in via
654
+ // config.autopilot.stop_on_ontology_convergence. Recorded on the
655
+ // separate `convergedAt` channel (codex r2 P2 on PR #40) so callers
656
+ // like runMultiMilestoneAutopilot / evolve do not classify graceful
657
+ // termination as a failure. Guards from codex r1: only fire when
658
+ // there's a NEXT wave to skip, and require non-overlapping windows
659
+ // (handled by isOntologyConverged).
660
+ if (config.autopilot?.stop_on_ontology_convergence === true &&
661
+ waveIdx < waves.length - 1) {
662
+ const threshold = config.autopilot.ontology_convergence_threshold ?? 0.95;
663
+ const result = isOntologyConverged(cwd, threshold);
664
+ if (result.converged && result.similarity !== undefined) {
665
+ convergedAt = `ontology-convergence (similarity ${result.similarity.toFixed(3)} >= ${threshold})`;
666
+ log(`Autopilot: converged early — ${convergedAt}`);
667
+ }
668
+ }
669
+ }
670
+ }
671
+ // ── Milestone mode: run wireup after all phases complete ──
672
+ // codex r3 P2: convergence skips later waves intentionally, so the
673
+ // milestone is NOT complete in the user's sense. Gate wireup on
674
+ // !convergedAt so wireup does not run as though everything finished.
675
+ const isMilestoneMode = options.milestone === true || (!phaseFrom && !phaseTo);
676
+ if (isMilestoneMode &&
677
+ !stoppedAt &&
678
+ !convergedAt &&
679
+ !dryRun &&
680
+ phasesCompleted === phasesAttempted &&
681
+ phasesCompleted > 0) {
682
+ log('Milestone mode: all phases complete — running wireup');
683
+ // Compute wireup prompt once for tier routing and dispatch.
684
+ const wireupPrompt = buildWireupPrompt();
685
+ // Resolve effective model for wireup via the Spec 4 chain.
686
+ const wireupTier = getEffectiveTierForDispatch({
687
+ agentType: 'grd-executor',
688
+ prompt: wireupPrompt,
689
+ config,
690
+ scheduler,
691
+ schedulerConfig: config.scheduler,
692
+ superpowersConfig: config.superpowers,
693
+ modelProfiles: MODEL_PROFILES,
694
+ });
695
+ const wireupModel = model
696
+ ? model
697
+ : resolveModelForAgent(config, 'grd-executor', cwd, {
698
+ effectiveTierOverride: wireupTier,
699
+ });
700
+ const wireupResult = scheduler
701
+ ? toSpawnResult(await scheduler.spawn(wireupPrompt, {
702
+ timeout: timeoutMs,
703
+ maxTurns,
704
+ model: wireupModel,
705
+ cwd,
706
+ workItemId: 'milestone-wireup',
707
+ agentType: 'grd-integration-checker',
708
+ }))
709
+ : await spawnClaudeAsync(cwd, wireupPrompt, {
710
+ timeout: timeoutMs,
711
+ maxTurns,
712
+ model: wireupModel,
713
+ });
714
+ if (wireupResult.exitCode !== 0) {
715
+ const reason = wireupResult.timedOut
716
+ ? 'timeout'
717
+ : `exit code ${wireupResult.exitCode}`;
718
+ log(`Wireup FAILED (${reason})`);
719
+ results.push({ phase: 'wireup', step: 'wireup', status: 'failed', reason });
720
+ }
721
+ else {
722
+ log('Wireup completed');
723
+ results.push({ phase: 'wireup', step: 'wireup', status: 'completed' });
724
+ }
725
+ }
726
+ log(`Done: ${phasesCompleted}/${phasesAttempted} phases completed${stoppedAt
727
+ ? ` (stopped: ${stoppedAt})`
728
+ : convergedAt
729
+ ? ` (converged: ${convergedAt})`
730
+ : ''}`);
731
+ if (scheduler) {
732
+ scheduler.persistState(path.join(cwd, '.planning'));
733
+ }
734
+ return {
735
+ phases_attempted: phasesAttempted,
736
+ phases_completed: phasesCompleted,
737
+ stopped_at: stoppedAt,
738
+ converged_at: convergedAt,
739
+ waves,
740
+ results,
741
+ };
742
+ }
743
+ // ─── Multi-Milestone Orchestration ───────────────────────────────────────────
744
+ /**
745
+ * Run the multi-milestone autopilot loop.
746
+ * Orchestrates across milestone boundaries: completes current milestone phases,
747
+ * detects milestone completion, resolves the next milestone, creates it, and continues.
748
+ *
749
+ * Safety: maxMilestones cap (default 10) prevents infinite loops.
750
+ *
751
+ * @param cwd - Absolute path to the project root directory
752
+ * @param options - Configuration options including maxMilestones cap, dryRun flag, resume flag, timeout, maxTurns, model, skipPlan, and skipExecute
753
+ * @returns Aggregate result with milestone and phase counts, per-milestone results, and the stop reason if any
754
+ */
755
+ async function runMultiMilestoneAutopilot(cwd, options = {}) {
756
+ const maxMilestones = options.maxMilestones ?? 10;
757
+ const dryRun = options.dryRun ?? false;
758
+ const timeoutMs = options.timeout ? options.timeout * 60 * 1000 : undefined;
759
+ // Set up logging (reuse existing autopilot log pattern)
760
+ const logFile = path.join(cwd, '.planning', 'autopilot', 'autopilot.log');
761
+ fs.mkdirSync(path.dirname(logFile), { recursive: true });
762
+ const log = (msg) => {
763
+ const line = `[${new Date().toISOString()}] [multi-milestone] ${msg}\n`;
764
+ process.stderr.write(`[multi-milestone] ${msg}\n`);
765
+ fs.appendFileSync(logFile, line);
766
+ };
767
+ // Initialize result tracking
768
+ const milestoneResults = [];
769
+ let milestonesAttempted = 0;
770
+ let milestonesCompleted = 0;
771
+ let totalPhasesAttempted = 0;
772
+ let totalPhasesCompleted = 0;
773
+ let stoppedAt = null;
774
+ // Graceful early termination at the milestone-chain level (Tier-3 #10).
775
+ // codex r4 P2 on PR #40: the maxMilestones cap check at the bottom of
776
+ // this function overwrites stoppedAt to "Reached maxMilestones cap"
777
+ // when convergence fires on the last permitted iteration — turning a
778
+ // graceful stop into a reported failure. Tracking convergence on a
779
+ // dedicated channel lets us bypass that overwrite cleanly.
780
+ let convergedAt = null;
781
+ log(`Starting multi-milestone autopilot (max: ${maxMilestones}, dryRun: ${dryRun})`);
782
+ const mmConfig = loadConfig(cwd);
783
+ const mmBackend = detectBackend(cwd);
784
+ const mmScheduler = createScheduler(mmConfig.scheduler, mmConfig.superpowers);
785
+ if (mmScheduler) {
786
+ mmScheduler.loadPersistedState(path.join(cwd, '.planning'));
787
+ }
788
+ for (let i = 0; i < maxMilestones; i++) {
789
+ if (stoppedAt)
790
+ break;
791
+ // Get current milestone info (re-read each iteration for fresh state)
792
+ const milestoneInfo = getMilestoneInfo(cwd);
793
+ const currentVersion = milestoneInfo.version;
794
+ log(`Milestone ${i + 1}/${maxMilestones}: ${currentVersion} (${milestoneInfo.name})`);
795
+ milestonesAttempted++;
796
+ // Check for incomplete phases in current milestone
797
+ const { phases, error: rangeError } = resolvePhaseRange(cwd, null, null);
798
+ if (rangeError) {
799
+ log(`Error resolving phases: ${rangeError}`);
800
+ milestoneResults.push({
801
+ milestone: currentVersion,
802
+ phases_attempted: 0,
803
+ phases_completed: 0,
804
+ status: 'failed',
805
+ reason: rangeError,
806
+ });
807
+ stoppedAt = `Failed to resolve phases for ${currentVersion}: ${rangeError}`;
808
+ break;
809
+ }
810
+ const incompletePhases = phases.filter((p) => p.disk_status !== 'complete');
811
+ if (incompletePhases.length > 0) {
812
+ log(`${currentVersion}: ${incompletePhases.length} incomplete phase(s), running autopilot...`);
813
+ if (dryRun) {
814
+ milestoneResults.push({
815
+ milestone: currentVersion,
816
+ phases_attempted: incompletePhases.length,
817
+ phases_completed: 0,
818
+ status: 'dry-run',
819
+ reason: `Would process ${incompletePhases.length} incomplete phase(s)`,
820
+ });
821
+ totalPhasesAttempted += incompletePhases.length;
822
+ }
823
+ else {
824
+ // Run single-milestone autopilot for current milestone's phases
825
+ const autopilotResult = await runAutopilot(cwd, {
826
+ skipPlan: options.skipPlan,
827
+ skipExecute: options.skipExecute,
828
+ skipPostPipeline: options.skipPostPipeline,
829
+ timeout: options.timeout,
830
+ maxTurns: options.maxTurns,
831
+ model: options.model,
832
+ });
833
+ totalPhasesAttempted += autopilotResult.phases_attempted;
834
+ totalPhasesCompleted += autopilotResult.phases_completed;
835
+ const autopilotFailed = autopilotResult.stopped_at !== null;
836
+ const autopilotConverged = autopilotResult.converged_at !== null;
837
+ milestoneResults.push({
838
+ milestone: currentVersion,
839
+ phases_attempted: autopilotResult.phases_attempted,
840
+ phases_completed: autopilotResult.phases_completed,
841
+ status: autopilotFailed
842
+ ? 'failed'
843
+ : autopilotConverged
844
+ ? 'converged'
845
+ : 'completed',
846
+ reason: autopilotResult.stopped_at || autopilotResult.converged_at || undefined,
847
+ });
848
+ if (autopilotFailed) {
849
+ log(`${currentVersion}: autopilot stopped: ${autopilotResult.stopped_at}`);
850
+ stoppedAt = `Autopilot failed for ${currentVersion}: ${autopilotResult.stopped_at}`;
851
+ break;
852
+ }
853
+ // codex r3 P2: convergence is a graceful TERMINAL state for this
854
+ // milestone chain — do not advance to the next milestone. Track
855
+ // on the dedicated `convergedAt` channel so the post-loop
856
+ // maxMilestones cap check (codex r4 P2) does not overwrite it.
857
+ if (autopilotConverged) {
858
+ convergedAt = autopilotResult.converged_at;
859
+ log(`${currentVersion}: autopilot converged early — ${convergedAt}`);
860
+ break;
861
+ }
862
+ }
863
+ }
864
+ else {
865
+ log(`${currentVersion}: all phases already complete`);
866
+ milestoneResults.push({
867
+ milestone: currentVersion,
868
+ phases_attempted: 0,
869
+ phases_completed: 0,
870
+ status: 'skipped',
871
+ reason: 'all phases already complete',
872
+ });
873
+ }
874
+ // Check milestone completion after autopilot run
875
+ if (isMilestoneComplete(cwd)) {
876
+ log(`${currentVersion}: milestone complete`);
877
+ if (!dryRun) {
878
+ // Complete the milestone via deterministic grd-tools command
879
+ const completePrompt = buildMilestoneCompletePrompt(currentVersion);
880
+ log(`${currentVersion}: completing milestone...`);
881
+ const completeResult = mmScheduler
882
+ ? toSpawnResult(await mmScheduler.spawn(completePrompt, {
883
+ timeout: timeoutMs,
884
+ maxTurns: options.maxTurns,
885
+ model: options.model,
886
+ cwd,
887
+ workItemId: `milestone-${currentVersion}-complete`,
888
+ agentType: 'grd-integration-checker',
889
+ }))
890
+ : spawnClaude(cwd, completePrompt, {
891
+ timeout: timeoutMs,
892
+ maxTurns: options.maxTurns,
893
+ model: options.model,
894
+ });
895
+ if (completeResult.exitCode !== 0) {
896
+ const reason = completeResult.timedOut
897
+ ? 'timeout'
898
+ : `exit code ${completeResult.exitCode}`;
899
+ log(`${currentVersion}: milestone complete FAILED (${reason})`);
900
+ stoppedAt = `Failed to complete milestone ${currentVersion}: ${reason}`;
901
+ break;
902
+ }
903
+ log(`${currentVersion}: milestone completed successfully`);
904
+ }
905
+ else {
906
+ log(`${currentVersion}: [dry-run] would complete milestone`);
907
+ }
908
+ milestonesCompleted++;
909
+ }
910
+ else {
911
+ log(`${currentVersion}: milestone not fully complete yet`);
912
+ stoppedAt = `Milestone ${currentVersion} is not fully complete after autopilot run`;
913
+ break;
914
+ }
915
+ // Resolve next milestone
916
+ const nextMs = resolveNextMilestone(cwd);
917
+ if (!nextMs) {
918
+ log('No next milestone found in LONG-TERM-ROADMAP.md — stopping');
919
+ stoppedAt = null; // Graceful completion, not an error
920
+ break;
921
+ }
922
+ log(`Next milestone: ${nextMs.version} (${nextMs.name})`);
923
+ if (dryRun) {
924
+ log(`[dry-run] Would create new milestone: ${nextMs.version}`);
925
+ continue;
926
+ }
927
+ // Spawn new milestone creation via claude -p
928
+ const newMilestonePrompt = buildNewMilestonePrompt(mmBackend);
929
+ log('Creating new milestone...');
930
+ const createResult = mmScheduler
931
+ ? toSpawnResult(await mmScheduler.spawn(newMilestonePrompt, {
932
+ timeout: timeoutMs,
933
+ maxTurns: options.maxTurns,
934
+ model: options.model,
935
+ cwd,
936
+ workItemId: 'new-milestone',
937
+ agentType: 'grd-planner',
938
+ }))
939
+ : spawnClaude(cwd, newMilestonePrompt, {
940
+ timeout: timeoutMs,
941
+ maxTurns: options.maxTurns,
942
+ model: options.model,
943
+ });
944
+ if (createResult.exitCode !== 0) {
945
+ const reason = createResult.timedOut
946
+ ? 'timeout'
947
+ : `exit code ${createResult.exitCode}`;
948
+ log(`New milestone creation FAILED (${reason})`);
949
+ stoppedAt = `Failed to create new milestone: ${reason}`;
950
+ break;
951
+ }
952
+ log('New milestone created, continuing loop...');
953
+ }
954
+ // codex r4 P2: do not overwrite a graceful convergence with the
955
+ // "Reached maxMilestones cap" failure signal. Convergence is the
956
+ // terminal reason; the cap only matters when the loop exhausted
957
+ // milestones without converging.
958
+ if (!stoppedAt && !convergedAt && milestonesAttempted >= maxMilestones) {
959
+ stoppedAt = `Reached maxMilestones cap (${maxMilestones})`;
960
+ log(stoppedAt);
961
+ }
962
+ log(`Multi-milestone autopilot done: ${milestonesCompleted}/${milestonesAttempted} milestones completed` +
963
+ (stoppedAt
964
+ ? ` (stopped: ${stoppedAt})`
965
+ : convergedAt
966
+ ? ` (converged: ${convergedAt})`
967
+ : ''));
968
+ if (mmScheduler) {
969
+ mmScheduler.persistState(path.join(cwd, '.planning'));
970
+ }
971
+ return {
972
+ milestones_attempted: milestonesAttempted,
973
+ milestones_completed: milestonesCompleted,
974
+ milestone_results: milestoneResults,
975
+ stopped_at: stoppedAt,
976
+ converged_at: convergedAt,
977
+ total_phases_attempted: totalPhasesAttempted,
978
+ total_phases_completed: totalPhasesCompleted,
979
+ };
980
+ }
981
+ // ─── CLI Entry Points ───────────────────────────────────────────────────────
982
+ /**
983
+ * Parse CLI flags and run the autopilot loop.
984
+ */
985
+ async function cmdAutopilot(cwd, args, raw) {
986
+ const flag = (name, fallback) => {
987
+ const i = args.indexOf(name);
988
+ return i !== -1 ? args[i + 1] : fallback;
989
+ };
990
+ const hasFlag = (name) => args.indexOf(name) !== -1;
991
+ const options = {
992
+ phaseFrom: flag('--phase-from', null),
993
+ phaseTo: flag('--phase-to', null),
994
+ milestone: hasFlag('--milestone'),
995
+ dryRun: hasFlag('--dry-run'),
996
+ skipPlan: hasFlag('--skip-plan'),
997
+ skipExecute: hasFlag('--skip-execute'),
998
+ skipPostPipeline: hasFlag('--skip-post-pipeline'),
999
+ timeout: (() => {
1000
+ if (!hasFlag('--timeout'))
1001
+ return undefined;
1002
+ const parsed = parseInt(flag('--timeout', '0'), 10);
1003
+ if (isNaN(parsed) || parsed <= 0) {
1004
+ process.stderr.write('Error: --timeout must be a positive integer\n');
1005
+ process.exit(1);
1006
+ }
1007
+ return parsed;
1008
+ })(),
1009
+ maxTurns: (() => {
1010
+ if (!flag('--max-turns', null))
1011
+ return undefined;
1012
+ const parsed = parseInt(flag('--max-turns', '0'), 10);
1013
+ if (isNaN(parsed) || parsed <= 0) {
1014
+ process.stderr.write('Error: --max-turns must be a positive integer\n');
1015
+ process.exit(1);
1016
+ }
1017
+ return parsed;
1018
+ })(),
1019
+ model: flag('--model', undefined) ?? undefined,
1020
+ };
1021
+ // Pre-execution dry-run plan: compute phase order, parallel groups, and model routing
1022
+ // and attach to the result (without short-circuiting — runAutopilot still runs).
1023
+ let dryRunPlan;
1024
+ if (options.dryRun) {
1025
+ const drConfig = loadConfig(cwd);
1026
+ const drAnalysis = analyzeRoadmap(cwd);
1027
+ const drPhases = (drAnalysis.phases ?? []).filter((p) => {
1028
+ if (options.phaseFrom && parseFloat(p.number) < parseFloat(options.phaseFrom))
1029
+ return false;
1030
+ if (options.phaseTo && parseFloat(p.number) > parseFloat(options.phaseTo))
1031
+ return false;
1032
+ return !p.roadmap_complete;
1033
+ });
1034
+ const drWaves = buildWaves(drPhases, {});
1035
+ const drScheduler = createScheduler(drConfig.scheduler, drConfig.superpowers);
1036
+ dryRunPlan = [];
1037
+ for (let wi = 0; wi < drWaves.length; wi++) {
1038
+ const wavePlan = drWaves[wi].map((phaseNum) => {
1039
+ const phaseInfo = drPhases.find((p) => p.number === phaseNum);
1040
+ const planPrompt = `plan phase ${phaseNum}`;
1041
+ const execPrompt = `execute phase ${phaseNum}`;
1042
+ const planTier = getEffectiveTierForDispatch({ agentType: 'grd-planner', prompt: planPrompt, config: drConfig, scheduler: drScheduler, schedulerConfig: drConfig.scheduler, superpowersConfig: drConfig.superpowers, modelProfiles: MODEL_PROFILES });
1043
+ const execTier = getEffectiveTierForDispatch({ agentType: 'grd-executor', prompt: execPrompt, config: drConfig, scheduler: drScheduler, schedulerConfig: drConfig.scheduler, superpowersConfig: drConfig.superpowers, modelProfiles: MODEL_PROFILES });
1044
+ const planModel = options.model ?? resolveModelForAgent(drConfig, 'grd-planner', cwd, { effectiveTierOverride: planTier });
1045
+ const execModel = options.model ?? resolveModelForAgent(drConfig, 'grd-executor', cwd, { effectiveTierOverride: execTier });
1046
+ return { phase: phaseNum, name: phaseInfo?.name ?? '', plan_model: planModel, execute_model: execModel };
1047
+ });
1048
+ dryRunPlan.push({ wave: wi + 1, phases: wavePlan });
1049
+ }
1050
+ }
1051
+ const result = await runAutopilot(cwd, options);
1052
+ const finalResult = dryRunPlan !== undefined
1053
+ ? { ...result, execution_plan: dryRunPlan }
1054
+ : result;
1055
+ const rawSummary = raw
1056
+ ? `Autopilot: ${result.phases_completed}/${result.phases_attempted} phases completed${result.stopped_at ? ` (stopped: ${result.stopped_at})` : ''}`
1057
+ : undefined;
1058
+ output(finalResult, raw, rawSummary);
1059
+ }
1060
+ /**
1061
+ * Pre-flight context for autopilot initialization.
1062
+ */
1063
+ function cmdInitAutopilot(cwd, raw) {
1064
+ const config = loadConfig(cwd);
1065
+ const analysis = analyzeRoadmap(cwd);
1066
+ // Check if claude CLI is available
1067
+ let claudeAvailable = false;
1068
+ try {
1069
+ const check = childProcess.spawnSync('claude', ['--version'], {
1070
+ stdio: 'pipe',
1071
+ timeout: config.timeouts.autopilot_check_ms,
1072
+ });
1073
+ claudeAvailable = check.status === 0;
1074
+ }
1075
+ catch {
1076
+ // claude CLI not found -- claudeAvailable stays false
1077
+ }
1078
+ const phases = analysis.phases || [];
1079
+ const incomplete = phases.filter((p) => p.disk_status !== 'complete' && !p.roadmap_complete);
1080
+ const backend = detectBackend(cwd);
1081
+ const caps = getBackendCapabilities(backend);
1082
+ const result = {
1083
+ claude_available: claudeAvailable,
1084
+ cron_available: caps.cron === true,
1085
+ total_phases: phases.length,
1086
+ incomplete_phases: incomplete.length,
1087
+ phase_range: {
1088
+ first: phases.length > 0 ? phases[0].number : null,
1089
+ last: phases.length > 0 ? phases[phases.length - 1].number : null,
1090
+ first_incomplete: incomplete.length > 0 ? incomplete[0].number : null,
1091
+ },
1092
+ config: {
1093
+ model_profile: config.model_profile,
1094
+ autonomous_mode: config.autonomous_mode,
1095
+ },
1096
+ phases: phases.map((p) => ({
1097
+ number: p.number,
1098
+ name: p.name,
1099
+ disk_status: p.disk_status || 'unknown',
1100
+ roadmap_complete: p.roadmap_complete || false,
1101
+ })),
1102
+ };
1103
+ output(result, raw, raw ? JSON.stringify(result) : undefined);
1104
+ }
1105
+ /**
1106
+ * Parse CLI flags and run the multi-milestone autopilot loop.
1107
+ */
1108
+ async function cmdMultiMilestoneAutopilot(cwd, args, raw) {
1109
+ const flag = (name, fallback) => {
1110
+ const i = args.indexOf(name);
1111
+ return i !== -1 ? args[i + 1] : fallback;
1112
+ };
1113
+ const hasFlag = (name) => args.indexOf(name) !== -1;
1114
+ const options = {
1115
+ maxMilestones: hasFlag('--max-milestones')
1116
+ ? parseInt(flag('--max-milestones', '10'), 10)
1117
+ : undefined,
1118
+ dryRun: hasFlag('--dry-run'),
1119
+ timeout: (() => {
1120
+ if (!hasFlag('--timeout'))
1121
+ return undefined;
1122
+ const parsed = parseInt(flag('--timeout', '0'), 10);
1123
+ if (isNaN(parsed) || parsed <= 0) {
1124
+ process.stderr.write('Error: --timeout must be a positive integer\n');
1125
+ process.exit(1);
1126
+ }
1127
+ return parsed;
1128
+ })(),
1129
+ maxTurns: (() => {
1130
+ if (!flag('--max-turns', null))
1131
+ return undefined;
1132
+ const parsed = parseInt(flag('--max-turns', '0'), 10);
1133
+ if (isNaN(parsed) || parsed <= 0) {
1134
+ process.stderr.write('Error: --max-turns must be a positive integer\n');
1135
+ process.exit(1);
1136
+ }
1137
+ return parsed;
1138
+ })(),
1139
+ model: flag('--model', undefined) ?? undefined,
1140
+ skipPlan: hasFlag('--skip-plan'),
1141
+ skipExecute: hasFlag('--skip-execute'),
1142
+ skipPostPipeline: hasFlag('--skip-post-pipeline'),
1143
+ };
1144
+ const result = await runMultiMilestoneAutopilot(cwd, options);
1145
+ const rawSummary = raw
1146
+ ? `Multi-milestone autopilot: ${result.milestones_completed}/${result.milestones_attempted} milestones completed (${result.total_phases_completed}/${result.total_phases_attempted} phases)${result.stopped_at ? ` (stopped: ${result.stopped_at})` : ''}`
1147
+ : undefined;
1148
+ output(result, raw, rawSummary);
1149
+ }
1150
+ /**
1151
+ * Pre-flight context for multi-milestone autopilot initialization.
1152
+ * Returns LT roadmap state, current milestone info, and next milestone resolution.
1153
+ */
1154
+ function cmdInitMultiMilestoneAutopilot(cwd, raw) {
1155
+ const config = loadConfig(cwd);
1156
+ const analysis = analyzeRoadmap(cwd);
1157
+ // Check if claude CLI is available
1158
+ let claudeAvailable = false;
1159
+ try {
1160
+ const check = childProcess.spawnSync('claude', ['--version'], {
1161
+ stdio: 'pipe',
1162
+ timeout: config.timeouts.autopilot_check_ms,
1163
+ });
1164
+ claudeAvailable = check.status === 0;
1165
+ }
1166
+ catch {
1167
+ // claude CLI not found -- claudeAvailable stays false
1168
+ }
1169
+ // Current milestone info
1170
+ const milestoneInfo = getMilestoneInfo(cwd);
1171
+ // Current milestone completion state
1172
+ const milestoneComplete = isMilestoneComplete(cwd);
1173
+ // Next milestone from LT roadmap
1174
+ const nextMilestone = resolveNextMilestone(cwd);
1175
+ // LT roadmap existence and state
1176
+ const ltRoadmapPath = path.join(cwd, '.planning', 'LONG-TERM-ROADMAP.md');
1177
+ const ltRoadmapExists = fs.existsSync(ltRoadmapPath);
1178
+ let ltMilestoneCount = 0;
1179
+ if (ltRoadmapExists) {
1180
+ const ltContent = fs.readFileSync(ltRoadmapPath, 'utf-8');
1181
+ const parsed = parseLongTermRoadmap(ltContent);
1182
+ if (parsed) {
1183
+ ltMilestoneCount = parsed.milestones.length;
1184
+ }
1185
+ }
1186
+ const phases = analysis.phases || [];
1187
+ const incomplete = phases.filter((p) => p.disk_status !== 'complete' && !p.roadmap_complete);
1188
+ const result = {
1189
+ claude_available: claudeAvailable,
1190
+ current_milestone: {
1191
+ version: milestoneInfo.version,
1192
+ name: milestoneInfo.name,
1193
+ is_complete: milestoneComplete,
1194
+ total_phases: phases.length,
1195
+ incomplete_phases: incomplete.length,
1196
+ },
1197
+ lt_roadmap: {
1198
+ exists: ltRoadmapExists,
1199
+ milestone_count: ltMilestoneCount,
1200
+ },
1201
+ next_milestone: nextMilestone,
1202
+ config: {
1203
+ model_profile: config.model_profile,
1204
+ autonomous_mode: config.autonomous_mode,
1205
+ },
1206
+ };
1207
+ output(result, raw, raw ? JSON.stringify(result) : undefined);
1208
+ }
1209
+ // ─── Spin Event Handler ──────────────────────────────────────────────────────
1210
+ /**
1211
+ * Handle a spin detection event by writing a SPIN-REPORT.md to the phase directory
1212
+ * and returning action options (resume, skip, abort) for the caller to present to the user.
1213
+ *
1214
+ * @param phaseDir - Absolute path to the phase directory
1215
+ * @param spinEvent - The SpinDetectedEvent from detectSpin()
1216
+ * @param phaseName - Human-readable phase name for the report header
1217
+ * @returns Path to the written SPIN-REPORT.md, or null if write failed
1218
+ */
1219
+ function handleSpinEvent(phaseDir, spinEvent, phaseName) {
1220
+ const pattern = spinEvent.repeated_pattern;
1221
+ // Auto-generate recovery suggestions based on error keywords in the pattern
1222
+ const suggestions = [];
1223
+ const lower = pattern.toLowerCase();
1224
+ if (/type.?error|cannot find|property .* does not exist/i.test(lower)) {
1225
+ suggestions.push('Run `npm run build:check` to identify type errors and fix them before retrying');
1226
+ }
1227
+ if (/test failed|expect|assertion/i.test(lower)) {
1228
+ suggestions.push('Run `npm test` to identify failing tests; review the test output for clues on missing implementation');
1229
+ }
1230
+ if (/cannot find module|module not found|require.*failed/i.test(lower)) {
1231
+ suggestions.push('Check that all required packages are installed (`npm install`) and import paths are correct');
1232
+ }
1233
+ if (suggestions.length === 0) {
1234
+ suggestions.push('Review the error pattern above and check for missing files, imports, or API mismatches');
1235
+ suggestions.push('Consider breaking the phase into smaller tasks or skipping and addressing manually');
1236
+ }
1237
+ suggestions.push('Check ROADMAP.md for any prerequisite phases that may not be complete yet');
1238
+ const reportLines = [
1239
+ `# Spin Detected — ${phaseName}`,
1240
+ '',
1241
+ `Generated: ${new Date().toISOString().slice(0, 19).replace('T', ' ')} UTC`,
1242
+ '',
1243
+ `## Summary`,
1244
+ '',
1245
+ `The autopilot detected **${spinEvent.consecutive_count} consecutive similar output chunks** (similarity: ${spinEvent.max_similarity}) suggesting the agent is looping on the same error without progress.`,
1246
+ '',
1247
+ '## Repeated Error Pattern',
1248
+ '',
1249
+ '```',
1250
+ pattern,
1251
+ '```',
1252
+ '',
1253
+ '## Recovery Suggestions',
1254
+ '',
1255
+ ...suggestions.map((s, i) => `${i + 1}. ${s}`),
1256
+ '',
1257
+ '## Actions',
1258
+ '',
1259
+ '- **Resume**: Fix the underlying issue above, then re-run `gd execute-phase <N>`',
1260
+ '- **Skip**: Mark the phase as skipped and continue autopilot with the next phase',
1261
+ '- **Abort**: Stop the autopilot run and investigate manually',
1262
+ ];
1263
+ try {
1264
+ const reportPath = path.join(phaseDir, 'SPIN-REPORT.md');
1265
+ fs.writeFileSync(reportPath, reportLines.join('\n') + '\n', 'utf-8');
1266
+ return reportPath;
1267
+ }
1268
+ catch {
1269
+ return null;
1270
+ }
1271
+ }
1272
+ // ─── Exports ────────────────────────────────────────────────────────────────
1273
+ module.exports = {
1274
+ createMergeQueue,
1275
+ cmdAutopilot,
1276
+ cmdInitAutopilot,
1277
+ cmdMultiMilestoneAutopilot,
1278
+ cmdInitMultiMilestoneAutopilot,
1279
+ runAutopilot,
1280
+ runMultiMilestoneAutopilot,
1281
+ resolvePhaseRange,
1282
+ isPhasePlanned,
1283
+ isPhaseExecuted,
1284
+ hasMultipleCandidates,
1285
+ isMilestoneComplete,
1286
+ resolveNextMilestone,
1287
+ buildNewMilestonePrompt,
1288
+ buildMilestoneCompletePrompt,
1289
+ spawnClaude,
1290
+ spawnClaudeAsync,
1291
+ buildPlanPrompt,
1292
+ buildExecutePrompt,
1293
+ buildSimplifyPrompt,
1294
+ buildCodeReviewPrompt,
1295
+ buildConflictResolvePrompt,
1296
+ buildWireupPrompt,
1297
+ buildKnowledgeMiningPrompt,
1298
+ runKnowledgeMining,
1299
+ buildCritiqueAgentPrompt,
1300
+ runRefinementLoop,
1301
+ runPostPhasePipeline,
1302
+ buildWaves,
1303
+ buildWavesFromPlans,
1304
+ parseWriteIntent,
1305
+ compareWriteIntent,
1306
+ formatWriteIntentMismatch,
1307
+ writeStatusMarker,
1308
+ updateStateProgress,
1309
+ DEFAULT_TIMEOUT_MINUTES,
1310
+ HEARTBEAT_INTERVAL_MS,
1311
+ _getSchedulerStates,
1312
+ handleSpinEvent,
1313
+ };
1314
+ //# sourceMappingURL=autopilot.js.map