@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
@@ -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,19 +2827,71 @@ 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")
2800
2883
  });
2884
+ var SupabaseSettingsSchema = z.object({
2885
+ projectRef: z.string().min(1).describe('Supabase project reference ID (e.g., "abcdefghijklmnop")'),
2886
+ parentBranch: z.string().min(1).optional().describe("Reserved for future use. Supabase currently always branches from the default branch."),
2887
+ withData: z.boolean().optional().describe("Whether to include data when creating a new branch (defaults to true)")
2888
+ });
2801
2889
  var DatabaseProvidersSettingsSchema = z.object({
2802
2890
  neon: NeonSettingsSchema.optional().describe(
2803
2891
  "Neon database configuration. Requires Neon CLI installed and authenticated for database branching."
2892
+ ),
2893
+ supabase: SupabaseSettingsSchema.optional().describe(
2894
+ "Supabase database configuration. Requires Supabase CLI installed and authenticated for database branching."
2804
2895
  )
2805
2896
  }).optional();
2806
2897
  var IloomSettingsSchema = z.object({
@@ -2845,6 +2936,7 @@ var IloomSettingsSchema = z.object({
2845
2936
  "Session summary generation configuration. Model defaults to sonnet when not configured."
2846
2937
  ),
2847
2938
  capabilities: CapabilitiesSettingsSchema.describe("Project capability configurations"),
2939
+ devServer: DevServerSettingsSchema.optional().describe("Docker-based dev server configuration"),
2848
2940
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
2849
2941
  issueManagement: z.object({
2850
2942
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
@@ -2869,17 +2961,28 @@ var IloomSettingsSchema = z.object({
2869
2961
  doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
2870
2962
  }).optional()
2871
2963
  }).optional().describe("Issue management configuration"),
2964
+ versionControl: z.object({
2965
+ provider: z.enum(["github", "bitbucket"]).optional().default("github").describe("Version control provider (github, bitbucket)"),
2966
+ bitbucket: z.object({
2967
+ username: z.string().min(1, "BitBucket username cannot be empty").describe("BitBucket username"),
2968
+ 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)"),
2969
+ workspace: z.string().optional().describe("BitBucket workspace (optional, auto-detected from git remote if not provided)"),
2970
+ repoSlug: z.string().optional().describe("BitBucket repository slug (optional, auto-detected from git remote if not provided)"),
2971
+ 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.")
2972
+ }).optional()
2973
+ }).optional().describe("Version control provider configuration"),
2872
2974
  mergeBehavior: z.object({
2873
2975
  // 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"),
2976
+ mode: z.enum(mergeModeValues).default("local").transform(mergeModeTransform),
2875
2977
  remote: z.string().optional(),
2876
2978
  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."
2979
+ "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is draft-pr."
2878
2980
  ),
2981
+ prTitlePrefix: z.boolean().default(false).optional().describe('Prefix PR titles with the issue number (e.g., "QLH-123: Title"). Default: false'),
2879
2982
  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."
2983
+ "Open the PR in the default browser after finishing in pr or draft-pr mode. Use --no-browser flag to override."
2881
2984
  )
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)"),
2985
+ }).optional().describe("Merge behavior configuration: local (merge locally), pr (create PR), or draft-pr (create draft PR at start, mark ready on finish)"),
2883
2986
  ide: z.object({
2884
2987
  // SYNC: If this default changes, update displayDefaultsBox() in src/utils/first-run-setup.ts
2885
2988
  type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).default("vscode").describe(
@@ -2941,12 +3044,14 @@ var IloomSettingsSchemaNoDefaults = z.object({
2941
3044
  plan: z.object({
2942
3045
  model: z.enum(["sonnet", "opus", "haiku"]).optional(),
2943
3046
  planner: z.enum(["claude", "gemini", "codex"]).optional(),
2944
- reviewer: z.enum(["claude", "gemini", "codex", "none"]).optional()
3047
+ reviewer: z.enum(["claude", "gemini", "codex", "none"]).optional(),
3048
+ waveVerification: z.boolean().optional()
2945
3049
  }).optional().describe("Plan command configuration"),
2946
3050
  summary: z.object({
2947
3051
  model: z.enum(["sonnet", "opus", "haiku"]).optional()
2948
3052
  }).optional().describe("Session summary generation configuration"),
2949
3053
  capabilities: CapabilitiesSettingsSchemaNoDefaults.describe("Project capability configurations"),
3054
+ devServer: DevServerSettingsSchemaNoDefaults.optional().describe("Docker-based dev server configuration"),
2950
3055
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
2951
3056
  issueManagement: z.object({
2952
3057
  provider: z.enum(["github", "linear", "jira"]).optional().describe("Issue tracker provider (github, linear, jira)"),
@@ -2970,16 +3075,27 @@ var IloomSettingsSchemaNoDefaults = z.object({
2970
3075
  doneStatuses: z.array(z.string()).optional().default(["Done"]).describe('Status names to exclude from issue lists (e.g., ["Done", "Closed", "Verify"])')
2971
3076
  }).optional()
2972
3077
  }).optional().describe("Issue management configuration"),
3078
+ versionControl: z.object({
3079
+ provider: z.enum(["github", "bitbucket"]).optional().describe("Version control provider (github, bitbucket)"),
3080
+ bitbucket: z.object({
3081
+ username: z.string().min(1, "BitBucket username cannot be empty").describe("BitBucket username"),
3082
+ 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)"),
3083
+ workspace: z.string().optional().describe("BitBucket workspace (optional, auto-detected from git remote if not provided)"),
3084
+ repoSlug: z.string().optional().describe("BitBucket repository slug (optional, auto-detected from git remote if not provided)"),
3085
+ 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.")
3086
+ }).optional()
3087
+ }).optional().describe("Version control provider configuration"),
2973
3088
  mergeBehavior: z.object({
2974
- mode: z.enum(["local", "github-pr", "github-draft-pr"]).optional(),
3089
+ mode: z.enum(mergeModeValues).transform(mergeModeTransform).optional(),
2975
3090
  remote: z.string().optional(),
2976
3091
  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."
3092
+ "Auto-commit and push after code review in draft PR mode. Defaults to true when mode is draft-pr."
2978
3093
  ),
3094
+ prTitlePrefix: z.boolean().optional(),
2979
3095
  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."
3096
+ "Open the PR in the default browser after finishing in pr or draft-pr mode. Use --no-browser flag to override."
2981
3097
  )
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)"),
3098
+ }).optional().describe("Merge behavior configuration: local (merge locally), pr (create PR), or draft-pr (create draft PR at start, mark ready on finish)"),
2983
3099
  ide: z.object({
2984
3100
  type: z.enum(["vscode", "cursor", "webstorm", "sublime", "intellij", "windsurf", "antigravity"]).optional().describe(
2985
3101
  "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 +3120,7 @@ function redactSensitiveFields(obj) {
3004
3120
  if (obj === null || obj === void 0) return obj;
3005
3121
  if (typeof obj !== "object") return obj;
3006
3122
  if (Array.isArray(obj)) return obj.map(redactSensitiveFields);
3007
- const sensitiveKeys = ["apitoken", "token", "secret", "password"];
3123
+ const sensitiveKeys = ["apitoken", "token", "secret", "password", "credential"];
3008
3124
  const result = {};
3009
3125
  for (const [key, value] of Object.entries(obj)) {
3010
3126
  const lowerKey = key.toLowerCase();
@@ -3269,6 +3385,17 @@ ${errorMessages.join("\n")}`
3269
3385
  var _a;
3270
3386
  return ((_a = settings2 == null ? void 0 : settings2.plan) == null ? void 0 : _a.reviewer) ?? "none";
3271
3387
  }
3388
+ /**
3389
+ * Get the plan command waveVerification setting with default applied
3390
+ * Default is true (verification tasks are generated)
3391
+ *
3392
+ * @param settings - Pre-loaded settings object
3393
+ * @returns Whether wave verification is enabled
3394
+ */
3395
+ getPlanWaveVerification(settings2) {
3396
+ var _a;
3397
+ return ((_a = settings2 == null ? void 0 : settings2.plan) == null ? void 0 : _a.waveVerification) !== false;
3398
+ }
3272
3399
  /**
3273
3400
  * Get the session summary model with default applied
3274
3401
  * Default is defined in SummarySettingsSchema
@@ -3730,8 +3857,672 @@ var JiraWikiSanitizer = class {
3730
3857
  }
3731
3858
  };
3732
3859
 
3860
+ // src/lib/providers/bitbucket/BitBucketApiClient.ts
3861
+ import https2 from "https";
3862
+ var BitBucketApiClient = class {
3863
+ constructor(config) {
3864
+ this.baseUrl = "https://api.bitbucket.org/2.0";
3865
+ const credentials = Buffer.from(`${config.username}:${config.apiToken}`).toString("base64");
3866
+ this.authHeader = `Basic ${credentials}`;
3867
+ this.workspace = config.workspace;
3868
+ this.repoSlug = config.repoSlug;
3869
+ }
3870
+ /**
3871
+ * Make an HTTP request to BitBucket API
3872
+ */
3873
+ async request(method, endpoint, body) {
3874
+ const url = endpoint.startsWith("http://") || endpoint.startsWith("https://") ? new URL(endpoint) : new URL(`${this.baseUrl}${endpoint}`);
3875
+ if ((endpoint.startsWith("http://") || endpoint.startsWith("https://")) && url.hostname !== "api.bitbucket.org") {
3876
+ throw new Error(`Refusing to send authenticated request to unexpected host: ${url.hostname} (expected api.bitbucket.org)`);
3877
+ }
3878
+ getLogger().debug(`BitBucket API ${method} request`, { url: url.toString() });
3879
+ return new Promise((resolve, reject) => {
3880
+ const options = {
3881
+ hostname: url.hostname,
3882
+ port: url.port || 443,
3883
+ path: url.pathname + url.search,
3884
+ method,
3885
+ headers: {
3886
+ "Authorization": this.authHeader,
3887
+ "Accept": "application/json",
3888
+ "Content-Type": "application/json"
3889
+ }
3890
+ };
3891
+ const req = https2.request(options, (res) => {
3892
+ let data = "";
3893
+ res.on("data", (chunk) => {
3894
+ data += chunk;
3895
+ });
3896
+ res.on("end", () => {
3897
+ if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
3898
+ reject(new Error(`BitBucket API error (${res.statusCode}): ${data}`));
3899
+ return;
3900
+ }
3901
+ if (res.statusCode === 204 || !data) {
3902
+ resolve({});
3903
+ return;
3904
+ }
3905
+ try {
3906
+ resolve(JSON.parse(data));
3907
+ } catch (error) {
3908
+ reject(new Error(`Failed to parse BitBucket API response: ${error}`));
3909
+ }
3910
+ });
3911
+ });
3912
+ req.on("error", (error) => {
3913
+ reject(new Error(`BitBucket API request failed: ${error.message}`));
3914
+ });
3915
+ if (body) {
3916
+ req.write(JSON.stringify(body));
3917
+ }
3918
+ req.end();
3919
+ });
3920
+ }
3921
+ /**
3922
+ * Make a GET request to BitBucket API
3923
+ */
3924
+ async get(endpoint) {
3925
+ return this.request("GET", endpoint);
3926
+ }
3927
+ /**
3928
+ * Make a POST request to BitBucket API
3929
+ */
3930
+ async post(endpoint, body) {
3931
+ return this.request("POST", endpoint, body);
3932
+ }
3933
+ /**
3934
+ * Make a PUT request to BitBucket API
3935
+ */
3936
+ async put(endpoint, body) {
3937
+ return this.request("PUT", endpoint, body);
3938
+ }
3939
+ /**
3940
+ * Get repository information
3941
+ */
3942
+ async getRepository(workspace, repoSlug) {
3943
+ return this.get(`/repositories/${workspace}/${repoSlug}`);
3944
+ }
3945
+ /**
3946
+ * Get a pull request by ID
3947
+ */
3948
+ async getPullRequest(workspace, repoSlug, prId) {
3949
+ return this.get(
3950
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}`
3951
+ );
3952
+ }
3953
+ /**
3954
+ * List open pull requests for a branch
3955
+ *
3956
+ * Note: BitBucket uses BBQL (BitBucket Query Language) for filtering.
3957
+ * The q parameter must use the format: q=source.branch.name="branch-name"
3958
+ * When using BBQL, we include state filter in the query to ensure it's applied.
3959
+ * See: https://developer.atlassian.com/cloud/bitbucket/rest/intro/#filtering
3960
+ */
3961
+ async listPullRequests(workspace, repoSlug, sourceBranch) {
3962
+ let endpoint = `/repositories/${workspace}/${repoSlug}/pullrequests`;
3963
+ if (sourceBranch) {
3964
+ const safeBranch = sourceBranch.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3965
+ const query = `state="OPEN" AND source.branch.name="${safeBranch}"`;
3966
+ endpoint += `?q=${encodeURIComponent(query)}`;
3967
+ } else {
3968
+ endpoint += `?state=OPEN`;
3969
+ }
3970
+ const response = await this.get(endpoint);
3971
+ return response.values;
3972
+ }
3973
+ /**
3974
+ * Create a pull request
3975
+ */
3976
+ async createPullRequest(workspace, repoSlug, title, description, sourceBranch, destinationBranch, reviewerAccountIds) {
3977
+ const payload = {
3978
+ title,
3979
+ description,
3980
+ source: {
3981
+ branch: {
3982
+ name: sourceBranch
3983
+ }
3984
+ },
3985
+ destination: {
3986
+ branch: {
3987
+ name: destinationBranch
3988
+ }
3989
+ }
3990
+ };
3991
+ if (reviewerAccountIds && reviewerAccountIds.length > 0) {
3992
+ payload.reviewers = reviewerAccountIds.map((id) => ({ account_id: id }));
3993
+ }
3994
+ return this.post(
3995
+ `/repositories/${workspace}/${repoSlug}/pullrequests`,
3996
+ payload
3997
+ );
3998
+ }
3999
+ /**
4000
+ * Add a comment to a pull request
4001
+ */
4002
+ async addPRComment(workspace, repoSlug, prId, content) {
4003
+ return this.post(
4004
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`,
4005
+ {
4006
+ content: {
4007
+ raw: content
4008
+ }
4009
+ }
4010
+ );
4011
+ }
4012
+ /**
4013
+ * Update an existing comment on a pull request
4014
+ */
4015
+ async updatePRComment(workspace, repoSlug, prId, commentId, content) {
4016
+ return this.put(
4017
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments/${commentId}`,
4018
+ {
4019
+ content: {
4020
+ raw: content
4021
+ }
4022
+ }
4023
+ );
4024
+ }
4025
+ /**
4026
+ * List all comments on a pull request with pagination
4027
+ */
4028
+ async listPRComments(workspace, repoSlug, prId) {
4029
+ const MAX_PAGES = 50;
4030
+ const allComments = [];
4031
+ let nextUrl = `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`;
4032
+ let pageCount = 0;
4033
+ while (nextUrl) {
4034
+ pageCount++;
4035
+ if (pageCount > MAX_PAGES) {
4036
+ console.error(`BitBucket listPRComments: exceeded maximum pagination limit of ${MAX_PAGES} pages, returning ${allComments.length} comments collected so far`);
4037
+ break;
4038
+ }
4039
+ const response = await this.get(nextUrl);
4040
+ allComments.push(...response.values);
4041
+ nextUrl = response.next ?? null;
4042
+ }
4043
+ getLogger().debug(`Fetched ${allComments.length} PR comments from BitBucket`);
4044
+ return allComments;
4045
+ }
4046
+ /**
4047
+ * Add an inline comment to a specific file and line in a pull request
4048
+ */
4049
+ async addInlinePRComment(workspace, repoSlug, prId, content, filePath, line) {
4050
+ return this.post(
4051
+ `/repositories/${workspace}/${repoSlug}/pullrequests/${prId}/comments`,
4052
+ {
4053
+ content: {
4054
+ raw: content
4055
+ },
4056
+ inline: {
4057
+ to: line,
4058
+ path: filePath
4059
+ }
4060
+ }
4061
+ );
4062
+ }
4063
+ /**
4064
+ * Find workspace members by usernames
4065
+ * Returns a map of username -> account_id for resolved users
4066
+ * Handles pagination to fetch all workspace members
4067
+ */
4068
+ async findUsersByUsername(workspace, usernames) {
4069
+ const result = /* @__PURE__ */ new Map();
4070
+ const allMembers = await this.getAllWorkspaceMembers(workspace);
4071
+ getLogger().debug(`Resolving ${usernames.length} usernames against ${allMembers.length} workspace members`);
4072
+ for (const username of usernames) {
4073
+ const usernameLower = username.toLowerCase();
4074
+ const member = allMembers.find(
4075
+ (m) => {
4076
+ var _a;
4077
+ return ((_a = m.user.nickname) == null ? void 0 : _a.toLowerCase()) === usernameLower || m.user.display_name.toLowerCase() === usernameLower;
4078
+ }
4079
+ );
4080
+ if (member) {
4081
+ result.set(username, member.user.account_id);
4082
+ getLogger().debug(`Resolved reviewer ${username} to account ID ${member.user.account_id}`);
4083
+ } else {
4084
+ getLogger().warn(`Could not resolve reviewer ${username} to a BitBucket account ID`);
4085
+ }
4086
+ }
4087
+ return result;
4088
+ }
4089
+ /**
4090
+ * Fetch all workspace members with pagination
4091
+ */
4092
+ async getAllWorkspaceMembers(workspace) {
4093
+ const allMembers = [];
4094
+ let nextUrl = `/workspaces/${workspace}/members`;
4095
+ while (nextUrl) {
4096
+ const response = await this.get(nextUrl);
4097
+ allMembers.push(...response.values);
4098
+ nextUrl = response.next ?? null;
4099
+ }
4100
+ getLogger().debug(`Fetched ${allMembers.length} workspace members from BitBucket`);
4101
+ return allMembers;
4102
+ }
4103
+ /**
4104
+ * Get the currently authenticated user
4105
+ */
4106
+ async getCurrentUser() {
4107
+ return this.get("/user");
4108
+ }
4109
+ /**
4110
+ * Test connection to BitBucket API
4111
+ */
4112
+ async testConnection() {
4113
+ try {
4114
+ await this.getCurrentUser();
4115
+ return true;
4116
+ } catch (error) {
4117
+ getLogger().error("BitBucket connection test failed", { error });
4118
+ return false;
4119
+ }
4120
+ }
4121
+ /**
4122
+ * Get configured workspace
4123
+ */
4124
+ getWorkspace() {
4125
+ return this.workspace;
4126
+ }
4127
+ /**
4128
+ * Get configured repository slug
4129
+ */
4130
+ getRepoSlug() {
4131
+ return this.repoSlug;
4132
+ }
4133
+ };
4134
+
4135
+ // src/utils/remote.ts
4136
+ import { execa as execa3 } from "execa";
4137
+ async function parseGitRemotes(cwd) {
4138
+ const result = await execa3("git", ["remote", "-v"], {
4139
+ cwd: cwd ?? process.cwd(),
4140
+ encoding: "utf8"
4141
+ });
4142
+ const lines = result.stdout.trim().split("\n");
4143
+ const remoteMap = /* @__PURE__ */ new Map();
4144
+ for (const line of lines) {
4145
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((fetch|push)\)/);
4146
+ if (!match) continue;
4147
+ const name = match[1];
4148
+ const url = match[2];
4149
+ if (!name || !url) continue;
4150
+ if (remoteMap.has(name)) continue;
4151
+ const ownerRepo = extractOwnerRepoFromUrl(url);
4152
+ if (!ownerRepo) continue;
4153
+ remoteMap.set(name, {
4154
+ name,
4155
+ url,
4156
+ owner: ownerRepo.owner,
4157
+ repo: ownerRepo.repo
4158
+ });
4159
+ }
4160
+ return Array.from(remoteMap.values());
4161
+ }
4162
+ function extractOwnerRepoFromUrl(url) {
4163
+ const cleanUrl = url.replace(/\.git$/, "");
4164
+ const githubHttpsMatch = cleanUrl.match(/https?:\/\/github\.com\/([^/]+)\/([^/]+)/);
4165
+ if ((githubHttpsMatch == null ? void 0 : githubHttpsMatch[1]) && (githubHttpsMatch == null ? void 0 : githubHttpsMatch[2])) {
4166
+ return { owner: githubHttpsMatch[1], repo: githubHttpsMatch[2] };
4167
+ }
4168
+ const githubSshMatch = cleanUrl.match(/git@github\.com:([^/]+)\/(.+)/);
4169
+ if ((githubSshMatch == null ? void 0 : githubSshMatch[1]) && (githubSshMatch == null ? void 0 : githubSshMatch[2])) {
4170
+ return { owner: githubSshMatch[1], repo: githubSshMatch[2] };
4171
+ }
4172
+ const bitbucketHttpsMatch = cleanUrl.match(/https?:\/\/bitbucket\.org\/([^/]+)\/([^/]+)/);
4173
+ if ((bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[1]) && (bitbucketHttpsMatch == null ? void 0 : bitbucketHttpsMatch[2])) {
4174
+ return { owner: bitbucketHttpsMatch[1], repo: bitbucketHttpsMatch[2] };
4175
+ }
4176
+ const bitbucketSshMatch = cleanUrl.match(/git@bitbucket\.org:([^/]+)\/(.+)/);
4177
+ if ((bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[1]) && (bitbucketSshMatch == null ? void 0 : bitbucketSshMatch[2])) {
4178
+ return { owner: bitbucketSshMatch[1], repo: bitbucketSshMatch[2] };
4179
+ }
4180
+ return null;
4181
+ }
4182
+
4183
+ // src/lib/providers/bitbucket/BitBucketVCSProvider.ts
4184
+ var BitBucketVCSProvider = class _BitBucketVCSProvider {
4185
+ constructor(config) {
4186
+ this.providerName = "bitbucket";
4187
+ this.supportsForks = true;
4188
+ this.supportsDraftPRs = false;
4189
+ this.client = new BitBucketApiClient(config);
4190
+ if (config.reviewers) {
4191
+ this.reviewerUsernames = config.reviewers;
4192
+ }
4193
+ }
4194
+ /**
4195
+ * Create a BitBucketVCSProvider from IloomSettings
4196
+ * Extracts and validates BitBucket config from settings
4197
+ */
4198
+ static fromSettings(settings2) {
4199
+ var _a;
4200
+ const bbSettings = (_a = settings2.versionControl) == null ? void 0 : _a.bitbucket;
4201
+ if (!(bbSettings == null ? void 0 : bbSettings.username)) {
4202
+ throw new Error("BitBucket username is required. Configure versionControl.bitbucket.username in .iloom/settings.json");
4203
+ }
4204
+ if (!(bbSettings == null ? void 0 : bbSettings.apiToken)) {
4205
+ throw new Error("BitBucket API token is required. Configure versionControl.bitbucket.apiToken in .iloom/settings.local.json");
4206
+ }
4207
+ const config = {
4208
+ username: bbSettings.username,
4209
+ apiToken: bbSettings.apiToken
4210
+ };
4211
+ if (bbSettings.workspace) {
4212
+ config.workspace = bbSettings.workspace;
4213
+ }
4214
+ if (bbSettings.repoSlug) {
4215
+ config.repoSlug = bbSettings.repoSlug;
4216
+ }
4217
+ if (bbSettings.reviewers) {
4218
+ config.reviewers = bbSettings.reviewers;
4219
+ }
4220
+ return new _BitBucketVCSProvider(config);
4221
+ }
4222
+ /**
4223
+ * Check if a PR already exists for the given branch
4224
+ */
4225
+ async checkForExistingPR(branchName, cwd) {
4226
+ try {
4227
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4228
+ const prs = await this.client.listPullRequests(workspace, repoSlug, branchName);
4229
+ if (prs.length > 0 && prs[0]) {
4230
+ const pr = prs[0];
4231
+ return {
4232
+ number: pr.id,
4233
+ url: pr.links.html.href
4234
+ };
4235
+ }
4236
+ return null;
4237
+ } catch (error) {
4238
+ if (error instanceof Error) {
4239
+ const statusMatch = error.message.match(/BitBucket API error \((\d+)\)/);
4240
+ if (statusMatch == null ? void 0 : statusMatch[1]) {
4241
+ const statusCode = parseInt(statusMatch[1], 10);
4242
+ if (statusCode === 401 || statusCode === 403) {
4243
+ throw error;
4244
+ }
4245
+ }
4246
+ }
4247
+ getLogger().debug("Error checking for existing PR", { error });
4248
+ return null;
4249
+ }
4250
+ }
4251
+ /**
4252
+ * Create a pull request
4253
+ */
4254
+ async createPR(branchName, title, body, baseBranch, cwd) {
4255
+ var _a, _b;
4256
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4257
+ getLogger().info(`Creating BitBucket PR in ${workspace}/${repoSlug}`);
4258
+ getLogger().debug("PR details", { branchName, title, baseBranch });
4259
+ let reviewerIds;
4260
+ if (this.reviewerUsernames && this.reviewerUsernames.length > 0) {
4261
+ reviewerIds = await this.resolveReviewerUsernames(workspace, this.reviewerUsernames);
4262
+ if (reviewerIds.length > 0) {
4263
+ const currentUser = await this.client.getCurrentUser();
4264
+ const originalCount = reviewerIds.length;
4265
+ reviewerIds = reviewerIds.filter((id) => id !== currentUser.account_id);
4266
+ if (reviewerIds.length < originalCount) {
4267
+ getLogger().debug(
4268
+ `Removed current user (${currentUser.display_name}) from reviewers list - PR author cannot be a reviewer`
4269
+ );
4270
+ }
4271
+ }
4272
+ }
4273
+ const pr = await this.client.createPullRequest(
4274
+ workspace,
4275
+ repoSlug,
4276
+ title,
4277
+ body,
4278
+ branchName,
4279
+ baseBranch,
4280
+ reviewerIds
4281
+ );
4282
+ 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)) {
4283
+ getLogger().error("Invalid BitBucket API response", { pr });
4284
+ throw new Error(
4285
+ `BitBucket API returned invalid PR response. Expected PR with id and links.html.href, got: ${JSON.stringify(pr)}`
4286
+ );
4287
+ }
4288
+ getLogger().info(`BitBucket PR #${pr.id} created successfully`);
4289
+ return { url: pr.links.html.href, number: pr.id, wasExisting: false };
4290
+ }
4291
+ /**
4292
+ * Fetch PR details
4293
+ */
4294
+ async fetchPR(prNumber, cwd) {
4295
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4296
+ const bbPR = await this.client.getPullRequest(workspace, repoSlug, prNumber);
4297
+ return this.mapBitBucketPRToPullRequest(bbPR);
4298
+ }
4299
+ /**
4300
+ * Get PR URL
4301
+ */
4302
+ async getPRUrl(prNumber, cwd) {
4303
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4304
+ const bbPR = await this.client.getPullRequest(workspace, repoSlug, prNumber);
4305
+ return bbPR.links.html.href;
4306
+ }
4307
+ /**
4308
+ * Create a comment on a PR
4309
+ */
4310
+ async createPRComment(prNumber, body, cwd) {
4311
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4312
+ getLogger().debug("Creating BitBucket PR comment", { workspace, repoSlug, prNumber });
4313
+ const comment = await this.client.addPRComment(workspace, repoSlug, prNumber, body);
4314
+ return { id: String(comment.id), url: comment.links.html.href };
4315
+ }
4316
+ /**
4317
+ * Update an existing comment on a PR
4318
+ */
4319
+ async updatePRComment(prNumber, commentId, body, cwd) {
4320
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4321
+ getLogger().debug("Updating BitBucket PR comment", { workspace, repoSlug, prNumber, commentId });
4322
+ const numericCommentId = parseInt(commentId, 10);
4323
+ if (isNaN(numericCommentId)) {
4324
+ throw new Error(`Invalid comment ID "${commentId}": expected a numeric value`);
4325
+ }
4326
+ const comment = await this.client.updatePRComment(workspace, repoSlug, prNumber, numericCommentId, body);
4327
+ return { id: String(comment.id), url: comment.links.html.href };
4328
+ }
4329
+ /**
4330
+ * Get inline review comments on a PR
4331
+ * Fetches all comments and filters for those with inline metadata
4332
+ */
4333
+ async getReviewComments(prNumber, cwd) {
4334
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4335
+ getLogger().debug("Fetching BitBucket PR review comments", { workspace, repoSlug, prNumber });
4336
+ const allComments = await this.client.listPRComments(workspace, repoSlug, prNumber);
4337
+ const inlineComments = [];
4338
+ for (const c of allComments) {
4339
+ if (c.inline == null) continue;
4340
+ inlineComments.push({
4341
+ id: String(c.id),
4342
+ body: c.content.raw,
4343
+ path: c.inline.path,
4344
+ line: c.inline.to ?? c.inline.from ?? null,
4345
+ side: null,
4346
+ // BitBucket doesn't have a "side" concept like GitHub
4347
+ author: c.user ? { id: c.user.uuid, displayName: c.user.display_name } : null,
4348
+ createdAt: c.created_on ?? "",
4349
+ updatedAt: c.updated_on ?? null,
4350
+ inReplyToId: null
4351
+ // BitBucket uses nested comments, not reply chains
4352
+ });
4353
+ }
4354
+ return inlineComments;
4355
+ }
4356
+ /**
4357
+ * Create an inline review comment on a specific file and line in a PR
4358
+ */
4359
+ async createReviewComment(prNumber, path3, line, body, cwd) {
4360
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4361
+ getLogger().debug("Creating BitBucket inline PR comment", { workspace, repoSlug, prNumber, path: path3, line });
4362
+ const comment = await this.client.addInlinePRComment(workspace, repoSlug, prNumber, body, path3, line);
4363
+ return { id: String(comment.id), url: comment.links.html.href };
4364
+ }
4365
+ /**
4366
+ * List open pull requests for the repository
4367
+ * Uses getWorkspaceAndRepo for auto-detection from git remotes
4368
+ */
4369
+ async listPullRequests(cwd) {
4370
+ const { workspace, repoSlug } = await this.getWorkspaceAndRepo(cwd);
4371
+ return this.client.listPullRequests(workspace, repoSlug);
4372
+ }
4373
+ /**
4374
+ * Detect repository from git remote
4375
+ */
4376
+ async detectRepository(cwd) {
4377
+ try {
4378
+ const remotes = await parseGitRemotes(cwd);
4379
+ const bbRemote = remotes.find(
4380
+ (r) => r.url.includes("bitbucket.org")
4381
+ );
4382
+ if (!bbRemote) {
4383
+ return null;
4384
+ }
4385
+ return {
4386
+ owner: bbRemote.owner,
4387
+ // workspace
4388
+ repo: bbRemote.repo
4389
+ };
4390
+ } catch (error) {
4391
+ getLogger().error("Failed to detect BitBucket repository", { error });
4392
+ return null;
4393
+ }
4394
+ }
4395
+ /**
4396
+ * Get target remote for PR operations
4397
+ */
4398
+ async getTargetRemote(_cwd) {
4399
+ return "origin";
4400
+ }
4401
+ /**
4402
+ * Get workspace and repository slug from config or git remote
4403
+ */
4404
+ async getWorkspaceAndRepo(cwd) {
4405
+ let workspace = this.client.getWorkspace();
4406
+ let repoSlug = this.client.getRepoSlug();
4407
+ if (!workspace || !repoSlug) {
4408
+ const detected = await this.detectRepository(cwd);
4409
+ if (!detected) {
4410
+ throw new Error(
4411
+ "Could not determine BitBucket workspace/repository. Either configure them in settings or ensure git remote points to bitbucket.org"
4412
+ );
4413
+ }
4414
+ workspace = workspace ?? detected.owner;
4415
+ repoSlug = repoSlug ?? detected.repo;
4416
+ }
4417
+ return { workspace, repoSlug };
4418
+ }
4419
+ /**
4420
+ * Resolve reviewer usernames to BitBucket account IDs
4421
+ * Warns for any usernames that cannot be resolved but continues with partial list
4422
+ */
4423
+ async resolveReviewerUsernames(workspace, usernames) {
4424
+ getLogger().debug(`Resolving ${usernames.length} reviewer username(s) to BitBucket account IDs`);
4425
+ const usernameToAccountId = await this.client.findUsersByUsername(workspace, usernames);
4426
+ const resolvedIds = [];
4427
+ const unresolvedUsernames = [];
4428
+ for (const username of usernames) {
4429
+ const accountId = usernameToAccountId.get(username);
4430
+ if (accountId) {
4431
+ resolvedIds.push(accountId);
4432
+ } else {
4433
+ unresolvedUsernames.push(username);
4434
+ }
4435
+ }
4436
+ if (unresolvedUsernames.length > 0) {
4437
+ getLogger().warn(
4438
+ `Could not resolve ${unresolvedUsernames.length} reviewer username(s) to BitBucket account IDs: ${unresolvedUsernames.join(", ")}. These reviewers will not be added to the PR.`
4439
+ );
4440
+ }
4441
+ if (resolvedIds.length > 0) {
4442
+ getLogger().info(`Resolved ${resolvedIds.length} reviewer(s) for PR`);
4443
+ }
4444
+ return resolvedIds;
4445
+ }
4446
+ /**
4447
+ * Map BitBucket PR to generic PullRequest type
4448
+ */
4449
+ mapBitBucketPRToPullRequest(bbPR) {
4450
+ let state;
4451
+ if (bbPR.state === "OPEN") {
4452
+ state = "open";
4453
+ } else if (bbPR.state === "MERGED") {
4454
+ state = "merged";
4455
+ } else {
4456
+ state = "closed";
4457
+ }
4458
+ return {
4459
+ number: bbPR.id,
4460
+ title: bbPR.title,
4461
+ body: bbPR.description,
4462
+ state,
4463
+ branch: bbPR.source.branch.name,
4464
+ baseBranch: bbPR.destination.branch.name,
4465
+ url: bbPR.links.html.href,
4466
+ isDraft: false
4467
+ // BitBucket doesn't have draft PRs
4468
+ };
4469
+ }
4470
+ };
4471
+
4472
+ // src/lib/VCSProviderFactory.ts
4473
+ var VCSProviderFactory = class {
4474
+ /**
4475
+ * Create a VersionControlProvider instance based on settings configuration
4476
+ *
4477
+ * @param settings - iloom settings containing versionControl.provider
4478
+ * @returns VersionControlProvider instance configured for the specified provider
4479
+ * @throws Error if provider type is not supported or required config is missing
4480
+ */
4481
+ static create(settings2) {
4482
+ var _a;
4483
+ const provider = (_a = settings2.versionControl) == null ? void 0 : _a.provider;
4484
+ if (!provider) {
4485
+ getLogger().debug("VCSProviderFactory: No versionControl.provider configured, using legacy PRManager");
4486
+ return null;
4487
+ }
4488
+ getLogger().debug(`VCSProviderFactory: Creating VCS provider for "${provider}"`);
4489
+ switch (provider) {
4490
+ case "github":
4491
+ getLogger().debug("VCSProviderFactory: GitHub uses legacy PRManager, returning null");
4492
+ return null;
4493
+ case "bitbucket": {
4494
+ getLogger().debug(`VCSProviderFactory: Creating BitBucketVCSProvider from settings`);
4495
+ return BitBucketVCSProvider.fromSettings(settings2);
4496
+ }
4497
+ default:
4498
+ throw new Error(`Unsupported VCS provider: ${provider}`);
4499
+ }
4500
+ }
4501
+ /**
4502
+ * Check if a VCS provider is configured
4503
+ *
4504
+ * @param settings - iloom settings
4505
+ * @returns true if versionControl provider is configured
4506
+ */
4507
+ static isConfigured(settings2) {
4508
+ var _a, _b;
4509
+ return ((_a = settings2.versionControl) == null ? void 0 : _a.provider) !== void 0 && ((_b = settings2.versionControl) == null ? void 0 : _b.provider) !== "github";
4510
+ }
4511
+ /**
4512
+ * Get the configured provider name from settings
4513
+ *
4514
+ * @param settings - iloom settings
4515
+ * @returns Provider type string or undefined if not configured
4516
+ */
4517
+ static getProviderName(settings2) {
4518
+ var _a;
4519
+ return (_a = settings2.versionControl) == null ? void 0 : _a.provider;
4520
+ }
4521
+ };
4522
+
3733
4523
  // src/mcp/issue-management-server.ts
3734
4524
  var settings;
4525
+ var vcsProvider = null;
3735
4526
  function validateEnvironment() {
3736
4527
  const provider = process.env.ISSUE_PROVIDER;
3737
4528
  if (!provider) {
@@ -3849,7 +4640,7 @@ server.registerTool(
3849
4640
  "get_pr",
3850
4641
  {
3851
4642
  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.",
4643
+ 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
4644
  inputSchema: {
3854
4645
  number: z2.string().describe("The PR number"),
3855
4646
  includeComments: z2.boolean().optional().describe("Whether to include comments (default: true)"),
@@ -3900,6 +4691,34 @@ server.registerTool(
3900
4691
  async ({ number, includeComments, repo }) => {
3901
4692
  console.error(`Fetching PR ${number}${repo ? ` from ${repo}` : ""}`);
3902
4693
  try {
4694
+ if (vcsProvider) {
4695
+ if (repo) {
4696
+ console.error(`VCS provider path does not support 'repo' override parameter, using configured repository`);
4697
+ }
4698
+ const pr = await vcsProvider.fetchPR(parseInt(number, 10));
4699
+ const result2 = {
4700
+ id: String(pr.number),
4701
+ number: pr.number,
4702
+ title: pr.title,
4703
+ body: pr.body,
4704
+ state: pr.state.toUpperCase(),
4705
+ url: pr.url,
4706
+ headRefName: pr.branch,
4707
+ baseRefName: pr.baseBranch,
4708
+ author: null,
4709
+ isDraft: pr.isDraft
4710
+ };
4711
+ console.error(`PR fetched successfully: #${result2.number} - ${result2.title}`);
4712
+ return {
4713
+ content: [
4714
+ {
4715
+ type: "text",
4716
+ text: JSON.stringify(result2)
4717
+ }
4718
+ ],
4719
+ structuredContent: result2
4720
+ };
4721
+ }
3903
4722
  const provider = new GitHubIssueManagementProvider();
3904
4723
  const result = await provider.getPR({ number, includeComments, repo });
3905
4724
  console.error(`PR fetched successfully: #${result.number} - ${result.title}`);
@@ -3923,7 +4742,7 @@ server.registerTool(
3923
4742
  "get_review_comments",
3924
4743
  {
3925
4744
  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.",
4745
+ 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
4746
  inputSchema: {
3928
4747
  number: z2.string().describe("The PR number"),
3929
4748
  reviewId: z2.string().optional().describe("Optional review ID to filter comments by a specific review"),
@@ -3951,6 +4770,30 @@ server.registerTool(
3951
4770
  async ({ number, reviewId, repo }) => {
3952
4771
  console.error(`Fetching review comments for PR ${number}${reviewId ? ` (review ${reviewId})` : ""}${repo ? ` from ${repo}` : ""}`);
3953
4772
  try {
4773
+ if (vcsProvider == null ? void 0 : vcsProvider.getReviewComments) {
4774
+ if (repo) {
4775
+ console.error(`VCS provider path does not support 'repo' override parameter, using configured repository`);
4776
+ }
4777
+ if (reviewId) {
4778
+ console.error(`VCS provider path does not support 'reviewId' filter, returning all inline comments`);
4779
+ }
4780
+ const reviewComments = await vcsProvider.getReviewComments(parseInt(number, 10));
4781
+ const comments2 = reviewComments.map((c) => ({
4782
+ ...c,
4783
+ pullRequestReviewId: null
4784
+ }));
4785
+ console.error(`Review comments fetched successfully: ${comments2.length} comments`);
4786
+ const result2 = { comments: comments2 };
4787
+ return {
4788
+ content: [
4789
+ {
4790
+ type: "text",
4791
+ text: JSON.stringify(result2)
4792
+ }
4793
+ ],
4794
+ structuredContent: result2
4795
+ };
4796
+ }
3954
4797
  const provider = new GitHubIssueManagementProvider();
3955
4798
  const comments = await provider.getReviewComments({ number, reviewId, repo });
3956
4799
  console.error(`Review comments fetched successfully: ${comments.length} comments`);
@@ -4039,6 +4882,22 @@ server.registerTool(
4039
4882
  console.error(`Creating ${type} comment on ${number}`);
4040
4883
  try {
4041
4884
  const sanitizedBody = JiraWikiSanitizer.sanitize(body);
4885
+ if (type === "pr" && vcsProvider) {
4886
+ const vcsResult = await vcsProvider.createPRComment(parseInt(number, 10), sanitizedBody);
4887
+ console.error(
4888
+ `Comment created successfully: ${vcsResult.id} at ${vcsResult.url}`
4889
+ );
4890
+ const result2 = { id: vcsResult.id, url: vcsResult.url, created_at: (/* @__PURE__ */ new Date()).toISOString() };
4891
+ return {
4892
+ content: [
4893
+ {
4894
+ type: "text",
4895
+ text: JSON.stringify(result2)
4896
+ }
4897
+ ],
4898
+ structuredContent: result2
4899
+ };
4900
+ }
4042
4901
  const providerType = type === "pr" ? "github" : process.env.ISSUE_PROVIDER;
4043
4902
  const provider = IssueManagementProviderFactory.create(providerType, settings);
4044
4903
  const result = await provider.createComment({ number, body: sanitizedBody, type });
@@ -4083,6 +4942,22 @@ server.registerTool(
4083
4942
  console.error(`Updating comment ${commentId} on ${type === "pr" ? "PR" : "issue"} ${number}`);
4084
4943
  try {
4085
4944
  const sanitizedBody = JiraWikiSanitizer.sanitize(body);
4945
+ if (type === "pr" && (vcsProvider == null ? void 0 : vcsProvider.updatePRComment)) {
4946
+ const vcsResult = await vcsProvider.updatePRComment(parseInt(number, 10), commentId, sanitizedBody);
4947
+ console.error(
4948
+ `Comment updated successfully: ${vcsResult.id} at ${vcsResult.url}`
4949
+ );
4950
+ const result2 = { id: vcsResult.id, url: vcsResult.url, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
4951
+ return {
4952
+ content: [
4953
+ {
4954
+ type: "text",
4955
+ text: JSON.stringify(result2)
4956
+ }
4957
+ ],
4958
+ structuredContent: result2
4959
+ };
4960
+ }
4086
4961
  const providerType = type === "pr" ? "github" : process.env.ISSUE_PROVIDER;
4087
4962
  const provider = IssueManagementProviderFactory.create(providerType, settings);
4088
4963
  const result = await provider.updateComment({ commentId, number, body: sanitizedBody });
@@ -4532,6 +5407,19 @@ async function main() {
4532
5407
  const settingsManager = new SettingsManager();
4533
5408
  settings = await settingsManager.loadSettings();
4534
5409
  console.error("Settings loaded");
5410
+ try {
5411
+ vcsProvider = VCSProviderFactory.create(settings);
5412
+ if (vcsProvider) {
5413
+ console.error(`VCS provider initialized: ${vcsProvider.providerName}`);
5414
+ }
5415
+ } catch (error) {
5416
+ if (error instanceof Error && (error.message.includes("is required") || error.message.includes("Unsupported VCS provider"))) {
5417
+ console.error(`Failed to initialize VCS provider (falling back to GitHub): ${error.message}`);
5418
+ vcsProvider = null;
5419
+ } else {
5420
+ throw error;
5421
+ }
5422
+ }
4535
5423
  const provider = validateEnvironment();
4536
5424
  console.error("Environment validated");
4537
5425
  console.error(`Issue management provider: ${provider}`);