@iloom/cli 0.11.1 → 0.13.0-beta.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 (290) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +170 -15
  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-RRGREEZQ.js +14 -0
  7. package/dist/ClaudeService-LEPW6QAC.js +13 -0
  8. package/dist/GitHubService-UTAYZXL3.js +12 -0
  9. package/dist/IssueTrackerFactory-KE2BDCLC.js +15 -0
  10. package/dist/{LoomLauncher-5AZU2F5I.js → LoomLauncher-GKQMR5E6.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 +170 -15
  15. package/dist/{SettingsManager-WQ5NSGAH.js → SettingsManager-KQU7OX7G.js} +15 -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-V3KADFMO.js +27 -0
  28. package/dist/{chunk-XXFSOVL3.js → chunk-3XEXT35Z.js} +4 -4
  29. package/dist/{chunk-YRCEOQPX.js → chunk-4JZEQBWV.js} +4 -3
  30. package/dist/chunk-4JZEQBWV.js.map +1 -0
  31. package/dist/{chunk-LE2NOUTN.js → chunk-4VQXMEEP.js} +3 -3
  32. package/dist/{chunk-G2MNSPA4.js → chunk-772N5WCA.js} +2 -2
  33. package/dist/{chunk-WG4MLJ6J.js → chunk-7RCUWU3I.js} +2 -2
  34. package/dist/chunk-7RCUWU3I.js.map +1 -0
  35. package/dist/{chunk-NOMQ5RFG.js → chunk-7UBEHQTP.js} +2 -2
  36. package/dist/{chunk-7NFCGKZT.js → chunk-AQUSMNBF.js} +3 -3
  37. package/dist/{chunk-IDCE26KD.js → chunk-AUYSAMXV.js} +3 -3
  38. package/dist/chunk-AYLC633W.js +406 -0
  39. package/dist/chunk-AYLC633W.js.map +1 -0
  40. package/dist/{chunk-QVAA5KHK.js → chunk-BZ7KTXPB.js} +16 -8
  41. package/dist/chunk-BZ7KTXPB.js.map +1 -0
  42. package/dist/{chunk-K7R5QY6C.js → chunk-CE676WCN.js} +2 -2
  43. package/dist/{chunk-5UFGO4ZT.js → chunk-CQHHEW2M.js} +6 -3
  44. package/dist/chunk-CQHHEW2M.js.map +1 -0
  45. package/dist/{chunk-LHDD4JHC.js → chunk-D4Q7T5KD.js} +4 -4
  46. package/dist/{chunk-RBYTXYGD.js → chunk-D75KSI3V.js} +2 -2
  47. package/dist/{chunk-Y3RX7LZT.js → chunk-DDHWZNGL.js} +18 -12
  48. package/dist/chunk-DDHWZNGL.js.map +1 -0
  49. package/dist/{chunk-5LTID2AF.js → chunk-DMSL5BAP.js} +35 -6
  50. package/dist/{chunk-5LTID2AF.js.map → chunk-DMSL5BAP.js.map} +1 -1
  51. package/dist/{chunk-SQYHPBFP.js → chunk-EGNUOALL.js} +2 -2
  52. package/dist/{chunk-ZAXRQLK3.js → chunk-FTYWGQFM.js} +2 -2
  53. package/dist/{chunk-5PNZBH6V.js → chunk-H3T3EPF3.js} +2 -2
  54. package/dist/{chunk-VNYWBHKR.js → chunk-JD3K2344.js} +3 -3
  55. package/dist/{chunk-6YVJVUR4.js → chunk-JDN4SPV3.js} +3 -3
  56. package/dist/{chunk-NCPZYQ4B.js → chunk-K3QGG4O2.js} +2 -2
  57. package/dist/{chunk-ABVMUNCD.js → chunk-KQSV7FOG.js} +64 -10
  58. package/dist/chunk-KQSV7FOG.js.map +1 -0
  59. package/dist/{chunk-NH3QZYE5.js → chunk-KV4NU3RP.js} +2 -2
  60. package/dist/{chunk-NDSGJZI2.js → chunk-LOAYWTJJ.js} +2 -2
  61. package/dist/{chunk-GMDSYLI6.js → chunk-MY2Q3FJ3.js} +2 -2
  62. package/dist/{chunk-CV47VCMQ.js → chunk-NPVA65KS.js} +2 -2
  63. package/dist/{chunk-RMLADZRY.js → chunk-NTDY5AMO.js} +5 -5
  64. package/dist/{chunk-UHIBKD73.js → chunk-NUUFP53X.js} +13 -32
  65. package/dist/{chunk-UHIBKD73.js.map → chunk-NUUFP53X.js.map} +1 -1
  66. package/dist/{chunk-7OCGBJLR.js → chunk-OIVFHJOA.js} +2 -2
  67. package/dist/chunk-P5MXXHXQ.js +284 -0
  68. package/dist/chunk-P5MXXHXQ.js.map +1 -0
  69. package/dist/{chunk-TEJAGQX2.js → chunk-PD75ZCFT.js} +35 -35
  70. package/dist/chunk-PD75ZCFT.js.map +1 -0
  71. package/dist/{chunk-NN5RYWXA.js → chunk-PH65MFQM.js} +6 -6
  72. package/dist/{chunk-LL6TOX3G.js → chunk-Q7VXHJP6.js} +10 -10
  73. package/dist/chunk-Q7VXHJP6.js.map +1 -0
  74. package/dist/chunk-QC65IOV3.js +304 -0
  75. package/dist/chunk-QC65IOV3.js.map +1 -0
  76. package/dist/{chunk-V4STTBQD.js → chunk-QED2WB2D.js} +9 -9
  77. package/dist/{chunk-3RXYOBME.js → chunk-QNPJXO53.js} +5 -5
  78. package/dist/{chunk-3RXYOBME.js.map → chunk-QNPJXO53.js.map} +1 -1
  79. package/dist/chunk-QQULYI2S.js +696 -0
  80. package/dist/chunk-QQULYI2S.js.map +1 -0
  81. package/dist/{chunk-QNHZM5ZV.js → chunk-QXGM32TO.js} +3 -3
  82. package/dist/{chunk-TZNNJLGT.js → chunk-RFCAPHL5.js} +6 -6
  83. package/dist/{chunk-7FIXNAUO.js → chunk-SA446KA2.js} +66 -43
  84. package/dist/chunk-SA446KA2.js.map +1 -0
  85. package/dist/{chunk-UDCI3QTS.js → chunk-SN4S5CWL.js} +2 -2
  86. package/dist/{chunk-VUUN3KE4.js → chunk-TAEVA4QR.js} +8 -8
  87. package/dist/chunk-TAEVA4QR.js.map +1 -0
  88. package/dist/{chunk-IR74O2F6.js → chunk-TN2D2RX7.js} +253 -174
  89. package/dist/chunk-TN2D2RX7.js.map +1 -0
  90. package/dist/{chunk-3GTUXW26.js → chunk-VIQOQ463.js} +19 -3
  91. package/dist/chunk-VIQOQ463.js.map +1 -0
  92. package/dist/{chunk-H2SSF24U.js → chunk-VRPPI6GU.js} +17 -6
  93. package/dist/{chunk-H2SSF24U.js.map → chunk-VRPPI6GU.js.map} +1 -1
  94. package/dist/{chunk-XFQGI2E3.js → chunk-VVQQIG64.js} +58 -53
  95. package/dist/chunk-VVQQIG64.js.map +1 -0
  96. package/dist/{chunk-YETJNRQM.js → chunk-WEBMMJKL.js} +2 -1
  97. package/dist/{chunk-ET6A2JR4.js → chunk-WGUGB54H.js} +120 -18
  98. package/dist/chunk-WGUGB54H.js.map +1 -0
  99. package/dist/{chunk-QR4FU53I.js → chunk-X5DRLONY.js} +22 -12
  100. package/dist/chunk-X5DRLONY.js.map +1 -0
  101. package/dist/{chunk-KQFIGI37.js → chunk-XCP2WDYA.js} +7 -7
  102. package/dist/{chunk-VMZG66UV.js → chunk-YUOVWWJX.js} +312 -7
  103. package/dist/chunk-YUOVWWJX.js.map +1 -0
  104. package/dist/{chunk-HLDY5S4C.js → chunk-ZUIFO7B4.js} +3 -3
  105. package/dist/{claude-ONQTDWV3.js → claude-ACL7G4CF.js} +4 -4
  106. package/dist/{cleanup-YOM6PQCN.js → cleanup-RJKLI47I.js} +40 -37
  107. package/dist/cleanup-RJKLI47I.js.map +1 -0
  108. package/dist/cli.js +322 -169
  109. package/dist/cli.js.map +1 -1
  110. package/dist/{color-VQD52LOI.js → color-AC6F2QE7.js} +3 -3
  111. package/dist/{commit-DC2Q5CDY.js → commit-SUHRUMDE.js} +15 -15
  112. package/dist/{compile-4NCQECKE.js → compile-2MD346PO.js} +11 -11
  113. package/dist/{contribute-M5UWXCAV.js → contribute-P4BMRY7C.js} +11 -11
  114. package/dist/{contribute-M5UWXCAV.js.map → contribute-P4BMRY7C.js.map} +1 -1
  115. package/dist/{mcp/darwin-3JFFE3W2.js → darwin-5K3I4FTH.js} +2 -2
  116. package/dist/database-helpers-PRDFNDRO.js +11 -0
  117. package/dist/{dev-server-CYRP6M73.js → dev-server-ZNTLWOL5.js} +35 -21
  118. package/dist/dev-server-ZNTLWOL5.js.map +1 -0
  119. package/dist/{feedback-BMAZGKRW.js → feedback-Q6WG2WX4.js} +17 -17
  120. package/dist/{git-BXUD6CL5.js → git-TX2IEMB3.js} +6 -6
  121. package/dist/ignite-P644W2PK.js +35 -0
  122. package/dist/index.d.ts +236 -18
  123. package/dist/index.js +180 -63
  124. package/dist/index.js.map +1 -1
  125. package/dist/{init-CI43GJHV.js → init-5HFY7JG6.js} +18 -18
  126. package/dist/{install-deps-SRTM5U7D.js → install-deps-J4ALTM27.js} +11 -11
  127. package/dist/{installation-detector-HF6QN7KP.js → installation-detector-PYAZ2O6U.js} +3 -3
  128. package/dist/{issues-DMRQJH7E.js → issues-LZMIF22U.js} +69 -56
  129. package/dist/issues-LZMIF22U.js.map +1 -0
  130. package/dist/lint-XIXKU22H.js +27 -0
  131. package/dist/{linux-RYLOP2LY.js → linux-WUGRYCJY.js} +2 -2
  132. package/dist/mcp/{chunk-PIIRD4LO.js → chunk-4HZMW2V3.js} +1 -1
  133. package/dist/mcp/{chunk-PIIRD4LO.js.map → chunk-4HZMW2V3.js.map} +1 -1
  134. package/dist/{darwin-5BHWRJ7D.js → mcp/darwin-U25WIGH6.js} +2 -2
  135. package/dist/mcp/issue-management-server.js +908 -20
  136. package/dist/mcp/issue-management-server.js.map +1 -1
  137. package/dist/mcp/{linux-JBVS4R3A.js → linux-5BXVBGSY.js} +2 -2
  138. package/dist/mcp/recap-server.js +24 -22
  139. package/dist/mcp/recap-server.js.map +1 -1
  140. package/dist/mcp/{tmux-RYBLEHUZ.js → tmux-CU26ZTNM.js} +2 -2
  141. package/dist/mcp/{wsl-4QZIQLLE.js → wsl-KI25UDOF.js} +2 -2
  142. package/dist/{open-2Y7GSUTJ.js → open-KUO35JIJ.js} +36 -21
  143. package/dist/open-KUO35JIJ.js.map +1 -0
  144. package/dist/{plan-SWFPLNJE.js → plan-7CF56OIR.js} +47 -43
  145. package/dist/{plan-SWFPLNJE.js.map → plan-7CF56OIR.js.map} +1 -1
  146. package/dist/{projects-IUSUXD5D.js → projects-L5AHUBGA.js} +6 -6
  147. package/dist/{prompt-7LZB4PAT.js → prompt-FUU5NMJQ.js} +3 -3
  148. package/dist/prompt-FUU5NMJQ.js.map +1 -0
  149. package/dist/prompts/init-prompt.txt +184 -23
  150. package/dist/prompts/issue-prompt.txt +94 -158
  151. package/dist/prompts/plan-prompt.txt +55 -0
  152. package/dist/prompts/regular-prompt.txt +1 -1
  153. package/dist/prompts/swarm-orchestrator-prompt.txt +78 -21
  154. package/dist/{rebase-S6OHAOOF.js → rebase-MAMWPA2L.js} +12 -12
  155. package/dist/{recap-GGVCG5VH.js → recap-IDBO3KM5.js} +9 -9
  156. package/dist/{remote-MZTFHHTU.js → remote-RO4LZKT2.js} +3 -3
  157. package/dist/remote-RO4LZKT2.js.map +1 -0
  158. package/dist/{run-ST3FR75O.js → run-RGZHCQ6M.js} +36 -21
  159. package/dist/run-RGZHCQ6M.js.map +1 -0
  160. package/dist/schema/settings.schema.json +171 -11
  161. package/dist/{shell-W4SBQPTE.js → shell-7ADCDFIV.js} +8 -8
  162. package/dist/{summary-P2JCIIJO.js → summary-7J2HORFD.js} +21 -19
  163. package/dist/summary-7J2HORFD.js.map +1 -0
  164. package/dist/test-SRB7EWU6.js +27 -0
  165. package/dist/{test-git-2KFFAQ6B.js → test-git-G7ATVIXG.js} +6 -6
  166. package/dist/{test-jira-FKDKG6CD.js → test-jira-Q2HPA522.js} +8 -8
  167. package/dist/{test-prefix-GP2DAX37.js → test-prefix-JMDGXR5A.js} +6 -6
  168. package/dist/{test-tabs-YDWMWTVA.js → test-tabs-NGPTFD5T.js} +2 -2
  169. package/dist/{test-webserver-QI3QQFZ3.js → test-webserver-GZFVXBGD.js} +8 -8
  170. package/dist/{tmux-7ZTA3BDI.js → tmux-6LRFH3DM.js} +2 -2
  171. package/dist/{update-XLW7R7FL.js → update-AD3GE5C4.js} +4 -4
  172. package/dist/{update-notifier-EYLAXZAA.js → update-notifier-VYDTDMSJ.js} +3 -3
  173. package/dist/update-notifier-VYDTDMSJ.js.map +1 -0
  174. package/dist/{vscode-TOGE5N67.js → vscode-3I7ISHUU.js} +12 -12
  175. package/dist/{vscode-announcement-NIX7O2MG.js → vscode-announcement-AL3EHORH.js} +3 -3
  176. package/dist/{wsl-Y4GUTOQ7.js → wsl-4VMVT2PO.js} +2 -2
  177. package/package.json +1 -1
  178. package/dist/ClaudeContextManager-SXDCWDJA.js +0 -14
  179. package/dist/ClaudeService-6E6MCGJE.js +0 -13
  180. package/dist/GitHubService-2R5GQG4K.js +0 -12
  181. package/dist/IssueTrackerFactory-XN6MQ4UN.js +0 -14
  182. package/dist/MetadataManager-CMQQTFLQ.js +0 -10
  183. package/dist/ProjectCapabilityDetector-IC6NAFGY.js +0 -11
  184. package/dist/SettingsMigrationManager-S6J7OHUH.js +0 -10
  185. package/dist/build-OLS6J5KZ.js +0 -27
  186. package/dist/chunk-3GTUXW26.js.map +0 -1
  187. package/dist/chunk-5UFGO4ZT.js.map +0 -1
  188. package/dist/chunk-7FIXNAUO.js.map +0 -1
  189. package/dist/chunk-ABVMUNCD.js.map +0 -1
  190. package/dist/chunk-ET6A2JR4.js.map +0 -1
  191. package/dist/chunk-IR74O2F6.js.map +0 -1
  192. package/dist/chunk-LL6TOX3G.js.map +0 -1
  193. package/dist/chunk-QR4FU53I.js.map +0 -1
  194. package/dist/chunk-QVAA5KHK.js.map +0 -1
  195. package/dist/chunk-RVI6C2H5.js +0 -220
  196. package/dist/chunk-RVI6C2H5.js.map +0 -1
  197. package/dist/chunk-TEJAGQX2.js.map +0 -1
  198. package/dist/chunk-VMZG66UV.js.map +0 -1
  199. package/dist/chunk-VUUN3KE4.js.map +0 -1
  200. package/dist/chunk-WG4MLJ6J.js.map +0 -1
  201. package/dist/chunk-XFQGI2E3.js.map +0 -1
  202. package/dist/chunk-Y3RX7LZT.js.map +0 -1
  203. package/dist/chunk-YRCEOQPX.js.map +0 -1
  204. package/dist/cleanup-YOM6PQCN.js.map +0 -1
  205. package/dist/dev-server-CYRP6M73.js.map +0 -1
  206. package/dist/ignite-IO4LXVXJ.js +0 -35
  207. package/dist/issues-DMRQJH7E.js.map +0 -1
  208. package/dist/lint-BSWRMGPZ.js +0 -27
  209. package/dist/neon-helpers-HWIYRKOW.js +0 -11
  210. package/dist/open-2Y7GSUTJ.js.map +0 -1
  211. package/dist/run-ST3FR75O.js.map +0 -1
  212. package/dist/summary-P2JCIIJO.js.map +0 -1
  213. package/dist/test-6JH4FE2X.js +0 -27
  214. /package/dist/{BranchNamingService-XBCO747L.js.map → BitBucketApiClient-J2ZSCS5N.js.map} +0 -0
  215. /package/dist/{ClaudeContextManager-SXDCWDJA.js.map → BitBucketVCSProvider-5X64IXXW.js.map} +0 -0
  216. /package/dist/{ClaudeService-6E6MCGJE.js.map → BranchNamingService-MEK2WZUD.js.map} +0 -0
  217. /package/dist/{GitHubService-2R5GQG4K.js.map → ClaudeContextManager-RRGREEZQ.js.map} +0 -0
  218. /package/dist/{IssueTrackerFactory-XN6MQ4UN.js.map → ClaudeService-LEPW6QAC.js.map} +0 -0
  219. /package/dist/{MetadataManager-CMQQTFLQ.js.map → GitHubService-UTAYZXL3.js.map} +0 -0
  220. /package/dist/{ProjectCapabilityDetector-IC6NAFGY.js.map → IssueTrackerFactory-KE2BDCLC.js.map} +0 -0
  221. /package/dist/{LoomLauncher-5AZU2F5I.js.map → LoomLauncher-GKQMR5E6.js.map} +0 -0
  222. /package/dist/{PromptTemplateManager-T5VTLJP3.js.map → MetadataManager-V4LSJ2PB.js.map} +0 -0
  223. /package/dist/{SettingsManager-WQ5NSGAH.js.map → ProjectCapabilityDetector-I4J66WKF.js.map} +0 -0
  224. /package/dist/{SettingsMigrationManager-S6J7OHUH.js.map → PromptTemplateManager-I75WKXM4.js.map} +0 -0
  225. /package/dist/{claude-ONQTDWV3.js.map → SettingsManager-KQU7OX7G.js.map} +0 -0
  226. /package/dist/{color-VQD52LOI.js.map → SettingsMigrationManager-ZPARZ5KH.js.map} +0 -0
  227. /package/dist/{darwin-5BHWRJ7D.js.map → browser-VZY7F2DF.js.map} +0 -0
  228. /package/dist/{build-OLS6J5KZ.js.map → build-V3KADFMO.js.map} +0 -0
  229. /package/dist/{chunk-XXFSOVL3.js.map → chunk-3XEXT35Z.js.map} +0 -0
  230. /package/dist/{chunk-LE2NOUTN.js.map → chunk-4VQXMEEP.js.map} +0 -0
  231. /package/dist/{chunk-G2MNSPA4.js.map → chunk-772N5WCA.js.map} +0 -0
  232. /package/dist/{chunk-NOMQ5RFG.js.map → chunk-7UBEHQTP.js.map} +0 -0
  233. /package/dist/{chunk-7NFCGKZT.js.map → chunk-AQUSMNBF.js.map} +0 -0
  234. /package/dist/{chunk-IDCE26KD.js.map → chunk-AUYSAMXV.js.map} +0 -0
  235. /package/dist/{chunk-K7R5QY6C.js.map → chunk-CE676WCN.js.map} +0 -0
  236. /package/dist/{chunk-LHDD4JHC.js.map → chunk-D4Q7T5KD.js.map} +0 -0
  237. /package/dist/{chunk-RBYTXYGD.js.map → chunk-D75KSI3V.js.map} +0 -0
  238. /package/dist/{chunk-SQYHPBFP.js.map → chunk-EGNUOALL.js.map} +0 -0
  239. /package/dist/{chunk-ZAXRQLK3.js.map → chunk-FTYWGQFM.js.map} +0 -0
  240. /package/dist/{chunk-5PNZBH6V.js.map → chunk-H3T3EPF3.js.map} +0 -0
  241. /package/dist/{chunk-VNYWBHKR.js.map → chunk-JD3K2344.js.map} +0 -0
  242. /package/dist/{chunk-6YVJVUR4.js.map → chunk-JDN4SPV3.js.map} +0 -0
  243. /package/dist/{chunk-NCPZYQ4B.js.map → chunk-K3QGG4O2.js.map} +0 -0
  244. /package/dist/{chunk-NH3QZYE5.js.map → chunk-KV4NU3RP.js.map} +0 -0
  245. /package/dist/{chunk-NDSGJZI2.js.map → chunk-LOAYWTJJ.js.map} +0 -0
  246. /package/dist/{chunk-GMDSYLI6.js.map → chunk-MY2Q3FJ3.js.map} +0 -0
  247. /package/dist/{chunk-CV47VCMQ.js.map → chunk-NPVA65KS.js.map} +0 -0
  248. /package/dist/{chunk-RMLADZRY.js.map → chunk-NTDY5AMO.js.map} +0 -0
  249. /package/dist/{chunk-7OCGBJLR.js.map → chunk-OIVFHJOA.js.map} +0 -0
  250. /package/dist/{chunk-NN5RYWXA.js.map → chunk-PH65MFQM.js.map} +0 -0
  251. /package/dist/{chunk-V4STTBQD.js.map → chunk-QED2WB2D.js.map} +0 -0
  252. /package/dist/{chunk-QNHZM5ZV.js.map → chunk-QXGM32TO.js.map} +0 -0
  253. /package/dist/{chunk-TZNNJLGT.js.map → chunk-RFCAPHL5.js.map} +0 -0
  254. /package/dist/{chunk-UDCI3QTS.js.map → chunk-SN4S5CWL.js.map} +0 -0
  255. /package/dist/{chunk-YETJNRQM.js.map → chunk-WEBMMJKL.js.map} +0 -0
  256. /package/dist/{chunk-KQFIGI37.js.map → chunk-XCP2WDYA.js.map} +0 -0
  257. /package/dist/{chunk-HLDY5S4C.js.map → chunk-ZUIFO7B4.js.map} +0 -0
  258. /package/dist/{git-BXUD6CL5.js.map → claude-ACL7G4CF.js.map} +0 -0
  259. /package/dist/{ignite-IO4LXVXJ.js.map → color-AC6F2QE7.js.map} +0 -0
  260. /package/dist/{commit-DC2Q5CDY.js.map → commit-SUHRUMDE.js.map} +0 -0
  261. /package/dist/{compile-4NCQECKE.js.map → compile-2MD346PO.js.map} +0 -0
  262. /package/dist/{installation-detector-HF6QN7KP.js.map → darwin-5K3I4FTH.js.map} +0 -0
  263. /package/dist/{mcp/darwin-3JFFE3W2.js.map → database-helpers-PRDFNDRO.js.map} +0 -0
  264. /package/dist/{feedback-BMAZGKRW.js.map → feedback-Q6WG2WX4.js.map} +0 -0
  265. /package/dist/{neon-helpers-HWIYRKOW.js.map → git-TX2IEMB3.js.map} +0 -0
  266. /package/dist/{prompt-7LZB4PAT.js.map → ignite-P644W2PK.js.map} +0 -0
  267. /package/dist/{init-CI43GJHV.js.map → init-5HFY7JG6.js.map} +0 -0
  268. /package/dist/{install-deps-SRTM5U7D.js.map → install-deps-J4ALTM27.js.map} +0 -0
  269. /package/dist/{remote-MZTFHHTU.js.map → installation-detector-PYAZ2O6U.js.map} +0 -0
  270. /package/dist/{lint-BSWRMGPZ.js.map → lint-XIXKU22H.js.map} +0 -0
  271. /package/dist/{linux-RYLOP2LY.js.map → linux-WUGRYCJY.js.map} +0 -0
  272. /package/dist/{update-notifier-EYLAXZAA.js.map → mcp/darwin-U25WIGH6.js.map} +0 -0
  273. /package/dist/mcp/{linux-JBVS4R3A.js.map → linux-5BXVBGSY.js.map} +0 -0
  274. /package/dist/mcp/{tmux-RYBLEHUZ.js.map → tmux-CU26ZTNM.js.map} +0 -0
  275. /package/dist/mcp/{wsl-4QZIQLLE.js.map → wsl-KI25UDOF.js.map} +0 -0
  276. /package/dist/{projects-IUSUXD5D.js.map → projects-L5AHUBGA.js.map} +0 -0
  277. /package/dist/{rebase-S6OHAOOF.js.map → rebase-MAMWPA2L.js.map} +0 -0
  278. /package/dist/{recap-GGVCG5VH.js.map → recap-IDBO3KM5.js.map} +0 -0
  279. /package/dist/{shell-W4SBQPTE.js.map → shell-7ADCDFIV.js.map} +0 -0
  280. /package/dist/{test-6JH4FE2X.js.map → test-SRB7EWU6.js.map} +0 -0
  281. /package/dist/{test-git-2KFFAQ6B.js.map → test-git-G7ATVIXG.js.map} +0 -0
  282. /package/dist/{test-jira-FKDKG6CD.js.map → test-jira-Q2HPA522.js.map} +0 -0
  283. /package/dist/{test-prefix-GP2DAX37.js.map → test-prefix-JMDGXR5A.js.map} +0 -0
  284. /package/dist/{test-tabs-YDWMWTVA.js.map → test-tabs-NGPTFD5T.js.map} +0 -0
  285. /package/dist/{test-webserver-QI3QQFZ3.js.map → test-webserver-GZFVXBGD.js.map} +0 -0
  286. /package/dist/{tmux-7ZTA3BDI.js.map → tmux-6LRFH3DM.js.map} +0 -0
  287. /package/dist/{update-XLW7R7FL.js.map → update-AD3GE5C4.js.map} +0 -0
  288. /package/dist/{vscode-TOGE5N67.js.map → vscode-3I7ISHUU.js.map} +0 -0
  289. /package/dist/{vscode-announcement-NIX7O2MG.js.map → vscode-announcement-AL3EHORH.js.map} +0 -0
  290. /package/dist/{wsl-Y4GUTOQ7.js.map → wsl-4VMVT2PO.js.map} +0 -0
@@ -0,0 +1,406 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ logger,
4
+ restoreTerminalState
5
+ } from "./chunk-VRPPI6GU.js";
6
+
7
+ // src/lib/DockerManager.ts
8
+ import { execa as execa2 } from "execa";
9
+
10
+ // src/utils/docker.ts
11
+ import { execa } from "execa";
12
+ import { readFile } from "fs/promises";
13
+ var MAX_CONTAINER_NAME_LENGTH = 63;
14
+ async function isDockerInstalled() {
15
+ try {
16
+ const result = await execa("docker", ["--version"], { reject: false });
17
+ return result.exitCode === 0;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ async function isDockerRunning() {
23
+ try {
24
+ const result = await execa("docker", ["info"], { reject: false });
25
+ return result.exitCode === 0;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ async function assertDockerAvailable() {
31
+ const installed = await isDockerInstalled();
32
+ if (!installed) {
33
+ throw new Error(
34
+ "Docker is not installed. Please install Docker to use this feature.\nInstall Docker: https://docs.docker.com/get-docker/"
35
+ );
36
+ }
37
+ const running = await isDockerRunning();
38
+ if (!running) {
39
+ throw new Error(
40
+ "Docker daemon is not running. Please start Docker and try again.\nOn macOS/Windows: Open the Docker Desktop application.\nOn Linux: Run `sudo systemctl start docker`"
41
+ );
42
+ }
43
+ }
44
+ async function parseDockerfileExpose(dockerfilePath) {
45
+ try {
46
+ const content = await readFile(dockerfilePath, "utf-8");
47
+ const lines = content.split("\n");
48
+ let lastPort = null;
49
+ for (const line of lines) {
50
+ const trimmed = line.trim();
51
+ if (trimmed.startsWith("#")) {
52
+ continue;
53
+ }
54
+ const match = /^EXPOSE\s+(\d+)/i.exec(trimmed);
55
+ if (match == null ? void 0 : match[1]) {
56
+ const port = parseInt(match[1], 10);
57
+ if (!isNaN(port) && port >= 1 && port <= 65535) {
58
+ lastPort = port;
59
+ }
60
+ }
61
+ }
62
+ return lastPort;
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+ async function inspectImagePorts(imageName) {
68
+ try {
69
+ const result = await execa("docker", [
70
+ "image",
71
+ "inspect",
72
+ imageName,
73
+ "--format",
74
+ "{{json .Config.ExposedPorts}}"
75
+ ], { reject: false });
76
+ if (result.exitCode !== 0 || !result.stdout.trim()) {
77
+ return null;
78
+ }
79
+ const output = result.stdout.trim();
80
+ if (output === "null" || output === "<nil>" || output === "{}") {
81
+ return null;
82
+ }
83
+ const parsed = JSON.parse(output);
84
+ if (typeof parsed !== "object" || parsed === null) {
85
+ return null;
86
+ }
87
+ const firstKey = Object.keys(parsed)[0];
88
+ if (!firstKey) {
89
+ return null;
90
+ }
91
+ const portMatch = /^(\d+)/.exec(firstKey);
92
+ if (portMatch == null ? void 0 : portMatch[1]) {
93
+ const port = parseInt(portMatch[1], 10);
94
+ if (!isNaN(port) && port >= 1 && port <= 65535) {
95
+ return port;
96
+ }
97
+ }
98
+ return null;
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+ function sanitizeContainerName(name) {
104
+ let sanitized = String(name);
105
+ sanitized = sanitized.replace(/[^a-zA-Z0-9_.-]/g, "-");
106
+ sanitized = sanitized.replace(/-{2,}/g, "-");
107
+ sanitized = sanitized.replace(/^[^a-zA-Z0-9]+/, "");
108
+ sanitized = sanitized.replace(/-+$/, "");
109
+ if (sanitized.length > MAX_CONTAINER_NAME_LENGTH) {
110
+ sanitized = sanitized.substring(0, MAX_CONTAINER_NAME_LENGTH);
111
+ sanitized = sanitized.replace(/-+$/, "");
112
+ }
113
+ if (sanitized.length === 0) {
114
+ sanitized = "iloom-container";
115
+ }
116
+ return sanitized;
117
+ }
118
+ function buildContainerName(identifier) {
119
+ return sanitizeContainerName(`iloom-dev-${identifier}`);
120
+ }
121
+ function buildImageName(identifier) {
122
+ return sanitizeContainerName(`iloom-dev-${identifier}`).toLowerCase();
123
+ }
124
+
125
+ // src/lib/DockerManager.ts
126
+ var DockerManager = class _DockerManager {
127
+ /**
128
+ * Check if Docker CLI is available and daemon is running.
129
+ * @returns true if Docker is ready, false otherwise
130
+ */
131
+ static async isAvailable() {
132
+ const installed = await isDockerInstalled();
133
+ if (!installed) return false;
134
+ return isDockerRunning();
135
+ }
136
+ /**
137
+ * Assert that Docker is available, throwing a clear error if not.
138
+ * Call this early in any workflow that requires Docker.
139
+ */
140
+ static async assertAvailable() {
141
+ return assertDockerAvailable();
142
+ }
143
+ /**
144
+ * Build a Docker image.
145
+ *
146
+ * @param cwd - Working directory (worktree path)
147
+ * @param imageName - Image tag name
148
+ * @param dockerFile - Path to Dockerfile (relative to cwd)
149
+ * @param buildArgs - Optional build arguments passed as --build-arg
150
+ */
151
+ static async buildImage(cwd, imageName, dockerFile, buildArgs) {
152
+ const args = ["build", "-t", imageName, "-f", dockerFile];
153
+ if (buildArgs) {
154
+ for (const [key, value] of Object.entries(buildArgs)) {
155
+ args.push("--build-arg", `${key}=${value}`);
156
+ }
157
+ }
158
+ args.push(".");
159
+ logger.info(`Building Docker image "${imageName}" from ${dockerFile}...`);
160
+ try {
161
+ await execa2("docker", args, {
162
+ cwd,
163
+ stdio: "inherit"
164
+ });
165
+ } catch (error) {
166
+ const message = error instanceof Error ? error.message : "Unknown error";
167
+ throw new Error(`Docker build failed for image "${imageName}": ${message}`);
168
+ }
169
+ logger.success(`Docker image "${imageName}" built successfully`);
170
+ }
171
+ /**
172
+ * Run a container in detached mode (background).
173
+ * If a container with the same name already exists, it is force-removed first.
174
+ *
175
+ * @param imageName - Image to run
176
+ * @param containerName - Container name (must be sanitized)
177
+ * @param hostPort - Port on the host to map
178
+ * @param containerPort - Port inside the container
179
+ * @param additionalArgs - Additional docker run flags (e.g., volume mounts)
180
+ * @returns Container ID
181
+ */
182
+ static async runDetached(imageName, containerName, hostPort, containerPort, additionalArgs) {
183
+ await _DockerManager.forceRemoveContainer(containerName);
184
+ const args = [
185
+ "run",
186
+ "-d",
187
+ "--name",
188
+ containerName,
189
+ "-p",
190
+ `${hostPort}:${containerPort}`
191
+ ];
192
+ if (additionalArgs) {
193
+ args.push(...additionalArgs);
194
+ }
195
+ args.push(imageName);
196
+ logger.info(`Starting Docker container "${containerName}" (${hostPort}:${containerPort})...`);
197
+ try {
198
+ const result = await execa2("docker", args);
199
+ const containerId = result.stdout.trim();
200
+ logger.success(`Docker container "${containerName}" started (ID: ${containerId.substring(0, 12)})`);
201
+ return containerId;
202
+ } catch (error) {
203
+ const message = error instanceof Error ? error.message : "Unknown error";
204
+ throw new Error(`Failed to start Docker container "${containerName}": ${message}`);
205
+ }
206
+ }
207
+ /**
208
+ * Run a container in foreground mode (attached, blocking).
209
+ * The container is automatically removed on exit (--rm flag).
210
+ * Stdout/stderr are streamed to the terminal.
211
+ *
212
+ * Signal forwarding: Captures SIGINT/SIGTERM on the host process and
213
+ * forwards them to the container via `docker kill --signal` for graceful
214
+ * shutdown of the framework running inside the container.
215
+ *
216
+ * @param imageName - Image to run
217
+ * @param containerName - Container name (must be sanitized)
218
+ * @param hostPort - Port on the host to map
219
+ * @param containerPort - Port inside the container
220
+ * @param additionalArgs - Additional docker run flags
221
+ * @param redirectToStderr - If true, redirect stdout/stderr to stderr
222
+ */
223
+ static async runForeground(imageName, containerName, hostPort, containerPort, additionalArgs, redirectToStderr) {
224
+ await _DockerManager.forceRemoveContainer(containerName);
225
+ const args = [
226
+ "run",
227
+ "--name",
228
+ containerName,
229
+ "--rm",
230
+ "-p",
231
+ `${hostPort}:${containerPort}`
232
+ ];
233
+ if (additionalArgs) {
234
+ args.push(...additionalArgs);
235
+ }
236
+ args.push(imageName);
237
+ logger.info(`Running Docker container "${containerName}" in foreground (${hostPort}:${containerPort})...`);
238
+ const stdio = redirectToStderr ? [process.stdin, process.stderr, process.stderr] : "inherit";
239
+ const forwardSignal = (signal) => {
240
+ logger.debug(`Forwarding ${signal} to container "${containerName}"`);
241
+ void execa2("docker", ["kill", `--signal=${signal}`, containerName], { reject: false });
242
+ };
243
+ const onSigint = () => forwardSignal("SIGINT");
244
+ const onSigterm = () => forwardSignal("SIGTERM");
245
+ process.on("SIGINT", onSigint);
246
+ process.on("SIGTERM", onSigterm);
247
+ try {
248
+ await execa2("docker", args, { stdio });
249
+ } finally {
250
+ process.removeListener("SIGINT", onSigint);
251
+ process.removeListener("SIGTERM", onSigterm);
252
+ restoreTerminalState();
253
+ }
254
+ }
255
+ /**
256
+ * Stop and remove a container by name using atomic force-remove.
257
+ * No-op if the container doesn't exist or is already removed.
258
+ * Uses `docker rm -f` which handles both running and stopped containers
259
+ * atomically, eliminating race conditions between stop and remove.
260
+ *
261
+ * @param containerName - Name of the container to remove
262
+ * @returns true if a container was removed, false if no container was found
263
+ */
264
+ static async stopAndRemoveContainer(containerName) {
265
+ const isRunning = await _DockerManager.isContainerRunning(containerName);
266
+ if (!isRunning) {
267
+ logger.debug(`No running container found with name "${containerName}"`);
268
+ await execa2("docker", ["rm", "-f", containerName], { reject: false });
269
+ return false;
270
+ }
271
+ logger.info(`Removing Docker container "${containerName}"...`);
272
+ await execa2("docker", ["rm", "-f", containerName], { reject: false });
273
+ logger.success(`Docker container "${containerName}" removed`);
274
+ return true;
275
+ }
276
+ /**
277
+ * Check if a named container is currently running.
278
+ *
279
+ * @param containerName - Name of the container to check
280
+ * @returns true if the container is running, false otherwise
281
+ */
282
+ static async isContainerRunning(containerName) {
283
+ try {
284
+ const result = await execa2("docker", [
285
+ "ps",
286
+ "--filter",
287
+ `name=^${containerName}$`,
288
+ "--format",
289
+ "{{.Names}}"
290
+ ], { reject: false });
291
+ return result.exitCode === 0 && result.stdout.trim() === containerName;
292
+ } catch {
293
+ return false;
294
+ }
295
+ }
296
+ /**
297
+ * Parse the EXPOSE directive from a Dockerfile.
298
+ * Returns the last exposed port number (handles multi-stage builds correctly),
299
+ * or null if none found.
300
+ *
301
+ * @param dockerfilePath - Absolute path to the Dockerfile
302
+ * @returns Last exposed port number, or null if no EXPOSE directive found
303
+ */
304
+ static async parseExposeFromDockerfile(dockerfilePath) {
305
+ return parseDockerfileExpose(dockerfilePath);
306
+ }
307
+ /**
308
+ * Sanitize a string for use as a Docker container name.
309
+ *
310
+ * @param name - Raw name to sanitize
311
+ * @returns Sanitized container name
312
+ */
313
+ static sanitizeContainerName(name) {
314
+ return sanitizeContainerName(name);
315
+ }
316
+ /**
317
+ * Build the standard container name for an iloom dev server.
318
+ *
319
+ * @param identifier - Issue number, branch name, or other identifier
320
+ * @returns Sanitized container name in the format "iloom-dev-{identifier}"
321
+ */
322
+ static buildContainerName(identifier) {
323
+ return buildContainerName(identifier);
324
+ }
325
+ /**
326
+ * Build the standard image name for an iloom dev server.
327
+ *
328
+ * @param identifier - Issue number, branch name, or other identifier
329
+ * @returns Sanitized image name
330
+ */
331
+ static buildImageName(identifier) {
332
+ return buildImageName(identifier);
333
+ }
334
+ /**
335
+ * Detect exposed ports from a built Docker image using `docker image inspect`.
336
+ *
337
+ * @param imageName - Name of the built Docker image to inspect
338
+ * @returns First exposed port number, or null if none found
339
+ */
340
+ static async inspectImagePorts(imageName) {
341
+ return inspectImagePorts(imageName);
342
+ }
343
+ /**
344
+ * Resolve the container port from config, image inspection, or Dockerfile EXPOSE directive.
345
+ * Priority: config > docker image inspect > Dockerfile regex
346
+ * Throws a clear error if no source provides a port.
347
+ *
348
+ * @param configPort - Port from settings (containerPort field)
349
+ * @param dockerfilePath - Absolute path to the Dockerfile
350
+ * @param imageName - Optional built image name for inspection (preferred over Dockerfile regex)
351
+ * @returns Resolved container port number
352
+ */
353
+ static async resolveContainerPort(configPort, dockerfilePath, imageName) {
354
+ if (configPort !== void 0) {
355
+ return configPort;
356
+ }
357
+ if (imageName) {
358
+ const inspectedPort = await _DockerManager.inspectImagePorts(imageName);
359
+ if (inspectedPort !== null) {
360
+ logger.debug(`Auto-detected container port ${inspectedPort} from Docker image inspect`);
361
+ return inspectedPort;
362
+ }
363
+ }
364
+ const exposedPort = await _DockerManager.parseExposeFromDockerfile(dockerfilePath);
365
+ if (exposedPort !== null) {
366
+ logger.debug(`Auto-detected container port ${exposedPort} from Dockerfile EXPOSE directive`);
367
+ return exposedPort;
368
+ }
369
+ throw new Error(
370
+ `Cannot determine container port. No "containerPort" configured in settings and no EXPOSE directive found in ${dockerfilePath}.
371
+ Either add an EXPOSE directive to your Dockerfile or set "containerPort" in capabilities.web settings.`
372
+ );
373
+ }
374
+ /**
375
+ * Force-remove a container by name (no-op if it doesn't exist).
376
+ * Used internally before running a new container to avoid name collisions.
377
+ */
378
+ static async forceRemoveContainer(containerName) {
379
+ await execa2("docker", ["rm", "-f", containerName], { reject: false });
380
+ }
381
+ /**
382
+ * Build a DockerConfig from iloom web settings and an identifier.
383
+ * Centralizes the Docker config extraction logic used by dev-server, open, and run commands.
384
+ *
385
+ * @param webSettings - The capabilities.web section from IloomSettings
386
+ * @param identifier - Identifier for container naming (issue number, branch name, etc.)
387
+ * @returns DockerConfig if Docker mode is enabled, undefined otherwise
388
+ */
389
+ static buildDockerConfigFromSettings(webSettings, identifier) {
390
+ if (!webSettings || webSettings.devServer !== "docker") {
391
+ return void 0;
392
+ }
393
+ return {
394
+ dockerFile: webSettings.dockerFile ?? "./Dockerfile",
395
+ containerPort: webSettings.containerPort,
396
+ dockerBuildArgs: webSettings.dockerBuildArgs,
397
+ dockerRunArgs: webSettings.dockerRunArgs,
398
+ identifier
399
+ };
400
+ }
401
+ };
402
+
403
+ export {
404
+ DockerManager
405
+ };
406
+ //# sourceMappingURL=chunk-AYLC633W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/DockerManager.ts","../src/utils/docker.ts"],"sourcesContent":["import { execa } from 'execa'\nimport { logger } from '../utils/logger.js'\nimport { restoreTerminalState } from '../utils/terminal.js'\nimport {\n\tisDockerInstalled,\n\tisDockerRunning,\n\tassertDockerAvailable,\n\tparseDockerfileExpose,\n\tinspectImagePorts,\n\tsanitizeContainerName,\n\tbuildContainerName,\n\tbuildImageName,\n} from '../utils/docker.js'\n\n/**\n * Configuration for Docker-based dev server mode.\n * When provided to DevServerManager methods, the server runs inside a Docker container\n * with port mapping instead of as a local process.\n */\nexport interface DockerConfig {\n\t/** Path to Dockerfile (relative to worktree) */\n\tdockerFile: string\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\tdockerBuildArgs?: Record<string, string> | undefined\n\t/** Additional docker run flags (e.g., volume mounts) */\n\tdockerRunArgs?: string[] | undefined\n\t/** Identifier for container naming (issue number, branch name) */\n\tidentifier: string\n}\n\n/**\n * Web settings shape accepted by buildDockerConfigFromSettings.\n * Matches the capabilities.web section of IloomSettings.\n * Uses `| undefined` for optional properties to satisfy exactOptionalPropertyTypes.\n */\ninterface WebSettings {\n\tdevServer?: 'process' | 'docker' | undefined\n\tdockerFile?: string | undefined\n\tcontainerPort?: number | undefined\n\tdockerBuildArgs?: Record<string, string> | undefined\n\tdockerRunArgs?: string[] | undefined\n}\n\n/**\n * DockerManager encapsulates all Docker CLI interactions.\n * Used by DevServerManager and ResourceCleanup for Docker-based dev server operations.\n *\n * All methods are static since no instance state is needed -- Docker CLI is stateless.\n */\nexport class DockerManager {\n\t/**\n\t * Check if Docker CLI is available and daemon is running.\n\t * @returns true if Docker is ready, false otherwise\n\t */\n\tstatic async isAvailable(): Promise<boolean> {\n\t\tconst installed = await isDockerInstalled()\n\t\tif (!installed) return false\n\t\treturn isDockerRunning()\n\t}\n\n\t/**\n\t * Assert that Docker is available, throwing a clear error if not.\n\t * Call this early in any workflow that requires Docker.\n\t */\n\tstatic async assertAvailable(): Promise<void> {\n\t\treturn assertDockerAvailable()\n\t}\n\n\t/**\n\t * Build a Docker image.\n\t *\n\t * @param cwd - Working directory (worktree path)\n\t * @param imageName - Image tag name\n\t * @param dockerFile - Path to Dockerfile (relative to cwd)\n\t * @param buildArgs - Optional build arguments passed as --build-arg\n\t */\n\tstatic async buildImage(\n\t\tcwd: string,\n\t\timageName: string,\n\t\tdockerFile: string,\n\t\tbuildArgs?: Record<string, string>\n\t): Promise<void> {\n\t\tconst args = ['build', '-t', imageName, '-f', dockerFile]\n\n\t\tif (buildArgs) {\n\t\t\tfor (const [key, value] of Object.entries(buildArgs)) {\n\t\t\t\targs.push('--build-arg', `${key}=${value}`)\n\t\t\t}\n\t\t}\n\n\t\t// Context directory is always cwd\n\t\targs.push('.')\n\n\t\tlogger.info(`Building Docker image \"${imageName}\" from ${dockerFile}...`)\n\n\t\ttry {\n\t\t\tawait execa('docker', args, {\n\t\t\t\tcwd,\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 mode (background).\n\t * If a container with the same name already exists, it is force-removed first.\n\t *\n\t * @param imageName - Image to run\n\t * @param containerName - Container name (must be sanitized)\n\t * @param hostPort - Port on the host to map\n\t * @param containerPort - Port inside the container\n\t * @param additionalArgs - Additional docker run flags (e.g., volume mounts)\n\t * @returns Container ID\n\t */\n\tstatic async runDetached(\n\t\timageName: string,\n\t\tcontainerName: string,\n\t\thostPort: number,\n\t\tcontainerPort: number,\n\t\tadditionalArgs?: string[]\n\t): Promise<string> {\n\t\t// Force-remove any existing container with same name to avoid name collision\n\t\tawait DockerManager.forceRemoveContainer(containerName)\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]\n\n\t\tif (additionalArgs) {\n\t\t\targs.push(...additionalArgs)\n\t\t}\n\n\t\targs.push(imageName)\n\n\t\tlogger.info(`Starting Docker container \"${containerName}\" (${hostPort}:${containerPort})...`)\n\n\t\ttry {\n\t\t\tconst result = await execa('docker', args)\n\t\t\tconst containerId = result.stdout.trim()\n\t\t\tlogger.success(`Docker container \"${containerName}\" started (ID: ${containerId.substring(0, 12)})`)\n\t\t\treturn containerId\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\t}\n\n\t/**\n\t * Run a container in foreground mode (attached, blocking).\n\t * The container is automatically removed on exit (--rm flag).\n\t * Stdout/stderr are streamed to the terminal.\n\t *\n\t * Signal forwarding: Captures SIGINT/SIGTERM on the host process and\n\t * forwards them to the container via `docker kill --signal` for graceful\n\t * shutdown of the framework running inside the container.\n\t *\n\t * @param imageName - Image to run\n\t * @param containerName - Container name (must be sanitized)\n\t * @param hostPort - Port on the host to map\n\t * @param containerPort - Port inside the container\n\t * @param additionalArgs - Additional docker run flags\n\t * @param redirectToStderr - If true, redirect stdout/stderr to stderr\n\t */\n\tstatic async runForeground(\n\t\timageName: string,\n\t\tcontainerName: string,\n\t\thostPort: number,\n\t\tcontainerPort: number,\n\t\tadditionalArgs?: string[],\n\t\tredirectToStderr?: boolean\n\t): Promise<void> {\n\t\t// Force-remove any existing container with same name to avoid name collision\n\t\tawait DockerManager.forceRemoveContainer(containerName)\n\n\t\tconst args = [\n\t\t\t'run',\n\t\t\t'--name', containerName,\n\t\t\t'--rm',\n\t\t\t'-p', `${hostPort}:${containerPort}`,\n\t\t]\n\n\t\tif (additionalArgs) {\n\t\t\targs.push(...additionalArgs)\n\t\t}\n\n\t\targs.push(imageName)\n\n\t\tlogger.info(`Running Docker container \"${containerName}\" in foreground (${hostPort}:${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// Set up signal forwarding to gracefully shut down the container\n\t\tconst forwardSignal = (signal: string): void => {\n\t\t\tlogger.debug(`Forwarding ${signal} to container \"${containerName}\"`)\n\t\t\tvoid execa('docker', ['kill', `--signal=${signal}`, containerName], { reject: false })\n\t\t}\n\n\t\tconst onSigint = (): void => forwardSignal('SIGINT')\n\t\tconst onSigterm = (): void => forwardSignal('SIGTERM')\n\n\t\tprocess.on('SIGINT', onSigint)\n\t\tprocess.on('SIGTERM', onSigterm)\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\t}\n\n\t/**\n\t * Stop and remove a container by name using atomic force-remove.\n\t * No-op if the container doesn't exist or is already removed.\n\t * Uses `docker rm -f` which handles both running and stopped containers\n\t * atomically, eliminating race conditions between stop and remove.\n\t *\n\t * @param containerName - Name of the container to remove\n\t * @returns true if a container was removed, false if no container was found\n\t */\n\tstatic async stopAndRemoveContainer(containerName: string): Promise<boolean> {\n\t\tconst isRunning = await DockerManager.isContainerRunning(containerName)\n\n\t\tif (!isRunning) {\n\t\t\tlogger.debug(`No running container found with name \"${containerName}\"`)\n\t\t\t// Still try to remove in case container exists but is stopped\n\t\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\t\t\treturn false\n\t\t}\n\n\t\tlogger.info(`Removing Docker container \"${containerName}\"...`)\n\n\t\t// Atomic force-remove: handles running and stopped containers\n\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\n\t\tlogger.success(`Docker container \"${containerName}\" removed`)\n\t\treturn true\n\t}\n\n\t/**\n\t * Check if a named container is currently running.\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\tstatic async 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 * Parse the EXPOSE directive from a Dockerfile.\n\t * Returns the last exposed port number (handles multi-stage builds correctly),\n\t * or null if none found.\n\t *\n\t * @param dockerfilePath - Absolute path to the Dockerfile\n\t * @returns Last exposed port number, or null if no EXPOSE directive found\n\t */\n\tstatic async parseExposeFromDockerfile(\n\t\tdockerfilePath: string\n\t): Promise<number | null> {\n\t\treturn parseDockerfileExpose(dockerfilePath)\n\t}\n\n\t/**\n\t * Sanitize a string for use as a Docker container name.\n\t *\n\t * @param name - Raw name to sanitize\n\t * @returns Sanitized container name\n\t */\n\tstatic sanitizeContainerName(name: string): string {\n\t\treturn sanitizeContainerName(name)\n\t}\n\n\t/**\n\t * Build the standard container name for an iloom dev server.\n\t *\n\t * @param identifier - Issue number, branch name, or other identifier\n\t * @returns Sanitized container name in the format \"iloom-dev-{identifier}\"\n\t */\n\tstatic buildContainerName(identifier: string | number): string {\n\t\treturn buildContainerName(identifier)\n\t}\n\n\t/**\n\t * Build the standard image name for an iloom dev server.\n\t *\n\t * @param identifier - Issue number, branch name, or other identifier\n\t * @returns Sanitized image name\n\t */\n\tstatic buildImageName(identifier: string | number): string {\n\t\treturn buildImageName(identifier)\n\t}\n\n\t/**\n\t * Detect exposed ports from a built Docker image using `docker image inspect`.\n\t *\n\t * @param imageName - Name of the built Docker image to inspect\n\t * @returns First exposed port number, or null if none found\n\t */\n\tstatic async inspectImagePorts(imageName: string): Promise<number | null> {\n\t\treturn inspectImagePorts(imageName)\n\t}\n\n\t/**\n\t * Resolve the container port from config, image inspection, or Dockerfile EXPOSE directive.\n\t * Priority: config > docker image inspect > Dockerfile regex\n\t * Throws a clear error if no source provides a port.\n\t *\n\t * @param configPort - Port from settings (containerPort field)\n\t * @param dockerfilePath - Absolute path to the Dockerfile\n\t * @param imageName - Optional built image name for inspection (preferred over Dockerfile regex)\n\t * @returns Resolved container port number\n\t */\n\tstatic async resolveContainerPort(\n\t\tconfigPort: number | undefined,\n\t\tdockerfilePath: string,\n\t\timageName?: string\n\t): Promise<number> {\n\t\tif (configPort !== undefined) {\n\t\t\treturn configPort\n\t\t}\n\n\t\t// Try image inspection first (most accurate - handles multi-stage builds, inherited images)\n\t\tif (imageName) {\n\t\t\tconst inspectedPort = await DockerManager.inspectImagePorts(imageName)\n\t\t\tif (inspectedPort !== null) {\n\t\t\t\tlogger.debug(`Auto-detected container port ${inspectedPort} from Docker image inspect`)\n\t\t\t\treturn inspectedPort\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to Dockerfile regex\n\t\tconst exposedPort = await DockerManager.parseExposeFromDockerfile(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. No \"containerPort\" configured in settings and no EXPOSE directive found in ${dockerfilePath}.\\n` +\n\t\t\t\t'Either add an EXPOSE directive to your Dockerfile or set \"containerPort\" in capabilities.web settings.'\n\t\t)\n\t}\n\n\t/**\n\t * Force-remove a container by name (no-op if it doesn't exist).\n\t * Used internally before running a new container to avoid name collisions.\n\t */\n\tprivate static async forceRemoveContainer(containerName: string): Promise<void> {\n\t\tawait execa('docker', ['rm', '-f', containerName], { reject: false })\n\t}\n\n\t/**\n\t * Build a DockerConfig from iloom web settings and an identifier.\n\t * Centralizes the Docker config extraction logic used by dev-server, open, and run commands.\n\t *\n\t * @param webSettings - The capabilities.web section from IloomSettings\n\t * @param identifier - Identifier for container naming (issue number, branch name, etc.)\n\t * @returns DockerConfig if Docker mode is enabled, undefined otherwise\n\t */\n\tstatic buildDockerConfigFromSettings(\n\t\twebSettings: WebSettings | undefined,\n\t\tidentifier: string\n\t): DockerConfig | undefined {\n\t\tif (!webSettings || webSettings.devServer !== 'docker') {\n\t\t\treturn undefined\n\t\t}\n\n\t\treturn {\n\t\t\tdockerFile: webSettings.dockerFile ?? './Dockerfile',\n\t\t\tcontainerPort: webSettings.containerPort,\n\t\t\tdockerBuildArgs: webSettings.dockerBuildArgs,\n\t\t\tdockerRunArgs: webSettings.dockerRunArgs,\n\t\t\tidentifier,\n\t\t}\n\t}\n}\n","import { execa } from 'execa'\nimport { readFile } from 'fs/promises'\n\n/**\n * Maximum length for Docker container names.\n * Docker allows up to 63 characters for container names.\n */\nconst MAX_CONTAINER_NAME_LENGTH = 63\n\n/**\n * Check if Docker CLI is installed.\n * Runs `docker --version` — only checks CLI presence, not daemon status.\n * @returns true if Docker CLI is installed, false otherwise\n */\nexport async function isDockerInstalled(): Promise<boolean> {\n\ttry {\n\t\tconst result = await execa('docker', ['--version'], { reject: false })\n\t\treturn result.exitCode === 0\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Check if the Docker daemon is running.\n * Runs `docker info` — requires the daemon to be running.\n * @returns true if Docker daemon is running, false otherwise\n */\nexport async function isDockerRunning(): Promise<boolean> {\n\ttry {\n\t\tconst result = await execa('docker', ['info'], { reject: false })\n\t\treturn result.exitCode === 0\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Assert that Docker is installed and the daemon is running.\n * Throws a clear, actionable error if either check fails.\n */\nexport async function assertDockerAvailable(): Promise<void> {\n\tconst installed = await isDockerInstalled()\n\tif (!installed) {\n\t\tthrow new Error(\n\t\t\t'Docker is not installed. Please install Docker to use this feature.\\n' +\n\t\t\t\t'Install Docker: https://docs.docker.com/get-docker/'\n\t\t)\n\t}\n\n\tconst running = await isDockerRunning()\n\tif (!running) {\n\t\tthrow new Error(\n\t\t\t'Docker daemon is not running. Please start Docker and try again.\\n' +\n\t\t\t\t'On macOS/Windows: Open the Docker Desktop application.\\n' +\n\t\t\t\t'On Linux: Run `sudo systemctl start docker`'\n\t\t)\n\t}\n}\n\n/**\n * Parse the EXPOSE directive from a Dockerfile.\n * Returns the LAST exposed port number (handles multi-stage builds correctly),\n * or null if none found.\n *\n * Handles formats like:\n * - EXPOSE 4200\n * - EXPOSE 4200/tcp\n * - EXPOSE 8080/udp\n * - Ignores comment lines (# EXPOSE ...)\n *\n * @param dockerfilePath - Absolute path to the Dockerfile\n * @returns Last exposed port number, or null if no valid EXPOSE directive found\n */\nexport async function parseDockerfileExpose(\n\tdockerfilePath: string\n): Promise<number | null> {\n\ttry {\n\t\tconst content = await readFile(dockerfilePath, 'utf-8')\n\t\tconst lines = content.split('\\n')\n\t\tlet lastPort: number | null = null\n\n\t\tfor (const line of lines) {\n\t\t\tconst trimmed = line.trim()\n\t\t\t// Skip comment lines\n\t\t\tif (trimmed.startsWith('#')) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tconst match = /^EXPOSE\\s+(\\d+)/i.exec(trimmed)\n\t\t\tif (match?.[1]) {\n\t\t\t\tconst port = parseInt(match[1], 10)\n\t\t\t\tif (!isNaN(port) && port >= 1 && port <= 65535) {\n\t\t\t\t\tlastPort = port\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lastPort\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Detect exposed ports from a built Docker image using `docker image inspect`.\n * Returns the first exposed port number, or null if none found.\n *\n * @param imageName - Name of the built Docker image to inspect\n * @returns First exposed port number, or null if none found\n */\nexport async function inspectImagePorts(imageName: string): Promise<number | null> {\n\ttry {\n\t\tconst result = await execa('docker', [\n\t\t\t'image', 'inspect', imageName,\n\t\t\t'--format', '{{json .Config.ExposedPorts}}',\n\t\t], { reject: false })\n\n\t\tif (result.exitCode !== 0 || !result.stdout.trim()) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst output = result.stdout.trim()\n\t\t// Output format: {\"4200/tcp\":{},\"8080/tcp\":{}} or null\n\t\tif (output === 'null' || output === '<nil>' || output === '{}') {\n\t\t\treturn null\n\t\t}\n\n\t\tconst parsed: unknown = JSON.parse(output)\n\t\tif (typeof parsed !== 'object' || parsed === null) {\n\t\t\treturn null\n\t\t}\n\n\t\t// Get first key (e.g., \"4200/tcp\") and extract port number\n\t\tconst firstKey = Object.keys(parsed)[0]\n\t\tif (!firstKey) {\n\t\t\treturn null\n\t\t}\n\n\t\tconst portMatch = /^(\\d+)/.exec(firstKey)\n\t\tif (portMatch?.[1]) {\n\t\t\tconst port = parseInt(portMatch[1], 10)\n\t\t\tif (!isNaN(port) && port >= 1 && port <= 65535) {\n\t\t\t\treturn port\n\t\t\t}\n\t\t}\n\n\t\treturn null\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Sanitize a string for use as a Docker container name.\n *\n * Docker container names must match: [a-zA-Z0-9][a-zA-Z0-9_.-]\n * - Replace slashes, spaces, and other invalid characters with hyphens\n * - Ensure the name starts with an alphanumeric character\n * - Truncate to a maximum of 63 characters\n *\n * @param name - Raw name to sanitize\n * @returns Sanitized container name\n */\nexport function sanitizeContainerName(name: string | number): string {\n\tlet sanitized = String(name)\n\n\t// Replace any character that isn't alphanumeric, underscore, dot, or hyphen with a hyphen\n\tsanitized = sanitized.replace(/[^a-zA-Z0-9_.-]/g, '-')\n\n\t// Collapse consecutive hyphens into one\n\tsanitized = sanitized.replace(/-{2,}/g, '-')\n\n\t// Remove leading non-alphanumeric characters (Docker requires starting with [a-zA-Z0-9])\n\tsanitized = sanitized.replace(/^[^a-zA-Z0-9]+/, '')\n\n\t// Remove trailing hyphens\n\tsanitized = sanitized.replace(/-+$/, '')\n\n\t// Truncate to max length\n\tif (sanitized.length > MAX_CONTAINER_NAME_LENGTH) {\n\t\tsanitized = sanitized.substring(0, MAX_CONTAINER_NAME_LENGTH)\n\t\t// Remove trailing hyphen if truncation created one\n\t\tsanitized = sanitized.replace(/-+$/, '')\n\t}\n\n\t// Fallback if everything was stripped\n\tif (sanitized.length === 0) {\n\t\tsanitized = 'iloom-container'\n\t}\n\n\treturn sanitized\n}\n\n/**\n * Build the standard container name for an iloom dev server.\n *\n * @param identifier - Issue number, branch name, or other identifier\n * @returns Sanitized container name in the format \"iloom-dev-{identifier}\"\n */\nexport function buildContainerName(identifier: string | number): string {\n\treturn sanitizeContainerName(`iloom-dev-${identifier}`)\n}\n\n/**\n * Build the standard image name for an iloom dev server.\n *\n * @param identifier - Issue number, branch name, or other identifier\n * @returns Sanitized image name in the format \"iloom-dev-{identifier}\"\n */\nexport function buildImageName(identifier: string | number): string {\n\t// Docker image tags must be lowercase\n\treturn sanitizeContainerName(`iloom-dev-${identifier}`).toLowerCase()\n}\n"],"mappings":"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","names":["execa","execa"]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger_default
4
- } from "./chunk-H2SSF24U.js";
4
+ } from "./chunk-VRPPI6GU.js";
5
5
 
6
6
  // src/utils/remote.ts
7
7
  import { execa } from "execa";
@@ -32,13 +32,21 @@ async function parseGitRemotes(cwd) {
32
32
  }
33
33
  function extractOwnerRepoFromUrl(url) {
34
34
  const cleanUrl = url.replace(/\.git$/, "");
35
- const httpsMatch = cleanUrl.match(/https?:\/\/github\.com\/([^/]+)\/([^/]+)/);
36
- if ((httpsMatch == null ? void 0 : httpsMatch[1]) && (httpsMatch == null ? void 0 : httpsMatch[2])) {
37
- return { owner: httpsMatch[1], repo: httpsMatch[2] };
35
+ const githubHttpsMatch = cleanUrl.match(/https?:\/\/github\.com\/([^/]+)\/([^/]+)/);
36
+ if ((githubHttpsMatch == null ? void 0 : githubHttpsMatch[1]) && (githubHttpsMatch == null ? void 0 : githubHttpsMatch[2])) {
37
+ return { owner: githubHttpsMatch[1], repo: githubHttpsMatch[2] };
38
38
  }
39
- const sshMatch = cleanUrl.match(/git@github\.com:([^/]+)\/(.+)/);
40
- if ((sshMatch == null ? void 0 : sshMatch[1]) && (sshMatch == null ? void 0 : sshMatch[2])) {
41
- return { owner: sshMatch[1], repo: sshMatch[2] };
39
+ const githubSshMatch = cleanUrl.match(/git@github\.com:([^/]+)\/(.+)/);
40
+ if ((githubSshMatch == null ? void 0 : githubSshMatch[1]) && (githubSshMatch == null ? void 0 : githubSshMatch[2])) {
41
+ return { owner: githubSshMatch[1], repo: githubSshMatch[2] };
42
+ }
43
+ const bitbucketHttpsMatch = cleanUrl.match(/https?:\/\/bitbucket\.org\/([^/]+)\/([^/]+)/);
44
+ if ((bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[1]) && (bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[2])) {
45
+ return { owner: bitbucketHttpsMatch[1], repo: bitbucketHttpsMatch[2] };
46
+ }
47
+ const bitbucketSshMatch = cleanUrl.match(/git@bitbucket\.org:([^/]+)\/(.+)/);
48
+ if ((bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[1]) && (bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[2])) {
49
+ return { owner: bitbucketSshMatch[1], repo: bitbucketSshMatch[2] };
42
50
  }
43
51
  return null;
44
52
  }
@@ -100,4 +108,4 @@ export {
100
108
  validateConfiguredRemote,
101
109
  getEffectivePRTargetRemote
102
110
  };
103
- //# sourceMappingURL=chunk-QVAA5KHK.js.map
111
+ //# sourceMappingURL=chunk-BZ7KTXPB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/remote.ts"],"sourcesContent":["import { execa } from 'execa'\nimport type { IloomSettings } from '../lib/SettingsManager.js'\nimport logger from './logger.js'\n\n/**\n * Represents a parsed git remote\n */\nexport interface GitRemote {\n\tname: string\n\turl: string\n\towner: string\n\trepo: string\n}\n\n/**\n * Parse git remotes from `git remote -v` output\n * Deduplicates fetch/push entries and extracts owner/repo from URLs\n */\nexport async function parseGitRemotes(cwd?: string): Promise<GitRemote[]> {\n\tconst result = await execa('git', ['remote', '-v'], {\n\t\tcwd: cwd ?? process.cwd(),\n\t\tencoding: 'utf8',\n\t})\n\n\tconst lines = result.stdout.trim().split('\\n')\n\tconst remoteMap = new Map<string, GitRemote>()\n\n\tfor (const line of lines) {\n\t\t// Format: \"origin git@github.com:owner/repo.git (fetch)\"\n\t\t// Format: \"origin https://github.com/owner/repo.git (fetch)\"\n\t\tconst match = line.match(/^(\\S+)\\s+(\\S+)\\s+\\((fetch|push)\\)/)\n\t\tif (!match) continue\n\n\t\tconst name = match[1]\n\t\tconst url = match[2]\n\t\tif (!name || !url) continue\n\n\t\t// Skip if we already processed this remote\n\t\tif (remoteMap.has(name)) continue\n\n\t\t// Extract owner/repo from URL\n\t\tconst ownerRepo = extractOwnerRepoFromUrl(url)\n\t\tif (!ownerRepo) continue\n\n\t\tremoteMap.set(name, {\n\t\t\tname,\n\t\t\turl,\n\t\t\towner: ownerRepo.owner,\n\t\t\trepo: ownerRepo.repo,\n\t\t})\n\t}\n\n\treturn Array.from(remoteMap.values())\n}\n\n/**\n * Extract owner and repo from Git remote URL\n * Supports both HTTPS and SSH formats for GitHub and BitBucket\n */\nfunction extractOwnerRepoFromUrl(url: string): { owner: string; repo: string } | null {\n\t// Remove .git suffix if present\n\tconst cleanUrl = url.replace(/\\.git$/, '')\n\n\t// GitHub HTTPS format: https://github.com/owner/repo\n\tconst githubHttpsMatch = cleanUrl.match(/https?:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)/)\n\tif (githubHttpsMatch?.[1] && githubHttpsMatch?.[2]) {\n\t\treturn { owner: githubHttpsMatch[1], repo: githubHttpsMatch[2] }\n\t}\n\n\t// GitHub SSH format: git@github.com:owner/repo\n\tconst githubSshMatch = cleanUrl.match(/git@github\\.com:([^/]+)\\/(.+)/)\n\tif (githubSshMatch?.[1] && githubSshMatch?.[2]) {\n\t\treturn { owner: githubSshMatch[1], repo: githubSshMatch[2] }\n\t}\n\n\t// BitBucket HTTPS format: https://bitbucket.org/workspace/repo\n\tconst bitbucketHttpsMatch = cleanUrl.match(/https?:\\/\\/bitbucket\\.org\\/([^/]+)\\/([^/]+)/)\n\tif (bitbucketHttpsMatch?.[1] && bitbucketHttpsMatch?.[2]) {\n\t\treturn { owner: bitbucketHttpsMatch[1], repo: bitbucketHttpsMatch[2] }\n\t}\n\n\t// BitBucket SSH format: git@bitbucket.org:workspace/repo\n\tconst bitbucketSshMatch = cleanUrl.match(/git@bitbucket\\.org:([^/]+)\\/(.+)/)\n\tif (bitbucketSshMatch?.[1] && bitbucketSshMatch?.[2]) {\n\t\treturn { owner: bitbucketSshMatch[1], repo: bitbucketSshMatch[2] }\n\t}\n\n\treturn null\n}\n\n/**\n * Check if repository has multiple remotes\n */\nexport async function hasMultipleRemotes(cwd?: string): Promise<boolean> {\n\ttry {\n\t\tconst remotes = await parseGitRemotes(cwd)\n\t\treturn remotes.length > 1\n\t} catch (error) {\n\t\t// if error is \"not a git repository\" then just log a debug message, otherwise log a warning message\n\t\tconst errMsg = error instanceof Error ? error.message : String(error)\n\t\tif (/not a git repository/i.test(errMsg)) {\n\t\t\tlogger.debug('Skipping git remote check: not a git repository')\n\t\t} else {\n\t\t\tlogger.warn(`Unable to check git remotes: ${errMsg}`)\n\t\t}\n\t\treturn false\n\t}\n}\n\n/**\n * Get configured repository string from settings\n * Returns \"owner/repo\" format for use with gh CLI --repo flag\n * Throws if configured remote not found\n */\nexport async function getConfiguredRepoFromSettings(\n\tsettings: IloomSettings,\n\tcwd?: string,\n): Promise<string> {\n\tconst remoteName = settings.issueManagement?.github?.remote\n\n\tif (!remoteName) {\n\t\tthrow new Error(\n\t\t\t'GitHub remote not configured. Run \"il init\" to configure which repository to use for GitHub operations.',\n\t\t)\n\t}\n\n\t// Validate configured remote exists\n\tawait validateConfiguredRemote(remoteName, cwd)\n\n\t// Parse remotes and find the configured one\n\tconst remotes = await parseGitRemotes(cwd)\n\tconst remote = remotes.find((r) => r.name === remoteName)\n\n\tif (!remote) {\n\t\tthrow new Error(\n\t\t\t`Configured remote \"${remoteName}\" not found in git remotes. Run \"il init\" to reconfigure.`,\n\t\t)\n\t}\n\n\treturn `${remote.owner}/${remote.repo}`\n}\n\n/**\n * Validate that a remote exists in git config\n * Throws if remote doesn't exist\n */\nexport async function validateConfiguredRemote(remoteName: string, cwd?: string): Promise<void> {\n\ttry {\n\t\tawait execa('git', ['remote', 'get-url', remoteName], {\n\t\t\tcwd: cwd ?? process.cwd(),\n\t\t\tencoding: 'utf8',\n\t\t})\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Remote \"${remoteName}\" does not exist in git configuration. Run \"il init\" to reconfigure.`,\n\t\t)\n\t}\n}\n\n/**\n * Get the effective PR target remote based on settings\n * Priority: mergeBehavior.remote > issueManagement.github.remote > 'origin'\n */\nexport async function getEffectivePRTargetRemote(\n\tsettings: IloomSettings,\n\tcwd?: string,\n): Promise<string> {\n\tconst prRemote =\n\t\tsettings.mergeBehavior?.remote ?? settings.issueManagement?.github?.remote ?? 'origin'\n\tawait validateConfiguredRemote(prRemote, cwd)\n\treturn prRemote\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger
4
- } from "./chunk-H2SSF24U.js";
4
+ } from "./chunk-VRPPI6GU.js";
5
5
 
6
6
  // src/utils/ide.ts
7
7
  import { execa } from "execa";
@@ -69,4 +69,4 @@ export {
69
69
  getInstallHint,
70
70
  openIdeWindow
71
71
  };
72
- //# sourceMappingURL=chunk-K7R5QY6C.js.map
72
+ //# sourceMappingURL=chunk-CE676WCN.js.map
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getRepoInfo
4
- } from "./chunk-NH3QZYE5.js";
4
+ } from "./chunk-KV4NU3RP.js";
5
5
  import {
6
6
  logger
7
- } from "./chunk-H2SSF24U.js";
7
+ } from "./chunk-VRPPI6GU.js";
8
8
 
9
9
  // src/utils/mcp.ts
10
10
  import path from "path";
@@ -143,6 +143,9 @@ function generateRecapMcpConfig(loomPath, loomMetadata) {
143
143
  LOOM_METADATA_JSON: JSON.stringify(loomMetadata),
144
144
  METADATA_FILE_PATH: metadataFilePath
145
145
  };
146
+ if (loomMetadata.issueType === "issue" || loomMetadata.issueType === "epic") {
147
+ envVars.RECAP_DISABLE_SET_GOAL = "true";
148
+ }
146
149
  logger.debug("Generated MCP config for recap server", {
147
150
  loomPath,
148
151
  recapFilePath,
@@ -247,4 +250,4 @@ export {
247
250
  generateHarnessMcpConfig,
248
251
  generateAndWriteMcpConfigFile
249
252
  };
250
- //# sourceMappingURL=chunk-5UFGO4ZT.js.map
253
+ //# sourceMappingURL=chunk-CQHHEW2M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/mcp.ts"],"sourcesContent":["import path from 'path'\nimport os from 'os'\nimport fs from 'fs-extra'\nimport { getRepoInfo } from './github.js'\nimport { logger } from './logger.js'\nimport type { IloomSettings } from '../lib/SettingsManager.js'\nimport type { LoomMetadata } from '../lib/MetadataManager.js'\n\n/**\n * Generate MCP configuration for issue management\n * Uses a single server that can handle both issues and pull requests\n * Returns array of MCP server config objects\n * @param contextType - Optional context type (issue or pr)\n * @param repo - Optional repo in \"owner/repo\" format. If not provided, will auto-detect from git.\n * @param provider - Issue management provider (default: 'github')\n * @param settings - Optional settings to extract Linear API token from\n * @param draftPrNumber - Optional draft PR number for draft-pr mode (routes comments to PR)\n */\nexport async function generateIssueManagementMcpConfig(\n\tcontextType?: 'issue' | 'pr',\n\trepo?: string,\n\tprovider: 'github' | 'linear' | 'jira' = 'github',\n\tsettings?: IloomSettings,\n\tdraftPrNumber?: number\n): Promise<Record<string, unknown>[]> {\n\t// When draftPrNumber is provided (draft-pr mode), force contextType to 'pr'\n\t// This ensures agents route comments to the draft PR instead of the issue\n\tconst effectiveContextType = draftPrNumber ? 'pr' : contextType\n\n\t// Build provider-specific environment variables\n\tlet envVars: Record<string, string> = {\n\t\tISSUE_PROVIDER: provider,\n\t}\n\n\t// Add draft PR number to env vars if provided\n\tif (draftPrNumber) {\n\t\tenvVars.DRAFT_PR_NUMBER = String(draftPrNumber)\n\t}\n\n\tif (provider === 'github') {\n\t\t// Get repository information for GitHub - either from provided repo string or auto-detect\n\t\tlet owner: string\n\t\tlet name: string\n\n\t\tif (repo) {\n\t\t\tconst parts = repo.split('/')\n\t\t\tif (parts.length !== 2 || !parts[0] || !parts[1]) {\n\t\t\t\tthrow new Error(`Invalid repo format: ${repo}. Expected \"owner/repo\"`)\n\t\t\t}\n\t\t\towner = parts[0]\n\t\t\tname = parts[1]\n\t\t} else {\n\t\t\tconst repoInfo = await getRepoInfo()\n\t\t\towner = repoInfo.owner\n\t\t\tname = repoInfo.name\n\t\t}\n\n\t\t// Map logical types to GitHub's webhook event names (handle GitHub's naming quirk here)\n\t\t// Use effectiveContextType which may be overridden by draftPrNumber\n\t\tconst githubEventName = effectiveContextType === 'issue' ? 'issues' : effectiveContextType === 'pr' ? 'pull_request' : undefined\n\n\t\tenvVars = {\n\t\t\t...envVars,\n\t\t\tREPO_OWNER: owner,\n\t\t\tREPO_NAME: name,\n\t\t\tGITHUB_API_URL: 'https://api.github.com/',\n\t\t\t...(githubEventName && { GITHUB_EVENT_NAME: githubEventName }),\n\t\t}\n\n\t\tlogger.debug('Generated MCP config for GitHub issue management', {\n\t\t\tprovider,\n\t\t\trepoOwner: owner,\n\t\t\trepoName: name,\n\t\t\tcontextType: effectiveContextType ?? 'auto-detect',\n\t\t\tgithubEventName: githubEventName ?? 'auto-detect',\n\t\t\tdraftPrNumber: draftPrNumber ?? undefined,\n\t\t})\n\t} else if (provider === 'linear') {\n\t\t// Linear needs API token passed through\n\t\tconst apiToken = settings?.issueManagement?.linear?.apiToken ?? process.env.LINEAR_API_TOKEN\n\n\t\tif (apiToken) {\n\t\t\tenvVars.LINEAR_API_TOKEN = apiToken\n\t\t}\n\n\t\t// Pass through LINEAR_TEAM_KEY from settings (primary) or env var (fallback)\n\t\t// Settings teamId is the preferred source as it's configured via `il init`\n\t\tconst teamKey = settings?.issueManagement?.linear?.teamId ?? process.env.LINEAR_TEAM_KEY\n\t\tif (teamKey) {\n\t\t\tenvVars.LINEAR_TEAM_KEY = teamKey\n\t\t}\n\n\t\tlogger.debug('Generated MCP config for Linear issue management', {\n\t\t\tprovider,\n\t\t\thasApiToken: !!apiToken,\n\t\t\thasTeamKey: !!teamKey,\n\t\t\tcontextType: contextType ?? 'auto-detect',\n\t\t})\n\t} else if (provider === 'jira') {\n\t\t// Jira configuration - pass credentials via environment variables\n\t\tconst jiraSettings = settings?.issueManagement?.jira\n\n\t\tif (jiraSettings?.host) {\n\t\t\tenvVars.JIRA_HOST = jiraSettings.host\n\t\t}\n\t\tif (jiraSettings?.username) {\n\t\t\tenvVars.JIRA_USERNAME = jiraSettings.username\n\t\t}\n\t\tif (jiraSettings?.apiToken) {\n\t\t\tenvVars.JIRA_API_TOKEN = jiraSettings.apiToken\n\t\t}\n\t\tif (jiraSettings?.projectKey) {\n\t\t\tenvVars.JIRA_PROJECT_KEY = jiraSettings.projectKey\n\t\t}\n\t\tif (jiraSettings?.transitionMappings) {\n\t\t\tenvVars.JIRA_TRANSITION_MAPPINGS = JSON.stringify(jiraSettings.transitionMappings)\n\t\t}\n\t\tif (jiraSettings?.defaultIssueType) {\n\t\t\tenvVars.JIRA_DEFAULT_ISSUE_TYPE = jiraSettings.defaultIssueType\n\t\t}\n\t\tif (jiraSettings?.defaultSubtaskType) {\n\t\t\tenvVars.JIRA_DEFAULT_SUBTASK_TYPE = jiraSettings.defaultSubtaskType\n\t\t}\n\n\t\tlogger.debug('Generated MCP config for Jira issue management', {\n\t\t\tprovider,\n\t\t\thasApiToken: !!jiraSettings?.apiToken,\n\t\t\tprojectKey: jiraSettings?.projectKey,\n\t\t\tcontextType: contextType ?? 'auto-detect',\n\t\t})\n\t}\n\n\t// Compute absolute path to the MCP server JS file\n\tconst serverJsPath = path.join(path.dirname(new globalThis.URL(import.meta.url).pathname), '../dist/mcp/issue-management-server.js')\n\tconst resolvedServerJsPath = path.resolve(serverJsPath)\n\n\t// Generate single MCP server config\n\tconst mcpServerConfig = {\n\t\tmcpServers: {\n\t\t\tissue_management: {\n\t\t\t\ttransport: 'stdio',\n\t\t\t\tcommand: 'node',\n\t\t\t\targs: [resolvedServerJsPath],\n\t\t\t\tenv: envVars,\n\t\t\t},\n\t\t},\n\t}\n\n\treturn [mcpServerConfig]\n}\n\n/**\n * Reuse MetadataManager.slugifyPath() algorithm for recap file naming\n *\n * Algorithm:\n * 1. Trim trailing slashes\n * 2. Replace all path separators (/ or \\) with ___ (triple underscore)\n * 3. Replace any other non-alphanumeric characters (except _ and -) with -\n * 4. Append .json\n */\nexport function slugifyPath(loomPath: string): string {\n\tlet slug = loomPath.replace(/[/\\\\]+$/, '')\n\tslug = slug.replace(/[/\\\\]/g, '___')\n\tslug = slug.replace(/[^a-zA-Z0-9_-]/g, '-')\n\treturn `${slug}.json`\n}\n\n/**\n * Resolve recap file path for a given worktree path\n */\nexport function resolveRecapFilePath(worktreePath: string): string {\n\tconst recapsDir = path.join(os.homedir(), '.config', 'iloom-ai', 'recaps')\n\treturn path.join(recapsDir, slugifyPath(worktreePath))\n}\n\n/**\n * Read recap file (returns empty object if not found or invalid)\n */\nexport async function readRecapFile(filePath: string): Promise<Record<string, unknown>> {\n\ttry {\n\t\tif (await fs.pathExists(filePath)) {\n\t\t\tconst content = await fs.readFile(filePath, 'utf8')\n\t\t\treturn JSON.parse(content) as Record<string, unknown>\n\t\t}\n\t} catch {\n\t\t// Ignore read errors - return empty recap\n\t}\n\treturn {}\n}\n\n/**\n * Write recap file (ensures parent directory exists)\n */\nexport async function writeRecapFile(filePath: string, recap: Record<string, unknown>): Promise<void> {\n\tawait fs.ensureDir(path.dirname(filePath), { mode: 0o755 })\n\tawait fs.writeFile(filePath, JSON.stringify(recap, null, 2), { mode: 0o644 })\n}\n\n/**\n * Generate MCP configuration for recap server\n *\n * The recap server captures session context (goal, decisions, insights, risks, assumptions)\n * for the VS Code Loom Context Panel.\n *\n * @param loomPath - Absolute path to the loom workspace\n * @param loomMetadata - The loom metadata object (will be stringified as JSON)\n */\nexport function generateRecapMcpConfig(\n\tloomPath: string,\n\tloomMetadata: LoomMetadata\n): Record<string, unknown>[] {\n\t// Compute recap file path using slugifyPath algorithm (same as MetadataManager)\n\tconst recapsDir = path.join(os.homedir(), '.config', 'iloom-ai', 'recaps')\n\tconst recapFilePath = path.join(recapsDir, slugifyPath(loomPath))\n\n\t// Compute metadata file path (same directory/naming as MetadataManager)\n\tconst loomsDir = path.join(os.homedir(), '.config', 'iloom-ai', 'looms')\n\tconst metadataFilePath = path.join(loomsDir, slugifyPath(loomPath))\n\n\t// Pass env vars:\n\t// - RECAP_FILE_PATH: where to read/write recap data\n\t// - LOOM_METADATA_JSON: stringified loom metadata (parsed by MCP using LoomMetadata type)\n\t// - METADATA_FILE_PATH: path to loom metadata file (for state transition tools)\n\tconst envVars: Record<string, string> = {\n\t\tRECAP_FILE_PATH: recapFilePath,\n\t\tLOOM_METADATA_JSON: JSON.stringify(loomMetadata),\n\t\tMETADATA_FILE_PATH: metadataFilePath,\n\t}\n\n\t// Disable set_goal for issue and epic workflows\n\t// (set_goal should only be available in PR and regular/branch workflows)\n\tif (loomMetadata.issueType === 'issue' || loomMetadata.issueType === 'epic') {\n\t\tenvVars.RECAP_DISABLE_SET_GOAL = 'true'\n\t}\n\n\tlogger.debug('Generated MCP config for recap server', {\n\t\tloomPath,\n\t\trecapFilePath,\n\t\tloomMetadataDescription: loomMetadata.description,\n\t})\n\n\t// Compute absolute path to the recap MCP server JS file\n\tconst recapServerJsPath = path.resolve(\n\t\tpath.join(\n\t\t\tpath.dirname(new globalThis.URL(import.meta.url).pathname),\n\t\t\t'../dist/mcp/recap-server.js'\n\t\t)\n\t)\n\n\treturn [\n\t\t{\n\t\t\tmcpServers: {\n\t\t\t\trecap: {\n\t\t\t\t\ttransport: 'stdio',\n\t\t\t\t\tcommand: 'node',\n\t\t\t\t\targs: [recapServerJsPath],\n\t\t\t\t\tenv: envVars,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t]\n}\n\n/**\n * Generate MCP configuration for the harness server\n *\n * The harness server provides Claude with a `signal` tool to send structured\n * messages to the iloom harness process via Unix domain socket.\n *\n * @param socketPath - Absolute path to the harness Unix domain socket\n */\nexport function generateHarnessMcpConfig(socketPath: string): Record<string, unknown>[] {\n\tconst harnessServerJsPath = path.resolve(\n\t\tpath.join(\n\t\t\tpath.dirname(new globalThis.URL(import.meta.url).pathname),\n\t\t\t'../dist/mcp/harness-server.js'\n\t\t)\n\t)\n\n\tlogger.debug('Generated MCP config for harness server', { socketPath })\n\n\treturn [\n\t\t{\n\t\t\tmcpServers: {\n\t\t\t\tharness: {\n\t\t\t\t\ttransport: 'stdio',\n\t\t\t\t\tcommand: 'node',\n\t\t\t\t\targs: [harnessServerJsPath],\n\t\t\t\t\tenv: { ILOOM_HARNESS_SOCKET: socketPath },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t]\n}\n\n/**\n * Get the MCP configs directory path\n */\nexport function getMcpConfigsDir(): string {\n\treturn path.join(os.homedir(), '.config', 'iloom-ai', 'mcp-configs')\n}\n\n/**\n * Get the MCP config file path for a given loom path\n */\nexport function getMcpConfigFilePath(loomPath: string): string {\n\treturn path.join(getMcpConfigsDir(), slugifyPath(loomPath))\n}\n\n/**\n * Generate and write a per-loom MCP config file to ~/.config/iloom-ai/mcp-configs/<loom-slug>.json\n *\n * Merges issue management and recap MCP server configs into a single file.\n * Used by swarm workers to pass --mcp-config <path> to claude -p commands.\n *\n * @param loomPath - Absolute path to the loom workspace\n * @param loomMetadata - The loom metadata object\n * @param provider - Issue tracker provider name\n * @param settings - Optional settings for provider configuration\n * @returns The absolute path to the written MCP config file\n */\nexport async function generateAndWriteMcpConfigFile(\n\tloomPath: string,\n\tloomMetadata: LoomMetadata,\n\tprovider: 'github' | 'linear' | 'jira' = 'github',\n\tsettings?: IloomSettings,\n): Promise<string> {\n\tconst mcpConfigs: Record<string, unknown>[] = []\n\n\t// Generate issue management MCP config\n\ttry {\n\t\tconst issueMcpConfigs = await generateIssueManagementMcpConfig(\n\t\t\t'issue',\n\t\t\tundefined,\n\t\t\tprovider,\n\t\t\tsettings,\n\t\t)\n\t\tmcpConfigs.push(...issueMcpConfigs)\n\t} catch (error) {\n\t\tlogger.warn(`Failed to generate issue management MCP config for loom: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t}\n\n\t// Generate recap MCP config\n\ttry {\n\t\tconst recapMcpConfigs = generateRecapMcpConfig(loomPath, loomMetadata)\n\t\tmcpConfigs.push(...recapMcpConfigs)\n\t} catch (error) {\n\t\tlogger.warn(`Failed to generate recap MCP config for loom: ${error instanceof Error ? error.message : 'Unknown error'}`)\n\t}\n\n\t// Merge all mcpServers into a single config object\n\tconst mergedServers: Record<string, unknown> = {}\n\tfor (const config of mcpConfigs) {\n\t\tif ('mcpServers' in config && typeof config.mcpServers === 'object') {\n\t\t\tObject.assign(mergedServers, config.mcpServers)\n\t\t}\n\t}\n\n\tconst mergedConfig = { mcpServers: mergedServers }\n\n\t// Verify MCP server JS files exist before writing config\n\tfor (const [serverName, serverConfig] of Object.entries(mergedServers)) {\n\t\tconst config = serverConfig as { args?: string[] }\n\t\tconst jsPath = config.args?.[0]\n\t\tif (jsPath) {\n\t\t\tconst exists = await fs.pathExists(jsPath)\n\t\t\tif (!exists) {\n\t\t\t\tlogger.warn(`MCP server JS file not found: ${serverName} -> ${jsPath}`)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Write to file\n\tconst configDir = getMcpConfigsDir()\n\tawait fs.ensureDir(configDir, { mode: 0o755 })\n\n\tconst configFilePath = getMcpConfigFilePath(loomPath)\n\tawait fs.writeFile(configFilePath, JSON.stringify(mergedConfig, null, 2), { mode: 0o644 })\n\n\treturn configFilePath\n}"],"mappings":";;;;;;;;;AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,QAAQ;AAgBf,eAAsB,iCACrB,aACA,MACA,WAAyC,UACzC,UACA,eACqC;AAxBtC;AA2BC,QAAM,uBAAuB,gBAAgB,OAAO;AAGpD,MAAI,UAAkC;AAAA,IACrC,gBAAgB;AAAA,EACjB;AAGA,MAAI,eAAe;AAClB,YAAQ,kBAAkB,OAAO,aAAa;AAAA,EAC/C;AAEA,MAAI,aAAa,UAAU;AAE1B,QAAI;AACJ,QAAI;AAEJ,QAAI,MAAM;AACT,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,UAAI,MAAM,WAAW,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG;AACjD,cAAM,IAAI,MAAM,wBAAwB,IAAI,yBAAyB;AAAA,MACtE;AACA,cAAQ,MAAM,CAAC;AACf,aAAO,MAAM,CAAC;AAAA,IACf,OAAO;AACN,YAAM,WAAW,MAAM,YAAY;AACnC,cAAQ,SAAS;AACjB,aAAO,SAAS;AAAA,IACjB;AAIA,UAAM,kBAAkB,yBAAyB,UAAU,WAAW,yBAAyB,OAAO,iBAAiB;AAEvH,cAAU;AAAA,MACT,GAAG;AAAA,MACH,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,gBAAgB;AAAA,MAChB,GAAI,mBAAmB,EAAE,mBAAmB,gBAAgB;AAAA,IAC7D;AAEA,WAAO,MAAM,oDAAoD;AAAA,MAChE;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,wBAAwB;AAAA,MACrC,iBAAiB,mBAAmB;AAAA,MACpC,eAAe,iBAAiB;AAAA,IACjC,CAAC;AAAA,EACF,WAAW,aAAa,UAAU;AAEjC,UAAM,aAAW,gDAAU,oBAAV,mBAA2B,WAA3B,mBAAmC,aAAY,QAAQ,IAAI;AAE5E,QAAI,UAAU;AACb,cAAQ,mBAAmB;AAAA,IAC5B;AAIA,UAAM,YAAU,gDAAU,oBAAV,mBAA2B,WAA3B,mBAAmC,WAAU,QAAQ,IAAI;AACzE,QAAI,SAAS;AACZ,cAAQ,kBAAkB;AAAA,IAC3B;AAEA,WAAO,MAAM,oDAAoD;AAAA,MAChE;AAAA,MACA,aAAa,CAAC,CAAC;AAAA,MACf,YAAY,CAAC,CAAC;AAAA,MACd,aAAa,eAAe;AAAA,IAC7B,CAAC;AAAA,EACF,WAAW,aAAa,QAAQ;AAE/B,UAAM,gBAAe,0CAAU,oBAAV,mBAA2B;AAEhD,QAAI,6CAAc,MAAM;AACvB,cAAQ,YAAY,aAAa;AAAA,IAClC;AACA,QAAI,6CAAc,UAAU;AAC3B,cAAQ,gBAAgB,aAAa;AAAA,IACtC;AACA,QAAI,6CAAc,UAAU;AAC3B,cAAQ,iBAAiB,aAAa;AAAA,IACvC;AACA,QAAI,6CAAc,YAAY;AAC7B,cAAQ,mBAAmB,aAAa;AAAA,IACzC;AACA,QAAI,6CAAc,oBAAoB;AACrC,cAAQ,2BAA2B,KAAK,UAAU,aAAa,kBAAkB;AAAA,IAClF;AACA,QAAI,6CAAc,kBAAkB;AACnC,cAAQ,0BAA0B,aAAa;AAAA,IAChD;AACA,QAAI,6CAAc,oBAAoB;AACrC,cAAQ,4BAA4B,aAAa;AAAA,IAClD;AAEA,WAAO,MAAM,kDAAkD;AAAA,MAC9D;AAAA,MACA,aAAa,CAAC,EAAC,6CAAc;AAAA,MAC7B,YAAY,6CAAc;AAAA,MAC1B,aAAa,eAAe;AAAA,IAC7B,CAAC;AAAA,EACF;AAGA,QAAM,eAAe,KAAK,KAAK,KAAK,QAAQ,IAAI,WAAW,IAAI,YAAY,GAAG,EAAE,QAAQ,GAAG,wCAAwC;AACnI,QAAM,uBAAuB,KAAK,QAAQ,YAAY;AAGtD,QAAM,kBAAkB;AAAA,IACvB,YAAY;AAAA,MACX,kBAAkB;AAAA,QACjB,WAAW;AAAA,QACX,SAAS;AAAA,QACT,MAAM,CAAC,oBAAoB;AAAA,QAC3B,KAAK;AAAA,MACN;AAAA,IACD;AAAA,EACD;AAEA,SAAO,CAAC,eAAe;AACxB;AAWO,SAAS,YAAY,UAA0B;AACrD,MAAI,OAAO,SAAS,QAAQ,WAAW,EAAE;AACzC,SAAO,KAAK,QAAQ,UAAU,KAAK;AACnC,SAAO,KAAK,QAAQ,mBAAmB,GAAG;AAC1C,SAAO,GAAG,IAAI;AACf;AAKO,SAAS,qBAAqB,cAA8B;AAClE,QAAM,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY,QAAQ;AACzE,SAAO,KAAK,KAAK,WAAW,YAAY,YAAY,CAAC;AACtD;AAKA,eAAsB,cAAc,UAAoD;AACvF,MAAI;AACH,QAAI,MAAM,GAAG,WAAW,QAAQ,GAAG;AAClC,YAAM,UAAU,MAAM,GAAG,SAAS,UAAU,MAAM;AAClD,aAAO,KAAK,MAAM,OAAO;AAAA,IAC1B;AAAA,EACD,QAAQ;AAAA,EAER;AACA,SAAO,CAAC;AACT;AAKA,eAAsB,eAAe,UAAkB,OAA+C;AACrG,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,GAAG,EAAE,MAAM,IAAM,CAAC;AAC1D,QAAM,GAAG,UAAU,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAC7E;AAWO,SAAS,uBACf,UACA,cAC4B;AAE5B,QAAM,YAAY,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY,QAAQ;AACzE,QAAM,gBAAgB,KAAK,KAAK,WAAW,YAAY,QAAQ,CAAC;AAGhE,QAAM,WAAW,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY,OAAO;AACvE,QAAM,mBAAmB,KAAK,KAAK,UAAU,YAAY,QAAQ,CAAC;AAMlE,QAAM,UAAkC;AAAA,IACvC,iBAAiB;AAAA,IACjB,oBAAoB,KAAK,UAAU,YAAY;AAAA,IAC/C,oBAAoB;AAAA,EACrB;AAIA,MAAI,aAAa,cAAc,WAAW,aAAa,cAAc,QAAQ;AAC5E,YAAQ,yBAAyB;AAAA,EAClC;AAEA,SAAO,MAAM,yCAAyC;AAAA,IACrD;AAAA,IACA;AAAA,IACA,yBAAyB,aAAa;AAAA,EACvC,CAAC;AAGD,QAAM,oBAAoB,KAAK;AAAA,IAC9B,KAAK;AAAA,MACJ,KAAK,QAAQ,IAAI,WAAW,IAAI,YAAY,GAAG,EAAE,QAAQ;AAAA,MACzD;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AAAA,IACN;AAAA,MACC,YAAY;AAAA,QACX,OAAO;AAAA,UACN,WAAW;AAAA,UACX,SAAS;AAAA,UACT,MAAM,CAAC,iBAAiB;AAAA,UACxB,KAAK;AAAA,QACN;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAUO,SAAS,yBAAyB,YAA+C;AACvF,QAAM,sBAAsB,KAAK;AAAA,IAChC,KAAK;AAAA,MACJ,KAAK,QAAQ,IAAI,WAAW,IAAI,YAAY,GAAG,EAAE,QAAQ;AAAA,MACzD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,MAAM,2CAA2C,EAAE,WAAW,CAAC;AAEtE,SAAO;AAAA,IACN;AAAA,MACC,YAAY;AAAA,QACX,SAAS;AAAA,UACR,WAAW;AAAA,UACX,SAAS;AAAA,UACT,MAAM,CAAC,mBAAmB;AAAA,UAC1B,KAAK,EAAE,sBAAsB,WAAW;AAAA,QACzC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAKO,SAAS,mBAA2B;AAC1C,SAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW,YAAY,aAAa;AACpE;AAKO,SAAS,qBAAqB,UAA0B;AAC9D,SAAO,KAAK,KAAK,iBAAiB,GAAG,YAAY,QAAQ,CAAC;AAC3D;AAcA,eAAsB,8BACrB,UACA,cACA,WAAyC,UACzC,UACkB;AAtUnB;AAuUC,QAAM,aAAwC,CAAC;AAG/C,MAAI;AACH,UAAM,kBAAkB,MAAM;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,eAAW,KAAK,GAAG,eAAe;AAAA,EACnC,SAAS,OAAO;AACf,WAAO,KAAK,4DAA4D,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AAAA,EACnI;AAGA,MAAI;AACH,UAAM,kBAAkB,uBAAuB,UAAU,YAAY;AACrE,eAAW,KAAK,GAAG,eAAe;AAAA,EACnC,SAAS,OAAO;AACf,WAAO,KAAK,iDAAiD,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AAAA,EACxH;AAGA,QAAM,gBAAyC,CAAC;AAChD,aAAW,UAAU,YAAY;AAChC,QAAI,gBAAgB,UAAU,OAAO,OAAO,eAAe,UAAU;AACpE,aAAO,OAAO,eAAe,OAAO,UAAU;AAAA,IAC/C;AAAA,EACD;AAEA,QAAM,eAAe,EAAE,YAAY,cAAc;AAGjD,aAAW,CAAC,YAAY,YAAY,KAAK,OAAO,QAAQ,aAAa,GAAG;AACvE,UAAM,SAAS;AACf,UAAM,UAAS,YAAO,SAAP,mBAAc;AAC7B,QAAI,QAAQ;AACX,YAAM,SAAS,MAAM,GAAG,WAAW,MAAM;AACzC,UAAI,CAAC,QAAQ;AACZ,eAAO,KAAK,iCAAiC,UAAU,OAAO,MAAM,EAAE;AAAA,MACvE;AAAA,IACD;AAAA,EACD;AAGA,QAAM,YAAY,iBAAiB;AACnC,QAAM,GAAG,UAAU,WAAW,EAAE,MAAM,IAAM,CAAC;AAE7C,QAAM,iBAAiB,qBAAqB,QAAQ;AACpD,QAAM,GAAG,UAAU,gBAAgB,KAAK,UAAU,cAAc,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAEzF,SAAO;AACR;","names":[]}
@@ -10,13 +10,13 @@ import {
10
10
  getSubIssues,
11
11
  hasProjectScope,
12
12
  updateProjectItemField
13
- } from "./chunk-NH3QZYE5.js";
13
+ } from "./chunk-KV4NU3RP.js";
14
14
  import {
15
15
  promptConfirmation
16
- } from "./chunk-CV47VCMQ.js";
16
+ } from "./chunk-NPVA65KS.js";
17
17
  import {
18
18
  getLogger
19
- } from "./chunk-ZAXRQLK3.js";
19
+ } from "./chunk-FTYWGQFM.js";
20
20
 
21
21
  // src/lib/GitHubService.ts
22
22
  import { execSync } from "child_process";
@@ -358,4 +358,4 @@ State: ${entity.state}`;
358
358
  export {
359
359
  GitHubService
360
360
  };
361
- //# sourceMappingURL=chunk-LHDD4JHC.js.map
361
+ //# sourceMappingURL=chunk-D4Q7T5KD.js.map