@iloom/cli 0.11.1 → 0.12.0

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 (286) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +153 -13
  3. package/dist/BitBucketApiClient-J2ZSCS5N.js +10 -0
  4. package/dist/BitBucketVCSProvider-5X64IXXW.js +12 -0
  5. package/dist/{BranchNamingService-XBCO747L.js → BranchNamingService-MEK2WZUD.js} +4 -4
  6. package/dist/ClaudeContextManager-IENAE2CP.js +14 -0
  7. package/dist/ClaudeService-YIJCZUUB.js +13 -0
  8. package/dist/GitHubService-UTAYZXL3.js +12 -0
  9. package/dist/IssueTrackerFactory-2OI7YIN6.js +15 -0
  10. package/dist/{LoomLauncher-5AZU2F5I.js → LoomLauncher-3TSFW7QP.js} +10 -10
  11. package/dist/MetadataManager-V4LSJ2PB.js +10 -0
  12. package/dist/ProjectCapabilityDetector-I4J66WKF.js +11 -0
  13. package/dist/{PromptTemplateManager-T5VTLJP3.js → PromptTemplateManager-I75WKXM4.js} +3 -3
  14. package/dist/README.md +153 -13
  15. package/dist/{SettingsManager-WQ5NSGAH.js → SettingsManager-BMQCAXPP.js} +13 -5
  16. package/dist/SettingsMigrationManager-ZPARZ5KH.js +10 -0
  17. package/dist/agents/iloom-code-reviewer.md +2 -1
  18. package/dist/agents/iloom-framework-detector.md +0 -1
  19. package/dist/agents/iloom-issue-analyze-and-plan.md +4 -1
  20. package/dist/agents/iloom-issue-analyzer.md +4 -1
  21. package/dist/agents/iloom-issue-complexity-evaluator.md +4 -1
  22. package/dist/agents/iloom-issue-enhancer.md +4 -1
  23. package/dist/agents/iloom-issue-implementer.md +5 -2
  24. package/dist/agents/iloom-issue-planner.md +4 -1
  25. package/dist/agents/iloom-wave-verifier.md +186 -0
  26. package/dist/browser-VZY7F2DF.js +10 -0
  27. package/dist/build-DMWSIME6.js +27 -0
  28. package/dist/{chunk-UHIBKD73.js → chunk-35CBWAJL.js} +13 -32
  29. package/dist/{chunk-UHIBKD73.js.map → chunk-35CBWAJL.js.map} +1 -1
  30. package/dist/{chunk-YRCEOQPX.js → chunk-4JZEQBWV.js} +4 -3
  31. package/dist/chunk-4JZEQBWV.js.map +1 -0
  32. package/dist/{chunk-ET6A2JR4.js → chunk-653XBU3L.js} +111 -18
  33. package/dist/chunk-653XBU3L.js.map +1 -0
  34. package/dist/{chunk-G2MNSPA4.js → chunk-772N5WCA.js} +2 -2
  35. package/dist/{chunk-WG4MLJ6J.js → chunk-7RCUWU3I.js} +2 -2
  36. package/dist/chunk-7RCUWU3I.js.map +1 -0
  37. package/dist/{chunk-NOMQ5RFG.js → chunk-7UBEHQTP.js} +2 -2
  38. package/dist/{chunk-7NFCGKZT.js → chunk-AQUSMNBF.js} +3 -3
  39. package/dist/{chunk-IDCE26KD.js → chunk-AUYSAMXV.js} +3 -3
  40. package/dist/chunk-AYLC633W.js +406 -0
  41. package/dist/chunk-AYLC633W.js.map +1 -0
  42. package/dist/{chunk-HLDY5S4C.js → chunk-BFF27W3S.js} +3 -3
  43. package/dist/{chunk-QVAA5KHK.js → chunk-BZ7KTXPB.js} +16 -8
  44. package/dist/chunk-BZ7KTXPB.js.map +1 -0
  45. package/dist/{chunk-K7R5QY6C.js → chunk-CE676WCN.js} +2 -2
  46. package/dist/{chunk-5UFGO4ZT.js → chunk-CQHHEW2M.js} +6 -3
  47. package/dist/chunk-CQHHEW2M.js.map +1 -0
  48. package/dist/{chunk-LHDD4JHC.js → chunk-D4Q7T5KD.js} +4 -4
  49. package/dist/{chunk-RBYTXYGD.js → chunk-D75KSI3V.js} +2 -2
  50. package/dist/{chunk-Y3RX7LZT.js → chunk-DDHWZNGL.js} +18 -12
  51. package/dist/chunk-DDHWZNGL.js.map +1 -0
  52. package/dist/{chunk-5LTID2AF.js → chunk-DMSL5BAP.js} +35 -6
  53. package/dist/{chunk-5LTID2AF.js.map → chunk-DMSL5BAP.js.map} +1 -1
  54. package/dist/{chunk-SQYHPBFP.js → chunk-EGNUOALL.js} +2 -2
  55. package/dist/{chunk-LL6TOX3G.js → chunk-EQIII6GI.js} +10 -10
  56. package/dist/chunk-EQIII6GI.js.map +1 -0
  57. package/dist/{chunk-ZAXRQLK3.js → chunk-FTYWGQFM.js} +2 -2
  58. package/dist/{chunk-LE2NOUTN.js → chunk-FV4KXBGO.js} +3 -3
  59. package/dist/{chunk-XFQGI2E3.js → chunk-GWJWECZB.js} +51 -45
  60. package/dist/chunk-GWJWECZB.js.map +1 -0
  61. package/dist/{chunk-QNHZM5ZV.js → chunk-HIGWKLQR.js} +3 -3
  62. package/dist/{chunk-VMZG66UV.js → chunk-HKEXRZMU.js} +3 -3
  63. package/dist/{chunk-V4STTBQD.js → chunk-IHSA7VGI.js} +9 -9
  64. package/dist/{chunk-TEJAGQX2.js → chunk-IS46GQRA.js} +33 -33
  65. package/dist/{chunk-VNYWBHKR.js → chunk-JD3K2344.js} +3 -3
  66. package/dist/{chunk-NCPZYQ4B.js → chunk-K3QGG4O2.js} +2 -2
  67. package/dist/{chunk-QR4FU53I.js → chunk-KCZSUJUR.js} +22 -12
  68. package/dist/chunk-KCZSUJUR.js.map +1 -0
  69. package/dist/{chunk-NH3QZYE5.js → chunk-KV4NU3RP.js} +2 -2
  70. package/dist/{chunk-NDSGJZI2.js → chunk-LOAYWTJJ.js} +2 -2
  71. package/dist/{chunk-ABVMUNCD.js → chunk-M3FBM4T3.js} +64 -10
  72. package/dist/chunk-M3FBM4T3.js.map +1 -0
  73. package/dist/{chunk-GMDSYLI6.js → chunk-MY2Q3FJ3.js} +2 -2
  74. package/dist/{chunk-CV47VCMQ.js → chunk-NPVA65KS.js} +2 -2
  75. package/dist/{chunk-7OCGBJLR.js → chunk-OIVFHJOA.js} +2 -2
  76. package/dist/{chunk-7FIXNAUO.js → chunk-OKB2NEDQ.js} +66 -43
  77. package/dist/chunk-OKB2NEDQ.js.map +1 -0
  78. package/dist/{chunk-3RXYOBME.js → chunk-OPQC4OWM.js} +5 -5
  79. package/dist/{chunk-3RXYOBME.js.map → chunk-OPQC4OWM.js.map} +1 -1
  80. package/dist/chunk-P5MXXHXQ.js +284 -0
  81. package/dist/chunk-P5MXXHXQ.js.map +1 -0
  82. package/dist/{chunk-IR74O2F6.js → chunk-PDG74IJT.js} +239 -162
  83. package/dist/chunk-PDG74IJT.js.map +1 -0
  84. package/dist/{chunk-NN5RYWXA.js → chunk-PH65MFQM.js} +6 -6
  85. package/dist/{chunk-TZNNJLGT.js → chunk-PMB6TYV4.js} +6 -6
  86. package/dist/chunk-QC65IOV3.js +304 -0
  87. package/dist/chunk-QC65IOV3.js.map +1 -0
  88. package/dist/{chunk-6YVJVUR4.js → chunk-QF2DROQR.js} +3 -3
  89. package/dist/{chunk-XXFSOVL3.js → chunk-QFDM23CO.js} +4 -4
  90. package/dist/{chunk-RMLADZRY.js → chunk-R7DGN73N.js} +5 -5
  91. package/dist/{chunk-5PNZBH6V.js → chunk-V5IYLWRA.js} +2 -2
  92. package/dist/{chunk-KQFIGI37.js → chunk-VA6CWUAE.js} +7 -7
  93. package/dist/{chunk-3GTUXW26.js → chunk-VIQOQ463.js} +19 -3
  94. package/dist/chunk-VIQOQ463.js.map +1 -0
  95. package/dist/{chunk-H2SSF24U.js → chunk-VRPPI6GU.js} +17 -6
  96. package/dist/{chunk-H2SSF24U.js.map → chunk-VRPPI6GU.js.map} +1 -1
  97. package/dist/{chunk-YETJNRQM.js → chunk-WEBMMJKL.js} +2 -1
  98. package/dist/{chunk-VUUN3KE4.js → chunk-XVCGPTEQ.js} +8 -8
  99. package/dist/chunk-XVCGPTEQ.js.map +1 -0
  100. package/dist/chunk-YWNF5755.js +696 -0
  101. package/dist/chunk-YWNF5755.js.map +1 -0
  102. package/dist/{chunk-UDCI3QTS.js → chunk-ZM2AYHMO.js} +2 -2
  103. package/dist/{claude-ONQTDWV3.js → claude-ACL7G4CF.js} +4 -4
  104. package/dist/{cleanup-YOM6PQCN.js → cleanup-RLBLNQZN.js} +37 -34
  105. package/dist/{cleanup-YOM6PQCN.js.map → cleanup-RLBLNQZN.js.map} +1 -1
  106. package/dist/cli.js +290 -141
  107. package/dist/cli.js.map +1 -1
  108. package/dist/{color-VQD52LOI.js → color-AC6F2QE7.js} +3 -3
  109. package/dist/{commit-DC2Q5CDY.js → commit-RILBXFWO.js} +15 -15
  110. package/dist/{compile-4NCQECKE.js → compile-QEL5724K.js} +11 -11
  111. package/dist/{contribute-M5UWXCAV.js → contribute-EHWLYOMZ.js} +11 -11
  112. package/dist/{contribute-M5UWXCAV.js.map → contribute-EHWLYOMZ.js.map} +1 -1
  113. package/dist/{mcp/darwin-3JFFE3W2.js → darwin-5K3I4FTH.js} +2 -2
  114. package/dist/{dev-server-CYRP6M73.js → dev-server-2WSWZXJG.js} +35 -21
  115. package/dist/dev-server-2WSWZXJG.js.map +1 -0
  116. package/dist/{feedback-BMAZGKRW.js → feedback-I6ZEHEUB.js} +17 -17
  117. package/dist/{git-BXUD6CL5.js → git-I3PO6FY7.js} +6 -6
  118. package/dist/ignite-XZFYRVRJ.js +35 -0
  119. package/dist/index.d.ts +200 -16
  120. package/dist/index.js +164 -55
  121. package/dist/index.js.map +1 -1
  122. package/dist/{init-CI43GJHV.js → init-A6WRP77L.js} +18 -18
  123. package/dist/{install-deps-SRTM5U7D.js → install-deps-HXP2TM7G.js} +11 -11
  124. package/dist/{installation-detector-HF6QN7KP.js → installation-detector-PYAZ2O6U.js} +3 -3
  125. package/dist/{issues-DMRQJH7E.js → issues-SUFQJY6O.js} +69 -56
  126. package/dist/issues-SUFQJY6O.js.map +1 -0
  127. package/dist/lint-FDZC77GL.js +27 -0
  128. package/dist/{linux-RYLOP2LY.js → linux-WUGRYCJY.js} +2 -2
  129. package/dist/mcp/{chunk-PIIRD4LO.js → chunk-4HZMW2V3.js} +1 -1
  130. package/dist/mcp/{chunk-PIIRD4LO.js.map → chunk-4HZMW2V3.js.map} +1 -1
  131. package/dist/{darwin-5BHWRJ7D.js → mcp/darwin-U25WIGH6.js} +2 -2
  132. package/dist/mcp/issue-management-server.js +900 -20
  133. package/dist/mcp/issue-management-server.js.map +1 -1
  134. package/dist/mcp/{linux-JBVS4R3A.js → linux-5BXVBGSY.js} +2 -2
  135. package/dist/mcp/recap-server.js +24 -22
  136. package/dist/mcp/recap-server.js.map +1 -1
  137. package/dist/mcp/{tmux-RYBLEHUZ.js → tmux-CU26ZTNM.js} +2 -2
  138. package/dist/mcp/{wsl-4QZIQLLE.js → wsl-KI25UDOF.js} +2 -2
  139. package/dist/neon-helpers-LCZAN4U4.js +11 -0
  140. package/dist/{open-2Y7GSUTJ.js → open-US4XACLW.js} +36 -21
  141. package/dist/open-US4XACLW.js.map +1 -0
  142. package/dist/{plan-SWFPLNJE.js → plan-PL3ZB32J.js} +47 -43
  143. package/dist/{plan-SWFPLNJE.js.map → plan-PL3ZB32J.js.map} +1 -1
  144. package/dist/{projects-IUSUXD5D.js → projects-L5AHUBGA.js} +6 -6
  145. package/dist/{prompt-7LZB4PAT.js → prompt-FUU5NMJQ.js} +3 -3
  146. package/dist/prompt-FUU5NMJQ.js.map +1 -0
  147. package/dist/prompts/init-prompt.txt +160 -23
  148. package/dist/prompts/issue-prompt.txt +93 -157
  149. package/dist/prompts/plan-prompt.txt +55 -0
  150. package/dist/prompts/swarm-orchestrator-prompt.txt +78 -21
  151. package/dist/{rebase-S6OHAOOF.js → rebase-JA3RW2XO.js} +12 -12
  152. package/dist/{recap-GGVCG5VH.js → recap-5TO42HN2.js} +9 -9
  153. package/dist/{remote-MZTFHHTU.js → remote-RO4LZKT2.js} +3 -3
  154. package/dist/remote-RO4LZKT2.js.map +1 -0
  155. package/dist/{run-ST3FR75O.js → run-KKCRBRLW.js} +36 -21
  156. package/dist/run-KKCRBRLW.js.map +1 -0
  157. package/dist/schema/settings.schema.json +147 -11
  158. package/dist/{shell-W4SBQPTE.js → shell-GAB2FCXH.js} +8 -8
  159. package/dist/{summary-P2JCIIJO.js → summary-P7QE3TNW.js} +21 -19
  160. package/dist/summary-P7QE3TNW.js.map +1 -0
  161. package/dist/test-6LFB5WOO.js +27 -0
  162. package/dist/{test-git-2KFFAQ6B.js → test-git-PYJOYSED.js} +6 -6
  163. package/dist/{test-jira-FKDKG6CD.js → test-jira-SM7IU5HW.js} +8 -8
  164. package/dist/{test-prefix-GP2DAX37.js → test-prefix-HIRZBXTM.js} +6 -6
  165. package/dist/{test-tabs-YDWMWTVA.js → test-tabs-NGPTFD5T.js} +2 -2
  166. package/dist/{test-webserver-QI3QQFZ3.js → test-webserver-43PVP2JL.js} +8 -8
  167. package/dist/{tmux-7ZTA3BDI.js → tmux-6LRFH3DM.js} +2 -2
  168. package/dist/{update-XLW7R7FL.js → update-AD3GE5C4.js} +4 -4
  169. package/dist/{update-notifier-EYLAXZAA.js → update-notifier-VYDTDMSJ.js} +3 -3
  170. package/dist/update-notifier-VYDTDMSJ.js.map +1 -0
  171. package/dist/{vscode-TOGE5N67.js → vscode-HXIXRZ3A.js} +12 -12
  172. package/dist/{vscode-announcement-NIX7O2MG.js → vscode-announcement-AL3EHORH.js} +3 -3
  173. package/dist/{wsl-Y4GUTOQ7.js → wsl-4VMVT2PO.js} +2 -2
  174. package/package.json +1 -1
  175. package/dist/ClaudeContextManager-SXDCWDJA.js +0 -14
  176. package/dist/ClaudeService-6E6MCGJE.js +0 -13
  177. package/dist/GitHubService-2R5GQG4K.js +0 -12
  178. package/dist/IssueTrackerFactory-XN6MQ4UN.js +0 -14
  179. package/dist/MetadataManager-CMQQTFLQ.js +0 -10
  180. package/dist/ProjectCapabilityDetector-IC6NAFGY.js +0 -11
  181. package/dist/SettingsMigrationManager-S6J7OHUH.js +0 -10
  182. package/dist/build-OLS6J5KZ.js +0 -27
  183. package/dist/chunk-3GTUXW26.js.map +0 -1
  184. package/dist/chunk-5UFGO4ZT.js.map +0 -1
  185. package/dist/chunk-7FIXNAUO.js.map +0 -1
  186. package/dist/chunk-ABVMUNCD.js.map +0 -1
  187. package/dist/chunk-ET6A2JR4.js.map +0 -1
  188. package/dist/chunk-IR74O2F6.js.map +0 -1
  189. package/dist/chunk-LL6TOX3G.js.map +0 -1
  190. package/dist/chunk-QR4FU53I.js.map +0 -1
  191. package/dist/chunk-QVAA5KHK.js.map +0 -1
  192. package/dist/chunk-RVI6C2H5.js +0 -220
  193. package/dist/chunk-RVI6C2H5.js.map +0 -1
  194. package/dist/chunk-VUUN3KE4.js.map +0 -1
  195. package/dist/chunk-WG4MLJ6J.js.map +0 -1
  196. package/dist/chunk-XFQGI2E3.js.map +0 -1
  197. package/dist/chunk-Y3RX7LZT.js.map +0 -1
  198. package/dist/chunk-YRCEOQPX.js.map +0 -1
  199. package/dist/dev-server-CYRP6M73.js.map +0 -1
  200. package/dist/ignite-IO4LXVXJ.js +0 -35
  201. package/dist/issues-DMRQJH7E.js.map +0 -1
  202. package/dist/lint-BSWRMGPZ.js +0 -27
  203. package/dist/neon-helpers-HWIYRKOW.js +0 -11
  204. package/dist/open-2Y7GSUTJ.js.map +0 -1
  205. package/dist/run-ST3FR75O.js.map +0 -1
  206. package/dist/summary-P2JCIIJO.js.map +0 -1
  207. package/dist/test-6JH4FE2X.js +0 -27
  208. /package/dist/{BranchNamingService-XBCO747L.js.map → BitBucketApiClient-J2ZSCS5N.js.map} +0 -0
  209. /package/dist/{ClaudeContextManager-SXDCWDJA.js.map → BitBucketVCSProvider-5X64IXXW.js.map} +0 -0
  210. /package/dist/{ClaudeService-6E6MCGJE.js.map → BranchNamingService-MEK2WZUD.js.map} +0 -0
  211. /package/dist/{GitHubService-2R5GQG4K.js.map → ClaudeContextManager-IENAE2CP.js.map} +0 -0
  212. /package/dist/{IssueTrackerFactory-XN6MQ4UN.js.map → ClaudeService-YIJCZUUB.js.map} +0 -0
  213. /package/dist/{MetadataManager-CMQQTFLQ.js.map → GitHubService-UTAYZXL3.js.map} +0 -0
  214. /package/dist/{ProjectCapabilityDetector-IC6NAFGY.js.map → IssueTrackerFactory-2OI7YIN6.js.map} +0 -0
  215. /package/dist/{LoomLauncher-5AZU2F5I.js.map → LoomLauncher-3TSFW7QP.js.map} +0 -0
  216. /package/dist/{PromptTemplateManager-T5VTLJP3.js.map → MetadataManager-V4LSJ2PB.js.map} +0 -0
  217. /package/dist/{SettingsManager-WQ5NSGAH.js.map → ProjectCapabilityDetector-I4J66WKF.js.map} +0 -0
  218. /package/dist/{SettingsMigrationManager-S6J7OHUH.js.map → PromptTemplateManager-I75WKXM4.js.map} +0 -0
  219. /package/dist/{claude-ONQTDWV3.js.map → SettingsManager-BMQCAXPP.js.map} +0 -0
  220. /package/dist/{color-VQD52LOI.js.map → SettingsMigrationManager-ZPARZ5KH.js.map} +0 -0
  221. /package/dist/{darwin-5BHWRJ7D.js.map → browser-VZY7F2DF.js.map} +0 -0
  222. /package/dist/{build-OLS6J5KZ.js.map → build-DMWSIME6.js.map} +0 -0
  223. /package/dist/{chunk-G2MNSPA4.js.map → chunk-772N5WCA.js.map} +0 -0
  224. /package/dist/{chunk-NOMQ5RFG.js.map → chunk-7UBEHQTP.js.map} +0 -0
  225. /package/dist/{chunk-7NFCGKZT.js.map → chunk-AQUSMNBF.js.map} +0 -0
  226. /package/dist/{chunk-IDCE26KD.js.map → chunk-AUYSAMXV.js.map} +0 -0
  227. /package/dist/{chunk-HLDY5S4C.js.map → chunk-BFF27W3S.js.map} +0 -0
  228. /package/dist/{chunk-K7R5QY6C.js.map → chunk-CE676WCN.js.map} +0 -0
  229. /package/dist/{chunk-LHDD4JHC.js.map → chunk-D4Q7T5KD.js.map} +0 -0
  230. /package/dist/{chunk-RBYTXYGD.js.map → chunk-D75KSI3V.js.map} +0 -0
  231. /package/dist/{chunk-SQYHPBFP.js.map → chunk-EGNUOALL.js.map} +0 -0
  232. /package/dist/{chunk-ZAXRQLK3.js.map → chunk-FTYWGQFM.js.map} +0 -0
  233. /package/dist/{chunk-LE2NOUTN.js.map → chunk-FV4KXBGO.js.map} +0 -0
  234. /package/dist/{chunk-QNHZM5ZV.js.map → chunk-HIGWKLQR.js.map} +0 -0
  235. /package/dist/{chunk-VMZG66UV.js.map → chunk-HKEXRZMU.js.map} +0 -0
  236. /package/dist/{chunk-V4STTBQD.js.map → chunk-IHSA7VGI.js.map} +0 -0
  237. /package/dist/{chunk-TEJAGQX2.js.map → chunk-IS46GQRA.js.map} +0 -0
  238. /package/dist/{chunk-VNYWBHKR.js.map → chunk-JD3K2344.js.map} +0 -0
  239. /package/dist/{chunk-NCPZYQ4B.js.map → chunk-K3QGG4O2.js.map} +0 -0
  240. /package/dist/{chunk-NH3QZYE5.js.map → chunk-KV4NU3RP.js.map} +0 -0
  241. /package/dist/{chunk-NDSGJZI2.js.map → chunk-LOAYWTJJ.js.map} +0 -0
  242. /package/dist/{chunk-GMDSYLI6.js.map → chunk-MY2Q3FJ3.js.map} +0 -0
  243. /package/dist/{chunk-CV47VCMQ.js.map → chunk-NPVA65KS.js.map} +0 -0
  244. /package/dist/{chunk-7OCGBJLR.js.map → chunk-OIVFHJOA.js.map} +0 -0
  245. /package/dist/{chunk-NN5RYWXA.js.map → chunk-PH65MFQM.js.map} +0 -0
  246. /package/dist/{chunk-TZNNJLGT.js.map → chunk-PMB6TYV4.js.map} +0 -0
  247. /package/dist/{chunk-6YVJVUR4.js.map → chunk-QF2DROQR.js.map} +0 -0
  248. /package/dist/{chunk-XXFSOVL3.js.map → chunk-QFDM23CO.js.map} +0 -0
  249. /package/dist/{chunk-RMLADZRY.js.map → chunk-R7DGN73N.js.map} +0 -0
  250. /package/dist/{chunk-5PNZBH6V.js.map → chunk-V5IYLWRA.js.map} +0 -0
  251. /package/dist/{chunk-KQFIGI37.js.map → chunk-VA6CWUAE.js.map} +0 -0
  252. /package/dist/{chunk-YETJNRQM.js.map → chunk-WEBMMJKL.js.map} +0 -0
  253. /package/dist/{chunk-UDCI3QTS.js.map → chunk-ZM2AYHMO.js.map} +0 -0
  254. /package/dist/{git-BXUD6CL5.js.map → claude-ACL7G4CF.js.map} +0 -0
  255. /package/dist/{ignite-IO4LXVXJ.js.map → color-AC6F2QE7.js.map} +0 -0
  256. /package/dist/{commit-DC2Q5CDY.js.map → commit-RILBXFWO.js.map} +0 -0
  257. /package/dist/{compile-4NCQECKE.js.map → compile-QEL5724K.js.map} +0 -0
  258. /package/dist/{installation-detector-HF6QN7KP.js.map → darwin-5K3I4FTH.js.map} +0 -0
  259. /package/dist/{feedback-BMAZGKRW.js.map → feedback-I6ZEHEUB.js.map} +0 -0
  260. /package/dist/{mcp/darwin-3JFFE3W2.js.map → git-I3PO6FY7.js.map} +0 -0
  261. /package/dist/{neon-helpers-HWIYRKOW.js.map → ignite-XZFYRVRJ.js.map} +0 -0
  262. /package/dist/{init-CI43GJHV.js.map → init-A6WRP77L.js.map} +0 -0
  263. /package/dist/{install-deps-SRTM5U7D.js.map → install-deps-HXP2TM7G.js.map} +0 -0
  264. /package/dist/{prompt-7LZB4PAT.js.map → installation-detector-PYAZ2O6U.js.map} +0 -0
  265. /package/dist/{lint-BSWRMGPZ.js.map → lint-FDZC77GL.js.map} +0 -0
  266. /package/dist/{linux-RYLOP2LY.js.map → linux-WUGRYCJY.js.map} +0 -0
  267. /package/dist/{remote-MZTFHHTU.js.map → mcp/darwin-U25WIGH6.js.map} +0 -0
  268. /package/dist/mcp/{linux-JBVS4R3A.js.map → linux-5BXVBGSY.js.map} +0 -0
  269. /package/dist/mcp/{tmux-RYBLEHUZ.js.map → tmux-CU26ZTNM.js.map} +0 -0
  270. /package/dist/mcp/{wsl-4QZIQLLE.js.map → wsl-KI25UDOF.js.map} +0 -0
  271. /package/dist/{update-notifier-EYLAXZAA.js.map → neon-helpers-LCZAN4U4.js.map} +0 -0
  272. /package/dist/{projects-IUSUXD5D.js.map → projects-L5AHUBGA.js.map} +0 -0
  273. /package/dist/{rebase-S6OHAOOF.js.map → rebase-JA3RW2XO.js.map} +0 -0
  274. /package/dist/{recap-GGVCG5VH.js.map → recap-5TO42HN2.js.map} +0 -0
  275. /package/dist/{shell-W4SBQPTE.js.map → shell-GAB2FCXH.js.map} +0 -0
  276. /package/dist/{test-6JH4FE2X.js.map → test-6LFB5WOO.js.map} +0 -0
  277. /package/dist/{test-git-2KFFAQ6B.js.map → test-git-PYJOYSED.js.map} +0 -0
  278. /package/dist/{test-jira-FKDKG6CD.js.map → test-jira-SM7IU5HW.js.map} +0 -0
  279. /package/dist/{test-prefix-GP2DAX37.js.map → test-prefix-HIRZBXTM.js.map} +0 -0
  280. /package/dist/{test-tabs-YDWMWTVA.js.map → test-tabs-NGPTFD5T.js.map} +0 -0
  281. /package/dist/{test-webserver-QI3QQFZ3.js.map → test-webserver-43PVP2JL.js.map} +0 -0
  282. /package/dist/{tmux-7ZTA3BDI.js.map → tmux-6LRFH3DM.js.map} +0 -0
  283. /package/dist/{update-XLW7R7FL.js.map → update-AD3GE5C4.js.map} +0 -0
  284. /package/dist/{vscode-TOGE5N67.js.map → vscode-HXIXRZ3A.js.map} +0 -0
  285. /package/dist/{vscode-announcement-NIX7O2MG.js.map → vscode-announcement-AL3EHORH.js.map} +0 -0
  286. /package/dist/{wsl-Y4GUTOQ7.js.map → wsl-4VMVT2PO.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/DevServerManager.ts","../src/lib/DockerDevServerStrategy.ts","../src/lib/NativeDevServerStrategy.ts","../src/utils/dev-server.ts"],"sourcesContent":["import path from 'path'\nimport { ProcessManager } from './process/ProcessManager.js'\nimport { DockerManager, type DockerConfig } from './DockerManager.js'\nimport { DockerDevServerStrategy, type DockerConfig as StrategyDockerConfig, type DockerUtils } from './DockerDevServerStrategy.js'\nimport { NativeDevServerStrategy } from './NativeDevServerStrategy.js'\nimport { logger } from '../utils/logger.js'\n\n/**\n * Default startup timeout in milliseconds (180 seconds)\n * Can be overridden via ILOOM_DEV_SERVER_TIMEOUT environment variable\n */\nconst DEFAULT_STARTUP_TIMEOUT = 180000\n\n/**\n * Bridge DockerManager static methods to the DockerUtils interface\n * expected by DockerDevServerStrategy.\n */\nconst dockerUtils: DockerUtils = {\n\tparseDockerfileExpose: (filePath: string) => DockerManager.parseExposeFromDockerfile(filePath),\n\tinspectImagePorts: (imageName: string) => DockerManager.inspectImagePorts(imageName),\n\tbuildContainerName: (id: string | number) => DockerManager.buildContainerName(id),\n\tbuildImageName: (id: string | number) => DockerManager.buildImageName(id),\n\tassertDockerAvailable: () => DockerManager.assertAvailable(),\n}\n\nfunction getStartupTimeout(): number {\n\tconst envTimeout = process.env.ILOOM_DEV_SERVER_TIMEOUT\n\tif (envTimeout) {\n\t\tconst parsed = parseInt(envTimeout, 10)\n\t\tif (!isNaN(parsed) && parsed > 0) {\n\t\t\treturn parsed\n\t\t}\n\t}\n\treturn DEFAULT_STARTUP_TIMEOUT\n}\n\nexport interface DevServerManagerOptions {\n\t/**\n\t * Maximum time to wait for server to start (in milliseconds)\n\t * Default: 180000 (180 seconds)\n\t * Can be overridden via ILOOM_DEV_SERVER_TIMEOUT environment variable\n\t */\n\tstartupTimeout?: number\n\n\t/**\n\t * Interval between port checks (in milliseconds)\n\t * Default: 1000 (1 second)\n\t */\n\tcheckInterval?: number\n}\n\n// Re-export DockerConfig from DockerManager for backward compatibility\nexport type { DockerConfig } from './DockerManager.js'\n\n/**\n * Convert a DockerConfig (from DockerManager) to a StrategyDockerConfig\n * (for DockerDevServerStrategy).\n */\nfunction toStrategyConfig(config: DockerConfig): StrategyDockerConfig {\n\treturn {\n\t\tdockerFile: config.dockerFile,\n\t\tcontainerPort: config.containerPort,\n\t\tbuildArgs: config.dockerBuildArgs,\n\t\trunArgs: config.dockerRunArgs,\n\t\tidentifier: config.identifier,\n\t}\n}\n\n/**\n * DevServerManager handles auto-starting and monitoring dev servers.\n * Used by open/run commands to ensure dev server is running before opening browser.\n *\n * When devServer config is absent OR mode is not 'docker', behavior is identical\n * to the native process-based implementation via NativeDevServerStrategy.\n * When Docker mode is configured, all operations delegate to DockerDevServerStrategy.\n */\nexport class DevServerManager {\n\tprivate readonly processManager: ProcessManager\n\tprivate readonly options: Required<DevServerManagerOptions>\n\tprivate readonly nativeStrategy: NativeDevServerStrategy\n\tprivate runningDockerContainers: Map<number, string> = new Map()\n\n\tconstructor(\n\t\tprocessManager?: ProcessManager,\n\t\toptions: DevServerManagerOptions = {}\n\t) {\n\t\tthis.processManager = processManager ?? new ProcessManager()\n\t\tthis.options = {\n\t\t\tstartupTimeout: options.startupTimeout ?? getStartupTimeout(),\n\t\t\tcheckInterval: options.checkInterval ?? 1000,\n\t\t}\n\t\tthis.nativeStrategy = new NativeDevServerStrategy(\n\t\t\tthis.processManager,\n\t\t\tthis.options.startupTimeout,\n\t\t\tthis.options.checkInterval\n\t\t)\n\t}\n\n\t/**\n\t * Create a DockerDevServerStrategy for the given Docker config.\n\t * The strategy encapsulates all Docker container lifecycle operations.\n\t */\n\tprivate createDockerStrategy(dockerConfig: DockerConfig): DockerDevServerStrategy {\n\t\treturn new DockerDevServerStrategy(toStrategyConfig(dockerConfig), dockerUtils)\n\t}\n\n\t/**\n\t * Ensure dev server is running on the specified port.\n\t * If not running, start it and wait for it to be ready.\n\t *\n\t * @param worktreePath - Path to the worktree\n\t * @param port - Port the server should run on\n\t * @param dockerConfig - Optional Docker configuration for container-based server\n\t * @returns true if server is ready, false if startup failed/timed out\n\t */\n\tasync ensureServerRunning(worktreePath: string, port: number, dockerConfig?: DockerConfig): Promise<boolean> {\n\t\tlogger.debug(`Checking if dev server is running on port ${port}...`)\n\n\t\t// Docker mode: check if container is already running\n\t\tif (dockerConfig) {\n\t\t\tconst strategy = this.createDockerStrategy(dockerConfig)\n\t\t\tconst containerName = dockerUtils.buildContainerName(dockerConfig.identifier)\n\t\t\tconst isRunning = await strategy.isContainerRunning(containerName)\n\t\t\tif (isRunning) {\n\t\t\t\tlogger.debug(`Docker container \"${containerName}\" already running on port ${port}`)\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tlogger.info(`Docker dev server not running on port ${port}, starting...`)\n\t\t\ttry {\n\t\t\t\tawait this.startDockerServer(worktreePath, port, dockerConfig, strategy)\n\t\t\t\treturn true\n\t\t\t} catch (error) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t`Failed to start Docker dev server: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\t// Native mode: check if a process is listening on the port\n\t\tconst existingProcess = await this.processManager.detectDevServer(port)\n\t\tif (existingProcess) {\n\t\t\tlogger.debug(\n\t\t\t\t`Dev server already running on port ${port} (PID: ${existingProcess.pid})`\n\t\t\t)\n\t\t\treturn true\n\t\t}\n\n\t\t// Not running - start it\n\t\tlogger.info(`Dev server not running on port ${port}, starting...`)\n\n\t\ttry {\n\t\t\tawait this.nativeStrategy.startBackground(worktreePath, port)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`Failed to start dev server: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Start dev server in Docker container (background) and wait for it to be ready.\n\t * Builds the image, resolves the container port, starts the container detached,\n\t * and polls the host port for readiness.\n\t */\n\tprivate async startDockerServer(\n\t\tworktreePath: string,\n\t\tport: number,\n\t\tdockerConfig: DockerConfig,\n\t\tstrategy: DockerDevServerStrategy\n\t): Promise<void> {\n\t\tconst strategyConfig = toStrategyConfig(dockerConfig)\n\t\tconst imageName = dockerUtils.buildImageName(dockerConfig.identifier)\n\t\tconst dockerfilePath = path.resolve(worktreePath, dockerConfig.dockerFile)\n\n\t\t// Build image\n\t\tawait strategy.buildImage(worktreePath, strategyConfig)\n\n\t\t// Resolve container port (config > image inspect > Dockerfile EXPOSE)\n\t\tconst containerPort = await strategy.resolveContainerPort(\n\t\t\tstrategyConfig,\n\t\t\timageName,\n\t\t\tdockerfilePath\n\t\t)\n\n\t\t// Run container detached\n\t\tconst containerName = await strategy.runContainerDetached(\n\t\t\tworktreePath,\n\t\t\tport,\n\t\t\tcontainerPort,\n\t\t\tstrategyConfig\n\t\t)\n\n\t\t// Track for cleanup\n\t\tthis.runningDockerContainers.set(port, containerName)\n\n\t\t// Wait for server to be ready via TCP probe (Docker proxy listens on host port)\n\t\t// Pass container name for early crash detection\n\t\tlogger.info(`Waiting for Docker dev server to start on port ${port}...`)\n\t\tconst ready = await strategy.waitForReady(\n\t\t\tport,\n\t\t\tthis.options.startupTimeout,\n\t\t\tthis.options.checkInterval,\n\t\t\tcontainerName\n\t\t)\n\n\t\tif (!ready) {\n\t\t\t// Clean up the container if startup failed\n\t\t\tawait strategy.stopContainer(containerName)\n\t\t\tthis.runningDockerContainers.delete(port)\n\t\t\tthrow new Error(\n\t\t\t\t`Docker dev server failed to start within ${this.options.startupTimeout}ms timeout`\n\t\t\t)\n\t\t}\n\n\t\tlogger.success(`Docker dev server started successfully on port ${port}`)\n\t}\n\n\t/**\n\t * Check if a dev server is running on the specified port\n\t *\n\t * @param port - Port to check\n\t * @param dockerConfig - Optional Docker configuration; when provided, checks container status\n\t * @returns true if server is running, false otherwise\n\t */\n\tasync isServerRunning(port: number, dockerConfig?: DockerConfig): Promise<boolean> {\n\t\tif (dockerConfig) {\n\t\t\tconst strategy = this.createDockerStrategy(dockerConfig)\n\t\t\tconst containerName = dockerUtils.buildContainerName(dockerConfig.identifier)\n\t\t\treturn strategy.isContainerRunning(containerName)\n\t\t}\n\t\tconst existingProcess = await this.processManager.detectDevServer(port)\n\t\treturn existingProcess !== null\n\t}\n\n\t/**\n\t * Run dev server in foreground mode (blocking).\n\t * This method blocks until the server is stopped (e.g., via Ctrl+C).\n\t *\n\t * @param worktreePath - Path to the worktree\n\t * @param port - Port the server should run on\n\t * @param redirectToStderr - If true, redirect stdout/stderr to stderr (useful for JSON output)\n\t * @param onProcessStarted - Callback called immediately after process starts with PID\n\t * @returns Process information including PID\n\t */\n\tasync runServerForeground(\n\t\tworktreePath: string,\n\t\tport: number,\n\t\tredirectToStderr = false,\n\t\tonProcessStarted?: (pid?: number) => void,\n\t\tenvOverrides?: Record<string, string>,\n\t\tdockerConfig?: DockerConfig\n\t): Promise<{ pid?: number }> {\n\t\t// Docker mode: build image and run container in foreground\n\t\tif (dockerConfig) {\n\t\t\tlogger.debug(`Starting Docker dev server in foreground on port ${port}`)\n\n\t\t\tconst strategy = this.createDockerStrategy(dockerConfig)\n\t\t\tconst strategyConfig = toStrategyConfig(dockerConfig)\n\t\t\tconst imageName = dockerUtils.buildImageName(dockerConfig.identifier)\n\t\t\tconst containerName = dockerUtils.buildContainerName(dockerConfig.identifier)\n\t\t\tconst dockerfilePath = path.resolve(worktreePath, dockerConfig.dockerFile)\n\n\t\t\t// Build image\n\t\t\tawait strategy.buildImage(worktreePath, strategyConfig)\n\n\t\t\t// Resolve container port\n\t\t\tconst containerPort = await strategy.resolveContainerPort(\n\t\t\t\tstrategyConfig,\n\t\t\t\timageName,\n\t\t\t\tdockerfilePath\n\t\t\t)\n\n\t\t\tif (onProcessStarted) {\n\t\t\t\tonProcessStarted(undefined)\n\t\t\t}\n\n\t\t\t// Track container for cleanup\n\t\t\tthis.runningDockerContainers.set(port, containerName)\n\t\t\ttry {\n\t\t\t\t// Run container in foreground (blocks until stopped)\n\t\t\t\t// DockerDevServerStrategy.runContainerForeground handles signal forwarding internally\n\t\t\t\tawait strategy.runContainerForeground(\n\t\t\t\t\tworktreePath,\n\t\t\t\t\tport,\n\t\t\t\t\tcontainerPort,\n\t\t\t\t\tstrategyConfig,\n\t\t\t\t\t{ redirectToStderr, envOverrides }\n\t\t\t\t)\n\t\t\t} finally {\n\t\t\t\tthis.runningDockerContainers.delete(port)\n\t\t\t}\n\n\t\t\treturn {}\n\t\t}\n\n\t\t// Native mode: delegate to NativeDevServerStrategy\n\t\treturn this.nativeStrategy.startForeground(worktreePath, port, {\n\t\t\tredirectToStderr,\n\t\t\t...(onProcessStarted !== undefined && { onProcessStarted }),\n\t\t\t...(envOverrides !== undefined && { envOverrides }),\n\t\t})\n\t}\n\n\t/**\n\t * Clean up all running server processes and Docker containers.\n\t * This should be called when the manager is being disposed.\n\t */\n\tasync cleanup(): Promise<void> {\n\t\t// Clean up native process-based servers\n\t\tawait this.nativeStrategy.stopAll()\n\n\t\t// Clean up Docker containers using DockerDevServerStrategy\n\t\tfor (const [port, containerName] of this.runningDockerContainers.entries()) {\n\t\t\ttry {\n\t\t\t\tlogger.debug(`Cleaning up Docker container \"${containerName}\" on port ${port}`)\n\t\t\t\t// Create a minimal strategy just for stopContainer\n\t\t\t\tconst strategy = new DockerDevServerStrategy({}, dockerUtils)\n\t\t\t\tawait strategy.stopContainer(containerName)\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to stop Docker container \"${containerName}\" on port ${port}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tthis.runningDockerContainers.clear()\n\t}\n}\n","import { execa } from 'execa'\nimport net from 'net'\nimport { logger } from '../utils/logger.js'\nimport { restoreTerminalState } from '../utils/terminal.js'\n\n/**\n * Docker configuration shape consumed by DockerDevServerStrategy.\n * Matches the DevServerSettings['docker'] shape from the settings schema.\n */\nexport interface DockerConfig {\n\t/** Path to Dockerfile (relative to worktree) */\n\tdockerFile?: string | undefined\n\t/** Port inside the container (auto-detected from image inspect or Dockerfile EXPOSE if not set) */\n\tcontainerPort?: number | undefined\n\t/** Build arguments passed as --build-arg to docker build */\n\tbuildArgs?: Record<string, string> | undefined\n\t/** Additional docker run flags */\n\trunArgs?: string[] | undefined\n\t/** Identifier for naming containers/images (issue number, branch name). Falls back to worktreePath if not set. */\n\tidentifier?: string | undefined\n}\n\n/**\n * Options for runContainerForeground.\n */\nexport interface RunForegroundOptions {\n\t/** If true, redirect stdout/stderr to process.stderr */\n\tredirectToStderr?: boolean | undefined\n\t/** Called immediately after the container starts */\n\tonProcessStarted?: ((pid?: number) => void) | undefined\n\t/** Additional environment variables to forward into the container */\n\tenvOverrides?: Record<string, string> | undefined\n}\n\n/**\n * Utility function contracts from the docker-utils sibling issue.\n * Coded against these shapes so this class compiles without waiting for the sibling merge.\n */\ntype ParseDockerfileExposeFn = (path: string) => Promise<number | null>\ntype InspectImagePortsFn = (name: string) => Promise<number | null>\ntype BuildContainerNameFn = (id: string | number) => string\ntype BuildImageNameFn = (id: string | number) => string\ntype AssertDockerAvailableFn = () => Promise<void>\n\n/**\n * Injected docker utility functions.\n * Default implementations are imported from DockerManager for backward compatibility\n * until the dedicated docker-utils module is merged.\n */\nexport interface DockerUtils {\n\tparseDockerfileExpose: ParseDockerfileExposeFn\n\tinspectImagePorts: InspectImagePortsFn\n\tbuildContainerName: BuildContainerNameFn\n\tbuildImageName: BuildImageNameFn\n\tassertDockerAvailable: AssertDockerAvailableFn\n}\n\n/**\n * Attempt a single TCP connection to localhost:port.\n * Resolves true if the connection succeeds, false otherwise.\n */\nfunction tcpProbe(port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = net.createConnection({ port, host: '127.0.0.1' })\n\t\tsocket.once('connect', () => {\n\t\t\tsocket.destroy()\n\t\t\tresolve(true)\n\t\t})\n\t\tsocket.once('error', () => {\n\t\t\tsocket.destroy()\n\t\t\tresolve(false)\n\t\t})\n\t})\n}\n\n/**\n * DockerDevServerStrategy handles the full Docker container lifecycle for a dev server:\n * - Image building\n * - Container running (detached and foreground)\n * - Container stopping\n * - Readiness detection via TCP probe\n * - Port resolution (3-tier: config > image inspect > Dockerfile EXPOSE)\n *\n * This class is the core Docker logic delegated to by DevServerManager.\n * It does NOT modify DevServerManager, ResourceCleanup, or CLI commands.\n */\nexport class DockerDevServerStrategy {\n\tprivate readonly utils: DockerUtils\n\n\tconstructor(_config: DockerConfig, utils: DockerUtils) {\n\t\tthis.utils = utils\n\t}\n\n\t/**\n\t * Resolve the container port using 3-tier fallback:\n\t * 1. config.containerPort (explicit)\n\t * 2. inspectImagePorts(imageName) (from built image)\n\t * 3. parseDockerfileExpose(dockerfilePath) (from Dockerfile)\n\t *\n\t * Throws a clear error if all three return null.\n\t *\n\t * @param config - Docker config (may override the constructor config)\n\t * @param imageName - Name of the built Docker image\n\t * @param dockerfilePath - Absolute path to the Dockerfile\n\t */\n\tasync resolveContainerPort(\n\t\tconfig: DockerConfig,\n\t\timageName: string,\n\t\tdockerfilePath: string\n\t): Promise<number> {\n\t\tif (config.containerPort !== undefined) {\n\t\t\treturn config.containerPort\n\t\t}\n\n\t\tconst inspectedPort = await this.utils.inspectImagePorts(imageName)\n\t\tif (inspectedPort !== null) {\n\t\t\tlogger.debug(`Auto-detected container port ${inspectedPort} from Docker image inspect`)\n\t\t\treturn inspectedPort\n\t\t}\n\n\t\tconst exposedPort = await this.utils.parseDockerfileExpose(dockerfilePath)\n\t\tif (exposedPort !== null) {\n\t\t\tlogger.debug(`Auto-detected container port ${exposedPort} from Dockerfile EXPOSE directive`)\n\t\t\treturn exposedPort\n\t\t}\n\n\t\tthrow new Error(\n\t\t\t'Cannot determine container port. Set `devServer.docker.containerPort` in settings or add an `EXPOSE` directive to your Dockerfile.'\n\t\t)\n\t}\n\n\t/**\n\t * Build a Docker image for the worktree.\n\t * Build context is always the worktree root directory.\n\t *\n\t * @param worktreePath - Absolute path to the worktree (build context)\n\t * @param config - Docker config with Dockerfile path and build args\n\t */\n\tasync buildImage(worktreePath: string, config: DockerConfig): Promise<void> {\n\t\tconst imageName = this.utils.buildImageName(config.identifier ?? worktreePath)\n\t\tconst dockerfilePath = config.dockerFile ?? './Dockerfile'\n\n\t\tconst args = ['build', '-t', imageName, '-f', dockerfilePath]\n\n\t\tif (config.buildArgs) {\n\t\t\tfor (const [key, value] of Object.entries(config.buildArgs)) {\n\t\t\t\targs.push('--build-arg', `${key}=${value}`)\n\t\t\t}\n\t\t}\n\n\t\t// Context is always the worktree root\n\t\targs.push('.')\n\n\t\tlogger.info(`Building Docker image \"${imageName}\" from ${dockerfilePath}...`)\n\n\t\ttry {\n\t\t\tawait execa('docker', args, {\n\t\t\t\tcwd: worktreePath,\n\t\t\t\tstdio: 'inherit',\n\t\t\t})\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tthrow new Error(`Docker build failed for image \"${imageName}\": ${message}`)\n\t\t}\n\n\t\tlogger.success(`Docker image \"${imageName}\" built successfully`)\n\t}\n\n\t/**\n\t * Run a container in detached (background) mode.\n\t * Force-removes any existing container with the same name first.\n\t * Mounts the worktree at /app and adds an anonymous volume for node_modules.\n\t * Forwards PORT and any envOverrides into the container.\n\t *\n\t * @param worktreePath - Absolute path to the worktree (mounted at /app)\n\t * @param hostPort - Port on the host to map\n\t * @param containerPort - Port inside the container\n\t * @param config - Docker config with run args\n\t * @param envOverrides - Additional environment variables to set in the container\n\t * @returns The container name\n\t */\n\tasync runContainerDetached(\n\t\tworktreePath: string,\n\t\thostPort: number,\n\t\tcontainerPort: number,\n\t\tconfig: DockerConfig,\n\t\tenvOverrides?: Record<string, string>\n\t): Promise<string> {\n\t\tconst nameId = config.identifier ?? worktreePath\n\t\tconst imageName = this.utils.buildImageName(nameId)\n\t\tconst containerName = this.utils.buildContainerName(nameId)\n\n\t\t// Force-remove any existing container with same name\n\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\n\t\tconst args = [\n\t\t\t'run', '-d',\n\t\t\t'--name', containerName,\n\t\t\t'-p', `${hostPort}:${containerPort}`,\n\t\t\t// Mount worktree at /app\n\t\t\t'-v', `${worktreePath}:/app`,\n\t\t\t// Anonymous volume for node_modules to prevent host/container conflicts\n\t\t\t'-v', '/app/node_modules',\n\t\t\t// Forward PORT as the container port so the app listens where Docker expects.\n\t\t\t// The -p mapping handles host-to-container translation.\n\t\t\t'-e', `PORT=${containerPort}`,\n\t\t]\n\n\t\t// Forward additional environment variables\n\t\tif (envOverrides) {\n\t\t\tfor (const [key, value] of Object.entries(envOverrides)) {\n\t\t\t\targs.push('-e', `${key}=${value}`)\n\t\t\t}\n\t\t}\n\n\t\t// Additional run flags from config\n\t\tif (config.runArgs) {\n\t\t\targs.push(...config.runArgs)\n\t\t}\n\n\t\targs.push(imageName)\n\n\t\tlogger.info(`Starting Docker container \"${containerName}\" in background (http://localhost:${hostPort} → container:${containerPort})...`)\n\n\t\ttry {\n\t\t\tawait execa('docker', args)\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : 'Unknown error'\n\t\t\tthrow new Error(`Failed to start Docker container \"${containerName}\": ${message}`)\n\t\t}\n\n\t\tlogger.success(`Docker container \"${containerName}\" started on port ${hostPort}`)\n\t\treturn containerName\n\t}\n\n\t/**\n\t * Run a container in foreground (blocking) mode.\n\t * The container is automatically removed on exit (--rm flag).\n\t * Traps SIGINT and SIGTERM and forwards them to the container via docker stop.\n\t *\n\t * @param worktreePath - Absolute path to the worktree (mounted at /app)\n\t * @param hostPort - Port on the host to map\n\t * @param containerPort - Port inside the container\n\t * @param config - Docker config with run args\n\t * @param opts - Additional options (redirectToStderr, onProcessStarted, envOverrides)\n\t * @returns Object with optional pid (Docker containers don't expose host PID)\n\t */\n\tasync runContainerForeground(\n\t\tworktreePath: string,\n\t\thostPort: number,\n\t\tcontainerPort: number,\n\t\tconfig: DockerConfig,\n\t\topts: RunForegroundOptions = {}\n\t): Promise<{ pid?: number }> {\n\t\tconst nameId = config.identifier ?? worktreePath\n\t\tconst imageName = this.utils.buildImageName(nameId)\n\t\tconst containerName = this.utils.buildContainerName(nameId)\n\t\tconst { redirectToStderr, onProcessStarted, envOverrides } = opts\n\n\t\t// Force-remove any existing container with same name (stale from previous ungraceful exit)\n\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\n\t\tconst args = [\n\t\t\t'run', '--rm',\n\t\t\t'--name', containerName,\n\t\t\t'-p', `${hostPort}:${containerPort}`,\n\t\t\t// Mount worktree at /app\n\t\t\t'-v', `${worktreePath}:/app`,\n\t\t\t// Anonymous volume for node_modules to prevent host/container conflicts\n\t\t\t'-v', '/app/node_modules',\n\t\t\t// Forward PORT as the container port so the app listens where Docker expects.\n\t\t\t// The -p mapping handles host-to-container translation.\n\t\t\t'-e', `PORT=${containerPort}`,\n\t\t]\n\n\t\t// Forward additional environment variables\n\t\tif (envOverrides) {\n\t\t\tfor (const [key, value] of Object.entries(envOverrides)) {\n\t\t\t\targs.push('-e', `${key}=${value}`)\n\t\t\t}\n\t\t}\n\n\t\t// Additional run flags from config\n\t\tif (config.runArgs) {\n\t\t\targs.push(...config.runArgs)\n\t\t}\n\n\t\targs.push(imageName)\n\n\t\tlogger.info(`Running Docker container \"${containerName}\" in foreground (http://localhost:${hostPort} → container:${containerPort})...`)\n\n\t\tconst stdio = redirectToStderr\n\t\t\t? [process.stdin, process.stderr, process.stderr] as const\n\t\t\t: 'inherit' as const\n\n\t\t// Signal forwarding: trap SIGINT/SIGTERM and forward to container\n\t\tconst forwardSignal = (): void => {\n\t\t\tlogger.debug(`Stopping container \"${containerName}\"`)\n\t\t\tvoid execa('docker', ['stop', containerName], { reject: false })\n\t\t}\n\n\t\tconst onSigint = (): void => forwardSignal()\n\t\tconst onSigterm = (): void => forwardSignal()\n\n\t\tprocess.on('SIGINT', onSigint)\n\t\tprocess.on('SIGTERM', onSigterm)\n\n\t\tif (onProcessStarted) {\n\t\t\tonProcessStarted(undefined)\n\t\t}\n\n\t\ttry {\n\t\t\tawait execa('docker', args, { stdio })\n\t\t} finally {\n\t\t\t// Clean up signal handlers to avoid leaks\n\t\t\tprocess.removeListener('SIGINT', onSigint)\n\t\t\tprocess.removeListener('SIGTERM', onSigterm)\n\t\t\trestoreTerminalState()\n\t\t}\n\n\t\treturn {}\n\t}\n\n\t/**\n\t * Stop and remove a container by name.\n\t * Uses docker rm -f which handles both running and stopped containers atomically.\n\t * Handles already-stopped containers gracefully (no error thrown).\n\t *\n\t * @param containerName - Name of the container to stop and remove\n\t */\n\tasync stopContainer(containerName: string): Promise<void> {\n\t\tlogger.debug(`Stopping and removing container \"${containerName}\"...`)\n\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\t\tlogger.debug(`Container \"${containerName}\" stopped and removed`)\n\t}\n\n\t/**\n\t * Check if a named container is currently running.\n\t * Uses exact name matching with anchored regex to avoid partial name matches.\n\t *\n\t * @param containerName - Name of the container to check\n\t * @returns true if the container is running, false otherwise\n\t */\n\tasync isContainerRunning(containerName: string): Promise<boolean> {\n\t\ttry {\n\t\t\tconst result = await execa('docker', [\n\t\t\t\t'ps',\n\t\t\t\t'--filter', `name=^${containerName}$`,\n\t\t\t\t'--format', '{{.Names}}',\n\t\t\t], { reject: false })\n\n\t\t\treturn result.exitCode === 0 && result.stdout.trim() === containerName\n\t\t} catch {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Wait for the dev server to be ready by probing the TCP port.\n\t * Uses net.createConnection instead of lsof-based detection since Docker port\n\t * forwarding shows com.docker.backend as the listening process (not the dev server).\n\t * Exits early if the container has stopped (crash detection).\n\t *\n\t * @param port - Host port to probe\n\t * @param timeout - Maximum time to wait in milliseconds\n\t * @param interval - Interval between probes in milliseconds\n\t * @param containerName - Optional container name to monitor for early exit\n\t * @returns true if the port accepts connections within the timeout, false otherwise\n\t */\n\tasync waitForReady(port: number, timeout: number, interval: number, containerName?: string): Promise<boolean> {\n\t\tconst startTime = Date.now()\n\t\tlet attempts = 0\n\n\t\twhile (Date.now() - startTime < timeout) {\n\t\t\tattempts++\n\n\t\t\t// Early exit: if the container has stopped, stop polling\n\t\t\tif (containerName && attempts % 3 === 0) {\n\t\t\t\tconst stillRunning = await this.isContainerRunning(containerName)\n\t\t\t\tif (!stillRunning) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t`Docker container \"${containerName}\" exited before becoming ready (after ${attempts} attempts, ${Date.now() - startTime}ms)`\n\t\t\t\t\t)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst isReady = await tcpProbe(port)\n\t\t\tif (isReady) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tawait new Promise<void>((resolve) => globalThis.setTimeout(resolve, interval))\n\t\t}\n\n\t\treturn false\n\t}\n}\n","import { execa, type ExecaChildProcess, type ExecaError } from 'execa'\nimport { setTimeout } from 'timers/promises'\nimport { ProcessManager } from './process/ProcessManager.js'\nimport { buildDevServerCommand } from '../utils/dev-server.js'\nimport { runScript } from '../utils/package-manager.js'\nimport { getPackageScripts } from '../utils/package-json.js'\nimport { logger } from '../utils/logger.js'\nimport { restoreTerminalState } from '../utils/terminal.js'\nimport type { DevServerStrategy, ForegroundOpts } from './DevServerStrategy.js'\n\n/**\n * NativeDevServerStrategy implements DevServerStrategy for process-based dev servers.\n * This is the default mode — the dev server runs directly on the host as a child process.\n */\nexport class NativeDevServerStrategy implements DevServerStrategy {\n\tprivate readonly processManager: ProcessManager\n\tprivate readonly startupTimeout: number\n\tprivate readonly checkInterval: number\n\tprivate runningServers: Map<number, ExecaChildProcess> = new Map()\n\n\tconstructor(\n\t\tprocessManager: ProcessManager,\n\t\tstartupTimeout: number,\n\t\tcheckInterval: number\n\t) {\n\t\tthis.processManager = processManager\n\t\tthis.startupTimeout = startupTimeout\n\t\tthis.checkInterval = checkInterval\n\t}\n\n\tasync isRunning(port: number): Promise<boolean> {\n\t\tconst process = await this.processManager.detectDevServer(port)\n\t\treturn process !== null\n\t}\n\n\tasync startBackground(\n\t\tworktreePath: string,\n\t\tport: number,\n\t\tenvOverrides?: Record<string, string>\n\t): Promise<void> {\n\t\t// Guard: Check if a dev script exists in package.json or package.iloom.json\n\t\tconst scripts = await getPackageScripts(worktreePath)\n\t\tif (!scripts['dev']) {\n\t\t\tlogger.warn('Skipping auto-start: no \"dev\" script found in package.json or package.iloom.json')\n\t\t\treturn\n\t\t}\n\n\t\t// Build dev server command\n\t\tconst devCommand = await buildDevServerCommand(worktreePath)\n\t\tlogger.debug(`Starting dev server with command: ${devCommand}`)\n\n\t\t// Start server in background\n\t\tconst serverProcess = execa('sh', ['-c', devCommand], {\n\t\t\tcwd: worktreePath,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...envOverrides,\n\t\t\t\tPORT: port.toString(),\n\t\t\t},\n\t\t\t// Important: Don't inherit stdio - server runs in background\n\t\t\tstdio: 'ignore',\n\t\t\t// Detach from parent process so it continues running\n\t\t\tdetached: true,\n\t\t})\n\n\t\t// Store reference to prevent cleanup\n\t\tthis.runningServers.set(port, serverProcess)\n\n\t\t// Remove from map when process exits naturally or crashes\n\t\tserverProcess.on('exit', () => {\n\t\t\tthis.runningServers.delete(port)\n\t\t})\n\n\t\t// Unref so parent can exit\n\t\tserverProcess.unref()\n\n\t\t// Wait for server to be ready (pass process ref for early crash detection)\n\t\tlogger.info(`Waiting for dev server to start on port ${port}...`)\n\t\tconst ready = await this.waitForReady(port, serverProcess)\n\n\t\tif (!ready) {\n\t\t\tthrow new Error(\n\t\t\t\t`Dev server failed to start within ${this.startupTimeout}ms timeout`\n\t\t\t)\n\t\t}\n\n\t\tlogger.success(`Dev server started successfully on port ${port}`)\n\t}\n\n\tasync startForeground(\n\t\tworktreePath: string,\n\t\tport: number,\n\t\topts: ForegroundOpts\n\t): Promise<{ pid?: number }> {\n\t\tconst { redirectToStderr = false, onProcessStarted, envOverrides } = opts\n\n\t\tlogger.debug(`Starting dev server in foreground on port ${port}`)\n\n\t\tif (redirectToStderr) {\n\t\t\t// For redirectToStderr, we need direct execa control for custom stdio\n\t\t\tconst devCommand = await buildDevServerCommand(worktreePath)\n\t\t\tlogger.debug(`Starting dev server with command: ${devCommand}`)\n\n\t\t\tconst serverProcess = execa('sh', ['-c', devCommand], {\n\t\t\t\tcwd: worktreePath,\n\t\t\t\tenv: {\n\t\t\t\t\t...process.env,\n\t\t\t\t\t...envOverrides,\n\t\t\t\t\tPORT: port.toString(),\n\t\t\t\t},\n\t\t\t\tstdio: [process.stdin, process.stderr, process.stderr],\n\t\t\t})\n\n\t\t\tconst processInfo: { pid?: number } =\n\t\t\t\tserverProcess.pid !== undefined ? { pid: serverProcess.pid } : {}\n\n\t\t\tif (onProcessStarted) {\n\t\t\t\tonProcessStarted(processInfo.pid)\n\t\t\t}\n\n\t\t\t// Register no-op SIGINT handler to prevent signal-exit from re-raising SIGINT\n\t\t\t// before finally blocks can run, ensuring terminal state is restored on Ctrl+C.\n\t\t\tconst onSigint = (): void => {}\n\t\t\tprocess.on('SIGINT', onSigint)\n\n\t\t\ttry {\n\t\t\t\tawait serverProcess\n\t\t\t} catch (error) {\n\t\t\t\tconst execaError = error as ExecaError\n\t\t\t\t// If killed by SIGINT, the user intentionally cancelled — return silently\n\t\t\t\tif (execaError.signal !== 'SIGINT') {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tprocess.removeListener('SIGINT', onSigint)\n\t\t\t\trestoreTerminalState()\n\t\t\t}\n\n\t\t\treturn processInfo\n\t\t}\n\n\t\t// Use runScript for standard foreground mode\n\t\treturn await runScript('dev', worktreePath, [], {\n\t\t\tenv: {\n\t\t\t\t...envOverrides,\n\t\t\t\tPORT: port.toString(),\n\t\t\t},\n\t\t\tforeground: true,\n\t\t\t...(onProcessStarted && { onStart: onProcessStarted }),\n\t\t\tnoCi: true, // Dev servers should not have CI=true\n\t\t})\n\t}\n\n\tasync stop(port: number): Promise<boolean> {\n\t\tconst serverProcess = this.runningServers.get(port)\n\t\tif (!serverProcess) {\n\t\t\treturn false\n\t\t}\n\n\t\ttry {\n\t\t\t// Kill the entire process group (negative PID) since the server is\n\t\t\t// spawned with detached:true via `sh -c`. Without this, only the\n\t\t\t// shell process receives the signal and the actual dev server\n\t\t\t// (node/vite/next) remains running as an orphan.\n\t\t\tif (serverProcess.pid) {\n\t\t\t\tprocess.kill(-serverProcess.pid, 'SIGTERM')\n\t\t\t} else {\n\t\t\t\tserverProcess.kill()\n\t\t\t}\n\t\t\tthis.runningServers.delete(port)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tlogger.warn(\n\t\t\t\t`Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Stop all tracked server processes. Called during cleanup.\n\t */\n\tasync stopAll(): Promise<void> {\n\t\tfor (const [port] of this.runningServers.entries()) {\n\t\t\tawait this.stop(port)\n\t\t}\n\t}\n\n\t/**\n\t * Wait for server to be ready by polling the port.\n\t * Exits early if the spawned process has already exited (crash detection).\n\t * Public so DevServerManager can reuse it for Docker mode readiness checks.\n\t *\n\t * @param port - Port to poll\n\t * @param processRef - Optional spawned process to monitor for early exit\n\t */\n\tasync waitForReady(port: number, processRef?: ExecaChildProcess): Promise<boolean> {\n\t\tconst startTime = Date.now()\n\t\tlet attempts = 0\n\n\t\twhile (Date.now() - startTime < this.startupTimeout) {\n\t\t\tattempts++\n\n\t\t\t// Early exit: if the spawned process has already exited, stop polling\n\t\t\t// Check both null and undefined since exitCode is undefined before the process exits\n\t\t\tif (processRef && processRef.exitCode != null) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Dev server process exited with code ${processRef.exitCode} before becoming ready (after ${attempts} attempts, ${Date.now() - startTime}ms)`\n\t\t\t\t)\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst processInfo = await this.processManager.detectDevServer(port)\n\n\t\t\tif (processInfo) {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t`Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`\n\t\t\t\t)\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\tawait setTimeout(this.checkInterval)\n\t\t}\n\n\t\tlogger.warn(\n\t\t\t`Server did not start on port ${port} after ${this.startupTimeout}ms (${attempts} attempts)`\n\t\t)\n\t\treturn false\n\t}\n}\n","import { detectPackageManager } from './package-manager.js'\nimport { logger } from './logger.js'\nimport type { Capability } from '../types/loom.js'\n\n/**\n * Build dev server command for workspace\n * Detects package manager and constructs appropriate command\n */\nexport async function buildDevServerCommand(\n\tworkspacePath: string\n): Promise<string> {\n\tconst packageManager = await detectPackageManager(workspacePath)\n\n\tlet devCommand: string\n\n\tswitch (packageManager) {\n\t\tcase 'pnpm':\n\t\t\tdevCommand = 'pnpm dev'\n\t\t\tbreak\n\t\tcase 'npm':\n\t\t\tdevCommand = 'npm run dev'\n\t\t\tbreak\n\t\tcase 'yarn':\n\t\t\tdevCommand = 'yarn dev'\n\t\t\tbreak\n\t\tdefault:\n\t\t\t// Fallback to npm (handles bun and other package managers)\n\t\t\tlogger.warn(`Unknown or unsupported package manager: ${packageManager}, defaulting to npm`)\n\t\t\tdevCommand = 'npm run dev'\n\t}\n\n\tlogger.debug(`Dev server command: ${devCommand}`)\n\treturn devCommand\n}\n\n/**\n * Build complete dev server launch command for terminal\n * Includes VSCode launch, echo message (only for web projects), and dev server start\n */\nexport async function getDevServerLaunchCommand(\n\tworkspacePath: string,\n\tport?: number,\n\tcapabilities: Capability[] = []\n): Promise<string> {\n\tconst devCommand = await buildDevServerCommand(workspacePath)\n\n\tconst commands: string[] = []\n\n\t// // Open VSCode\n\t// commands.push('code .')\n\n\t// Echo message (only for web projects)\n\tif (capabilities.includes('web')) {\n\t\tif (port !== undefined) {\n\t\t\tcommands.push(`echo 'Starting dev server on PORT=${port}...'`)\n\t\t} else {\n\t\t\tcommands.push(`echo 'Starting dev server...'`)\n\t\t}\n\t}\n\n\t// Start dev server\n\tcommands.push(devCommand)\n\n\treturn commands.join(' && ')\n}\n"],"mappings":"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","names":["execa","process","execa"]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  extractIssueNumber,
4
4
  extractPRNumber
5
- } from "./chunk-3RXYOBME.js";
5
+ } from "./chunk-OPQC4OWM.js";
6
6
 
7
7
  // src/utils/IdentifierParser.ts
8
8
  function matchIssueIdentifier(input) {
@@ -108,4 +108,4 @@ export {
108
108
  matchIssueIdentifier,
109
109
  IdentifierParser
110
110
  };
111
- //# sourceMappingURL=chunk-UDCI3QTS.js.map
111
+ //# sourceMappingURL=chunk-ZM2AYHMO.js.map
@@ -7,9 +7,9 @@ import {
7
7
  getClaudeVersion,
8
8
  launchClaude,
9
9
  launchClaudeInNewTerminalWindow
10
- } from "./chunk-Y3RX7LZT.js";
11
- import "./chunk-ZAXRQLK3.js";
12
- import "./chunk-H2SSF24U.js";
10
+ } from "./chunk-DDHWZNGL.js";
11
+ import "./chunk-FTYWGQFM.js";
12
+ import "./chunk-VRPPI6GU.js";
13
13
  export {
14
14
  detectClaudeCli,
15
15
  generateBranchName,
@@ -19,4 +19,4 @@ export {
19
19
  launchClaude,
20
20
  launchClaudeInNewTerminalWindow
21
21
  };
22
- //# sourceMappingURL=claude-ONQTDWV3.js.map
22
+ //# sourceMappingURL=claude-ACL7G4CF.js.map
@@ -1,59 +1,62 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ResourceCleanup
4
- } from "./chunk-7FIXNAUO.js";
5
- import "./chunk-XXFSOVL3.js";
4
+ } from "./chunk-OKB2NEDQ.js";
5
+ import "./chunk-QFDM23CO.js";
6
6
  import {
7
7
  CLIIsolationManager,
8
8
  DatabaseManager,
9
9
  EnvironmentManager,
10
10
  LoomManager
11
- } from "./chunk-XFQGI2E3.js";
12
- import "./chunk-ABVMUNCD.js";
13
- import "./chunk-NOMQ5RFG.js";
14
- import "./chunk-RMLADZRY.js";
15
- import "./chunk-4232AHNQ.js";
11
+ } from "./chunk-GWJWECZB.js";
12
+ import "./chunk-M3FBM4T3.js";
13
+ import "./chunk-7UBEHQTP.js";
14
+ import "./chunk-AYLC633W.js";
16
15
  import {
17
16
  ProcessManager
18
- } from "./chunk-5PNZBH6V.js";
17
+ } from "./chunk-V5IYLWRA.js";
18
+ import "./chunk-BFF27W3S.js";
19
19
  import {
20
20
  IdentifierParser
21
- } from "./chunk-UDCI3QTS.js";
22
- import "./chunk-YETJNRQM.js";
23
- import "./chunk-HLDY5S4C.js";
24
- import "./chunk-3GTUXW26.js";
25
- import "./chunk-NCPZYQ4B.js";
21
+ } from "./chunk-ZM2AYHMO.js";
26
22
  import {
27
23
  createNeonProviderFromSettings
28
- } from "./chunk-VMZG66UV.js";
24
+ } from "./chunk-HKEXRZMU.js";
29
25
  import {
30
26
  TelemetryService
31
- } from "./chunk-GMDSYLI6.js";
27
+ } from "./chunk-MY2Q3FJ3.js";
28
+ import "./chunk-R7DGN73N.js";
29
+ import "./chunk-4232AHNQ.js";
30
+ import "./chunk-VIQOQ463.js";
32
31
  import {
33
32
  GitWorktreeManager
34
- } from "./chunk-LE2NOUTN.js";
35
- import "./chunk-5LTID2AF.js";
36
- import "./chunk-LHDD4JHC.js";
37
- import "./chunk-NH3QZYE5.js";
33
+ } from "./chunk-FV4KXBGO.js";
34
+ import "./chunk-WEBMMJKL.js";
35
+ import "./chunk-K3QGG4O2.js";
36
+ import "./chunk-DMSL5BAP.js";
37
+ import "./chunk-D4Q7T5KD.js";
38
+ import "./chunk-KV4NU3RP.js";
38
39
  import {
39
40
  promptConfirmation
40
- } from "./chunk-CV47VCMQ.js";
41
- import "./chunk-7OCGBJLR.js";
42
- import "./chunk-QVAA5KHK.js";
43
- import "./chunk-Y3RX7LZT.js";
44
- import "./chunk-3RXYOBME.js";
41
+ } from "./chunk-NPVA65KS.js";
42
+ import "./chunk-QC65IOV3.js";
43
+ import "./chunk-P5MXXHXQ.js";
44
+ import "./chunk-BZ7KTXPB.js";
45
+ import "./chunk-OIVFHJOA.js";
46
+ import "./chunk-DDHWZNGL.js";
47
+ import "./chunk-OPQC4OWM.js";
45
48
  import {
46
49
  SettingsManager
47
- } from "./chunk-ET6A2JR4.js";
50
+ } from "./chunk-653XBU3L.js";
48
51
  import {
49
52
  MetadataManager
50
- } from "./chunk-YRCEOQPX.js";
53
+ } from "./chunk-4JZEQBWV.js";
51
54
  import {
52
55
  getLogger
53
- } from "./chunk-ZAXRQLK3.js";
56
+ } from "./chunk-FTYWGQFM.js";
54
57
  import {
55
58
  loadEnvIntoProcess
56
- } from "./chunk-H2SSF24U.js";
59
+ } from "./chunk-VRPPI6GU.js";
57
60
 
58
61
  // src/commands/cleanup.ts
59
62
  function trackLoomAbandoned(metadata) {
@@ -104,10 +107,10 @@ var CleanupCommand = class {
104
107
  cliIsolationManager
105
108
  );
106
109
  if (!this.loomManager) {
107
- const { IssueTrackerFactory } = await import("./IssueTrackerFactory-XN6MQ4UN.js");
108
- const { ClaudeContextManager } = await import("./ClaudeContextManager-SXDCWDJA.js");
109
- const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-IC6NAFGY.js");
110
- const { DefaultBranchNamingService } = await import("./BranchNamingService-XBCO747L.js");
110
+ const { IssueTrackerFactory } = await import("./IssueTrackerFactory-2OI7YIN6.js");
111
+ const { ClaudeContextManager } = await import("./ClaudeContextManager-IENAE2CP.js");
112
+ const { ProjectCapabilityDetector } = await import("./ProjectCapabilityDetector-I4J66WKF.js");
113
+ const { DefaultBranchNamingService } = await import("./BranchNamingService-MEK2WZUD.js");
111
114
  this.loomManager = new LoomManager(
112
115
  this.gitWorktreeManager,
113
116
  IssueTrackerFactory.create(settings),
@@ -311,7 +314,7 @@ var CleanupCommand = class {
311
314
  const { force, dryRun } = parsed.options;
312
315
  let parsedInput = await this.identifierParser.parseForPatternDetection(identifier);
313
316
  if (parsedInput.type === "branch" && parsedInput.branchName) {
314
- const { extractIssueNumber } = await import("./git-BXUD6CL5.js");
317
+ const { extractIssueNumber } = await import("./git-I3PO6FY7.js");
315
318
  const extractedNumber = extractIssueNumber(parsedInput.branchName);
316
319
  if (extractedNumber !== null) {
317
320
  parsedInput = {
@@ -541,4 +544,4 @@ var CleanupCommand = class {
541
544
  export {
542
545
  CleanupCommand
543
546
  };
544
- //# sourceMappingURL=cleanup-YOM6PQCN.js.map
547
+ //# sourceMappingURL=cleanup-RLBLNQZN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/cleanup.ts"],"sourcesContent":["import { getLogger } from '../utils/logger-context.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { ResourceCleanup } from '../lib/ResourceCleanup.js'\nimport { ProcessManager } from '../lib/process/ProcessManager.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport { IdentifierParser } from '../utils/IdentifierParser.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { createNeonProviderFromSettings } from '../utils/neon-helpers.js'\nimport { LoomManager } from '../lib/LoomManager.js'\nimport { TelemetryService } from '../lib/TelemetryService.js'\nimport { MetadataManager } from '../lib/MetadataManager.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\n\nfunction trackLoomAbandoned(metadata: LoomMetadata): void {\n\ttry {\n\t\tconst durationMinutes = metadata.created_at\n\t\t\t? Math.round((Date.now() - new Date(metadata.created_at).getTime()) / 60000)\n\t\t\t: 0\n\t\tTelemetryService.getInstance().track('loom.abandoned', {\n\t\t\tduration_minutes: isNaN(durationMinutes) ? 0 : durationMinutes,\n\t\t\tphase_reached: metadata.state ?? 'unknown',\n\t\t})\n\t} catch (error: unknown) {\n\t\tgetLogger().debug(`Failed to track loom.abandoned telemetry: ${error instanceof Error ? error.message : String(error)}`)\n\t}\n}\nimport type { CleanupOptions } from '../types/index.js'\nimport type { CleanupResult } from '../types/cleanup.js'\nimport type { ParsedInput } from './start.js'\n\n/**\n * Input structure for CleanupCommand.execute()\n */\nexport interface CleanupCommandInput {\n identifier?: string\n options: CleanupOptions\n}\n\n/**\n * Parsed and validated cleanup command input\n * Mode determines which cleanup operation to perform\n */\nexport interface ParsedCleanupInput {\n mode: 'list' | 'single' | 'issue' | 'all'\n identifier?: string\n issueNumber?: string | number\n branchName?: string\n originalInput?: string\n options: CleanupOptions\n}\n\n/**\n * Manages cleanup command execution with option parsing and validation\n * Follows the command pattern established by StartCommand\n *\n * This implementation handles ONLY parsing, validation, and mode determination.\n * Actual cleanup operations are deferred to subsequent sub-issues.\n */\nexport class CleanupCommand {\n private readonly gitWorktreeManager: GitWorktreeManager\n private resourceCleanup?: ResourceCleanup\n private loomManager?: import('../lib/LoomManager.js').LoomManager\n private readonly identifierParser: IdentifierParser\n\n constructor(\n gitWorktreeManager?: GitWorktreeManager,\n resourceCleanup?: ResourceCleanup\n ) {\n // Load environment variables first\n const envResult = loadEnvIntoProcess()\n if (envResult.error) {\n getLogger().debug(`Environment loading warning: ${envResult.error.message}`)\n }\n if (envResult.parsed) {\n getLogger().debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n }\n\n this.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\n // Initialize ResourceCleanup with DatabaseManager and CLIIsolationManager\n // ResourceCleanup will be initialized lazily with proper configuration\n if (resourceCleanup) {\n this.resourceCleanup = resourceCleanup\n }\n\n // Initialize IdentifierParser for pattern-based detection\n this.identifierParser = new IdentifierParser(this.gitWorktreeManager)\n }\n\n /**\n * Lazy initialization of ResourceCleanup and LoomManager with properly configured DatabaseManager\n */\n private async ensureResourceCleanup(): Promise<void> {\n if (this.resourceCleanup && this.loomManager) {\n return\n }\n\n const settingsManager = new SettingsManager()\n const settings = await settingsManager.loadSettings()\n const databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n const environmentManager = new EnvironmentManager()\n const neonProvider = createNeonProviderFromSettings(settings)\n const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName)\n const cliIsolationManager = new CLIIsolationManager()\n\n this.resourceCleanup ??= new ResourceCleanup(\n this.gitWorktreeManager,\n new ProcessManager(),\n databaseManager,\n cliIsolationManager\n )\n\n // Initialize LoomManager if not provided (for child loom detection)\n if (!this.loomManager) {\n const { IssueTrackerFactory } = await import('../lib/IssueTrackerFactory.js')\n const { ClaudeContextManager } = await import('../lib/ClaudeContextManager.js')\n const { ProjectCapabilityDetector } = await import('../lib/ProjectCapabilityDetector.js')\n const { DefaultBranchNamingService } = await import('../lib/BranchNamingService.js')\n\n this.loomManager = new LoomManager(\n this.gitWorktreeManager,\n IssueTrackerFactory.create(settings),\n new DefaultBranchNamingService({ useClaude: true }),\n environmentManager,\n new ClaudeContextManager(),\n new ProjectCapabilityDetector(),\n cliIsolationManager,\n settingsManager,\n databaseManager\n )\n }\n }\n\n /**\n * Check for child looms and exit gracefully if any exist\n * Always checks the TARGET loom (the one being cleaned up), not the current directory's loom\n *\n * @param parsed - The parsed input identifying the loom being cleaned up\n */\n private async checkForChildLooms(parsed: ParsedCleanupInput): Promise<void> {\n await this.ensureResourceCleanup()\n if (!this.loomManager) {\n throw new Error('Failed to initialize LoomManager')\n }\n\n // Determine which branch is being cleaned up based on parsed input\n let targetBranch: string | undefined\n\n if (parsed.branchName) {\n targetBranch = parsed.branchName\n } else if (parsed.mode === 'issue' && parsed.issueNumber !== undefined) {\n // For issues, try to find the worktree by issue number to get the branch name\n const worktree = await this.gitWorktreeManager.findWorktreeForIssue(parsed.issueNumber)\n targetBranch = worktree?.branch\n }\n\n // If we can't determine the target branch, skip the check\n if (!targetBranch) {\n getLogger().debug(`Cannot determine target branch for child loom check`)\n return\n }\n\n // Check if the TARGET loom has any child looms\n const hasChildLooms = await this.loomManager.checkAndWarnChildLooms(targetBranch)\n if (hasChildLooms) {\n throw new Error('Cannot cleanup loom while child looms exist. Please \\'finish\\' or \\'cleanup\\' child looms first.')\n }\n }\n\n /**\n * Main entry point for the cleanup command\n * Parses input, validates options, and determines operation mode\n */\n public async execute(input: CleanupCommandInput): Promise<CleanupResult | void> {\n // Step 1: Parse input and determine mode\n const parsed = this.parseInput(input)\n\n // Step 2: Validate option combinations (fail fast before any delay)\n this.validateInput(parsed)\n\n // Note: JSON mode auto-skips routine confirmations (programmatic use can't interact)\n // Safety checks still require --force to bypass (ResourceCleanup.validateWorktreeSafety throws errors)\n\n // Step 3: Check for child looms AFTER parsing input\n // This ensures we only block when cleaning the CURRENT loom (parent), not a child\n await this.checkForChildLooms(parsed)\n\n // Step 4: Handle deferred execution (after all validation passes)\n if (input.options.defer) {\n getLogger().info(`Waiting ${input.options.defer}ms before cleanup...`)\n await new Promise(resolve => globalThis.setTimeout(resolve, input.options.defer))\n }\n\n // Step 5: Execute based on mode\n getLogger().info(`Cleanup mode: ${parsed.mode}`)\n\n if (parsed.mode === 'single') {\n return await this.executeSingleCleanup(parsed)\n } else if (parsed.mode === 'list') {\n getLogger().info('Would list all worktrees') // TODO: Implement in Sub-issue #2\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'list',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'all') {\n getLogger().info('Would remove all worktrees') // TODO: Implement in Sub-issue #5\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'all',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'issue') {\n return await this.executeIssueCleanup(parsed)\n }\n }\n\n /**\n * Parse input to determine cleanup mode and extract relevant data\n * Implements auto-detection: numeric input = issue number, non-numeric = branch name\n *\n * @private\n */\n private parseInput(input: CleanupCommandInput): ParsedCleanupInput {\n const { identifier, options } = input\n\n // Trim identifier if present\n const trimmedIdentifier = identifier?.trim() ?? undefined\n\n // Mode: List (takes priority - it's informational only)\n if (options.list) {\n const result: ParsedCleanupInput = {\n mode: 'list',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: All (remove everything)\n if (options.all) {\n const result: ParsedCleanupInput = {\n mode: 'all',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n if (options.issue !== undefined) {\n result.issueNumber = options.issue\n }\n return result\n }\n\n // Mode: Explicit issue number via --issue flag\n if (options.issue !== undefined) {\n // Need to determine if identifier is branch or numeric to set branchName\n if (trimmedIdentifier) {\n const numericPattern = /^[0-9]+$/\n if (!numericPattern.test(trimmedIdentifier)) {\n // Identifier is a branch name with explicit --issue flag\n return {\n mode: 'issue',\n issueNumber: options.issue,\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n const result: ParsedCleanupInput = {\n mode: 'issue',\n issueNumber: options.issue,\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: Auto-detect from identifier\n if (!trimmedIdentifier) {\n throw new Error('Missing required argument: identifier. Use --all to remove all worktrees or --list to list them.')\n }\n\n // Auto-detection: Check if identifier is purely numeric\n // Pattern from bash script line 364: ^[0-9]+$\n const numericPattern = /^[0-9]+$/\n if (numericPattern.test(trimmedIdentifier)) {\n // Numeric input = issue number\n return {\n mode: 'issue',\n issueNumber: parseInt(trimmedIdentifier, 10),\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n } else {\n // Non-numeric = branch name\n return {\n mode: 'single',\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n\n /**\n * Validate parsed input for option conflicts\n * Throws descriptive errors for invalid option combinations\n *\n * @private\n */\n private validateInput(parsed: ParsedCleanupInput): void {\n const { mode, options, branchName } = parsed\n\n // Conflict: --list is informational only, incompatible with destructive operations\n if (mode === 'list') {\n if (options.all) {\n throw new Error('Cannot use --list with --all (list is informational only)')\n }\n if (options.issue !== undefined) {\n throw new Error('Cannot use --list with --issue (list is informational only)')\n }\n if (parsed.identifier) {\n throw new Error('Cannot use --list with a specific identifier (list shows all worktrees)')\n }\n }\n\n // Conflict: --all removes everything, can't combine with specific identifier or --issue\n if (mode === 'all') {\n if (parsed.identifier) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n if (parsed.issueNumber !== undefined) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n }\n\n // Conflict: explicit --issue flag with branch name identifier\n // (This prevents confusion when user provides both)\n if (options.issue !== undefined && branchName) {\n throw new Error('Cannot use --issue flag with branch name identifier. Use numeric identifier or --issue flag alone.')\n }\n\n // Note: --force and --dry-run are compatible with all modes (no conflicts)\n }\n\n /**\n * Execute cleanup for single worktree\n * Implements two-stage confirmation: worktree removal, then branch deletion\n * Uses IdentifierParser for pattern-based detection without GitHub API calls\n */\n private async executeSingleCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const identifier = parsed.branchName ?? parsed.identifier ?? ''\n if (!identifier) {\n throw new Error('No identifier found for cleanup')\n }\n const { force, dryRun } = parsed.options\n\n // Step 1: Parse identifier using pattern-based detection\n let parsedInput: ParsedInput = await this.identifierParser.parseForPatternDetection(identifier)\n\n // If type is 'branch', try to extract issue number for CLI symlink cleanup\n if (parsedInput.type === 'branch' && parsedInput.branchName) {\n const { extractIssueNumber } = await import('../utils/git.js')\n const extractedNumber = extractIssueNumber(parsedInput.branchName)\n if (extractedNumber !== null) {\n parsedInput = {\n ...parsedInput,\n number: extractedNumber // Add number for CLI symlink cleanup\n }\n }\n }\n\n // Step 2: Display worktree details\n getLogger().info(`Preparing to cleanup worktree: ${identifier}`)\n\n // Step 3: Routine confirmation - worktree removal\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmWorktree = await promptConfirmation('Remove this worktree?', true)\n if (!confirmWorktree) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier,\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 3.5: Read metadata BEFORE cleanup (cleanup deletes the worktree)\n let preCleanupMetadata: LoomMetadata | null = null\n try {\n // Find worktree path for metadata lookup\n const worktree = parsedInput.type === 'branch' && parsedInput.branchName\n ? await this.gitWorktreeManager.findWorktreeForBranch(parsedInput.branchName)\n : parsedInput.number !== undefined\n ? await this.gitWorktreeManager.findWorktreeForIssue(parsedInput.number)\n : null\n if (worktree) {\n const metadataManager = new MetadataManager()\n preCleanupMetadata = await metadataManager.readMetadata(worktree.path)\n }\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n // Step 4: Execute worktree cleanup (includes safety validation)\n // Issue #275 fix: Run 5-point safety check BEFORE any deletion\n // This prevents the scenario where worktree is deleted but branch deletion fails\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n const cleanupResult = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Always include branch deletion (safety checks run first)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n })\n\n // Add dryRun flag to result\n cleanupResult.dryRun = dryRun ?? false\n\n // Step 5: Report cleanup results\n this.reportCleanupResults(cleanupResult)\n\n // Track loom.abandoned telemetry event (only for unfinished looms)\n if (cleanupResult.success && preCleanupMetadata && preCleanupMetadata.status !== 'finished') {\n trackLoomAbandoned(preCleanupMetadata)\n }\n\n // Final success message\n if (cleanupResult.success) {\n getLogger().success('Cleanup completed successfully')\n } else {\n getLogger().warn('Cleanup completed with errors - see details above')\n }\n\n return cleanupResult\n }\n\n /**\n * Report cleanup operation results to user\n */\n private reportCleanupResults(result: CleanupResult): void {\n getLogger().info('Cleanup operations:')\n\n result.operations.forEach(op => {\n const status = op.success ? '✓' : '✗'\n const message = op.error ? `${op.message}: ${op.error}` : op.message\n\n if (op.success) {\n getLogger().info(` ${status} ${message}`)\n } else {\n getLogger().error(` ${status} ${message}`)\n }\n })\n\n if (result.errors.length > 0) {\n getLogger().warn(`${result.errors.length} error(s) occurred during cleanup`)\n }\n }\n\n /**\n * Execute cleanup for all worktrees associated with an issue or PR number\n * Searches for worktrees by their path patterns (e.g., issue-25, pr-25, 25-feature, _pr_25)\n * Implements bash cleanup-worktree.sh remove_worktrees_by_issue() (lines 157-242)\n */\n private async executeIssueCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const issueNumber = parsed.issueNumber\n if (issueNumber === undefined) {\n throw new Error('No issue/PR number provided for cleanup')\n }\n\n const { force, dryRun } = parsed.options\n\n getLogger().info(`Finding worktrees related to issue/PR #${issueNumber}...`)\n\n // Step 1: Get all worktrees and filter by path pattern\n const worktrees = await this.gitWorktreeManager.listWorktrees()\n const matchingWorktrees = worktrees.filter(wt => {\n const path = wt.path.toLowerCase()\n // Lowercase for case-insensitive matching (Linear IDs are uppercase like MARK-1)\n const idStr = String(issueNumber).toLowerCase()\n\n // Check if path contains the identifier with proper word boundaries\n // Matches: issue-25, pr-25, 25-feature, _pr_25, issue-mark-1, etc.\n // Uses word boundary or common separators (-, _, /) for alphanumeric IDs\n const pattern = new RegExp(`(?:^|[/_-])${idStr}(?:[/_-]|$)`)\n return pattern.test(path)\n })\n\n if (matchingWorktrees.length === 0) {\n getLogger().warn(`No worktrees found for issue/PR #${issueNumber}`)\n getLogger().info(`Searched for worktree paths containing: ${issueNumber}, _pr_${issueNumber}, issue-${issueNumber}, etc.`)\n return {\n identifier: String(issueNumber),\n success: true,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n\n // Step 2: Build targets list from matching worktrees\n const targets: Array<{ branchName: string; hasWorktree: boolean; worktreePath?: string }> =\n matchingWorktrees.map(wt => ({\n branchName: wt.branch,\n hasWorktree: true,\n worktreePath: wt.path\n }))\n\n // Step 3: Display preview\n getLogger().info(`Found ${targets.length} worktree(s) related to issue/PR #${issueNumber}:`)\n for (const target of targets) {\n getLogger().info(` Branch: ${target.branchName} (${target.worktreePath})`)\n }\n\n // Step 4: Routine batch confirmation\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks per-worktree (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmCleanup = await promptConfirmation(\n `Remove ${targets.length} worktree(s)?`,\n true\n )\n if (!confirmCleanup) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier: String(issueNumber),\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 5: Process each target sequentially\n let worktreesRemoved = 0\n let branchesDeleted = 0\n const databaseBranchesDeletedList: string[] = []\n let failed = 0\n\n for (const target of targets) {\n getLogger().info(`Processing worktree: ${target.branchName}`)\n\n // Cleanup worktree using ResourceCleanup with ParsedInput\n // Now includes branch deletion with 5-point safety check BEFORE any deletion\n try {\n // Read metadata BEFORE cleanup for telemetry\n let targetMetadata: LoomMetadata | null = null\n if (target.worktreePath) {\n try {\n const metadataManager = new MetadataManager()\n targetMetadata = await metadataManager.readMetadata(target.worktreePath)\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n // Use the known issue number directly instead of parsing from branch name\n // This ensures CLI symlinks (created with issue number) are properly cleaned up\n const parsedInput: ParsedInput = {\n type: 'issue',\n number: issueNumber, // Use the known issue number, not parsed from branch\n branchName: target.branchName,\n originalInput: String(issueNumber)\n }\n\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n // Issue #275 fix: Run safety checks BEFORE deleting worktree\n // This prevents the scenario where worktree is deleted but branch deletion fails\n const result = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Include branch deletion (with safety checks)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n ...(target.worktreePath && { worktree: { path: target.worktreePath, branch: target.branchName } }),\n })\n\n if (result.success) {\n worktreesRemoved++\n getLogger().success(` Worktree removed: ${target.branchName}`)\n\n // Check if branch was deleted\n const branchOperation = result.operations.find(op => op.type === 'branch')\n if (branchOperation?.success) {\n branchesDeleted++\n getLogger().success(` Branch deleted: ${target.branchName}`)\n }\n\n // Check if database branch was actually deleted (use explicit deleted field)\n const dbOperation = result.operations.find(op => op.type === 'database')\n if (dbOperation?.deleted) {\n // Get branch name from result or use the target branch name\n const deletedBranchName = target.branchName\n databaseBranchesDeletedList.push(deletedBranchName)\n }\n\n // Track loom.abandoned telemetry (only for unfinished looms)\n if (targetMetadata && targetMetadata.status !== 'finished') {\n trackLoomAbandoned(targetMetadata)\n }\n } else {\n failed++\n getLogger().error(` Failed to remove worktree: ${target.branchName}`)\n for (const err of result.errors) {\n getLogger().error(` ${err.message}`)\n }\n }\n } catch (error) {\n failed++\n const errMsg = error instanceof Error ? error.message : 'Unknown error'\n getLogger().error(` Failed to cleanup: ${errMsg}`)\n continue // Continue with next worktree even if this one failed\n }\n }\n\n // Step 7: Report statistics\n getLogger().success(`Completed cleanup for issue/PR #${issueNumber}:`)\n getLogger().info(` Worktrees removed: ${worktreesRemoved}`)\n getLogger().info(` Branches deleted: ${branchesDeleted}`)\n if (databaseBranchesDeletedList.length > 0) {\n // Display branch names in the format requested\n getLogger().info(` Database branches deleted: ${databaseBranchesDeletedList.join(', ')}`)\n }\n if (failed > 0) {\n getLogger().warn(` Failed operations: ${failed}`)\n }\n\n // Return aggregated result\n return {\n identifier: String(issueNumber),\n success: failed === 0,\n dryRun: dryRun ?? false,\n operations: [\n { type: 'worktree' as const, success: true, message: `Removed ${worktreesRemoved} worktree(s)` },\n { type: 'branch' as const, success: true, message: `Deleted ${branchesDeleted} branch(es)` },\n ...(databaseBranchesDeletedList.length > 0 ? [{ type: 'database' as const, success: true, message: `Deleted ${databaseBranchesDeletedList.length} database branch(es)`, deleted: true }] : []),\n ],\n errors: [],\n rollbackRequired: false,\n }\n }\n}\n"],"mappings":"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","names":["numericPattern"]}
1
+ {"version":3,"sources":["../src/commands/cleanup.ts"],"sourcesContent":["import { getLogger } from '../utils/logger-context.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { ResourceCleanup } from '../lib/ResourceCleanup.js'\nimport { ProcessManager } from '../lib/process/ProcessManager.js'\nimport { DatabaseManager } from '../lib/DatabaseManager.js'\nimport { EnvironmentManager } from '../lib/EnvironmentManager.js'\nimport { CLIIsolationManager } from '../lib/CLIIsolationManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { promptConfirmation } from '../utils/prompt.js'\nimport { IdentifierParser } from '../utils/IdentifierParser.js'\nimport { loadEnvIntoProcess } from '../utils/env.js'\nimport { createNeonProviderFromSettings } from '../utils/neon-helpers.js'\nimport { LoomManager } from '../lib/LoomManager.js'\nimport { TelemetryService } from '../lib/TelemetryService.js'\nimport { MetadataManager } from '../lib/MetadataManager.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\n\nfunction trackLoomAbandoned(metadata: LoomMetadata): void {\n\ttry {\n\t\tconst durationMinutes = metadata.created_at\n\t\t\t? Math.round((Date.now() - new Date(metadata.created_at).getTime()) / 60000)\n\t\t\t: 0\n\t\tTelemetryService.getInstance().track('loom.abandoned', {\n\t\t\tduration_minutes: isNaN(durationMinutes) ? 0 : durationMinutes,\n\t\t\tphase_reached: metadata.state ?? 'unknown',\n\t\t})\n\t} catch (error: unknown) {\n\t\tgetLogger().debug(`Failed to track loom.abandoned telemetry: ${error instanceof Error ? error.message : String(error)}`)\n\t}\n}\nimport type { CleanupOptions } from '../types/index.js'\nimport type { CleanupResult } from '../types/cleanup.js'\nimport type { ParsedInput } from './start.js'\n\n/**\n * Input structure for CleanupCommand.execute()\n */\nexport interface CleanupCommandInput {\n identifier?: string\n options: CleanupOptions\n}\n\n/**\n * Parsed and validated cleanup command input\n * Mode determines which cleanup operation to perform\n */\nexport interface ParsedCleanupInput {\n mode: 'list' | 'single' | 'issue' | 'all'\n identifier?: string\n issueNumber?: string | number\n branchName?: string\n originalInput?: string\n options: CleanupOptions\n}\n\n/**\n * Manages cleanup command execution with option parsing and validation\n * Follows the command pattern established by StartCommand\n *\n * This implementation handles ONLY parsing, validation, and mode determination.\n * Actual cleanup operations are deferred to subsequent sub-issues.\n */\nexport class CleanupCommand {\n private readonly gitWorktreeManager: GitWorktreeManager\n private resourceCleanup?: ResourceCleanup\n private loomManager?: import('../lib/LoomManager.js').LoomManager\n private readonly identifierParser: IdentifierParser\n\n constructor(\n gitWorktreeManager?: GitWorktreeManager,\n resourceCleanup?: ResourceCleanup\n ) {\n // Load environment variables first\n const envResult = loadEnvIntoProcess()\n if (envResult.error) {\n getLogger().debug(`Environment loading warning: ${envResult.error.message}`)\n }\n if (envResult.parsed) {\n getLogger().debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`)\n }\n\n this.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\n // Initialize ResourceCleanup with DatabaseManager and CLIIsolationManager\n // ResourceCleanup will be initialized lazily with proper configuration\n if (resourceCleanup) {\n this.resourceCleanup = resourceCleanup\n }\n\n // Initialize IdentifierParser for pattern-based detection\n this.identifierParser = new IdentifierParser(this.gitWorktreeManager)\n }\n\n /**\n * Lazy initialization of ResourceCleanup and LoomManager with properly configured DatabaseManager\n */\n private async ensureResourceCleanup(): Promise<void> {\n if (this.resourceCleanup && this.loomManager) {\n return\n }\n\n const settingsManager = new SettingsManager()\n const settings = await settingsManager.loadSettings()\n const databaseUrlEnvVarName = settings.capabilities?.database?.databaseUrlEnvVarName ?? 'DATABASE_URL'\n\n const environmentManager = new EnvironmentManager()\n const neonProvider = createNeonProviderFromSettings(settings)\n const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName)\n const cliIsolationManager = new CLIIsolationManager()\n\n this.resourceCleanup ??= new ResourceCleanup(\n this.gitWorktreeManager,\n new ProcessManager(),\n databaseManager,\n cliIsolationManager\n )\n\n // Initialize LoomManager if not provided (for child loom detection)\n if (!this.loomManager) {\n const { IssueTrackerFactory } = await import('../lib/IssueTrackerFactory.js')\n const { ClaudeContextManager } = await import('../lib/ClaudeContextManager.js')\n const { ProjectCapabilityDetector } = await import('../lib/ProjectCapabilityDetector.js')\n const { DefaultBranchNamingService } = await import('../lib/BranchNamingService.js')\n\n this.loomManager = new LoomManager(\n this.gitWorktreeManager,\n IssueTrackerFactory.create(settings),\n new DefaultBranchNamingService({ useClaude: true }),\n environmentManager,\n new ClaudeContextManager(),\n new ProjectCapabilityDetector(),\n cliIsolationManager,\n settingsManager,\n databaseManager\n )\n }\n }\n\n /**\n * Check for child looms and exit gracefully if any exist\n * Always checks the TARGET loom (the one being cleaned up), not the current directory's loom\n *\n * @param parsed - The parsed input identifying the loom being cleaned up\n */\n private async checkForChildLooms(parsed: ParsedCleanupInput): Promise<void> {\n await this.ensureResourceCleanup()\n if (!this.loomManager) {\n throw new Error('Failed to initialize LoomManager')\n }\n\n // Determine which branch is being cleaned up based on parsed input\n let targetBranch: string | undefined\n\n if (parsed.branchName) {\n targetBranch = parsed.branchName\n } else if (parsed.mode === 'issue' && parsed.issueNumber !== undefined) {\n // For issues, try to find the worktree by issue number to get the branch name\n const worktree = await this.gitWorktreeManager.findWorktreeForIssue(parsed.issueNumber)\n targetBranch = worktree?.branch\n }\n\n // If we can't determine the target branch, skip the check\n if (!targetBranch) {\n getLogger().debug(`Cannot determine target branch for child loom check`)\n return\n }\n\n // Check if the TARGET loom has any child looms\n const hasChildLooms = await this.loomManager.checkAndWarnChildLooms(targetBranch)\n if (hasChildLooms) {\n throw new Error('Cannot cleanup loom while child looms exist. Please \\'finish\\' or \\'cleanup\\' child looms first.')\n }\n }\n\n /**\n * Main entry point for the cleanup command\n * Parses input, validates options, and determines operation mode\n */\n public async execute(input: CleanupCommandInput): Promise<CleanupResult | void> {\n // Step 1: Parse input and determine mode\n const parsed = this.parseInput(input)\n\n // Step 2: Validate option combinations (fail fast before any delay)\n this.validateInput(parsed)\n\n // Note: JSON mode auto-skips routine confirmations (programmatic use can't interact)\n // Safety checks still require --force to bypass (ResourceCleanup.validateWorktreeSafety throws errors)\n\n // Step 3: Check for child looms AFTER parsing input\n // This ensures we only block when cleaning the CURRENT loom (parent), not a child\n await this.checkForChildLooms(parsed)\n\n // Step 4: Handle deferred execution (after all validation passes)\n if (input.options.defer) {\n getLogger().info(`Waiting ${input.options.defer}ms before cleanup...`)\n await new Promise(resolve => globalThis.setTimeout(resolve, input.options.defer))\n }\n\n // Step 5: Execute based on mode\n getLogger().info(`Cleanup mode: ${parsed.mode}`)\n\n if (parsed.mode === 'single') {\n return await this.executeSingleCleanup(parsed)\n } else if (parsed.mode === 'list') {\n getLogger().info('Would list all worktrees') // TODO: Implement in Sub-issue #2\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'list',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'all') {\n getLogger().info('Would remove all worktrees') // TODO: Implement in Sub-issue #5\n getLogger().success('Command parsing and validation successful')\n return {\n identifier: 'all',\n success: true,\n dryRun: parsed.options.dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n } else if (parsed.mode === 'issue') {\n return await this.executeIssueCleanup(parsed)\n }\n }\n\n /**\n * Parse input to determine cleanup mode and extract relevant data\n * Implements auto-detection: numeric input = issue number, non-numeric = branch name\n *\n * @private\n */\n private parseInput(input: CleanupCommandInput): ParsedCleanupInput {\n const { identifier, options } = input\n\n // Trim identifier if present\n const trimmedIdentifier = identifier?.trim() ?? undefined\n\n // Mode: List (takes priority - it's informational only)\n if (options.list) {\n const result: ParsedCleanupInput = {\n mode: 'list',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: All (remove everything)\n if (options.all) {\n const result: ParsedCleanupInput = {\n mode: 'all',\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n if (options.issue !== undefined) {\n result.issueNumber = options.issue\n }\n return result\n }\n\n // Mode: Explicit issue number via --issue flag\n if (options.issue !== undefined) {\n // Need to determine if identifier is branch or numeric to set branchName\n if (trimmedIdentifier) {\n const numericPattern = /^[0-9]+$/\n if (!numericPattern.test(trimmedIdentifier)) {\n // Identifier is a branch name with explicit --issue flag\n return {\n mode: 'issue',\n issueNumber: options.issue,\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n const result: ParsedCleanupInput = {\n mode: 'issue',\n issueNumber: options.issue,\n options\n }\n if (trimmedIdentifier) {\n result.identifier = trimmedIdentifier\n }\n return result\n }\n\n // Mode: Auto-detect from identifier\n if (!trimmedIdentifier) {\n throw new Error('Missing required argument: identifier. Use --all to remove all worktrees or --list to list them.')\n }\n\n // Auto-detection: Check if identifier is purely numeric\n // Pattern from bash script line 364: ^[0-9]+$\n const numericPattern = /^[0-9]+$/\n if (numericPattern.test(trimmedIdentifier)) {\n // Numeric input = issue number\n return {\n mode: 'issue',\n issueNumber: parseInt(trimmedIdentifier, 10),\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n } else {\n // Non-numeric = branch name\n return {\n mode: 'single',\n branchName: trimmedIdentifier,\n identifier: trimmedIdentifier,\n originalInput: trimmedIdentifier,\n options\n }\n }\n }\n\n /**\n * Validate parsed input for option conflicts\n * Throws descriptive errors for invalid option combinations\n *\n * @private\n */\n private validateInput(parsed: ParsedCleanupInput): void {\n const { mode, options, branchName } = parsed\n\n // Conflict: --list is informational only, incompatible with destructive operations\n if (mode === 'list') {\n if (options.all) {\n throw new Error('Cannot use --list with --all (list is informational only)')\n }\n if (options.issue !== undefined) {\n throw new Error('Cannot use --list with --issue (list is informational only)')\n }\n if (parsed.identifier) {\n throw new Error('Cannot use --list with a specific identifier (list shows all worktrees)')\n }\n }\n\n // Conflict: --all removes everything, can't combine with specific identifier or --issue\n if (mode === 'all') {\n if (parsed.identifier) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n if (parsed.issueNumber !== undefined) {\n throw new Error('Cannot use --all with a specific identifier. Use one or the other.')\n }\n }\n\n // Conflict: explicit --issue flag with branch name identifier\n // (This prevents confusion when user provides both)\n if (options.issue !== undefined && branchName) {\n throw new Error('Cannot use --issue flag with branch name identifier. Use numeric identifier or --issue flag alone.')\n }\n\n // Note: --force and --dry-run are compatible with all modes (no conflicts)\n }\n\n /**\n * Execute cleanup for single worktree\n * Implements two-stage confirmation: worktree removal, then branch deletion\n * Uses IdentifierParser for pattern-based detection without GitHub API calls\n */\n private async executeSingleCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const identifier = parsed.branchName ?? parsed.identifier ?? ''\n if (!identifier) {\n throw new Error('No identifier found for cleanup')\n }\n const { force, dryRun } = parsed.options\n\n // Step 1: Parse identifier using pattern-based detection\n let parsedInput: ParsedInput = await this.identifierParser.parseForPatternDetection(identifier)\n\n // If type is 'branch', try to extract issue number for CLI symlink cleanup\n if (parsedInput.type === 'branch' && parsedInput.branchName) {\n const { extractIssueNumber } = await import('../utils/git.js')\n const extractedNumber = extractIssueNumber(parsedInput.branchName)\n if (extractedNumber !== null) {\n parsedInput = {\n ...parsedInput,\n number: extractedNumber // Add number for CLI symlink cleanup\n }\n }\n }\n\n // Step 2: Display worktree details\n getLogger().info(`Preparing to cleanup worktree: ${identifier}`)\n\n // Step 3: Routine confirmation - worktree removal\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmWorktree = await promptConfirmation('Remove this worktree?', true)\n if (!confirmWorktree) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier,\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 3.5: Read metadata BEFORE cleanup (cleanup deletes the worktree)\n let preCleanupMetadata: LoomMetadata | null = null\n try {\n // Find worktree path for metadata lookup\n const worktree = parsedInput.type === 'branch' && parsedInput.branchName\n ? await this.gitWorktreeManager.findWorktreeForBranch(parsedInput.branchName)\n : parsedInput.number !== undefined\n ? await this.gitWorktreeManager.findWorktreeForIssue(parsedInput.number)\n : null\n if (worktree) {\n const metadataManager = new MetadataManager()\n preCleanupMetadata = await metadataManager.readMetadata(worktree.path)\n }\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n\n // Step 4: Execute worktree cleanup (includes safety validation)\n // Issue #275 fix: Run 5-point safety check BEFORE any deletion\n // This prevents the scenario where worktree is deleted but branch deletion fails\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n const cleanupResult = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Always include branch deletion (safety checks run first)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n })\n\n // Add dryRun flag to result\n cleanupResult.dryRun = dryRun ?? false\n\n // Step 5: Report cleanup results\n this.reportCleanupResults(cleanupResult)\n\n // Track loom.abandoned telemetry event (only for unfinished looms)\n if (cleanupResult.success && preCleanupMetadata && preCleanupMetadata.status !== 'finished') {\n trackLoomAbandoned(preCleanupMetadata)\n }\n\n // Final success message\n if (cleanupResult.success) {\n getLogger().success('Cleanup completed successfully')\n } else {\n getLogger().warn('Cleanup completed with errors - see details above')\n }\n\n return cleanupResult\n }\n\n /**\n * Report cleanup operation results to user\n */\n private reportCleanupResults(result: CleanupResult): void {\n getLogger().info('Cleanup operations:')\n\n result.operations.forEach(op => {\n const status = op.success ? '✓' : '✗'\n const message = op.error ? `${op.message}: ${op.error}` : op.message\n\n if (op.success) {\n getLogger().info(` ${status} ${message}`)\n } else {\n getLogger().error(` ${status} ${message}`)\n }\n })\n\n if (result.errors.length > 0) {\n getLogger().warn(`${result.errors.length} error(s) occurred during cleanup`)\n }\n }\n\n /**\n * Execute cleanup for all worktrees associated with an issue or PR number\n * Searches for worktrees by their path patterns (e.g., issue-25, pr-25, 25-feature, _pr_25)\n * Implements bash cleanup-worktree.sh remove_worktrees_by_issue() (lines 157-242)\n */\n private async executeIssueCleanup(parsed: ParsedCleanupInput): Promise<CleanupResult> {\n const issueNumber = parsed.issueNumber\n if (issueNumber === undefined) {\n throw new Error('No issue/PR number provided for cleanup')\n }\n\n const { force, dryRun } = parsed.options\n\n getLogger().info(`Finding worktrees related to issue/PR #${issueNumber}...`)\n\n // Step 1: Get all worktrees and filter by path pattern\n const worktrees = await this.gitWorktreeManager.listWorktrees()\n const matchingWorktrees = worktrees.filter(wt => {\n const path = wt.path.toLowerCase()\n // Lowercase for case-insensitive matching (Linear IDs are uppercase like MARK-1)\n const idStr = String(issueNumber).toLowerCase()\n\n // Check if path contains the identifier with proper word boundaries\n // Matches: issue-25, pr-25, 25-feature, _pr_25, issue-mark-1, etc.\n // Uses word boundary or common separators (-, _, /) for alphanumeric IDs\n const pattern = new RegExp(`(?:^|[/_-])${idStr}(?:[/_-]|$)`)\n return pattern.test(path)\n })\n\n if (matchingWorktrees.length === 0) {\n getLogger().warn(`No worktrees found for issue/PR #${issueNumber}`)\n getLogger().info(`Searched for worktree paths containing: ${issueNumber}, _pr_${issueNumber}, issue-${issueNumber}, etc.`)\n return {\n identifier: String(issueNumber),\n success: true,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n\n // Step 2: Build targets list from matching worktrees\n const targets: Array<{ branchName: string; hasWorktree: boolean; worktreePath?: string }> =\n matchingWorktrees.map(wt => ({\n branchName: wt.branch,\n hasWorktree: true,\n worktreePath: wt.path\n }))\n\n // Step 3: Display preview\n getLogger().info(`Found ${targets.length} worktree(s) related to issue/PR #${issueNumber}:`)\n for (const target of targets) {\n getLogger().info(` Branch: ${target.branchName} (${target.worktreePath})`)\n }\n\n // Step 4: Routine batch confirmation\n // Skip if --force (user explicitly bypasses) or --json (programmatic use can't interact)\n // Note: Safety checks per-worktree (uncommitted changes, unmerged work) still require --force to bypass\n if (!force && !parsed.options.json) {\n const confirmCleanup = await promptConfirmation(\n `Remove ${targets.length} worktree(s)?`,\n true\n )\n if (!confirmCleanup) {\n getLogger().info('Cleanup cancelled')\n return {\n identifier: String(issueNumber),\n success: false,\n dryRun: dryRun ?? false,\n operations: [],\n errors: [],\n rollbackRequired: false,\n }\n }\n }\n\n // Step 5: Process each target sequentially\n let worktreesRemoved = 0\n let branchesDeleted = 0\n const databaseBranchesDeletedList: string[] = []\n let failed = 0\n\n for (const target of targets) {\n getLogger().info(`Processing worktree: ${target.branchName}`)\n\n // Cleanup worktree using ResourceCleanup with ParsedInput\n // Now includes branch deletion with 5-point safety check BEFORE any deletion\n try {\n // Read metadata BEFORE cleanup for telemetry\n let targetMetadata: LoomMetadata | null = null\n if (target.worktreePath) {\n try {\n const metadataManager = new MetadataManager()\n targetMetadata = await metadataManager.readMetadata(target.worktreePath)\n } catch (error: unknown) {\n getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n\n // Use the known issue number directly instead of parsing from branch name\n // This ensures CLI symlinks (created with issue number) are properly cleaned up\n const parsedInput: ParsedInput = {\n type: 'issue',\n number: issueNumber, // Use the known issue number, not parsed from branch\n branchName: target.branchName,\n originalInput: String(issueNumber)\n }\n\n await this.ensureResourceCleanup()\n if (!this.resourceCleanup) {\n throw new Error('Failed to initialize ResourceCleanup')\n }\n // Issue #275 fix: Run safety checks BEFORE deleting worktree\n // This prevents the scenario where worktree is deleted but branch deletion fails\n const result = await this.resourceCleanup.cleanupWorktree(parsedInput, {\n dryRun: dryRun ?? false,\n force: force ?? false,\n deleteBranch: true, // Include branch deletion (with safety checks)\n keepDatabase: false,\n checkMergeSafety: true, // Run 5-point safety check BEFORE any deletion\n archive: parsed.options.archive ?? false,\n ...(target.worktreePath && { worktree: { path: target.worktreePath, branch: target.branchName } }),\n })\n\n if (result.success) {\n worktreesRemoved++\n getLogger().success(` Worktree removed: ${target.branchName}`)\n\n // Check if branch was deleted\n const branchOperation = result.operations.find(op => op.type === 'branch')\n if (branchOperation?.success) {\n branchesDeleted++\n getLogger().success(` Branch deleted: ${target.branchName}`)\n }\n\n // Check if database branch was actually deleted (use explicit deleted field)\n const dbOperation = result.operations.find(op => op.type === 'database')\n if (dbOperation?.deleted) {\n // Get branch name from result or use the target branch name\n const deletedBranchName = target.branchName\n databaseBranchesDeletedList.push(deletedBranchName)\n }\n\n // Track loom.abandoned telemetry (only for unfinished looms)\n if (targetMetadata && targetMetadata.status !== 'finished') {\n trackLoomAbandoned(targetMetadata)\n }\n } else {\n failed++\n getLogger().error(` Failed to remove worktree: ${target.branchName}`)\n for (const err of result.errors) {\n getLogger().error(` ${err.message}`)\n }\n }\n } catch (error) {\n failed++\n const errMsg = error instanceof Error ? error.message : 'Unknown error'\n getLogger().error(` Failed to cleanup: ${errMsg}`)\n continue // Continue with next worktree even if this one failed\n }\n }\n\n // Step 7: Report statistics\n getLogger().success(`Completed cleanup for issue/PR #${issueNumber}:`)\n getLogger().info(` Worktrees removed: ${worktreesRemoved}`)\n getLogger().info(` Branches deleted: ${branchesDeleted}`)\n if (databaseBranchesDeletedList.length > 0) {\n // Display branch names in the format requested\n getLogger().info(` Database branches deleted: ${databaseBranchesDeletedList.join(', ')}`)\n }\n if (failed > 0) {\n getLogger().warn(` Failed operations: ${failed}`)\n }\n\n // Return aggregated result\n return {\n identifier: String(issueNumber),\n success: failed === 0,\n dryRun: dryRun ?? false,\n operations: [\n { type: 'worktree' as const, success: true, message: `Removed ${worktreesRemoved} worktree(s)` },\n { type: 'branch' as const, success: true, message: `Deleted ${branchesDeleted} branch(es)` },\n ...(databaseBranchesDeletedList.length > 0 ? [{ type: 'database' as const, success: true, message: `Deleted ${databaseBranchesDeletedList.length} database branch(es)`, deleted: true }] : []),\n ],\n errors: [],\n rollbackRequired: false,\n }\n }\n}\n"],"mappings":"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","names":["numericPattern"]}