@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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  logger
4
- } from "./chunk-PIIRD4LO.js";
4
+ } from "./chunk-4HZMW2V3.js";
5
5
 
6
6
  // src/mcp/issue-management-server.ts
7
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -2398,7 +2398,7 @@ async function promptConfirmation(message, defaultValue = false) {
2398
2398
  }
2399
2399
 
2400
2400
  // src/lib/providers/jira/JiraIssueTracker.ts
2401
- var JiraIssueTracker = class {
2401
+ var JiraIssueTracker = class _JiraIssueTracker {
2402
2402
  constructor(config, options) {
2403
2403
  this.providerName = "jira";
2404
2404
  this.supportsPullRequests = false;
@@ -2410,6 +2410,36 @@ var JiraIssueTracker = class {
2410
2410
  });
2411
2411
  this.prompter = (options == null ? void 0 : options.prompter) ?? promptConfirmation;
2412
2412
  }
2413
+ /**
2414
+ * Create a JiraIssueTracker from IloomSettings
2415
+ * Extracts and validates Jira config from settings
2416
+ */
2417
+ static fromSettings(settings2) {
2418
+ var _a;
2419
+ const jiraSettings = (_a = settings2.issueManagement) == null ? void 0 : _a.jira;
2420
+ if (!(jiraSettings == null ? void 0 : jiraSettings.host)) {
2421
+ throw new Error("Jira host is required. Configure issueManagement.jira.host in .iloom/settings.json");
2422
+ }
2423
+ if (!(jiraSettings == null ? void 0 : jiraSettings.username)) {
2424
+ throw new Error("Jira username is required. Configure issueManagement.jira.username in .iloom/settings.json");
2425
+ }
2426
+ if (!(jiraSettings == null ? void 0 : jiraSettings.apiToken)) {
2427
+ throw new Error("Jira API token is required. Configure issueManagement.jira.apiToken in .iloom/settings.local.json");
2428
+ }
2429
+ if (!(jiraSettings == null ? void 0 : jiraSettings.projectKey)) {
2430
+ throw new Error("Jira project key is required. Configure issueManagement.jira.projectKey in .iloom/settings.json");
2431
+ }
2432
+ const config = {
2433
+ host: jiraSettings.host,
2434
+ username: jiraSettings.username,
2435
+ apiToken: jiraSettings.apiToken,
2436
+ projectKey: jiraSettings.projectKey
2437
+ };
2438
+ if (jiraSettings.transitionMappings) {
2439
+ config.transitionMappings = jiraSettings.transitionMappings;
2440
+ }
2441
+ return new _JiraIssueTracker(config);
2442
+ }
2413
2443
  /**
2414
2444
  * Normalize identifier to canonical uppercase form
2415
2445
  * Jira issue keys are case-sensitive in the API (must be uppercase)
@@ -2723,6 +2753,11 @@ import path2 from "path";
2723
2753
  import os2 from "os";
2724
2754
  import { z } from "zod";
2725
2755
  import deepmerge from "deepmerge";
2756
+ var mergeModeValues = ["local", "pr", "draft-pr", "github-pr", "github-draft-pr", "bitbucket-pr"];
2757
+ var mergeModeTransform = (val) => {
2758
+ const map = { "github-pr": "pr", "github-draft-pr": "draft-pr", "bitbucket-pr": "pr" };
2759
+ return map[val] ?? val;
2760
+ };
2726
2761
  var BaseAgentSettingsSchema = z.object({
2727
2762
  model: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Claude model shorthand: sonnet, opus, or haiku"),
2728
2763
  swarmModel: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Model to use for this agent in swarm mode. Overrides the base model when running inside swarm workers."),
@@ -2734,9 +2769,7 @@ var BaseAgentSettingsSchema = z.object({
2734
2769
  review: z.boolean().optional().describe("Whether artifacts from this agent should be reviewed before posting (defaults to false)"),
2735
2770
  swarmReview: z.boolean().optional().describe("Whether artifacts from this agent should be reviewed in swarm mode. Defaults to false if not set (review is off in swarm mode for speed and cost unless explicitly enabled).")
2736
2771
  });
2737
- var AgentSettingsSchema = BaseAgentSettingsSchema.extend({
2738
- subAgentTimeout: z.number().min(1, "Sub-agent timeout must be at least 1 minute").max(120, "Sub-agent timeout cannot exceed 120 minutes").default(10).describe("Timeout in minutes for sub-agent claude -p invocations in swarm mode. Applies to each phase agent (evaluator, analyzer, planner, implementer) when invoked via the Bash tool. Default: 10 minutes. Only meaningful under the iloom-swarm-worker agent entry.")
2739
- });
2772
+ var AgentSettingsSchema = BaseAgentSettingsSchema;
2740
2773
  var SpinAgentSettingsSchema = z.object({
2741
2774
  model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for spin orchestrator"),
2742
2775
  swarmModel: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Model for the spin orchestrator when running in swarm mode. Overrides spin.model for swarm workflows."),
@@ -2745,7 +2778,8 @@ var SpinAgentSettingsSchema = z.object({
2745
2778
  var PlanCommandSettingsSchema = z.object({
2746
2779
  model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for plan command"),
2747
2780
  planner: z.enum(["claude", "gemini", "codex"]).default("claude").describe("AI provider for creating the plan"),
2748
- reviewer: z.enum(["claude", "gemini", "codex", "none"]).default("none").describe("AI provider for reviewing the plan (none to skip review)")
2781
+ reviewer: z.enum(["claude", "gemini", "codex", "none"]).default("none").describe("AI provider for reviewing the plan (none to skip review)"),
2782
+ waveVerification: z.boolean().default(true).describe("When enabled, the planner generates verification child issues between dependency waves to catch integration issues early.")
2749
2783
  });
2750
2784
  var SummarySettingsSchema = z.object({
2751
2785
  model: z.enum(["sonnet", "opus", "haiku"]).default("sonnet").describe("Claude model shorthand for session summary generation")
@@ -2780,7 +2814,12 @@ var WorkflowsSettingsSchemaNoDefaults = z.object({
2780
2814
  }).optional();
2781
2815
  var CapabilitiesSettingsSchema = z.object({
2782
2816
  web: z.object({
2783
- basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)")
2817
+ basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)"),
2818
+ devServer: z.enum(["process", "docker"]).default("process").describe('Dev server mode: "process" runs natively, "docker" runs inside a Docker container with port mapping'),
2819
+ dockerFile: z.string().default("./Dockerfile").describe('Path to Dockerfile relative to worktree root (only used when devServer is "docker")'),
2820
+ containerPort: z.number().min(1, "Container port must be >= 1").max(65535, "Container port must be <= 65535").optional().describe("Port the app runs on inside the Docker container (auto-detected from EXPOSE directive if not set)"),
2821
+ dockerBuildArgs: z.record(z.string()).optional().describe('Build arguments to pass to docker build (e.g., {"NODE_ENV": "development"})'),
2822
+ dockerRunArgs: z.array(z.string()).optional().describe('Additional arguments for docker run (e.g., ["-v", "./src:/app/src"] for volume mounts)')
2784
2823
  }).optional().describe('Web dev server settings. To declare a project as a web project, add "web" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),
2785
2824
  database: z.object({
2786
2825
  databaseUrlEnvVarName: z.string().min(1, "Database URL variable name cannot be empty").regex(/^[A-Z_][A-Z0-9_]*$/, "Must be valid env var name (uppercase, underscores)").optional().default("DATABASE_URL").describe("Name of environment variable for database connection URL")
@@ -2788,12 +2827,56 @@ var CapabilitiesSettingsSchema = z.object({
2788
2827
  }).optional();
2789
2828
  var CapabilitiesSettingsSchemaNoDefaults = z.object({
2790
2829
  web: z.object({
2791
- basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)")
2830
+ basePort: z.number().min(1, "Base port must be >= 1").max(65535, "Base port must be <= 65535").optional().describe("Base port for web workspace port calculations (default: 3000)"),
2831
+ devServer: z.enum(["process", "docker"]).optional().describe('Dev server mode: "process" runs natively, "docker" runs inside a Docker container with port mapping'),
2832
+ dockerFile: z.string().optional().describe('Path to Dockerfile relative to worktree root (only used when devServer is "docker")'),
2833
+ containerPort: z.number().min(1, "Container port must be >= 1").max(65535, "Container port must be <= 65535").optional().describe("Port the app runs on inside the Docker container (auto-detected from EXPOSE directive if not set)"),
2834
+ dockerBuildArgs: z.record(z.string()).optional().describe('Build arguments to pass to docker build (e.g., {"NODE_ENV": "development"})'),
2835
+ dockerRunArgs: z.array(z.string()).optional().describe('Additional arguments for docker run (e.g., ["-v", "./src:/app/src"] for volume mounts)')
2792
2836
  }).optional().describe('Web dev server settings. To declare a project as a web project, add "web" to the capabilities array in .iloom/package.iloom.json or .iloom/package.iloom.local.json.'),
2793
2837
  database: z.object({
2794
2838
  databaseUrlEnvVarName: z.string().min(1, "Database URL variable name cannot be empty").regex(/^[A-Z_][A-Z0-9_]*$/, "Must be valid env var name (uppercase, underscores)").optional().describe("Name of environment variable for database connection URL")
2795
2839
  }).optional()
2796
2840
  }).optional();
2841
+ var DevServerSettingsSchema = z.object({
2842
+ mode: z.enum(["docker"]).default("docker").describe('Dev server mode. Currently only "docker" is supported.'),
2843
+ docker: z.object({
2844
+ dockerFile: z.string().default("./Dockerfile").refine(
2845
+ (val) => {
2846
+ if (path2.isAbsolute(val)) return false;
2847
+ const normalized = path2.normalize(val);
2848
+ if (normalized.startsWith("..")) return false;
2849
+ return true;
2850
+ },
2851
+ {
2852
+ message: 'dockerFile must be a relative path that does not traverse outside the project root (no leading "/" and no "../" escaping)'
2853
+ }
2854
+ ).describe("Path to Dockerfile relative to worktree root"),
2855
+ containerPort: z.number().min(1, "Container port must be >= 1").max(65535, "Container port must be <= 65535").optional().describe("Port the app runs on inside the Docker container (auto-detected from EXPOSE directive if not set)"),
2856
+ buildArgs: z.record(z.string(), z.string()).optional().describe("Build arguments to pass to docker build"),
2857
+ runArgs: z.array(z.string()).optional().describe("Additional arguments for docker run")
2858
+ }).optional()
2859
+ });
2860
+ var DevServerSettingsSchemaNoDefaults = z.object({
2861
+ mode: z.enum(["docker"]).optional().describe('Dev server mode. Currently only "docker" is supported.'),
2862
+ docker: z.object({
2863
+ dockerFile: z.string().optional().refine(
2864
+ (val) => {
2865
+ if (val === void 0) return true;
2866
+ if (path2.isAbsolute(val)) return false;
2867
+ const normalized = path2.normalize(val);
2868
+ if (normalized.startsWith("..")) return false;
2869
+ return true;
2870
+ },
2871
+ {
2872
+ message: 'dockerFile must be a relative path that does not traverse outside the project root (no leading "/" and no "../" escaping)'
2873
+ }
2874
+ ).describe("Path to Dockerfile relative to worktree root"),
2875
+ containerPort: z.number().min(1, "Container port must be >= 1").max(65535, "Container port must be <= 65535").optional().describe("Port the app runs on inside the Docker container (auto-detected from EXPOSE directive if not set)"),
2876
+ buildArgs: z.record(z.string(), z.string()).optional().describe("Build arguments to pass to docker build"),
2877
+ runArgs: z.array(z.string()).optional().describe("Additional arguments for docker run")
2878
+ }).optional()
2879
+ });
2797
2880
  var NeonSettingsSchema = z.object({
2798
2881
  projectId: z.string().min(1).regex(/^[a-zA-Z0-9-]+$/, "Neon project ID must contain only letters, numbers, and hyphens").describe('Neon project ID found in your project URL (e.g., "fantastic-fox-3566354")'),
2799
2882
  parentBranch: z.string().min(1).describe("Branch from which new database branches are created")
@@ -2845,6 +2928,7 @@ var IloomSettingsSchema = z.object({
2845
2928
  "Session summary generation configuration. Model defaults to sonnet when not configured."
2846
2929
  ),
2847
2930
  capabilities: CapabilitiesSettingsSchema.describe("Project capability configurations"),
2931
+ devServer: DevServerSettingsSchema.optional().describe("Docker-based dev server configuration"),
2848
2932
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
2849
2933
  issueManagement: z.object({
2850
2934
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
@@ -2869,17 +2953,28 @@ var IloomSettingsSchema = z.object({
2869
2953
  doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
2870
2954
  }).optional()
2871
2955
  }).optional().describe("Issue management configuration"),
2956
+ versionControl: z.object({
2957
+ provider: z.enum(["github", "bitbucket"]).optional().default("github").describe("Version control provider (github, bitbucket)"),
2958
+ bitbucket: z.object({
2959
+ username: z.string().min(1, "BitBucket username cannot be empty").describe("BitBucket username"),
2960
+ apiToken: z.string().optional().describe("BitBucket API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://bitbucket.org/account/settings/app-passwords/ (Note: App passwords deprecated Sep 2025, use API tokens)"),
2961
+ workspace: z.string().optional().describe("BitBucket workspace (optional, auto-detected from git remote if not provided)"),
2962
+ repoSlug: z.string().optional().describe("BitBucket repository slug (optional, auto-detected from git remote if not provided)"),
2963
+ reviewers: z.array(z.string().describe("Reviewer username")).optional().describe("List of usernames to add as PR reviewers. Usernames are resolved to Bitbucket account IDs at PR creation time.")
2964
+ }).optional()
2965
+ }).optional().describe("Version control provider configuration"),
2872
2966
  mergeBehavior: z.object({
2873
2967
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
2874
- mode: z.enum(["local", "github-pr", "github-draft-pr"]).default("local"),
2968
+ mode: z.enum(mergeModeValues).default("local").transform(mergeModeTransform),
2875
2969
  remote: z.string().optional(),
2876
2970
  autoCommitPush: z.boolean().optional().describe(
2877
- "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr."
2971
+ "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is draft-pr."
2878
2972
  ),
2973
+ prTitlePrefix: z.boolean().default(false).optional().describe('Prefix PR titles with the issue number (e.g., "QLH-123: Title"). Default: false'),
2879
2974
  openBrowserOnFinish: z.boolean().default(true).describe(
2880
- "Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override."
2975
+ "Open the PR in the default browser after finishing in pr or draft-pr mode. Use --no-browser flag to override."
2881
2976
  )
2882
- }).optional().describe("Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)"),
2977
+ }).optional().describe("Merge behavior configuration: local (merge locally), pr (create PR), or draft-pr (create draft PR at start, mark ready on finish)"),
2883
2978
  ide: z.object({
2884
2979
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
2885
2980
  type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).default("vscode").describe(
@@ -2941,12 +3036,14 @@ var IloomSettingsSchemaNoDefaults = z.object({
2941
3036
  plan: z.object({
2942
3037
  model: z.enum(["sonnet", "opus", "haiku"]).optional(),
2943
3038
  planner: z.enum(["claude", "gemini", "codex"]).optional(),
2944
- reviewer: z.enum(["claude", "gemini", "codex", "none"]).optional()
3039
+ reviewer: z.enum(["claude", "gemini", "codex", "none"]).optional(),
3040
+ waveVerification: z.boolean().optional()
2945
3041
  }).optional().describe("Plan command configuration"),
2946
3042
  summary: z.object({
2947
3043
  model: z.enum(["sonnet", "opus", "haiku"]).optional()
2948
3044
  }).optional().describe("Session summary generation configuration"),
2949
3045
  capabilities: CapabilitiesSettingsSchemaNoDefaults.describe("Project capability configurations"),
3046
+ devServer: DevServerSettingsSchemaNoDefaults.optional().describe("Docker-based dev server configuration"),
2950
3047
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
2951
3048
  issueManagement: z.object({
2952
3049
  provider: z.enum(["github", "linear", "jira"]).optional().describe("Issue tracker provider (github, linear, jira)"),
@@ -2970,16 +3067,27 @@ var IloomSettingsSchemaNoDefaults = z.object({
2970
3067
  doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
2971
3068
  }).optional()
2972
3069
  }).optional().describe("Issue management configuration"),
3070
+ versionControl: z.object({
3071
+ provider: z.enum(["github", "bitbucket"]).optional().describe("Version control provider (github, bitbucket)"),
3072
+ bitbucket: z.object({
3073
+ username: z.string().min(1, "BitBucket username cannot be empty").describe("BitBucket username"),
3074
+ apiToken: z.string().optional().describe("BitBucket API token. SECURITY: Store in settings.local.json only, never commit to source control. Generate at: https://bitbucket.org/account/settings/app-passwords/ (Note: App passwords deprecated Sep 2025, use API tokens)"),
3075
+ workspace: z.string().optional().describe("BitBucket workspace (optional, auto-detected from git remote if not provided)"),
3076
+ repoSlug: z.string().optional().describe("BitBucket repository slug (optional, auto-detected from git remote if not provided)"),
3077
+ reviewers: z.array(z.string().describe("Reviewer username")).optional().describe("List of usernames to add as PR reviewers. Usernames are resolved to Bitbucket account IDs at PR creation time.")
3078
+ }).optional()
3079
+ }).optional().describe("Version control provider configuration"),
2973
3080
  mergeBehavior: z.object({
2974
- mode: z.enum(["local", "github-pr", "github-draft-pr"]).optional(),
3081
+ mode: z.enum(mergeModeValues).transform(mergeModeTransform).optional(),
2975
3082
  remote: z.string().optional(),
2976
3083
  autoCommitPush: z.boolean().optional().describe(
2977
- "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is github-draft-pr."
3084
+ "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is draft-pr."
2978
3085
  ),
3086
+ prTitlePrefix: z.boolean().optional(),
2979
3087
  openBrowserOnFinish: z.boolean().optional().describe(
2980
- "Open the PR in the default browser after finishing in github-pr or github-draft-pr mode. Use --no-browser flag to override."
3088
+ "Open the PR in the default browser after finishing in pr or draft-pr mode. Use --no-browser flag to override."
2981
3089
  )
2982
- }).optional().describe("Merge behavior configuration: local (merge locally), github-pr (create PR), or github-draft-pr (create draft PR at start, mark ready on finish)"),
3090
+ }).optional().describe("Merge behavior configuration: local (merge locally), pr (create PR), or draft-pr (create draft PR at start, mark ready on finish)"),
2983
3091
  ide: z.object({
2984
3092
  type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).optional().describe(
2985
3093
  "IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor), antigravity (Antigravity IDE)."
@@ -3004,7 +3112,7 @@ function redactSensitiveFields(obj) {
3004
3112
  if (obj === null || obj === void 0) return obj;
3005
3113
  if (typeof obj !== "object") return obj;
3006
3114
  if (Array.isArray(obj)) return obj.map(redactSensitiveFields);
3007
- const sensitiveKeys = ["apitoken", "token", "secret", "password"];
3115
+ const sensitiveKeys = ["apitoken", "token", "secret", "password", "credential"];
3008
3116
  const result = {};
3009
3117
  for (const [key, value] of Object.entries(obj)) {
3010
3118
  const lowerKey = key.toLowerCase();
@@ -3269,6 +3377,17 @@ ${errorMessages.join("\n")}`
3269
3377
  var _a;
3270
3378
  return ((_a = settings2 == null ? void 0 : settings2.plan) == null ? void 0 : _a.reviewer) ?? "none";
3271
3379
  }
3380
+ /**
3381
+ * Get the plan command waveVerification setting with default applied
3382
+ * Default is true (verification tasks are generated)
3383
+ *
3384
+ * @param settings - Pre-loaded settings object
3385
+ * @returns Whether wave verification is enabled
3386
+ */
3387
+ getPlanWaveVerification(settings2) {
3388
+ var _a;
3389
+ return ((_a = settings2 == null ? void 0 : settings2.plan) == null ? void 0 : _a.waveVerification) !== false;
3390
+ }
3272
3391
  /**
3273
3392
  * Get the session summary model with default applied
3274
3393
  * Default is defined in SummarySettingsSchema
@@ -3730,8 +3849,672 @@ var JiraWikiSanitizer = class {
3730
3849
  }
3731
3850
  };
3732
3851
 
3852
+ // src/lib/providers/bitbucket/BitBucketApiClient.ts
3853
+ import https2 from "https";
3854
+ var BitBucketApiClient = class {
3855
+ constructor(config) {
3856
+ this.baseUrl = "https://api.bitbucket.org/2.0";
3857
+ const credentials = Buffer.from(`${config.username}:${config.apiToken}`).toString("base64");
3858
+ this.authHeader = `Basic ${credentials}`;
3859
+ this.workspace = config.workspace;
3860
+ this.repoSlug = config.repoSlug;
3861
+ }
3862
+ /**
3863
+ * Make an HTTP request to BitBucket API
3864
+ */
3865
+ async request(method, endpoint, body) {
3866
+ const url = endpoint.startsWith("http://") || endpoint.startsWith("https://") ? new URL(endpoint) : new URL(`${this.baseUrl}${endpoint}`);
3867
+ if ((endpoint.startsWith("http://") || endpoint.startsWith("https://")) && url.hostname !== "api.bitbucket.org") {
3868
+ throw new Error(`Refusing to send authenticated request to unexpected host: ${url.hostname} (expected api.bitbucket.org)`);
3869
+ }
3870
+ getLogger().debug(`BitBucket API ${method} request`, { url: url.toString() });
3871
+ return new Promise((resolve, reject) => {
3872
+ const options = {
3873
+ hostname: url.hostname,
3874
+ port: url.port || 443,
3875
+ path: url.pathname + url.search,
3876
+ method,
3877
+ headers: {
3878
+ "Authorization": this.authHeader,
3879
+ "Accept": "application/json",
3880
+ "Content-Type": "application/json"
3881
+ }
3882
+ };
3883
+ const req = https2.request(options, (res) => {
3884
+ let data = "";
3885
+ res.on("data", (chunk) => {
3886
+ data += chunk;
3887
+ });
3888
+ res.on("end", () => {
3889
+ if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
3890
+ reject(new Error(`BitBucket API error (${res.statusCode}): ${data}`));
3891
+ return;
3892
+ }
3893
+ if (res.statusCode === 204 || !data) {
3894
+ resolve({});
3895
+ return;
3896
+ }
3897
+ try {
3898
+ resolve(JSON.parse(data));
3899
+ } catch (error) {
3900
+ reject(new Error(`Failed to parse BitBucket API response: ${error}`));
3901
+ }
3902
+ });
3903
+ });
3904
+ req.on("error", (error) => {
3905
+ reject(new Error(`BitBucket API request failed: ${error.message}`));
3906
+ });
3907
+ if (body) {
3908
+ req.write(JSON.stringify(body));
3909
+ }
3910
+ req.end();
3911
+ });
3912
+ }
3913
+ /**
3914
+ * Make a GET request to BitBucket API
3915
+ */
3916
+ async get(endpoint) {
3917
+ return this.request("GET", endpoint);
3918
+ }
3919
+ /**
3920
+ * Make a POST request to BitBucket API
3921
+ */
3922
+ async post(endpoint, body) {
3923
+ return this.request("POST", endpoint, body);
3924
+ }
3925
+ /**
3926
+ * Make a PUT request to BitBucket API
3927
+ */
3928
+ async put(endpoint, body) {
3929
+ return this.request("PUT", endpoint, body);
3930
+ }
3931
+ /**
3932
+ * Get repository information
3933
+ */
3934
+ async getRepository(workspace, repoSlug) {
3935
+ return this.get(`/repositories/${workspace}/${repoSlug}`);
3936
+ }
3937
+ /**
3938
+ * Get a pull request by ID
3939
+ */
3940
+ async getPullRequest(workspace, repoSlug, prId) {
3941
+ return this.get(
3942
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}`
3943
+ );
3944
+ }
3945
+ /**
3946
+ * List open pull requests for a branch
3947
+ *
3948
+ * Note: BitBucket uses BBQL (BitBucket Query Language) for filtering.
3949
+ * The q parameter must use the format: q=source.branch.name="branch-name"
3950
+ * When using BBQL, we include state filter in the query to ensure it's applied.
3951
+ * See: https://developer.atlassian.com/cloud/bitbucket/rest/intro/#filtering
3952
+ */
3953
+ async listPullRequests(workspace, repoSlug, sourceBranch) {
3954
+ let endpoint = `/repositories/${workspace}/${repoSlug}/pullrequests`;
3955
+ if (sourceBranch) {
3956
+ const safeBranch = sourceBranch.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3957
+ const query = `state="OPEN" AND source.branch.name="${safeBranch}"`;
3958
+ endpoint += `?q=${encodeURIComponent(query)}`;
3959
+ } else {
3960
+ endpoint += `?state=OPEN`;
3961
+ }
3962
+ const response = await this.get(endpoint);
3963
+ return response.values;
3964
+ }
3965
+ /**
3966
+ * Create a pull request
3967
+ */
3968
+ async createPullRequest(workspace, repoSlug, title, description, sourceBranch, destinationBranch, reviewerAccountIds) {
3969
+ const payload = {
3970
+ title,
3971
+ description,
3972
+ source: {
3973
+ branch: {
3974
+ name: sourceBranch
3975
+ }
3976
+ },
3977
+ destination: {
3978
+ branch: {
3979
+ name: destinationBranch
3980
+ }
3981
+ }
3982
+ };
3983
+ if (reviewerAccountIds && reviewerAccountIds.length > 0) {
3984
+ payload.reviewers = reviewerAccountIds.map((id) => ({ account_id: id }));
3985
+ }
3986
+ return this.post(
3987
+ `/repositories/${workspace}/${repoSlug}/pullrequests`,
3988
+ payload
3989
+ );
3990
+ }
3991
+ /**
3992
+ * Add a comment to a pull request
3993
+ */
3994
+ async addPRComment(workspace, repoSlug, prId, content) {
3995
+ return this.post(
3996
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`,
3997
+ {
3998
+ content: {
3999
+ raw: content
4000
+ }
4001
+ }
4002
+ );
4003
+ }
4004
+ /**
4005
+ * Update an existing comment on a pull request
4006
+ */
4007
+ async updatePRComment(workspace, repoSlug, prId, commentId, content) {
4008
+ return this.put(
4009
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments/${commentId}`,
4010
+ {
4011
+ content: {
4012
+ raw: content
4013
+ }
4014
+ }
4015
+ );
4016
+ }
4017
+ /**
4018
+ * List all comments on a pull request with pagination
4019
+ */
4020
+ async listPRComments(workspace, repoSlug, prId) {
4021
+ const MAX_PAGES = 50;
4022
+ const allComments = [];
4023
+ let nextUrl = `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`;
4024
+ let pageCount = 0;
4025
+ while (nextUrl) {
4026
+ pageCount++;
4027
+ if (pageCount > MAX_PAGES) {
4028
+ console.error(`BitBucket listPRComments: exceeded maximum pagination limit of ${MAX_PAGES} pages, returning ${allComments.length} comments collected so far`);
4029
+ break;
4030
+ }
4031
+ const response = await this.get(nextUrl);
4032
+ allComments.push(...response.values);
4033
+ nextUrl = response.next ?? null;
4034
+ }
4035
+ getLogger().debug(`Fetched ${allComments.length} PR comments from BitBucket`);
4036
+ return allComments;
4037
+ }
4038
+ /**
4039
+ * Add an inline comment to a specific file and line in a pull request
4040
+ */
4041
+ async addInlinePRComment(workspace, repoSlug, prId, content, filePath, line) {
4042
+ return this.post(
4043
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`,
4044
+ {
4045
+ content: {
4046
+ raw: content
4047
+ },
4048
+ inline: {
4049
+ to: line,
4050
+ path: filePath
4051
+ }
4052
+ }
4053
+ );
4054
+ }
4055
+ /**
4056
+ * Find workspace members by usernames
4057
+ * Returns a map of username -> account_id for resolved users
4058
+ * Handles pagination to fetch all workspace members
4059
+ */
4060
+ async findUsersByUsername(workspace, usernames) {
4061
+ const result = /* @__PURE__ */ new Map();
4062
+ const allMembers = await this.getAllWorkspaceMembers(workspace);
4063
+ getLogger().debug(`Resolving ${usernames.length} usernames against ${allMembers.length} workspace members`);
4064
+ for (const username of usernames) {
4065
+ const usernameLower = username.toLowerCase();
4066
+ const member = allMembers.find(
4067
+ (m) => {
4068
+ var _a;
4069
+ return ((_a = m.user.nickname) == null ? void 0 : _a.toLowerCase()) === usernameLower || m.user.display_name.toLowerCase() === usernameLower;
4070
+ }
4071
+ );
4072
+ if (member) {
4073
+ result.set(username, member.user.account_id);
4074
+ getLogger().debug(`Resolved reviewer ${username} to account ID ${member.user.account_id}`);
4075
+ } else {
4076
+ getLogger().warn(`Could not resolve reviewer ${username} to a BitBucket account ID`);
4077
+ }
4078
+ }
4079
+ return result;
4080
+ }
4081
+ /**
4082
+ * Fetch all workspace members with pagination
4083
+ */
4084
+ async getAllWorkspaceMembers(workspace) {
4085
+ const allMembers = [];
4086
+ let nextUrl = `/workspaces/${workspace}/members`;
4087
+ while (nextUrl) {
4088
+ const response = await this.get(nextUrl);
4089
+ allMembers.push(...response.values);
4090
+ nextUrl = response.next ?? null;
4091
+ }
4092
+ getLogger().debug(`Fetched ${allMembers.length} workspace members from BitBucket`);
4093
+ return allMembers;
4094
+ }
4095
+ /**
4096
+ * Get the currently authenticated user
4097
+ */
4098
+ async getCurrentUser() {
4099
+ return this.get("/user");
4100
+ }
4101
+ /**
4102
+ * Test connection to BitBucket API
4103
+ */
4104
+ async testConnection() {
4105
+ try {
4106
+ await this.getCurrentUser();
4107
+ return true;
4108
+ } catch (error) {
4109
+ getLogger().error("BitBucket connection test failed", { error });
4110
+ return false;
4111
+ }
4112
+ }
4113
+ /**
4114
+ * Get configured workspace
4115
+ */
4116
+ getWorkspace() {
4117
+ return this.workspace;
4118
+ }
4119
+ /**
4120
+ * Get configured repository slug
4121
+ */
4122
+ getRepoSlug() {
4123
+ return this.repoSlug;
4124
+ }
4125
+ };
4126
+
4127
+ // src/utils/remote.ts
4128
+ import { execa as execa3 } from "execa";
4129
+ async function parseGitRemotes(cwd) {
4130
+ const result = await execa3("git", ["remote", "-v"], {
4131
+ cwd: cwd ?? process.cwd(),
4132
+ encoding: "utf8"
4133
+ });
4134
+ const lines = result.stdout.trim().split("\n");
4135
+ const remoteMap = /* @__PURE__ */ new Map();
4136
+ for (const line of lines) {
4137
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((fetch|push)\)/);
4138
+ if (!match) continue;
4139
+ const name = match[1];
4140
+ const url = match[2];
4141
+ if (!name || !url) continue;
4142
+ if (remoteMap.has(name)) continue;
4143
+ const ownerRepo = extractOwnerRepoFromUrl(url);
4144
+ if (!ownerRepo) continue;
4145
+ remoteMap.set(name, {
4146
+ name,
4147
+ url,
4148
+ owner: ownerRepo.owner,
4149
+ repo: ownerRepo.repo
4150
+ });
4151
+ }
4152
+ return Array.from(remoteMap.values());
4153
+ }
4154
+ function extractOwnerRepoFromUrl(url) {
4155
+ const cleanUrl = url.replace(/\.git$/, "");
4156
+ const githubHttpsMatch = cleanUrl.match(/https?:\/\/github\.com\/([^/]+)\/([^/]+)/);
4157
+ if ((githubHttpsMatch == null ? void 0 : githubHttpsMatch[1]) && (githubHttpsMatch == null ? void 0 : githubHttpsMatch[2])) {
4158
+ return { owner: githubHttpsMatch[1], repo: githubHttpsMatch[2] };
4159
+ }
4160
+ const githubSshMatch = cleanUrl.match(/git@github\.com:([^/]+)\/(.+)/);
4161
+ if ((githubSshMatch == null ? void 0 : githubSshMatch[1]) && (githubSshMatch == null ? void 0 : githubSshMatch[2])) {
4162
+ return { owner: githubSshMatch[1], repo: githubSshMatch[2] };
4163
+ }
4164
+ const bitbucketHttpsMatch = cleanUrl.match(/https?:\/\/bitbucket\.org\/([^/]+)\/([^/]+)/);
4165
+ if ((bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[1]) && (bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[2])) {
4166
+ return { owner: bitbucketHttpsMatch[1], repo: bitbucketHttpsMatch[2] };
4167
+ }
4168
+ const bitbucketSshMatch = cleanUrl.match(/git@bitbucket\.org:([^/]+)\/(.+)/);
4169
+ if ((bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[1]) && (bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[2])) {
4170
+ return { owner: bitbucketSshMatch[1], repo: bitbucketSshMatch[2] };
4171
+ }
4172
+ return null;
4173
+ }
4174
+
4175
+ // src/lib/providers/bitbucket/BitBucketVCSProvider.ts
4176
+ var BitBucketVCSProvider = class _BitBucketVCSProvider {
4177
+ constructor(config) {
4178
+ this.providerName = "bitbucket";
4179
+ this.supportsForks = true;
4180
+ this.supportsDraftPRs = false;
4181
+ this.client = new BitBucketApiClient(config);
4182
+ if (config.reviewers) {
4183
+ this.reviewerUsernames = config.reviewers;
4184
+ }
4185
+ }
4186
+ /**
4187
+ * Create a BitBucketVCSProvider from IloomSettings
4188
+ * Extracts and validates BitBucket config from settings
4189
+ */
4190
+ static fromSettings(settings2) {
4191
+ var _a;
4192
+ const bbSettings = (_a = settings2.versionControl) == null ? void 0 : _a.bitbucket;
4193
+ if (!(bbSettings == null ? void 0 : bbSettings.username)) {
4194
+ throw new Error("BitBucket username is required. Configure versionControl.bitbucket.username in .iloom/settings.json");
4195
+ }
4196
+ if (!(bbSettings == null ? void 0 : bbSettings.apiToken)) {
4197
+ throw new Error("BitBucket API token is required. Configure versionControl.bitbucket.apiToken in .iloom/settings.local.json");
4198
+ }
4199
+ const config = {
4200
+ username: bbSettings.username,
4201
+ apiToken: bbSettings.apiToken
4202
+ };
4203
+ if (bbSettings.workspace) {
4204
+ config.workspace = bbSettings.workspace;
4205
+ }
4206
+ if (bbSettings.repoSlug) {
4207
+ config.repoSlug = bbSettings.repoSlug;
4208
+ }
4209
+ if (bbSettings.reviewers) {
4210
+ config.reviewers = bbSettings.reviewers;
4211
+ }
4212
+ return new _BitBucketVCSProvider(config);
4213
+ }
4214
+ /**
4215
+ * Check if a PR already exists for the given branch
4216
+ */
4217
+ async checkForExistingPR(branchName, cwd) {
4218
+ try {
4219
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4220
+ const prs = await this.client.listPullRequests(workspace, repoSlug, branchName);
4221
+ if (prs.length > 0 && prs[0]) {
4222
+ const pr = prs[0];
4223
+ return {
4224
+ number: pr.id,
4225
+ url: pr.links.html.href
4226
+ };
4227
+ }
4228
+ return null;
4229
+ } catch (error) {
4230
+ if (error instanceof Error) {
4231
+ const statusMatch = error.message.match(/BitBucket API error \((\d+)\)/);
4232
+ if (statusMatch == null ? void 0 : statusMatch[1]) {
4233
+ const statusCode = parseInt(statusMatch[1], 10);
4234
+ if (statusCode === 401 || statusCode === 403) {
4235
+ throw error;
4236
+ }
4237
+ }
4238
+ }
4239
+ getLogger().debug("Error checking for existing PR", { error });
4240
+ return null;
4241
+ }
4242
+ }
4243
+ /**
4244
+ * Create a pull request
4245
+ */
4246
+ async createPR(branchName, title, body, baseBranch, cwd) {
4247
+ var _a, _b;
4248
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4249
+ getLogger().info(`Creating BitBucket PR in ${workspace}/${repoSlug}`);
4250
+ getLogger().debug("PR details", { branchName, title, baseBranch });
4251
+ let reviewerIds;
4252
+ if (this.reviewerUsernames && this.reviewerUsernames.length > 0) {
4253
+ reviewerIds = await this.resolveReviewerUsernames(workspace, this.reviewerUsernames);
4254
+ if (reviewerIds.length > 0) {
4255
+ const currentUser = await this.client.getCurrentUser();
4256
+ const originalCount = reviewerIds.length;
4257
+ reviewerIds = reviewerIds.filter((id) => id !== currentUser.account_id);
4258
+ if (reviewerIds.length < originalCount) {
4259
+ getLogger().debug(
4260
+ `Removed current user (${currentUser.display_name}) from reviewers list - PR author cannot be a reviewer`
4261
+ );
4262
+ }
4263
+ }
4264
+ }
4265
+ const pr = await this.client.createPullRequest(
4266
+ workspace,
4267
+ repoSlug,
4268
+ title,
4269
+ body,
4270
+ branchName,
4271
+ baseBranch,
4272
+ reviewerIds
4273
+ );
4274
+ if (!(pr == null ? void 0 : pr.id) || !((_b = (_a = pr == null ? void 0 : pr.links) == null ? void 0 : _a.html) == null ? void 0 : _b.href)) {
4275
+ getLogger().error("Invalid BitBucket API response", { pr });
4276
+ throw new Error(
4277
+ `BitBucket API returned invalid PR response. Expected PR with id and links.html.href, got: ${JSON.stringify(pr)}`
4278
+ );
4279
+ }
4280
+ getLogger().info(`BitBucket PR #${pr.id} created successfully`);
4281
+ return { url: pr.links.html.href, number: pr.id, wasExisting: false };
4282
+ }
4283
+ /**
4284
+ * Fetch PR details
4285
+ */
4286
+ async fetchPR(prNumber, cwd) {
4287
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4288
+ const bbPR = await this.client.getPullRequest(workspace, repoSlug, prNumber);
4289
+ return this.mapBitBucketPRToPullRequest(bbPR);
4290
+ }
4291
+ /**
4292
+ * Get PR URL
4293
+ */
4294
+ async getPRUrl(prNumber, cwd) {
4295
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4296
+ const bbPR = await this.client.getPullRequest(workspace, repoSlug, prNumber);
4297
+ return bbPR.links.html.href;
4298
+ }
4299
+ /**
4300
+ * Create a comment on a PR
4301
+ */
4302
+ async createPRComment(prNumber, body, cwd) {
4303
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4304
+ getLogger().debug("Creating BitBucket PR comment", { workspace, repoSlug, prNumber });
4305
+ const comment = await this.client.addPRComment(workspace, repoSlug, prNumber, body);
4306
+ return { id: String(comment.id), url: comment.links.html.href };
4307
+ }
4308
+ /**
4309
+ * Update an existing comment on a PR
4310
+ */
4311
+ async updatePRComment(prNumber, commentId, body, cwd) {
4312
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4313
+ getLogger().debug("Updating BitBucket PR comment", { workspace, repoSlug, prNumber, commentId });
4314
+ const numericCommentId = parseInt(commentId, 10);
4315
+ if (isNaN(numericCommentId)) {
4316
+ throw new Error(`Invalid comment ID "${commentId}": expected a numeric value`);
4317
+ }
4318
+ const comment = await this.client.updatePRComment(workspace, repoSlug, prNumber, numericCommentId, body);
4319
+ return { id: String(comment.id), url: comment.links.html.href };
4320
+ }
4321
+ /**
4322
+ * Get inline review comments on a PR
4323
+ * Fetches all comments and filters for those with inline metadata
4324
+ */
4325
+ async getReviewComments(prNumber, cwd) {
4326
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4327
+ getLogger().debug("Fetching BitBucket PR review comments", { workspace, repoSlug, prNumber });
4328
+ const allComments = await this.client.listPRComments(workspace, repoSlug, prNumber);
4329
+ const inlineComments = [];
4330
+ for (const c of allComments) {
4331
+ if (c.inline == null) continue;
4332
+ inlineComments.push({
4333
+ id: String(c.id),
4334
+ body: c.content.raw,
4335
+ path: c.inline.path,
4336
+ line: c.inline.to ?? c.inline.from ?? null,
4337
+ side: null,
4338
+ // BitBucket doesn't have a "side" concept like GitHub
4339
+ author: c.user ? { id: c.user.uuid, displayName: c.user.display_name } : null,
4340
+ createdAt: c.created_on ?? "",
4341
+ updatedAt: c.updated_on ?? null,
4342
+ inReplyToId: null
4343
+ // BitBucket uses nested comments, not reply chains
4344
+ });
4345
+ }
4346
+ return inlineComments;
4347
+ }
4348
+ /**
4349
+ * Create an inline review comment on a specific file and line in a PR
4350
+ */
4351
+ async createReviewComment(prNumber, path3, line, body, cwd) {
4352
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4353
+ getLogger().debug("Creating BitBucket inline PR comment", { workspace, repoSlug, prNumber, path: path3, line });
4354
+ const comment = await this.client.addInlinePRComment(workspace, repoSlug, prNumber, body, path3, line);
4355
+ return { id: String(comment.id), url: comment.links.html.href };
4356
+ }
4357
+ /**
4358
+ * List open pull requests for the repository
4359
+ * Uses getWorkspaceAndRepo for auto-detection from git remotes
4360
+ */
4361
+ async listPullRequests(cwd) {
4362
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4363
+ return this.client.listPullRequests(workspace, repoSlug);
4364
+ }
4365
+ /**
4366
+ * Detect repository from git remote
4367
+ */
4368
+ async detectRepository(cwd) {
4369
+ try {
4370
+ const remotes = await parseGitRemotes(cwd);
4371
+ const bbRemote = remotes.find(
4372
+ (r) => r.url.includes("bitbucket.org")
4373
+ );
4374
+ if (!bbRemote) {
4375
+ return null;
4376
+ }
4377
+ return {
4378
+ owner: bbRemote.owner,
4379
+ // workspace
4380
+ repo: bbRemote.repo
4381
+ };
4382
+ } catch (error) {
4383
+ getLogger().error("Failed to detect BitBucket repository", { error });
4384
+ return null;
4385
+ }
4386
+ }
4387
+ /**
4388
+ * Get target remote for PR operations
4389
+ */
4390
+ async getTargetRemote(_cwd) {
4391
+ return "origin";
4392
+ }
4393
+ /**
4394
+ * Get workspace and repository slug from config or git remote
4395
+ */
4396
+ async getWorkspaceAndRepo(cwd) {
4397
+ let workspace = this.client.getWorkspace();
4398
+ let repoSlug = this.client.getRepoSlug();
4399
+ if (!workspace || !repoSlug) {
4400
+ const detected = await this.detectRepository(cwd);
4401
+ if (!detected) {
4402
+ throw new Error(
4403
+ "Could not determine BitBucket workspace/repository. Either configure them in settings or ensure git remote points to bitbucket.org"
4404
+ );
4405
+ }
4406
+ workspace = workspace ?? detected.owner;
4407
+ repoSlug = repoSlug ?? detected.repo;
4408
+ }
4409
+ return { workspace, repoSlug };
4410
+ }
4411
+ /**
4412
+ * Resolve reviewer usernames to BitBucket account IDs
4413
+ * Warns for any usernames that cannot be resolved but continues with partial list
4414
+ */
4415
+ async resolveReviewerUsernames(workspace, usernames) {
4416
+ getLogger().debug(`Resolving ${usernames.length} reviewer username(s) to BitBucket account IDs`);
4417
+ const usernameToAccountId = await this.client.findUsersByUsername(workspace, usernames);
4418
+ const resolvedIds = [];
4419
+ const unresolvedUsernames = [];
4420
+ for (const username of usernames) {
4421
+ const accountId = usernameToAccountId.get(username);
4422
+ if (accountId) {
4423
+ resolvedIds.push(accountId);
4424
+ } else {
4425
+ unresolvedUsernames.push(username);
4426
+ }
4427
+ }
4428
+ if (unresolvedUsernames.length > 0) {
4429
+ getLogger().warn(
4430
+ `Could not resolve ${unresolvedUsernames.length} reviewer username(s) to BitBucket account IDs: ${unresolvedUsernames.join(", ")}. These reviewers will not be added to the PR.`
4431
+ );
4432
+ }
4433
+ if (resolvedIds.length > 0) {
4434
+ getLogger().info(`Resolved ${resolvedIds.length} reviewer(s) for PR`);
4435
+ }
4436
+ return resolvedIds;
4437
+ }
4438
+ /**
4439
+ * Map BitBucket PR to generic PullRequest type
4440
+ */
4441
+ mapBitBucketPRToPullRequest(bbPR) {
4442
+ let state;
4443
+ if (bbPR.state === "OPEN") {
4444
+ state = "open";
4445
+ } else if (bbPR.state === "MERGED") {
4446
+ state = "merged";
4447
+ } else {
4448
+ state = "closed";
4449
+ }
4450
+ return {
4451
+ number: bbPR.id,
4452
+ title: bbPR.title,
4453
+ body: bbPR.description,
4454
+ state,
4455
+ branch: bbPR.source.branch.name,
4456
+ baseBranch: bbPR.destination.branch.name,
4457
+ url: bbPR.links.html.href,
4458
+ isDraft: false
4459
+ // BitBucket doesn't have draft PRs
4460
+ };
4461
+ }
4462
+ };
4463
+
4464
+ // src/lib/VCSProviderFactory.ts
4465
+ var VCSProviderFactory = class {
4466
+ /**
4467
+ * Create a VersionControlProvider instance based on settings configuration
4468
+ *
4469
+ * @param settings - iloom settings containing versionControl.provider
4470
+ * @returns VersionControlProvider instance configured for the specified provider
4471
+ * @throws Error if provider type is not supported or required config is missing
4472
+ */
4473
+ static create(settings2) {
4474
+ var _a;
4475
+ const provider = (_a = settings2.versionControl) == null ? void 0 : _a.provider;
4476
+ if (!provider) {
4477
+ getLogger().debug("VCSProviderFactory: No versionControl.provider configured, using legacy PRManager");
4478
+ return null;
4479
+ }
4480
+ getLogger().debug(`VCSProviderFactory: Creating VCS provider for "${provider}"`);
4481
+ switch (provider) {
4482
+ case "github":
4483
+ getLogger().debug("VCSProviderFactory: GitHub uses legacy PRManager, returning null");
4484
+ return null;
4485
+ case "bitbucket": {
4486
+ getLogger().debug(`VCSProviderFactory: Creating BitBucketVCSProvider from settings`);
4487
+ return BitBucketVCSProvider.fromSettings(settings2);
4488
+ }
4489
+ default:
4490
+ throw new Error(`Unsupported VCS provider: ${provider}`);
4491
+ }
4492
+ }
4493
+ /**
4494
+ * Check if a VCS provider is configured
4495
+ *
4496
+ * @param settings - iloom settings
4497
+ * @returns true if versionControl provider is configured
4498
+ */
4499
+ static isConfigured(settings2) {
4500
+ var _a, _b;
4501
+ return ((_a = settings2.versionControl) == null ? void 0 : _a.provider) !== void 0 && ((_b = settings2.versionControl) == null ? void 0 : _b.provider) !== "github";
4502
+ }
4503
+ /**
4504
+ * Get the configured provider name from settings
4505
+ *
4506
+ * @param settings - iloom settings
4507
+ * @returns Provider type string or undefined if not configured
4508
+ */
4509
+ static getProviderName(settings2) {
4510
+ var _a;
4511
+ return (_a = settings2.versionControl) == null ? void 0 : _a.provider;
4512
+ }
4513
+ };
4514
+
3733
4515
  // src/mcp/issue-management-server.ts
3734
4516
  var settings;
4517
+ var vcsProvider = null;
3735
4518
  function validateEnvironment() {
3736
4519
  const provider = process.env.ISSUE_PROVIDER;
3737
4520
  if (!provider) {
@@ -3849,7 +4632,7 @@ server.registerTool(
3849
4632
  "get_pr",
3850
4633
  {
3851
4634
  title: "Get Pull Request",
3852
- description: "Fetch pull request details including title, body, comments, files, commits, and branch information. PRs only exist on GitHub, so this tool always uses GitHub regardless of configured issue tracker. Author fields have normalized core fields: { id, displayName } plus provider-specific fields.",
4635
+ description: "Fetch pull request details including title, body, comments, files, commits, and branch information. Uses the configured VCS provider (GitHub or BitBucket). Falls back to GitHub when no VCS provider is configured. Author fields have normalized core fields: { id, displayName } plus provider-specific fields.",
3853
4636
  inputSchema: {
3854
4637
  number: z2.string().describe("The PR number"),
3855
4638
  includeComments: z2.boolean().optional().describe("Whether to include comments (default: true)"),
@@ -3900,6 +4683,34 @@ server.registerTool(
3900
4683
  async ({ number, includeComments, repo }) => {
3901
4684
  console.error(`Fetching PR ${number}${repo ? ` from ${repo}` : ""}`);
3902
4685
  try {
4686
+ if (vcsProvider) {
4687
+ if (repo) {
4688
+ console.error(`VCS provider path does not support 'repo' override parameter, using configured repository`);
4689
+ }
4690
+ const pr = await vcsProvider.fetchPR(parseInt(number, 10));
4691
+ const result2 = {
4692
+ id: String(pr.number),
4693
+ number: pr.number,
4694
+ title: pr.title,
4695
+ body: pr.body,
4696
+ state: pr.state.toUpperCase(),
4697
+ url: pr.url,
4698
+ headRefName: pr.branch,
4699
+ baseRefName: pr.baseBranch,
4700
+ author: null,
4701
+ isDraft: pr.isDraft
4702
+ };
4703
+ console.error(`PR fetched successfully: #${result2.number} - ${result2.title}`);
4704
+ return {
4705
+ content: [
4706
+ {
4707
+ type: "text",
4708
+ text: JSON.stringify(result2)
4709
+ }
4710
+ ],
4711
+ structuredContent: result2
4712
+ };
4713
+ }
3903
4714
  const provider = new GitHubIssueManagementProvider();
3904
4715
  const result = await provider.getPR({ number, includeComments, repo });
3905
4716
  console.error(`PR fetched successfully: #${result.number} - ${result.title}`);
@@ -3923,7 +4734,7 @@ server.registerTool(
3923
4734
  "get_review_comments",
3924
4735
  {
3925
4736
  title: "Get PR Review Comments",
3926
- description: "Fetch inline code review comments on a pull request (comments on specific files and lines). Returns comments with file path, line number, diff side, author, and reply threading. Optionally filter by review ID. PRs only exist on GitHub, so this tool always uses GitHub.",
4737
+ description: "Fetch inline code review comments on a pull request (comments on specific files and lines). Returns comments with file path, line number, diff side, author, and reply threading. Uses the configured VCS provider when available, falls back to GitHub.",
3927
4738
  inputSchema: {
3928
4739
  number: z2.string().describe("The PR number"),
3929
4740
  reviewId: z2.string().optional().describe("Optional review ID to filter comments by a specific review"),
@@ -3951,6 +4762,30 @@ server.registerTool(
3951
4762
  async ({ number, reviewId, repo }) => {
3952
4763
  console.error(`Fetching review comments for PR ${number}${reviewId ? ` (review ${reviewId})` : ""}${repo ? ` from ${repo}` : ""}`);
3953
4764
  try {
4765
+ if (vcsProvider == null ? void 0 : vcsProvider.getReviewComments) {
4766
+ if (repo) {
4767
+ console.error(`VCS provider path does not support 'repo' override parameter, using configured repository`);
4768
+ }
4769
+ if (reviewId) {
4770
+ console.error(`VCS provider path does not support 'reviewId' filter, returning all inline comments`);
4771
+ }
4772
+ const reviewComments = await vcsProvider.getReviewComments(parseInt(number, 10));
4773
+ const comments2 = reviewComments.map((c) => ({
4774
+ ...c,
4775
+ pullRequestReviewId: null
4776
+ }));
4777
+ console.error(`Review comments fetched successfully: ${comments2.length} comments`);
4778
+ const result2 = { comments: comments2 };
4779
+ return {
4780
+ content: [
4781
+ {
4782
+ type: "text",
4783
+ text: JSON.stringify(result2)
4784
+ }
4785
+ ],
4786
+ structuredContent: result2
4787
+ };
4788
+ }
3954
4789
  const provider = new GitHubIssueManagementProvider();
3955
4790
  const comments = await provider.getReviewComments({ number, reviewId, repo });
3956
4791
  console.error(`Review comments fetched successfully: ${comments.length} comments`);
@@ -4039,6 +4874,22 @@ server.registerTool(
4039
4874
  console.error(`Creating ${type} comment on ${number}`);
4040
4875
  try {
4041
4876
  const sanitizedBody = JiraWikiSanitizer.sanitize(body);
4877
+ if (type === "pr" && vcsProvider) {
4878
+ const vcsResult = await vcsProvider.createPRComment(parseInt(number, 10), sanitizedBody);
4879
+ console.error(
4880
+ `Comment created successfully: ${vcsResult.id} at ${vcsResult.url}`
4881
+ );
4882
+ const result2 = { id: vcsResult.id, url: vcsResult.url, created_at: (/* @__PURE__ */ new Date()).toISOString() };
4883
+ return {
4884
+ content: [
4885
+ {
4886
+ type: "text",
4887
+ text: JSON.stringify(result2)
4888
+ }
4889
+ ],
4890
+ structuredContent: result2
4891
+ };
4892
+ }
4042
4893
  const providerType = type === "pr" ? "github" : process.env.ISSUE_PROVIDER;
4043
4894
  const provider = IssueManagementProviderFactory.create(providerType, settings);
4044
4895
  const result = await provider.createComment({ number, body: sanitizedBody, type });
@@ -4083,6 +4934,22 @@ server.registerTool(
4083
4934
  console.error(`Updating comment ${commentId} on ${type === "pr" ? "PR" : "issue"} ${number}`);
4084
4935
  try {
4085
4936
  const sanitizedBody = JiraWikiSanitizer.sanitize(body);
4937
+ if (type === "pr" && (vcsProvider == null ? void 0 : vcsProvider.updatePRComment)) {
4938
+ const vcsResult = await vcsProvider.updatePRComment(parseInt(number, 10), commentId, sanitizedBody);
4939
+ console.error(
4940
+ `Comment updated successfully: ${vcsResult.id} at ${vcsResult.url}`
4941
+ );
4942
+ const result2 = { id: vcsResult.id, url: vcsResult.url, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
4943
+ return {
4944
+ content: [
4945
+ {
4946
+ type: "text",
4947
+ text: JSON.stringify(result2)
4948
+ }
4949
+ ],
4950
+ structuredContent: result2
4951
+ };
4952
+ }
4086
4953
  const providerType = type === "pr" ? "github" : process.env.ISSUE_PROVIDER;
4087
4954
  const provider = IssueManagementProviderFactory.create(providerType, settings);
4088
4955
  const result = await provider.updateComment({ commentId, number, body: sanitizedBody });
@@ -4532,6 +5399,19 @@ async function main() {
4532
5399
  const settingsManager = new SettingsManager();
4533
5400
  settings = await settingsManager.loadSettings();
4534
5401
  console.error("Settings loaded");
5402
+ try {
5403
+ vcsProvider = VCSProviderFactory.create(settings);
5404
+ if (vcsProvider) {
5405
+ console.error(`VCS provider initialized: ${vcsProvider.providerName}`);
5406
+ }
5407
+ } catch (error) {
5408
+ if (error instanceof Error && (error.message.includes("is required") || error.message.includes("Unsupported VCS provider"))) {
5409
+ console.error(`Failed to initialize VCS provider (falling back to GitHub): ${error.message}`);
5410
+ vcsProvider = null;
5411
+ } else {
5412
+ throw error;
5413
+ }
5414
+ }
4535
5415
  const provider = validateEnvironment();
4536
5416
  console.error("Environment validated");
4537
5417
  console.error(`Issue management provider: ${provider}`);