@iloom/cli 0.11.0 → 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.
- package/LICENSE +1 -1
- package/README.md +153 -13
- package/dist/BitBucketApiClient-J2ZSCS5N.js +10 -0
- package/dist/BitBucketVCSProvider-5X64IXXW.js +12 -0
- package/dist/{BranchNamingService-XBCO747L.js → BranchNamingService-MEK2WZUD.js} +4 -4
- package/dist/ClaudeContextManager-IENAE2CP.js +14 -0
- package/dist/ClaudeService-YIJCZUUB.js +13 -0
- package/dist/GitHubService-UTAYZXL3.js +12 -0
- package/dist/IssueTrackerFactory-2OI7YIN6.js +15 -0
- package/dist/{LoomLauncher-5AZU2F5I.js → LoomLauncher-3TSFW7QP.js} +10 -10
- package/dist/MetadataManager-V4LSJ2PB.js +10 -0
- package/dist/ProjectCapabilityDetector-I4J66WKF.js +11 -0
- package/dist/{PromptTemplateManager-T5VTLJP3.js → PromptTemplateManager-I75WKXM4.js} +3 -3
- package/dist/README.md +153 -13
- package/dist/{SettingsManager-WQ5NSGAH.js → SettingsManager-BMQCAXPP.js} +13 -5
- package/dist/SettingsMigrationManager-ZPARZ5KH.js +10 -0
- package/dist/agents/iloom-code-reviewer.md +2 -1
- package/dist/agents/iloom-framework-detector.md +0 -1
- package/dist/agents/iloom-issue-analyze-and-plan.md +4 -1
- package/dist/agents/iloom-issue-analyzer.md +4 -1
- package/dist/agents/iloom-issue-complexity-evaluator.md +4 -1
- package/dist/agents/iloom-issue-enhancer.md +4 -1
- package/dist/agents/iloom-issue-implementer.md +8 -3
- package/dist/agents/iloom-issue-planner.md +4 -1
- package/dist/agents/iloom-wave-verifier.md +186 -0
- package/dist/browser-VZY7F2DF.js +10 -0
- package/dist/build-DMWSIME6.js +27 -0
- package/dist/{chunk-UHIBKD73.js → chunk-35CBWAJL.js} +13 -32
- package/dist/{chunk-UHIBKD73.js.map → chunk-35CBWAJL.js.map} +1 -1
- package/dist/{chunk-YRCEOQPX.js → chunk-4JZEQBWV.js} +4 -3
- package/dist/chunk-4JZEQBWV.js.map +1 -0
- package/dist/{chunk-ET6A2JR4.js → chunk-653XBU3L.js} +111 -18
- package/dist/chunk-653XBU3L.js.map +1 -0
- package/dist/{chunk-G2MNSPA4.js → chunk-772N5WCA.js} +2 -2
- package/dist/{chunk-WG4MLJ6J.js → chunk-7RCUWU3I.js} +2 -2
- package/dist/chunk-7RCUWU3I.js.map +1 -0
- package/dist/{chunk-NOMQ5RFG.js → chunk-7UBEHQTP.js} +2 -2
- package/dist/{chunk-7NFCGKZT.js → chunk-AQUSMNBF.js} +3 -3
- package/dist/{chunk-IDCE26KD.js → chunk-AUYSAMXV.js} +3 -3
- package/dist/chunk-AYLC633W.js +406 -0
- package/dist/chunk-AYLC633W.js.map +1 -0
- package/dist/{chunk-HLDY5S4C.js → chunk-BFF27W3S.js} +3 -3
- package/dist/{chunk-QVAA5KHK.js → chunk-BZ7KTXPB.js} +16 -8
- package/dist/chunk-BZ7KTXPB.js.map +1 -0
- package/dist/{chunk-K7R5QY6C.js → chunk-CE676WCN.js} +2 -2
- package/dist/{chunk-5UFGO4ZT.js → chunk-CQHHEW2M.js} +6 -3
- package/dist/chunk-CQHHEW2M.js.map +1 -0
- package/dist/{chunk-LHDD4JHC.js → chunk-D4Q7T5KD.js} +4 -4
- package/dist/{chunk-RBYTXYGD.js → chunk-D75KSI3V.js} +2 -2
- package/dist/{chunk-Y3RX7LZT.js → chunk-DDHWZNGL.js} +18 -12
- package/dist/chunk-DDHWZNGL.js.map +1 -0
- package/dist/{chunk-5LTID2AF.js → chunk-DMSL5BAP.js} +35 -6
- package/dist/{chunk-5LTID2AF.js.map → chunk-DMSL5BAP.js.map} +1 -1
- package/dist/{chunk-SQYHPBFP.js → chunk-EGNUOALL.js} +2 -2
- package/dist/{chunk-LL6TOX3G.js → chunk-EQIII6GI.js} +10 -10
- package/dist/chunk-EQIII6GI.js.map +1 -0
- package/dist/{chunk-ZAXRQLK3.js → chunk-FTYWGQFM.js} +2 -2
- package/dist/{chunk-LE2NOUTN.js → chunk-FV4KXBGO.js} +3 -3
- package/dist/{chunk-XFQGI2E3.js → chunk-GWJWECZB.js} +51 -45
- package/dist/chunk-GWJWECZB.js.map +1 -0
- package/dist/{chunk-QNHZM5ZV.js → chunk-HIGWKLQR.js} +3 -3
- package/dist/{chunk-VMZG66UV.js → chunk-HKEXRZMU.js} +3 -3
- package/dist/{chunk-V4STTBQD.js → chunk-IHSA7VGI.js} +9 -9
- package/dist/{chunk-TEJAGQX2.js → chunk-IS46GQRA.js} +33 -33
- package/dist/{chunk-VNYWBHKR.js → chunk-JD3K2344.js} +3 -3
- package/dist/{chunk-NCPZYQ4B.js → chunk-K3QGG4O2.js} +2 -2
- package/dist/{chunk-QR4FU53I.js → chunk-KCZSUJUR.js} +22 -12
- package/dist/chunk-KCZSUJUR.js.map +1 -0
- package/dist/{chunk-NH3QZYE5.js → chunk-KV4NU3RP.js} +2 -2
- package/dist/{chunk-NDSGJZI2.js → chunk-LOAYWTJJ.js} +2 -2
- package/dist/{chunk-ABVMUNCD.js → chunk-M3FBM4T3.js} +64 -10
- package/dist/chunk-M3FBM4T3.js.map +1 -0
- package/dist/{chunk-GMDSYLI6.js → chunk-MY2Q3FJ3.js} +2 -2
- package/dist/{chunk-CV47VCMQ.js → chunk-NPVA65KS.js} +2 -2
- package/dist/{chunk-7OCGBJLR.js → chunk-OIVFHJOA.js} +2 -2
- package/dist/{chunk-7FIXNAUO.js → chunk-OKB2NEDQ.js} +66 -43
- package/dist/chunk-OKB2NEDQ.js.map +1 -0
- package/dist/{chunk-3RXYOBME.js → chunk-OPQC4OWM.js} +5 -5
- package/dist/{chunk-3RXYOBME.js.map → chunk-OPQC4OWM.js.map} +1 -1
- package/dist/chunk-P5MXXHXQ.js +284 -0
- package/dist/chunk-P5MXXHXQ.js.map +1 -0
- package/dist/{chunk-IR74O2F6.js → chunk-PDG74IJT.js} +239 -162
- package/dist/chunk-PDG74IJT.js.map +1 -0
- package/dist/{chunk-NN5RYWXA.js → chunk-PH65MFQM.js} +6 -6
- package/dist/{chunk-TZNNJLGT.js → chunk-PMB6TYV4.js} +6 -6
- package/dist/chunk-QC65IOV3.js +304 -0
- package/dist/chunk-QC65IOV3.js.map +1 -0
- package/dist/{chunk-6YVJVUR4.js → chunk-QF2DROQR.js} +3 -3
- package/dist/{chunk-XXFSOVL3.js → chunk-QFDM23CO.js} +4 -4
- package/dist/{chunk-RMLADZRY.js → chunk-R7DGN73N.js} +5 -5
- package/dist/{chunk-5PNZBH6V.js → chunk-V5IYLWRA.js} +2 -2
- package/dist/{chunk-KQFIGI37.js → chunk-VA6CWUAE.js} +7 -7
- package/dist/{chunk-3GTUXW26.js → chunk-VIQOQ463.js} +19 -3
- package/dist/chunk-VIQOQ463.js.map +1 -0
- package/dist/{chunk-H2SSF24U.js → chunk-VRPPI6GU.js} +17 -6
- package/dist/{chunk-H2SSF24U.js.map → chunk-VRPPI6GU.js.map} +1 -1
- package/dist/{chunk-YETJNRQM.js → chunk-WEBMMJKL.js} +2 -1
- package/dist/{chunk-VUUN3KE4.js → chunk-XVCGPTEQ.js} +8 -8
- package/dist/chunk-XVCGPTEQ.js.map +1 -0
- package/dist/chunk-YWNF5755.js +696 -0
- package/dist/chunk-YWNF5755.js.map +1 -0
- package/dist/{chunk-UDCI3QTS.js → chunk-ZM2AYHMO.js} +2 -2
- package/dist/{claude-ONQTDWV3.js → claude-ACL7G4CF.js} +4 -4
- package/dist/{cleanup-YOM6PQCN.js → cleanup-RLBLNQZN.js} +37 -34
- package/dist/{cleanup-YOM6PQCN.js.map → cleanup-RLBLNQZN.js.map} +1 -1
- package/dist/cli.js +290 -141
- package/dist/cli.js.map +1 -1
- package/dist/{color-VQD52LOI.js → color-AC6F2QE7.js} +3 -3
- package/dist/{commit-DC2Q5CDY.js → commit-RILBXFWO.js} +15 -15
- package/dist/{compile-4NCQECKE.js → compile-QEL5724K.js} +11 -11
- package/dist/{contribute-M5UWXCAV.js → contribute-EHWLYOMZ.js} +11 -11
- package/dist/{contribute-M5UWXCAV.js.map → contribute-EHWLYOMZ.js.map} +1 -1
- package/dist/{mcp/darwin-3JFFE3W2.js → darwin-5K3I4FTH.js} +2 -2
- package/dist/{dev-server-CYRP6M73.js → dev-server-2WSWZXJG.js} +35 -21
- package/dist/dev-server-2WSWZXJG.js.map +1 -0
- package/dist/{feedback-BMAZGKRW.js → feedback-I6ZEHEUB.js} +17 -17
- package/dist/{git-BXUD6CL5.js → git-I3PO6FY7.js} +6 -6
- package/dist/ignite-XZFYRVRJ.js +35 -0
- package/dist/index.d.ts +200 -16
- package/dist/index.js +164 -55
- package/dist/index.js.map +1 -1
- package/dist/{init-CI43GJHV.js → init-A6WRP77L.js} +18 -18
- package/dist/{install-deps-SRTM5U7D.js → install-deps-HXP2TM7G.js} +11 -11
- package/dist/{installation-detector-HF6QN7KP.js → installation-detector-PYAZ2O6U.js} +3 -3
- package/dist/{issues-DMRQJH7E.js → issues-SUFQJY6O.js} +69 -56
- package/dist/issues-SUFQJY6O.js.map +1 -0
- package/dist/lint-FDZC77GL.js +27 -0
- package/dist/{linux-RYLOP2LY.js → linux-WUGRYCJY.js} +2 -2
- package/dist/mcp/{chunk-PIIRD4LO.js → chunk-4HZMW2V3.js} +1 -1
- package/dist/mcp/{chunk-PIIRD4LO.js.map → chunk-4HZMW2V3.js.map} +1 -1
- package/dist/{darwin-5BHWRJ7D.js → mcp/darwin-U25WIGH6.js} +2 -2
- package/dist/mcp/issue-management-server.js +900 -20
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/mcp/{linux-JBVS4R3A.js → linux-5BXVBGSY.js} +2 -2
- package/dist/mcp/recap-server.js +24 -22
- package/dist/mcp/recap-server.js.map +1 -1
- package/dist/mcp/{tmux-RYBLEHUZ.js → tmux-CU26ZTNM.js} +2 -2
- package/dist/mcp/{wsl-4QZIQLLE.js → wsl-KI25UDOF.js} +2 -2
- package/dist/neon-helpers-LCZAN4U4.js +11 -0
- package/dist/{open-2Y7GSUTJ.js → open-US4XACLW.js} +36 -21
- package/dist/open-US4XACLW.js.map +1 -0
- package/dist/{plan-SWFPLNJE.js → plan-PL3ZB32J.js} +47 -43
- package/dist/{plan-SWFPLNJE.js.map → plan-PL3ZB32J.js.map} +1 -1
- package/dist/{projects-IUSUXD5D.js → projects-L5AHUBGA.js} +6 -6
- package/dist/{prompt-7LZB4PAT.js → prompt-FUU5NMJQ.js} +3 -3
- package/dist/prompt-FUU5NMJQ.js.map +1 -0
- package/dist/prompts/init-prompt.txt +160 -23
- package/dist/prompts/issue-prompt.txt +93 -157
- package/dist/prompts/plan-prompt.txt +55 -0
- package/dist/prompts/swarm-orchestrator-prompt.txt +78 -21
- package/dist/{rebase-S6OHAOOF.js → rebase-JA3RW2XO.js} +12 -12
- package/dist/{recap-GGVCG5VH.js → recap-5TO42HN2.js} +9 -9
- package/dist/{remote-MZTFHHTU.js → remote-RO4LZKT2.js} +3 -3
- package/dist/remote-RO4LZKT2.js.map +1 -0
- package/dist/{run-ST3FR75O.js → run-KKCRBRLW.js} +36 -21
- package/dist/run-KKCRBRLW.js.map +1 -0
- package/dist/schema/settings.schema.json +147 -11
- package/dist/{shell-W4SBQPTE.js → shell-GAB2FCXH.js} +8 -8
- package/dist/{summary-P2JCIIJO.js → summary-P7QE3TNW.js} +21 -19
- package/dist/summary-P7QE3TNW.js.map +1 -0
- package/dist/test-6LFB5WOO.js +27 -0
- package/dist/{test-git-2KFFAQ6B.js → test-git-PYJOYSED.js} +6 -6
- package/dist/{test-jira-FKDKG6CD.js → test-jira-SM7IU5HW.js} +8 -8
- package/dist/{test-prefix-GP2DAX37.js → test-prefix-HIRZBXTM.js} +6 -6
- package/dist/{test-tabs-YDWMWTVA.js → test-tabs-NGPTFD5T.js} +2 -2
- package/dist/{test-webserver-QI3QQFZ3.js → test-webserver-43PVP2JL.js} +8 -8
- package/dist/{tmux-7ZTA3BDI.js → tmux-6LRFH3DM.js} +2 -2
- package/dist/{update-XLW7R7FL.js → update-AD3GE5C4.js} +4 -4
- package/dist/{update-notifier-EYLAXZAA.js → update-notifier-VYDTDMSJ.js} +3 -3
- package/dist/update-notifier-VYDTDMSJ.js.map +1 -0
- package/dist/{vscode-TOGE5N67.js → vscode-HXIXRZ3A.js} +12 -12
- package/dist/{vscode-announcement-NIX7O2MG.js → vscode-announcement-AL3EHORH.js} +3 -3
- package/dist/{wsl-Y4GUTOQ7.js → wsl-4VMVT2PO.js} +2 -2
- package/package.json +1 -1
- package/dist/ClaudeContextManager-SXDCWDJA.js +0 -14
- package/dist/ClaudeService-6E6MCGJE.js +0 -13
- package/dist/GitHubService-2R5GQG4K.js +0 -12
- package/dist/IssueTrackerFactory-XN6MQ4UN.js +0 -14
- package/dist/MetadataManager-CMQQTFLQ.js +0 -10
- package/dist/ProjectCapabilityDetector-IC6NAFGY.js +0 -11
- package/dist/SettingsMigrationManager-S6J7OHUH.js +0 -10
- package/dist/build-OLS6J5KZ.js +0 -27
- package/dist/chunk-3GTUXW26.js.map +0 -1
- package/dist/chunk-5UFGO4ZT.js.map +0 -1
- package/dist/chunk-7FIXNAUO.js.map +0 -1
- package/dist/chunk-ABVMUNCD.js.map +0 -1
- package/dist/chunk-ET6A2JR4.js.map +0 -1
- package/dist/chunk-IR74O2F6.js.map +0 -1
- package/dist/chunk-LL6TOX3G.js.map +0 -1
- package/dist/chunk-QR4FU53I.js.map +0 -1
- package/dist/chunk-QVAA5KHK.js.map +0 -1
- package/dist/chunk-RVI6C2H5.js +0 -220
- package/dist/chunk-RVI6C2H5.js.map +0 -1
- package/dist/chunk-VUUN3KE4.js.map +0 -1
- package/dist/chunk-WG4MLJ6J.js.map +0 -1
- package/dist/chunk-XFQGI2E3.js.map +0 -1
- package/dist/chunk-Y3RX7LZT.js.map +0 -1
- package/dist/chunk-YRCEOQPX.js.map +0 -1
- package/dist/dev-server-CYRP6M73.js.map +0 -1
- package/dist/ignite-IO4LXVXJ.js +0 -35
- package/dist/issues-DMRQJH7E.js.map +0 -1
- package/dist/lint-BSWRMGPZ.js +0 -27
- package/dist/neon-helpers-HWIYRKOW.js +0 -11
- package/dist/open-2Y7GSUTJ.js.map +0 -1
- package/dist/run-ST3FR75O.js.map +0 -1
- package/dist/summary-P2JCIIJO.js.map +0 -1
- package/dist/test-6JH4FE2X.js +0 -27
- /package/dist/{BranchNamingService-XBCO747L.js.map → BitBucketApiClient-J2ZSCS5N.js.map} +0 -0
- /package/dist/{ClaudeContextManager-SXDCWDJA.js.map → BitBucketVCSProvider-5X64IXXW.js.map} +0 -0
- /package/dist/{ClaudeService-6E6MCGJE.js.map → BranchNamingService-MEK2WZUD.js.map} +0 -0
- /package/dist/{GitHubService-2R5GQG4K.js.map → ClaudeContextManager-IENAE2CP.js.map} +0 -0
- /package/dist/{IssueTrackerFactory-XN6MQ4UN.js.map → ClaudeService-YIJCZUUB.js.map} +0 -0
- /package/dist/{MetadataManager-CMQQTFLQ.js.map → GitHubService-UTAYZXL3.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-IC6NAFGY.js.map → IssueTrackerFactory-2OI7YIN6.js.map} +0 -0
- /package/dist/{LoomLauncher-5AZU2F5I.js.map → LoomLauncher-3TSFW7QP.js.map} +0 -0
- /package/dist/{PromptTemplateManager-T5VTLJP3.js.map → MetadataManager-V4LSJ2PB.js.map} +0 -0
- /package/dist/{SettingsManager-WQ5NSGAH.js.map → ProjectCapabilityDetector-I4J66WKF.js.map} +0 -0
- /package/dist/{SettingsMigrationManager-S6J7OHUH.js.map → PromptTemplateManager-I75WKXM4.js.map} +0 -0
- /package/dist/{claude-ONQTDWV3.js.map → SettingsManager-BMQCAXPP.js.map} +0 -0
- /package/dist/{color-VQD52LOI.js.map → SettingsMigrationManager-ZPARZ5KH.js.map} +0 -0
- /package/dist/{darwin-5BHWRJ7D.js.map → browser-VZY7F2DF.js.map} +0 -0
- /package/dist/{build-OLS6J5KZ.js.map → build-DMWSIME6.js.map} +0 -0
- /package/dist/{chunk-G2MNSPA4.js.map → chunk-772N5WCA.js.map} +0 -0
- /package/dist/{chunk-NOMQ5RFG.js.map → chunk-7UBEHQTP.js.map} +0 -0
- /package/dist/{chunk-7NFCGKZT.js.map → chunk-AQUSMNBF.js.map} +0 -0
- /package/dist/{chunk-IDCE26KD.js.map → chunk-AUYSAMXV.js.map} +0 -0
- /package/dist/{chunk-HLDY5S4C.js.map → chunk-BFF27W3S.js.map} +0 -0
- /package/dist/{chunk-K7R5QY6C.js.map → chunk-CE676WCN.js.map} +0 -0
- /package/dist/{chunk-LHDD4JHC.js.map → chunk-D4Q7T5KD.js.map} +0 -0
- /package/dist/{chunk-RBYTXYGD.js.map → chunk-D75KSI3V.js.map} +0 -0
- /package/dist/{chunk-SQYHPBFP.js.map → chunk-EGNUOALL.js.map} +0 -0
- /package/dist/{chunk-ZAXRQLK3.js.map → chunk-FTYWGQFM.js.map} +0 -0
- /package/dist/{chunk-LE2NOUTN.js.map → chunk-FV4KXBGO.js.map} +0 -0
- /package/dist/{chunk-QNHZM5ZV.js.map → chunk-HIGWKLQR.js.map} +0 -0
- /package/dist/{chunk-VMZG66UV.js.map → chunk-HKEXRZMU.js.map} +0 -0
- /package/dist/{chunk-V4STTBQD.js.map → chunk-IHSA7VGI.js.map} +0 -0
- /package/dist/{chunk-TEJAGQX2.js.map → chunk-IS46GQRA.js.map} +0 -0
- /package/dist/{chunk-VNYWBHKR.js.map → chunk-JD3K2344.js.map} +0 -0
- /package/dist/{chunk-NCPZYQ4B.js.map → chunk-K3QGG4O2.js.map} +0 -0
- /package/dist/{chunk-NH3QZYE5.js.map → chunk-KV4NU3RP.js.map} +0 -0
- /package/dist/{chunk-NDSGJZI2.js.map → chunk-LOAYWTJJ.js.map} +0 -0
- /package/dist/{chunk-GMDSYLI6.js.map → chunk-MY2Q3FJ3.js.map} +0 -0
- /package/dist/{chunk-CV47VCMQ.js.map → chunk-NPVA65KS.js.map} +0 -0
- /package/dist/{chunk-7OCGBJLR.js.map → chunk-OIVFHJOA.js.map} +0 -0
- /package/dist/{chunk-NN5RYWXA.js.map → chunk-PH65MFQM.js.map} +0 -0
- /package/dist/{chunk-TZNNJLGT.js.map → chunk-PMB6TYV4.js.map} +0 -0
- /package/dist/{chunk-6YVJVUR4.js.map → chunk-QF2DROQR.js.map} +0 -0
- /package/dist/{chunk-XXFSOVL3.js.map → chunk-QFDM23CO.js.map} +0 -0
- /package/dist/{chunk-RMLADZRY.js.map → chunk-R7DGN73N.js.map} +0 -0
- /package/dist/{chunk-5PNZBH6V.js.map → chunk-V5IYLWRA.js.map} +0 -0
- /package/dist/{chunk-KQFIGI37.js.map → chunk-VA6CWUAE.js.map} +0 -0
- /package/dist/{chunk-YETJNRQM.js.map → chunk-WEBMMJKL.js.map} +0 -0
- /package/dist/{chunk-UDCI3QTS.js.map → chunk-ZM2AYHMO.js.map} +0 -0
- /package/dist/{git-BXUD6CL5.js.map → claude-ACL7G4CF.js.map} +0 -0
- /package/dist/{ignite-IO4LXVXJ.js.map → color-AC6F2QE7.js.map} +0 -0
- /package/dist/{commit-DC2Q5CDY.js.map → commit-RILBXFWO.js.map} +0 -0
- /package/dist/{compile-4NCQECKE.js.map → compile-QEL5724K.js.map} +0 -0
- /package/dist/{installation-detector-HF6QN7KP.js.map → darwin-5K3I4FTH.js.map} +0 -0
- /package/dist/{feedback-BMAZGKRW.js.map → feedback-I6ZEHEUB.js.map} +0 -0
- /package/dist/{mcp/darwin-3JFFE3W2.js.map → git-I3PO6FY7.js.map} +0 -0
- /package/dist/{neon-helpers-HWIYRKOW.js.map → ignite-XZFYRVRJ.js.map} +0 -0
- /package/dist/{init-CI43GJHV.js.map → init-A6WRP77L.js.map} +0 -0
- /package/dist/{install-deps-SRTM5U7D.js.map → install-deps-HXP2TM7G.js.map} +0 -0
- /package/dist/{prompt-7LZB4PAT.js.map → installation-detector-PYAZ2O6U.js.map} +0 -0
- /package/dist/{lint-BSWRMGPZ.js.map → lint-FDZC77GL.js.map} +0 -0
- /package/dist/{linux-RYLOP2LY.js.map → linux-WUGRYCJY.js.map} +0 -0
- /package/dist/{remote-MZTFHHTU.js.map → mcp/darwin-U25WIGH6.js.map} +0 -0
- /package/dist/mcp/{linux-JBVS4R3A.js.map → linux-5BXVBGSY.js.map} +0 -0
- /package/dist/mcp/{tmux-RYBLEHUZ.js.map → tmux-CU26ZTNM.js.map} +0 -0
- /package/dist/mcp/{wsl-4QZIQLLE.js.map → wsl-KI25UDOF.js.map} +0 -0
- /package/dist/{update-notifier-EYLAXZAA.js.map → neon-helpers-LCZAN4U4.js.map} +0 -0
- /package/dist/{projects-IUSUXD5D.js.map → projects-L5AHUBGA.js.map} +0 -0
- /package/dist/{rebase-S6OHAOOF.js.map → rebase-JA3RW2XO.js.map} +0 -0
- /package/dist/{recap-GGVCG5VH.js.map → recap-5TO42HN2.js.map} +0 -0
- /package/dist/{shell-W4SBQPTE.js.map → shell-GAB2FCXH.js.map} +0 -0
- /package/dist/{test-6JH4FE2X.js.map → test-6LFB5WOO.js.map} +0 -0
- /package/dist/{test-git-2KFFAQ6B.js.map → test-git-PYJOYSED.js.map} +0 -0
- /package/dist/{test-jira-FKDKG6CD.js.map → test-jira-SM7IU5HW.js.map} +0 -0
- /package/dist/{test-prefix-GP2DAX37.js.map → test-prefix-HIRZBXTM.js.map} +0 -0
- /package/dist/{test-tabs-YDWMWTVA.js.map → test-tabs-NGPTFD5T.js.map} +0 -0
- /package/dist/{test-webserver-QI3QQFZ3.js.map → test-webserver-43PVP2JL.js.map} +0 -0
- /package/dist/{tmux-7ZTA3BDI.js.map → tmux-6LRFH3DM.js.map} +0 -0
- /package/dist/{update-XLW7R7FL.js.map → update-AD3GE5C4.js.map} +0 -0
- /package/dist/{vscode-TOGE5N67.js.map → vscode-HXIXRZ3A.js.map} +0 -0
- /package/dist/{vscode-announcement-NIX7O2MG.js.map → vscode-announcement-AL3EHORH.js.map} +0 -0
- /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-
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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),
|
|
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(
|
|
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
|
|
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
|
|
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),
|
|
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.
|
|
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.
|
|
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}`);
|