@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,1309 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * GRD Worktree -- Git worktree lifecycle management for phase isolation
5
+ *
6
+ * Provides create, remove, list, and stale cleanup for git worktrees
7
+ * used during phase execution. Each phase executes in its own worktree
8
+ * at {project}/.worktrees/grd-worktree-{milestone}-{phase}.
9
+ *
10
+ * Dependencies: utils.ts (one-directional, no circular deps)
11
+ */
12
+
13
+
14
+ import type { ExecGitResult, GrdConfig, PhaseInfo, MilestoneInfo } from './types';
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { execFileSync } = require('child_process');
19
+ const {
20
+ execGit,
21
+ output,
22
+ error,
23
+ getMilestoneInfo,
24
+ loadConfig,
25
+ findPhaseInternal,
26
+ generateSlugInternal,
27
+ }: {
28
+ execGit: (cwd: string, args: string[], opts?: { allowBlocked?: boolean }) => ExecGitResult;
29
+ output: (result: unknown, raw: boolean, rawValue?: unknown) => never;
30
+ error: (message: string) => never;
31
+ getMilestoneInfo: (cwd: string) => MilestoneInfo;
32
+ loadConfig: (cwd: string) => GrdConfig;
33
+ findPhaseInternal: (cwd: string, phase: string) => PhaseInfo | null;
34
+ generateSlugInternal: (text: string) => string | null;
35
+ } = require('./utils');
36
+
37
+ // ─── Types ──────────────────────────────────────────────────────────────────
38
+
39
+ /**
40
+ * Parsed from git worktree list --porcelain output.
41
+ */
42
+ interface WorktreeEntry {
43
+ path: string;
44
+ head: string;
45
+ branch: string;
46
+ locked: boolean;
47
+ }
48
+
49
+ /**
50
+ * Enriched worktree info with GRD metadata.
51
+ */
52
+ interface GrdWorktreeEntry {
53
+ path: string;
54
+ branch: string;
55
+ phase: string;
56
+ milestone: string;
57
+ locked: boolean;
58
+ }
59
+
60
+ /**
61
+ * Options for cmdWorktreeCreate.
62
+ */
63
+ interface WorktreeCreateOptions {
64
+ phase: string;
65
+ milestone?: string;
66
+ slug?: string;
67
+ startPoint?: string;
68
+ force?: boolean;
69
+ }
70
+
71
+ /**
72
+ * Parsed phase and milestone from a GRD worktree directory name.
73
+ */
74
+ interface WorktreeParsedName {
75
+ phase: string;
76
+ milestone: string;
77
+ }
78
+
79
+ /**
80
+ * Options for cmdWorktreeRemove.
81
+ */
82
+ interface WorktreeRemoveOptions {
83
+ phase?: string;
84
+ milestone?: string;
85
+ path?: string;
86
+ force?: boolean;
87
+ }
88
+
89
+ /**
90
+ * Options for cmdWorktreeMerge.
91
+ */
92
+ interface MergeOptions {
93
+ phase: string;
94
+ milestone?: string;
95
+ slug?: string;
96
+ branch?: string;
97
+ base?: string;
98
+ deleteBranch?: boolean;
99
+ strategy?: string;
100
+ }
101
+
102
+ /**
103
+ * Result from createEvolveWorktree.
104
+ */
105
+ interface EvolveWorktreeResult {
106
+ path: string;
107
+ branch: string;
108
+ baseBranch: string;
109
+ created: string;
110
+ }
111
+
112
+ interface EvolveWorktreeError {
113
+ error: string;
114
+ }
115
+
116
+ /**
117
+ * Result from removeEvolveWorktree.
118
+ */
119
+ interface RemoveWorktreeResult {
120
+ removed: boolean;
121
+ already_gone?: boolean;
122
+ }
123
+
124
+ interface RemoveWorktreeError {
125
+ error: string;
126
+ }
127
+
128
+ /**
129
+ * Options for pushAndCreatePR programmatic helper.
130
+ */
131
+ interface PushPROptions {
132
+ title?: string;
133
+ body?: string;
134
+ base?: string;
135
+ }
136
+
137
+ /**
138
+ * Result from programmatic pushAndCreatePR.
139
+ */
140
+ interface PushPRSuccessResult {
141
+ pr_url: string;
142
+ branch: string;
143
+ base: string;
144
+ }
145
+
146
+ interface PushPRErrorResult {
147
+ error: string;
148
+ push_succeeded?: boolean;
149
+ }
150
+
151
+ // ─── Internal Helpers ─────────────────────────────────────────────────────────
152
+
153
+ /**
154
+ * Compute the worktree directory path for a given milestone and phase.
155
+ * Uses project-local .worktrees/ directory to avoid OS temp cleanup issues.
156
+ * Resolves cwd via realpathSync to handle macOS symlinks.
157
+ */
158
+ function worktreePath(cwd: string, milestone: string, phase: string): string {
159
+ const resolvedCwd: string = fs.realpathSync(cwd);
160
+ return path.join(resolvedCwd, '.worktrees', `grd-worktree-${milestone}-${phase}`);
161
+ }
162
+
163
+ /**
164
+ * Ensure .worktrees/ directory exists and is listed in .gitignore.
165
+ */
166
+ function ensureWorktreesDir(cwd: string): boolean {
167
+ const worktreesDir: string = path.join(cwd, '.worktrees');
168
+ if (!fs.existsSync(worktreesDir)) {
169
+ fs.mkdirSync(worktreesDir, { recursive: true });
170
+ }
171
+
172
+ // Add .worktrees/ to .gitignore if not already present
173
+ const gitignorePath: string = path.join(cwd, '.gitignore');
174
+ let gitignoreContent = '';
175
+ try {
176
+ gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8') as string;
177
+ } catch (e) {
178
+ if ((e as NodeJS.ErrnoException).code !== 'ENOENT') {
179
+ // Non-ENOENT errors (EISDIR, EPERM, etc.) are unexpected — re-throw
180
+ throw e;
181
+ }
182
+ // No .gitignore yet — will create
183
+ }
184
+ if (!gitignoreContent.includes('.worktrees')) {
185
+ const newline = gitignoreContent.length > 0 && !gitignoreContent.endsWith('\n') ? '\n' : '';
186
+ try {
187
+ fs.writeFileSync(gitignorePath, gitignoreContent + newline + '.worktrees/\n', 'utf-8');
188
+ } catch (e) {
189
+ process.stderr.write('Warning: could not update .gitignore: ' + (e as Error).message + '\n');
190
+ return false;
191
+ }
192
+ }
193
+ return true;
194
+ }
195
+
196
+ /**
197
+ * Compute the branch name for a worktree using the config template.
198
+ */
199
+ function worktreeBranch(cwd: string, milestone: string, phase: string, slug: string): string {
200
+ const config: GrdConfig = loadConfig(cwd);
201
+ const template: string = config.phase_branch_template || 'grd/{milestone}/{phase}-{slug}';
202
+ return template
203
+ .replace('{milestone}', milestone)
204
+ .replace('{phase}', phase)
205
+ .replace('{slug}', slug || phase);
206
+ }
207
+
208
+ /**
209
+ * Compute the milestone branch name using the config template.
210
+ */
211
+ function milestoneBranch(cwd: string, milestoneVersion?: string): string {
212
+ const config: GrdConfig = loadConfig(cwd);
213
+ const template: string = config.milestone_branch_template || 'grd/{milestone}-{slug}';
214
+ const milestone: MilestoneInfo = getMilestoneInfo(cwd);
215
+ const version: string = milestoneVersion || milestone.version;
216
+ const slug: string = generateSlugInternal(milestone.name) || 'milestone';
217
+ return template.replace('{milestone}', version).replace('{slug}', slug);
218
+ }
219
+
220
+ /**
221
+ * Parse git worktree list --porcelain output into structured entries.
222
+ * Each entry is separated by a blank line and has fields:
223
+ * worktree /path/to/worktree
224
+ * HEAD abc123
225
+ * branch refs/heads/branch-name
226
+ * (optional) locked
227
+ */
228
+ function parsePorcelainWorktrees(porcelainOutput: string): WorktreeEntry[] {
229
+ if (!porcelainOutput || !porcelainOutput.trim()) return [];
230
+
231
+ const blocks: string[] = porcelainOutput.trim().split(/\n\n+/);
232
+ const entries: WorktreeEntry[] = [];
233
+
234
+ for (const block of blocks) {
235
+ const lines: string[] = block.trim().split('\n');
236
+ const entry: WorktreeEntry = { path: '', head: '', branch: '', locked: false };
237
+
238
+ for (const line of lines) {
239
+ if (line.startsWith('worktree ')) {
240
+ entry.path = line.slice('worktree '.length);
241
+ } else if (line.startsWith('HEAD ')) {
242
+ entry.head = line.slice('HEAD '.length);
243
+ } else if (line.startsWith('branch ')) {
244
+ entry.branch = line.slice('branch '.length).replace('refs/heads/', '');
245
+ } else if (line === 'locked') {
246
+ entry.locked = true;
247
+ }
248
+ }
249
+
250
+ if (entry.path) {
251
+ entries.push(entry);
252
+ }
253
+ }
254
+
255
+ return entries;
256
+ }
257
+
258
+ /**
259
+ * Extract phase and milestone from a GRD worktree directory name.
260
+ * Expected format: grd-worktree-{milestone}-{phase}
261
+ */
262
+ function parseWorktreeName(wtPath: string): WorktreeParsedName | null {
263
+ const dirName: string = path.basename(wtPath);
264
+ const match: RegExpMatchArray | null = dirName.match(/^grd-worktree-(.+)-(\d+)$/);
265
+ if (!match) return null;
266
+ return { milestone: match[1], phase: match[2] };
267
+ }
268
+
269
+ /**
270
+ * Get all GRD-managed worktrees (filtering out main and non-GRD entries).
271
+ * Looks for worktrees in the project-local .worktrees/ directory.
272
+ */
273
+ function getGrdWorktrees(cwd: string): GrdWorktreeEntry[] {
274
+ const listResult: ExecGitResult = execGit(cwd, ['worktree', 'list', '--porcelain']);
275
+ if (listResult.exitCode !== 0) return [];
276
+
277
+ const all: WorktreeEntry[] = parsePorcelainWorktrees(listResult.stdout);
278
+ let resolvedCwd: string;
279
+ try {
280
+ resolvedCwd = fs.realpathSync(cwd);
281
+ } catch {
282
+ return [];
283
+ }
284
+ const worktreesDir: string = path.join(resolvedCwd, '.worktrees');
285
+
286
+ return all
287
+ .filter(
288
+ (wt: WorktreeEntry) =>
289
+ wt.path.startsWith(worktreesDir) && path.basename(wt.path).startsWith('grd-worktree-')
290
+ )
291
+ .map((wt: WorktreeEntry): GrdWorktreeEntry => {
292
+ const meta: WorktreeParsedName | null = parseWorktreeName(wt.path);
293
+ return {
294
+ path: wt.path,
295
+ branch: wt.branch,
296
+ phase: meta ? meta.phase : '',
297
+ milestone: meta ? meta.milestone : '',
298
+ locked: wt.locked,
299
+ };
300
+ });
301
+ }
302
+
303
+ // ─── CLI Commands ─────────────────────────────────────────────────────────────
304
+
305
+ /**
306
+ * Create a new git worktree for a phase.
307
+ *
308
+ * Creates a worktree at {cwd}/.worktrees/grd-worktree-{milestone}-{phase}
309
+ * with a branch following the configured phase_branch_template pattern.
310
+ * Ensures .worktrees/ directory exists and is listed in .gitignore.
311
+ *
312
+ * @param cwd - Project working directory
313
+ * @param options - Worktree creation options (phase, milestone, slug, startPoint, force)
314
+ * @param raw - If true, output raw text instead of JSON
315
+ * @returns void (outputs JSON or raw text to stdout and exits)
316
+ */
317
+ function cmdWorktreeCreate(cwd: string, options: WorktreeCreateOptions, raw: boolean): void {
318
+ const { phase, slug, startPoint } = options;
319
+ if (!phase) {
320
+ error('phase is required for worktree create');
321
+ return; // unreachable — error() calls process.exit()
322
+ }
323
+
324
+ // Resolve milestone from options or ROADMAP.md
325
+ const milestone: string = options.milestone || getMilestoneInfo(cwd).version;
326
+ const branchSlug: string = slug || phase;
327
+
328
+ // Ensure .worktrees/ directory exists and is in .gitignore
329
+ ensureWorktreesDir(cwd);
330
+
331
+ const wtPath: string = worktreePath(cwd, milestone, phase);
332
+ const branch: string = worktreeBranch(cwd, milestone, phase, branchSlug);
333
+
334
+ // Check if worktree already exists
335
+ if (fs.existsSync(wtPath)) {
336
+ output({ error: 'Worktree already exists', path: wtPath }, raw);
337
+ return; // unreachable — output() calls process.exit()
338
+ }
339
+
340
+ // Verify we are in a git repo
341
+ const revParse: ExecGitResult = execGit(cwd, ['rev-parse', '--git-dir']);
342
+ if (revParse.exitCode !== 0) {
343
+ output({ error: 'Not a git repository', details: revParse.stderr }, raw);
344
+ return; // unreachable
345
+ }
346
+
347
+ // Validate start-point exists if provided
348
+ if (startPoint) {
349
+ const check: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', startPoint]);
350
+ if (check.exitCode !== 0) {
351
+ output({ error: `Start point '${startPoint}' not found`, details: check.stderr }, raw);
352
+ return; // unreachable
353
+ }
354
+ }
355
+
356
+ // Create the worktree with a new branch, optionally from a start point
357
+ const gitArgs: string[] = ['worktree', 'add', '-b', branch, wtPath];
358
+ if (startPoint) {
359
+ gitArgs.push(startPoint);
360
+ }
361
+ // Check if branch already exists (before attempting worktree add)
362
+ if (!options.force) {
363
+ const branchCheck: ExecGitResult = execGit(cwd, [
364
+ 'rev-parse',
365
+ '--verify',
366
+ 'refs/heads/' + branch,
367
+ ]);
368
+ if (branchCheck.exitCode === 0) {
369
+ output({ error: `Branch '${branch}' already exists`, branch }, raw);
370
+ return; // unreachable
371
+ }
372
+ }
373
+
374
+ const result: ExecGitResult = execGit(cwd, gitArgs);
375
+ if (result.exitCode !== 0) {
376
+ output({ error: 'Failed to create worktree', details: result.stderr, branch }, raw);
377
+ return; // unreachable
378
+ }
379
+
380
+ const out: Record<string, string> = {
381
+ path: wtPath,
382
+ branch,
383
+ phase,
384
+ milestone,
385
+ created: new Date().toISOString(),
386
+ };
387
+ if (startPoint) {
388
+ out.start_point = startPoint;
389
+ }
390
+ output(out, raw, `Worktree created: ${out.path} (branch: ${out.branch})`);
391
+ }
392
+
393
+ /**
394
+ * Remove a git worktree by phase identifier or direct path.
395
+ *
396
+ * Gracefully handles non-existent worktrees (returns success with already_gone flag).
397
+ * Calls git worktree prune after removal to clean git state.
398
+ *
399
+ * @param cwd - Project working directory
400
+ * @param options - Removal options containing phase, milestone, path, or force flag
401
+ * @param raw - If true, output raw text instead of JSON
402
+ * @returns void (outputs JSON or raw text to stdout and exits)
403
+ */
404
+ function cmdWorktreeRemove(cwd: string, options: WorktreeRemoveOptions, raw: boolean): void {
405
+ let wtPath: string;
406
+
407
+ if (options.path) {
408
+ wtPath = options.path;
409
+ } else if (options.phase) {
410
+ const milestone: string = options.milestone || getMilestoneInfo(cwd).version;
411
+ wtPath = worktreePath(cwd, milestone, options.phase);
412
+ } else {
413
+ error(
414
+ 'Either --phase or --path is required for worktree remove. Specify which worktree to remove using --phase <N> or --path <worktree-path>. Example: worktree remove --phase 3. To list active worktrees: grd-tools.js worktree list'
415
+ );
416
+ return; // unreachable — error() calls process.exit()
417
+ }
418
+
419
+ // If path does not exist on disk, return graceful response
420
+ if (!fs.existsSync(wtPath)) {
421
+ // Also try to prune from git's perspective
422
+ execGit(cwd, ['worktree', 'prune']);
423
+ output({ removed: true, path: wtPath, already_gone: true }, raw);
424
+ return; // unreachable
425
+ }
426
+
427
+ // Try to remove via git worktree remove (--force for GRD-managed temp worktrees)
428
+ const removeResult: ExecGitResult = execGit(cwd, ['worktree', 'remove', wtPath, '--force'], {
429
+ allowBlocked: true,
430
+ });
431
+ if (removeResult.exitCode !== 0) {
432
+ process.stderr.write(
433
+ 'Warning: git worktree remove failed: ' +
434
+ (removeResult.stderr || 'unknown error').trim() +
435
+ '\n'
436
+ );
437
+ }
438
+
439
+ // Prune to clean git state
440
+ execGit(cwd, ['worktree', 'prune']);
441
+
442
+ // Clean up the temp directory if it still exists
443
+ if (fs.existsSync(wtPath)) {
444
+ fs.rmSync(wtPath, { recursive: true, force: true });
445
+ }
446
+
447
+ output({ removed: true, path: wtPath }, raw);
448
+ }
449
+
450
+ /**
451
+ * List all active GRD-managed worktrees.
452
+ *
453
+ * Parses git worktree list --porcelain output and filters to only
454
+ * GRD-created worktrees (those in .worktrees/ with grd-worktree- prefix).
455
+ * Returns empty array if no worktrees exist.
456
+ *
457
+ * @param cwd - Project working directory
458
+ * @param raw - If true, output raw text instead of JSON
459
+ * @returns void (outputs JSON or raw text to stdout and exits)
460
+ */
461
+ function cmdWorktreeList(cwd: string, raw: boolean): void {
462
+ const worktrees: GrdWorktreeEntry[] = getGrdWorktrees(cwd);
463
+ output({ worktrees, count: worktrees.length }, raw);
464
+ }
465
+
466
+ /**
467
+ * Remove stale worktrees whose disk directories no longer exist.
468
+ *
469
+ * A worktree is stale if its path does not exist on disk or is empty.
470
+ * Locked worktrees are never removed regardless of disk state.
471
+ *
472
+ * @param cwd - Project working directory
473
+ * @param raw - If true, output raw text instead of JSON
474
+ * @returns void (outputs JSON or raw text to stdout and exits)
475
+ */
476
+ function cmdWorktreeRemoveStale(cwd: string, raw: boolean): void {
477
+ const worktrees: GrdWorktreeEntry[] = getGrdWorktrees(cwd);
478
+ const removed: string[] = [];
479
+
480
+ for (const wt of worktrees) {
481
+ // Never remove locked worktrees
482
+ if (wt.locked) continue;
483
+
484
+ // Check if path exists and is non-empty
485
+ let isStale = false;
486
+ try {
487
+ if (!fs.existsSync(wt.path)) {
488
+ isStale = true;
489
+ } else {
490
+ const entries: string[] = fs.readdirSync(wt.path);
491
+ if (entries.length === 0) {
492
+ isStale = true;
493
+ }
494
+ }
495
+ } catch {
496
+ isStale = true;
497
+ }
498
+
499
+ if (isStale) {
500
+ // Remove from git's worktree tracking
501
+ execGit(cwd, ['worktree', 'remove', wt.path, '--force'], { allowBlocked: true });
502
+ removed.push(wt.path);
503
+ }
504
+ }
505
+
506
+ // Final prune to clean any remaining stale references
507
+ execGit(cwd, ['worktree', 'prune']);
508
+
509
+ output({ removed, count: removed.length }, raw);
510
+ }
511
+
512
+ /**
513
+ * Push worktree branch to remote and create a PR via gh CLI.
514
+ *
515
+ * Both error paths return structured JSON (exit 0) so callers (orchestrators,
516
+ * MCP) receive parseable output rather than a crash.
517
+ *
518
+ * @param cwd - Project working directory
519
+ * @param options - Options object containing phase, milestone, title, body, and base branch
520
+ * @param raw - If true, output raw text instead of JSON
521
+ * @returns void (outputs JSON or raw text to stdout and exits)
522
+ */
523
+ function cmdWorktreePushAndPR(cwd: string, options: Record<string, string>, raw: boolean): void {
524
+ const { phase } = options;
525
+ if (!phase) {
526
+ output({ error: 'phase is required for worktree push-pr' }, raw);
527
+ return; // unreachable
528
+ }
529
+
530
+ // Resolve milestone
531
+ const milestone: string = options.milestone || getMilestoneInfo(cwd).version;
532
+
533
+ // Compute worktree path
534
+ const wtPath: string = worktreePath(cwd, milestone, phase);
535
+
536
+ // Verify worktree directory exists on disk
537
+ if (!fs.existsSync(wtPath)) {
538
+ output({ error: `Worktree not found at ${wtPath}`, phase, milestone }, raw);
539
+ return; // unreachable
540
+ }
541
+
542
+ // Read the actual branch name from the worktree HEAD (more robust than recomputing)
543
+ const headResult: ExecGitResult = execGit(wtPath, ['rev-parse', '--abbrev-ref', 'HEAD']);
544
+ const branch: string =
545
+ headResult.exitCode === 0 && headResult.stdout
546
+ ? headResult.stdout.trim()
547
+ : worktreeBranch(cwd, milestone, phase, phase); // fallback
548
+
549
+ // Derive slug from branch name for title generation
550
+ const phaseInfo: PhaseInfo | null = findPhaseInternal(cwd, phase);
551
+ const slug: string =
552
+ phaseInfo && phaseInfo.phase_slug
553
+ ? phaseInfo.phase_slug
554
+ : branch.split('/').pop()?.replace(/^\d+-/, '') || phase;
555
+
556
+ // Push branch to origin from worktree directory
557
+ const pushResult: ExecGitResult = execGit(wtPath, ['push', '-u', 'origin', branch], {
558
+ allowBlocked: true,
559
+ });
560
+ if (pushResult.exitCode !== 0) {
561
+ output(
562
+ {
563
+ error: 'Failed to push branch',
564
+ details: pushResult.stderr,
565
+ phase,
566
+ milestone,
567
+ branch,
568
+ },
569
+ raw
570
+ );
571
+ return; // unreachable
572
+ }
573
+
574
+ // Resolve base branch
575
+ const config: GrdConfig = loadConfig(cwd);
576
+ const baseBranch: string = options.base || config.base_branch || 'main';
577
+
578
+ // Build PR title
579
+ const title: string = options.title || `Phase ${phase}: ${slug} (${milestone})`;
580
+
581
+ // Build PR body
582
+ const body: string =
583
+ options.body || `## Phase ${phase}\n\nMilestone: ${milestone}\nBranch: ${branch}\n`;
584
+
585
+ // Create PR via gh CLI
586
+ let ghOutput: string;
587
+ try {
588
+ ghOutput = execFileSync(
589
+ 'gh',
590
+ ['pr', 'create', '--title', title, '--body', body, '--base', baseBranch, '--head', branch],
591
+ { cwd: wtPath, stdio: 'pipe', encoding: 'utf-8' }
592
+ ) as string;
593
+ } catch (ghErr) {
594
+ // gh failed — return structured error with push_succeeded flag
595
+ const stderr: string = (ghErr as { stderr?: Buffer | string }).stderr
596
+ ? String((ghErr as { stderr?: Buffer | string }).stderr).trim()
597
+ : (ghErr as Error).message || 'Unknown gh error';
598
+ output(
599
+ {
600
+ error: 'Failed to create PR via gh CLI',
601
+ details: stderr,
602
+ push_succeeded: true,
603
+ phase,
604
+ milestone,
605
+ branch,
606
+ base: baseBranch,
607
+ title,
608
+ body,
609
+ },
610
+ raw
611
+ );
612
+ return; // unreachable
613
+ }
614
+
615
+ // gh pr create outputs the PR URL on stdout
616
+ const prUrl: string = ghOutput.trim();
617
+ const urlParts: string[] = prUrl.split('/');
618
+ const prNumber: string | null = urlParts.length > 0 ? urlParts[urlParts.length - 1] : null;
619
+
620
+ output(
621
+ {
622
+ pr_url: prUrl,
623
+ pr_number: prNumber,
624
+ branch,
625
+ base: baseBranch,
626
+ title,
627
+ body,
628
+ phase,
629
+ milestone,
630
+ },
631
+ raw
632
+ );
633
+ }
634
+
635
+ // ─── Programmatic Helpers (evolve, autopilot) ────────────────────────────────
636
+
637
+ /**
638
+ * Create a worktree for the evolve loop.
639
+ * Returns a result object instead of calling output() — suitable for
640
+ * programmatic callers that need the path/branch info.
641
+ *
642
+ * Worktree directory: {cwd}/.worktrees/grd-evolve-{YYYYMMDD-HHmmss}
643
+ * Branch name: grd/evolve/{YYYYMMDD-HHmmss}
644
+ *
645
+ * @param cwd - Project working directory
646
+ * @returns EvolveWorktreeResult with path, branch, baseBranch, and created timestamp, or EvolveWorktreeError with error message
647
+ */
648
+ function createEvolveWorktree(cwd: string): EvolveWorktreeResult | EvolveWorktreeError {
649
+ // Verify git repo
650
+ const revParse: ExecGitResult = execGit(cwd, ['rev-parse', '--git-dir']);
651
+ if (revParse.exitCode !== 0) {
652
+ return { error: 'Not a git repository' };
653
+ }
654
+
655
+ const now: Date = new Date();
656
+ const stamp: string = now
657
+ .toISOString()
658
+ .replace(/[-:T]/g, '')
659
+ .replace(/\.\d+Z$/, '')
660
+ .slice(0, 15);
661
+ // stamp format: YYYYMMDD + HHmmss (15 chars)
662
+ const tag = `${stamp.slice(0, 8)}-${stamp.slice(8)}`;
663
+
664
+ const config: GrdConfig = loadConfig(cwd);
665
+ const baseBranch: string = config.base_branch || 'main';
666
+
667
+ ensureWorktreesDir(cwd);
668
+
669
+ const resolvedCwd: string = fs.realpathSync(cwd);
670
+ const wtPath: string = path.join(resolvedCwd, '.worktrees', `grd-evolve-${tag}`);
671
+ const branch = `grd/evolve/${tag}`;
672
+
673
+ if (fs.existsSync(wtPath)) {
674
+ return { error: `Worktree already exists at ${wtPath}` };
675
+ }
676
+
677
+ const result: ExecGitResult = execGit(cwd, ['worktree', 'add', '-b', branch, wtPath, baseBranch]);
678
+ if (result.exitCode !== 0) {
679
+ return { error: `Failed to create worktree: ${result.stderr}` };
680
+ }
681
+
682
+ return {
683
+ path: wtPath,
684
+ branch,
685
+ baseBranch,
686
+ created: now.toISOString(),
687
+ };
688
+ }
689
+
690
+ /**
691
+ * Remove an evolve worktree and prune git state.
692
+ * Gracefully handles already-removed worktrees.
693
+ */
694
+ function removeEvolveWorktree(
695
+ cwd: string,
696
+ wtPath: string
697
+ ): RemoveWorktreeResult | RemoveWorktreeError {
698
+ if (!fs.existsSync(wtPath)) {
699
+ execGit(cwd, ['worktree', 'prune']);
700
+ return { removed: true, already_gone: true };
701
+ }
702
+
703
+ execGit(cwd, ['worktree', 'remove', wtPath, '--force'], { allowBlocked: true });
704
+ execGit(cwd, ['worktree', 'prune']);
705
+
706
+ if (fs.existsSync(wtPath)) {
707
+ fs.rmSync(wtPath, { recursive: true, force: true });
708
+ }
709
+
710
+ return { removed: true };
711
+ }
712
+
713
+ /**
714
+ * Push a worktree branch to remote and create a PR via gh CLI.
715
+ * Returns structured result instead of calling output().
716
+ */
717
+ function pushAndCreatePR(
718
+ cwd: string,
719
+ wtPath: string,
720
+ options: PushPROptions = {}
721
+ ): PushPRSuccessResult | PushPRErrorResult {
722
+ // Read branch from worktree HEAD
723
+ const headResult: ExecGitResult = execGit(wtPath, ['rev-parse', '--abbrev-ref', 'HEAD']);
724
+ if (headResult.exitCode !== 0) {
725
+ return { error: 'Failed to determine worktree branch' };
726
+ }
727
+ const branch: string = headResult.stdout.trim();
728
+
729
+ const config: GrdConfig = loadConfig(cwd);
730
+ const baseBranch: string = options.base || config.base_branch || 'main';
731
+
732
+ // Push branch
733
+ const pushResult: ExecGitResult = execGit(wtPath, ['push', '-u', 'origin', branch], {
734
+ allowBlocked: true,
735
+ });
736
+ if (pushResult.exitCode !== 0) {
737
+ return {
738
+ error: `Failed to push branch: ${pushResult.stderr}`,
739
+ push_succeeded: false,
740
+ };
741
+ }
742
+
743
+ const title: string = options.title || `Evolve: improvements on ${branch}`;
744
+ const body: string =
745
+ options.body || `Automated improvements from the evolve loop.\n\nBranch: ${branch}\n`;
746
+
747
+ // Create PR via gh CLI
748
+ let ghOutput: string;
749
+ try {
750
+ ghOutput = execFileSync(
751
+ 'gh',
752
+ ['pr', 'create', '--title', title, '--body', body, '--base', baseBranch, '--head', branch],
753
+ { cwd: wtPath, stdio: 'pipe', encoding: 'utf-8' }
754
+ ) as string;
755
+ } catch (ghErr) {
756
+ const stderr: string = (ghErr as { stderr?: Buffer | string }).stderr
757
+ ? String((ghErr as { stderr?: Buffer | string }).stderr).trim()
758
+ : (ghErr as Error).message || 'Unknown gh error';
759
+ return { error: `Failed to create PR: ${stderr}`, push_succeeded: true };
760
+ }
761
+
762
+ return {
763
+ pr_url: ghOutput.trim(),
764
+ branch,
765
+ base: baseBranch,
766
+ };
767
+ }
768
+
769
+ // ─── Milestone Branch Operations ──────────────────────────────────────────────
770
+
771
+ /**
772
+ * Ensure the milestone branch exists, creating it from baseBranch if needed.
773
+ */
774
+ function cmdWorktreeEnsureMilestoneBranch(
775
+ cwd: string,
776
+ options: Record<string, string>,
777
+ raw: boolean
778
+ ): void {
779
+ const milestoneVersion: string = options.milestone || getMilestoneInfo(cwd).version;
780
+ const config: GrdConfig = loadConfig(cwd);
781
+ const baseBranch: string = options.baseBranch || config.base_branch || 'main';
782
+ const branch: string = milestoneBranch(cwd, milestoneVersion);
783
+
784
+ // Check if branch already exists
785
+ const check: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', branch]);
786
+ if (check.exitCode === 0) {
787
+ output({ branch, already_existed: true }, raw);
788
+ return; // unreachable
789
+ }
790
+
791
+ // Verify base branch exists
792
+ const baseCheck: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', baseBranch]);
793
+ if (baseCheck.exitCode !== 0) {
794
+ output({ error: `Base branch '${baseBranch}' not found`, details: baseCheck.stderr }, raw);
795
+ return; // unreachable
796
+ }
797
+
798
+ // Create branch without checkout
799
+ const result: ExecGitResult = execGit(cwd, ['branch', branch, baseBranch]);
800
+ if (result.exitCode !== 0) {
801
+ output({ error: 'Failed to create milestone branch', details: result.stderr }, raw);
802
+ return; // unreachable
803
+ }
804
+
805
+ output({ branch, already_existed: false, base_branch: baseBranch }, raw);
806
+ }
807
+
808
+ /**
809
+ * Merge a phase branch into the target branch.
810
+ *
811
+ * Target branch is determined by: options.base > config.base_branch > milestone branch.
812
+ * When --base is provided, merges directly into that branch (no milestone branch required).
813
+ * Otherwise falls back to the milestone branch for backward compatibility.
814
+ *
815
+ * Records the current branch, checks out the target branch, merges the
816
+ * phase branch with --no-ff, and restores the original branch. On conflict,
817
+ * aborts the merge and restores the original branch.
818
+ *
819
+ * @param cwd - Project working directory
820
+ * @param options - Merge options including phase, milestone, slug, branch, base, deleteBranch, and strategy
821
+ * @param raw - If true, output raw text instead of JSON
822
+ * @returns void (outputs JSON or raw text to stdout and exits)
823
+ */
824
+ function cmdWorktreeMerge(cwd: string, options: MergeOptions, raw: boolean): void {
825
+ const { phase, slug, deleteBranch } = options;
826
+ if (!phase) {
827
+ error(
828
+ 'phase is required for worktree merge. Usage: worktree merge --phase <N>. Add the --phase flag, e.g.: worktree merge --phase 2'
829
+ );
830
+ return; // unreachable — error() calls process.exit()
831
+ }
832
+
833
+ const milestoneVersion: string = options.milestone || getMilestoneInfo(cwd).version;
834
+ const phaseBranch: string =
835
+ options.branch || worktreeBranch(cwd, milestoneVersion, phase, slug || phase);
836
+
837
+ // Determine target branch: explicit --base, or milestone branch (with fallback to config base_branch)
838
+ let targetBranch: string;
839
+ if (options.base) {
840
+ // Explicit base branch — merge directly into it (no milestone branch needed)
841
+ targetBranch = options.base;
842
+ } else {
843
+ // Try milestone branch first (backward compat); fall back to config.base_branch
844
+ const msBranch: string = milestoneBranch(cwd, milestoneVersion);
845
+ const msCheck: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', msBranch]);
846
+ if (msCheck.exitCode === 0) {
847
+ targetBranch = msBranch;
848
+ } else {
849
+ const config: GrdConfig = loadConfig(cwd);
850
+ targetBranch = config.base_branch || 'main';
851
+ }
852
+ }
853
+
854
+ // Verify target branch exists
855
+ const targetCheck: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', targetBranch]);
856
+ if (targetCheck.exitCode !== 0) {
857
+ output({ error: `Target branch '${targetBranch}' not found` }, raw);
858
+ return; // unreachable
859
+ }
860
+
861
+ // Verify phase branch exists
862
+ const phaseCheck: ExecGitResult = execGit(cwd, ['rev-parse', '--verify', phaseBranch]);
863
+ if (phaseCheck.exitCode !== 0) {
864
+ output({ error: `Phase branch '${phaseBranch}' not found` }, raw);
865
+ return; // unreachable
866
+ }
867
+
868
+ // Record current branch
869
+ const headResult: ExecGitResult = execGit(cwd, ['rev-parse', '--abbrev-ref', 'HEAD']);
870
+ const originalBranch: string = headResult.exitCode === 0 ? headResult.stdout.trim() : 'main';
871
+
872
+ // Checkout target branch
873
+ const coResult: ExecGitResult = execGit(cwd, ['checkout', targetBranch]);
874
+ if (coResult.exitCode !== 0) {
875
+ output(
876
+ {
877
+ error: `Failed to checkout target branch '${targetBranch}'`,
878
+ details: coResult.stderr,
879
+ },
880
+ raw
881
+ );
882
+ return; // unreachable
883
+ }
884
+
885
+ // Get phase info for merge commit message
886
+ const phaseInfo: PhaseInfo | null = findPhaseInternal(cwd, phase);
887
+ const phaseName: string = phaseInfo ? phaseInfo.phase_name || slug || phase : slug || phase;
888
+
889
+ // Merge phase branch with --no-ff
890
+ const mergeResult: ExecGitResult = execGit(cwd, [
891
+ 'merge',
892
+ '--no-ff',
893
+ phaseBranch,
894
+ '-m',
895
+ `Merge phase ${phase}: ${phaseName}`,
896
+ ]);
897
+
898
+ if (mergeResult.exitCode !== 0) {
899
+ // Merge conflict — abort and restore original branch
900
+ execGit(cwd, ['merge', '--abort']);
901
+ const abortRestore = execGit(cwd, ['checkout', originalBranch]);
902
+ if (abortRestore.exitCode !== 0) {
903
+ process.stderr.write(
904
+ `[grd] WARNING: failed to restore branch ${originalBranch} after merge abort\n`
905
+ );
906
+ }
907
+ output(
908
+ {
909
+ error: 'Merge conflict',
910
+ details: mergeResult.stderr,
911
+ target_branch: targetBranch,
912
+ phase_branch: phaseBranch,
913
+ },
914
+ raw
915
+ );
916
+ return; // unreachable
917
+ }
918
+
919
+ // Optionally delete phase branch
920
+ if (deleteBranch) {
921
+ execGit(cwd, ['branch', '-d', phaseBranch]);
922
+ }
923
+
924
+ // Restore original branch
925
+ const restoreResult = execGit(cwd, ['checkout', originalBranch]);
926
+ const restoredBranch = restoreResult.exitCode === 0;
927
+ if (!restoredBranch) {
928
+ process.stderr.write(`[grd] WARNING: failed to restore branch ${originalBranch} after merge\n`);
929
+ }
930
+
931
+ output(
932
+ {
933
+ merged: true,
934
+ target_branch: targetBranch,
935
+ phase_branch: phaseBranch,
936
+ phase,
937
+ branch_deleted: !!deleteBranch,
938
+ original_branch_restored: restoredBranch,
939
+ },
940
+ raw
941
+ );
942
+ }
943
+
944
+ // ─── Hook Handlers ────────────────────────────────────────────────────────────
945
+
946
+ /**
947
+ * Hook handler for WorktreeCreate events from Claude Code.
948
+ *
949
+ * When Claude Code creates a worktree natively (via `isolation: worktree`),
950
+ * this hook fires to optionally rename the branch to GRD's naming convention
951
+ * and log the lifecycle event. No-op when GRD is inactive or branching disabled.
952
+ *
953
+ * @param cwd - Project working directory
954
+ * @param wtPath - Path to the created worktree ($WORKTREE_PATH)
955
+ * @param wtBranch - Branch name of the created worktree ($WORKTREE_BRANCH)
956
+ * @param raw - If true, output raw text instead of JSON
957
+ * @returns void (outputs JSON or raw text to stdout and exits)
958
+ */
959
+ function cmdWorktreeHookCreate(cwd: string, wtPath: string, wtBranch: string, raw: boolean): void {
960
+ // No-op when GRD is inactive
961
+ if (!fs.existsSync(path.join(cwd, '.planning'))) {
962
+ output({ skipped: true, reason: 'no .planning directory' }, raw);
963
+ return; // unreachable
964
+ }
965
+
966
+ // No-op when branching is disabled
967
+ const config: GrdConfig = loadConfig(cwd);
968
+ if (config.branching_strategy === 'none') {
969
+ output({ skipped: true, reason: 'branching disabled' }, raw);
970
+ return; // unreachable
971
+ }
972
+
973
+ // Check if branch already follows GRD convention (starts with 'grd/')
974
+ if (wtBranch && wtBranch.startsWith('grd/')) {
975
+ output(
976
+ {
977
+ hooked: true,
978
+ worktree_path: wtPath,
979
+ branch: wtBranch,
980
+ renamed: false,
981
+ reason: 'branch already follows GRD convention',
982
+ },
983
+ raw
984
+ );
985
+ return; // unreachable
986
+ }
987
+
988
+ // Try to extract phase info from the worktree path for branch rename
989
+ const dirName: string = path.basename(wtPath || '');
990
+ const phaseMatch: RegExpMatchArray | null = dirName.match(/(\d+)$/);
991
+
992
+ if (phaseMatch) {
993
+ const phase: string = phaseMatch[1];
994
+ try {
995
+ const milestone: MilestoneInfo = getMilestoneInfo(cwd);
996
+ const phaseInfo: PhaseInfo | null = findPhaseInternal(cwd, phase);
997
+ const slug: string = phaseInfo
998
+ ? generateSlugInternal(phaseInfo.phase_slug || phaseInfo.phase_name || '') || phase
999
+ : phase;
1000
+ const grdBranch: string = worktreeBranch(cwd, milestone.version, phase, slug);
1001
+
1002
+ if (grdBranch !== wtBranch) {
1003
+ const renameResult: ExecGitResult = execGit(wtPath, ['branch', '-m', wtBranch, grdBranch]);
1004
+ if (renameResult.exitCode === 0) {
1005
+ output(
1006
+ {
1007
+ hooked: true,
1008
+ worktree_path: wtPath,
1009
+ branch: grdBranch,
1010
+ renamed: true,
1011
+ original_branch: wtBranch,
1012
+ },
1013
+ raw
1014
+ );
1015
+ return; // unreachable
1016
+ }
1017
+ // Rename failed — log warning to stderr and continue
1018
+ process.stderr.write(
1019
+ 'Warning: branch rename failed: ' +
1020
+ (renameResult.stderr || 'git branch rename failed').trim() +
1021
+ '\n'
1022
+ );
1023
+ output(
1024
+ {
1025
+ hooked: true,
1026
+ worktree_path: wtPath,
1027
+ branch: wtBranch,
1028
+ renamed: false,
1029
+ rename_failed: true,
1030
+ reason: renameResult.stderr || 'git branch rename failed',
1031
+ },
1032
+ raw
1033
+ );
1034
+ return; // unreachable
1035
+ }
1036
+ } catch (_e) {
1037
+ // Could not determine milestone/phase info — log creation without rename
1038
+ }
1039
+ }
1040
+
1041
+ // Default: log creation without rename
1042
+ output(
1043
+ {
1044
+ hooked: true,
1045
+ worktree_path: wtPath,
1046
+ branch: wtBranch,
1047
+ renamed: false,
1048
+ },
1049
+ raw
1050
+ );
1051
+ }
1052
+
1053
+ /**
1054
+ * Hook handler for WorktreeRemove events from Claude Code.
1055
+ *
1056
+ * Logs the worktree removal for tracking. Intentionally minimal —
1057
+ * Phase 46 will add state cleanup here if needed.
1058
+ * No-op when GRD is inactive or branching disabled.
1059
+ *
1060
+ * @param cwd - Project working directory
1061
+ * @param wtPath - Path to the removed worktree ($WORKTREE_PATH)
1062
+ * @param wtBranch - Branch name of the removed worktree ($WORKTREE_BRANCH)
1063
+ * @param raw - If true, output raw text instead of JSON
1064
+ * @returns void (outputs JSON or raw text to stdout and exits)
1065
+ */
1066
+ function cmdWorktreeHookRemove(cwd: string, wtPath: string, wtBranch: string, raw: boolean): void {
1067
+ // No-op when GRD is inactive
1068
+ if (!fs.existsSync(path.join(cwd, '.planning'))) {
1069
+ output({ skipped: true, reason: 'no .planning directory' }, raw);
1070
+ return; // unreachable
1071
+ }
1072
+
1073
+ // No-op when branching is disabled
1074
+ const config: GrdConfig = loadConfig(cwd);
1075
+ if (config.branching_strategy === 'none') {
1076
+ output({ skipped: true, reason: 'branching disabled' }, raw);
1077
+ return; // unreachable
1078
+ }
1079
+
1080
+ const result: Record<string, unknown> = {
1081
+ hooked: true,
1082
+ worktree_path: wtPath,
1083
+ branch: wtBranch,
1084
+ action: 'remove_logged',
1085
+ };
1086
+
1087
+ // Try to extract phase/milestone metadata from the worktree path
1088
+ // Expected GRD format: grd-worktree-{milestone}-{phase}
1089
+ try {
1090
+ const meta: WorktreeParsedName | null = parseWorktreeName(wtPath || '');
1091
+ if (meta) {
1092
+ result.phase_detected = meta.phase;
1093
+ result.milestone_detected = meta.milestone;
1094
+ }
1095
+ } catch (_e) {
1096
+ // Best-effort: metadata extraction failure is not an error
1097
+ }
1098
+
1099
+ output(result, raw, `Worktree hook: ${result.worktree_path}`);
1100
+ }
1101
+
1102
+ // ─── Hook Handlers ────────────────────────────────────────────────────────────
1103
+
1104
+ /**
1105
+ * Hook handler for TeammateIdle events.
1106
+ * Called when a teammate spawned via Agent tool becomes idle.
1107
+ * Supports {continue: false, stopReason: "..."} response to stop the teammate.
1108
+ *
1109
+ * Environment variables from hook payload:
1110
+ * - AGENT_ID: unique identifier of the idle agent
1111
+ * - AGENT_TYPE: type of the agent (e.g., "task", "teammate")
1112
+ */
1113
+ function cmdTeammateIdleHook(_cwd: string, raw: boolean): void {
1114
+ const agentId = process.env.AGENT_ID || 'unknown';
1115
+ const agentType = process.env.AGENT_TYPE || 'unknown';
1116
+
1117
+ // For now, allow all teammates to continue.
1118
+ // Future: filter by agent_type to stop non-GRD agents or agents that have completed their work.
1119
+ const result = {
1120
+ ok: true,
1121
+ hook: 'TeammateIdle',
1122
+ agent_id: agentId,
1123
+ agent_type: agentType,
1124
+ action: 'continue',
1125
+ };
1126
+
1127
+ if (raw) {
1128
+ process.stdout.write(`TeammateIdle: agent=${agentId} type=${agentType} action=continue\n`);
1129
+ } else {
1130
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
1131
+ }
1132
+ }
1133
+
1134
+ /**
1135
+ * Hook handler for TaskCompleted events.
1136
+ * Called when a background task completes.
1137
+ * Supports {continue: false, stopReason: "..."} response to stop the task.
1138
+ *
1139
+ * Environment variables from hook payload:
1140
+ * - AGENT_ID: unique identifier of the completed task agent
1141
+ * - AGENT_TYPE: type of the agent
1142
+ */
1143
+ function cmdTaskCompletedHook(_cwd: string, raw: boolean): void {
1144
+ const agentId = process.env.AGENT_ID || 'unknown';
1145
+ const agentType = process.env.AGENT_TYPE || 'unknown';
1146
+
1147
+ const result = {
1148
+ ok: true,
1149
+ hook: 'TaskCompleted',
1150
+ agent_id: agentId,
1151
+ agent_type: agentType,
1152
+ action: 'acknowledged',
1153
+ };
1154
+
1155
+ if (raw) {
1156
+ process.stdout.write(`TaskCompleted: agent=${agentId} type=${agentType}\n`);
1157
+ } else {
1158
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
1159
+ }
1160
+ }
1161
+
1162
+ /**
1163
+ * Hook handler for InstructionsLoaded events.
1164
+ * Called when CLAUDE.md or rules files are loaded.
1165
+ * Used for plugin setup verification (e.g., confirm .planning/ exists).
1166
+ *
1167
+ * Environment variables from hook payload:
1168
+ * - AGENT_ID: unique identifier of the agent loading instructions
1169
+ * - AGENT_TYPE: type of the agent
1170
+ */
1171
+ function cmdInstructionsLoadedHook(cwd: string, raw: boolean): void {
1172
+ const agentId = process.env.AGENT_ID || 'unknown';
1173
+ const agentType = process.env.AGENT_TYPE || 'unknown';
1174
+ const planningDir = path.join(cwd, '.planning');
1175
+ const planningExists = fs.existsSync(planningDir);
1176
+
1177
+ const result = {
1178
+ ok: true,
1179
+ hook: 'InstructionsLoaded',
1180
+ agent_id: agentId,
1181
+ agent_type: agentType,
1182
+ planning_exists: planningExists,
1183
+ };
1184
+
1185
+ if (raw) {
1186
+ process.stdout.write(`InstructionsLoaded: agent=${agentId} planning=${planningExists}\n`);
1187
+ } else {
1188
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
1189
+ }
1190
+ }
1191
+
1192
+ /**
1193
+ * Hook handler for StopFailure events (Claude Code v2.1.78+).
1194
+ *
1195
+ * Fires when a turn ends due to an API-level failure (rate limit, auth failure,
1196
+ * network error). GRD uses this to log failures to autopilot.log so the
1197
+ * autopilot/evolve retry logic can detect and act on them.
1198
+ *
1199
+ * Environment variables from hook payload:
1200
+ * - STOP_REASON: reason the turn stopped (e.g., "rate_limit", "auth_failure", "api_error")
1201
+ * - ERROR_MESSAGE: error message text (optional)
1202
+ * - AGENT_ID: unique identifier of the affected agent (optional)
1203
+ *
1204
+ * Note: allowRead sandbox setting (v2.1.77) can re-allow read access within
1205
+ * denyRead regions — relevant for plugin data paths that need to check autopilot.log.
1206
+ *
1207
+ * @param cwd - Project working directory
1208
+ * @param raw - If true, output raw text instead of JSON
1209
+ * @returns void (outputs JSON or raw text to stdout)
1210
+ */
1211
+ function cmdStopFailureHook(cwd: string, raw: boolean): void {
1212
+ const stopReason = process.env.STOP_REASON || 'unknown';
1213
+ const errorMessage = process.env.ERROR_MESSAGE || '';
1214
+ const agentId = process.env.AGENT_ID || 'unknown';
1215
+
1216
+ // Check if autopilot.log exists — indicates an active autopilot/evolve session
1217
+ const autopilotLogPath = path.join(cwd, '.planning', 'autopilot', 'autopilot.log');
1218
+ const autopilotActive = fs.existsSync(autopilotLogPath);
1219
+
1220
+ let logged = false;
1221
+ if (autopilotActive) {
1222
+ // Append timestamped failure entry to autopilot.log
1223
+ const timestamp = new Date().toISOString();
1224
+ const logEntry = `[${timestamp}] STOP_FAILURE: reason=${stopReason} error=${errorMessage || '(none)'} agent=${agentId}\n`;
1225
+ try {
1226
+ fs.appendFileSync(autopilotLogPath, logEntry, 'utf-8');
1227
+ logged = true;
1228
+ } catch (writeErr) {
1229
+ process.stderr.write(
1230
+ `[grd] WARNING: failed to write StopFailure to autopilot.log: ${(writeErr as Error).message}\n`
1231
+ );
1232
+ }
1233
+ }
1234
+
1235
+ const result = {
1236
+ ok: true,
1237
+ hook: 'StopFailure',
1238
+ stop_reason: stopReason,
1239
+ error_message: errorMessage,
1240
+ agent_id: agentId,
1241
+ logged,
1242
+ };
1243
+
1244
+ if (raw) {
1245
+ process.stdout.write(`StopFailure: reason=${stopReason} agent=${agentId} logged=${logged}\n`);
1246
+ } else {
1247
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
1248
+ }
1249
+ }
1250
+
1251
+ /**
1252
+ * Hook handler for PostCompact events (Claude Code v2.1.76+).
1253
+ *
1254
+ * Fires after context compaction completes. GRD acknowledges the event and
1255
+ * continues — this hook is informational only. Future use: could trigger
1256
+ * context reload or state refresh to account for compacted history.
1257
+ *
1258
+ * Environment variables from hook payload:
1259
+ * - AGENT_ID: unique identifier of the agent (optional)
1260
+ * - AGENT_TYPE: type of the agent (optional)
1261
+ *
1262
+ * @param _cwd - Project working directory (unused — compaction is informational)
1263
+ * @param raw - If true, output raw text instead of JSON
1264
+ * @returns void (outputs JSON or raw text to stdout)
1265
+ */
1266
+ function cmdPostCompactHook(_cwd: string, raw: boolean): void {
1267
+ const agentId = process.env.AGENT_ID || 'unknown';
1268
+ const agentType = process.env.AGENT_TYPE || 'unknown';
1269
+
1270
+ const result = {
1271
+ ok: true,
1272
+ hook: 'PostCompact',
1273
+ agent_id: agentId,
1274
+ agent_type: agentType,
1275
+ acknowledged: true,
1276
+ };
1277
+
1278
+ if (raw) {
1279
+ process.stdout.write(`PostCompact: agent=${agentId} type=${agentType} acknowledged=true\n`);
1280
+ } else {
1281
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
1282
+ }
1283
+ }
1284
+
1285
+ // ─── Exports ──────────────────────────────────────────────────────────────────
1286
+
1287
+ module.exports = {
1288
+ worktreePath,
1289
+ worktreeBranch,
1290
+ ensureWorktreesDir,
1291
+ createEvolveWorktree,
1292
+ removeEvolveWorktree,
1293
+ pushAndCreatePR,
1294
+ cmdWorktreeCreate,
1295
+ cmdWorktreeRemove,
1296
+ cmdWorktreeList,
1297
+ cmdWorktreeRemoveStale,
1298
+ cmdWorktreePushAndPR,
1299
+ milestoneBranch,
1300
+ cmdWorktreeEnsureMilestoneBranch,
1301
+ cmdWorktreeMerge,
1302
+ cmdWorktreeHookCreate,
1303
+ cmdWorktreeHookRemove,
1304
+ cmdTeammateIdleHook,
1305
+ cmdTaskCompletedHook,
1306
+ cmdInstructionsLoadedHook,
1307
+ cmdStopFailureHook,
1308
+ cmdPostCompactHook,
1309
+ };