@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.
- package/LICENSE +1 -1
- package/README.md +170 -15
- 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-RRGREEZQ.js +14 -0
- package/dist/ClaudeService-LEPW6QAC.js +13 -0
- package/dist/GitHubService-UTAYZXL3.js +12 -0
- package/dist/IssueTrackerFactory-KE2BDCLC.js +15 -0
- package/dist/{LoomLauncher-5AZU2F5I.js → LoomLauncher-GKQMR5E6.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 +170 -15
- package/dist/{SettingsManager-WQ5NSGAH.js → SettingsManager-KQU7OX7G.js} +15 -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 +5 -2
- 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-V3KADFMO.js +27 -0
- package/dist/{chunk-XXFSOVL3.js → chunk-3XEXT35Z.js} +4 -4
- package/dist/{chunk-YRCEOQPX.js → chunk-4JZEQBWV.js} +4 -3
- package/dist/chunk-4JZEQBWV.js.map +1 -0
- package/dist/{chunk-LE2NOUTN.js → chunk-4VQXMEEP.js} +3 -3
- 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-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-ZAXRQLK3.js → chunk-FTYWGQFM.js} +2 -2
- package/dist/{chunk-5PNZBH6V.js → chunk-H3T3EPF3.js} +2 -2
- package/dist/{chunk-VNYWBHKR.js → chunk-JD3K2344.js} +3 -3
- package/dist/{chunk-6YVJVUR4.js → chunk-JDN4SPV3.js} +3 -3
- package/dist/{chunk-NCPZYQ4B.js → chunk-K3QGG4O2.js} +2 -2
- package/dist/{chunk-ABVMUNCD.js → chunk-KQSV7FOG.js} +64 -10
- package/dist/chunk-KQSV7FOG.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-GMDSYLI6.js → chunk-MY2Q3FJ3.js} +2 -2
- package/dist/{chunk-CV47VCMQ.js → chunk-NPVA65KS.js} +2 -2
- package/dist/{chunk-RMLADZRY.js → chunk-NTDY5AMO.js} +5 -5
- package/dist/{chunk-UHIBKD73.js → chunk-NUUFP53X.js} +13 -32
- package/dist/{chunk-UHIBKD73.js.map → chunk-NUUFP53X.js.map} +1 -1
- package/dist/{chunk-7OCGBJLR.js → chunk-OIVFHJOA.js} +2 -2
- package/dist/chunk-P5MXXHXQ.js +284 -0
- package/dist/chunk-P5MXXHXQ.js.map +1 -0
- package/dist/{chunk-TEJAGQX2.js → chunk-PD75ZCFT.js} +35 -35
- package/dist/chunk-PD75ZCFT.js.map +1 -0
- package/dist/{chunk-NN5RYWXA.js → chunk-PH65MFQM.js} +6 -6
- package/dist/{chunk-LL6TOX3G.js → chunk-Q7VXHJP6.js} +10 -10
- package/dist/chunk-Q7VXHJP6.js.map +1 -0
- package/dist/chunk-QC65IOV3.js +304 -0
- package/dist/chunk-QC65IOV3.js.map +1 -0
- package/dist/{chunk-V4STTBQD.js → chunk-QED2WB2D.js} +9 -9
- package/dist/{chunk-3RXYOBME.js → chunk-QNPJXO53.js} +5 -5
- package/dist/{chunk-3RXYOBME.js.map → chunk-QNPJXO53.js.map} +1 -1
- package/dist/chunk-QQULYI2S.js +696 -0
- package/dist/chunk-QQULYI2S.js.map +1 -0
- package/dist/{chunk-QNHZM5ZV.js → chunk-QXGM32TO.js} +3 -3
- package/dist/{chunk-TZNNJLGT.js → chunk-RFCAPHL5.js} +6 -6
- package/dist/{chunk-7FIXNAUO.js → chunk-SA446KA2.js} +66 -43
- package/dist/chunk-SA446KA2.js.map +1 -0
- package/dist/{chunk-UDCI3QTS.js → chunk-SN4S5CWL.js} +2 -2
- package/dist/{chunk-VUUN3KE4.js → chunk-TAEVA4QR.js} +8 -8
- package/dist/chunk-TAEVA4QR.js.map +1 -0
- package/dist/{chunk-IR74O2F6.js → chunk-TN2D2RX7.js} +253 -174
- package/dist/chunk-TN2D2RX7.js.map +1 -0
- 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-XFQGI2E3.js → chunk-VVQQIG64.js} +58 -53
- package/dist/chunk-VVQQIG64.js.map +1 -0
- package/dist/{chunk-YETJNRQM.js → chunk-WEBMMJKL.js} +2 -1
- package/dist/{chunk-ET6A2JR4.js → chunk-WGUGB54H.js} +120 -18
- package/dist/chunk-WGUGB54H.js.map +1 -0
- package/dist/{chunk-QR4FU53I.js → chunk-X5DRLONY.js} +22 -12
- package/dist/chunk-X5DRLONY.js.map +1 -0
- package/dist/{chunk-KQFIGI37.js → chunk-XCP2WDYA.js} +7 -7
- package/dist/{chunk-VMZG66UV.js → chunk-YUOVWWJX.js} +312 -7
- package/dist/chunk-YUOVWWJX.js.map +1 -0
- package/dist/{chunk-HLDY5S4C.js → chunk-ZUIFO7B4.js} +3 -3
- package/dist/{claude-ONQTDWV3.js → claude-ACL7G4CF.js} +4 -4
- package/dist/{cleanup-YOM6PQCN.js → cleanup-RJKLI47I.js} +40 -37
- package/dist/cleanup-RJKLI47I.js.map +1 -0
- package/dist/cli.js +322 -169
- package/dist/cli.js.map +1 -1
- package/dist/{color-VQD52LOI.js → color-AC6F2QE7.js} +3 -3
- package/dist/{commit-DC2Q5CDY.js → commit-SUHRUMDE.js} +15 -15
- package/dist/{compile-4NCQECKE.js → compile-2MD346PO.js} +11 -11
- package/dist/{contribute-M5UWXCAV.js → contribute-P4BMRY7C.js} +11 -11
- package/dist/{contribute-M5UWXCAV.js.map → contribute-P4BMRY7C.js.map} +1 -1
- package/dist/{mcp/darwin-3JFFE3W2.js → darwin-5K3I4FTH.js} +2 -2
- package/dist/database-helpers-PRDFNDRO.js +11 -0
- package/dist/{dev-server-CYRP6M73.js → dev-server-ZNTLWOL5.js} +35 -21
- package/dist/dev-server-ZNTLWOL5.js.map +1 -0
- package/dist/{feedback-BMAZGKRW.js → feedback-Q6WG2WX4.js} +17 -17
- package/dist/{git-BXUD6CL5.js → git-TX2IEMB3.js} +6 -6
- package/dist/ignite-P644W2PK.js +35 -0
- package/dist/index.d.ts +236 -18
- package/dist/index.js +180 -63
- package/dist/index.js.map +1 -1
- package/dist/{init-CI43GJHV.js → init-5HFY7JG6.js} +18 -18
- package/dist/{install-deps-SRTM5U7D.js → install-deps-J4ALTM27.js} +11 -11
- package/dist/{installation-detector-HF6QN7KP.js → installation-detector-PYAZ2O6U.js} +3 -3
- package/dist/{issues-DMRQJH7E.js → issues-LZMIF22U.js} +69 -56
- package/dist/issues-LZMIF22U.js.map +1 -0
- package/dist/lint-XIXKU22H.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 +908 -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/{open-2Y7GSUTJ.js → open-KUO35JIJ.js} +36 -21
- package/dist/open-KUO35JIJ.js.map +1 -0
- package/dist/{plan-SWFPLNJE.js → plan-7CF56OIR.js} +47 -43
- package/dist/{plan-SWFPLNJE.js.map → plan-7CF56OIR.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 +184 -23
- package/dist/prompts/issue-prompt.txt +94 -158
- package/dist/prompts/plan-prompt.txt +55 -0
- package/dist/prompts/regular-prompt.txt +1 -1
- package/dist/prompts/swarm-orchestrator-prompt.txt +78 -21
- package/dist/{rebase-S6OHAOOF.js → rebase-MAMWPA2L.js} +12 -12
- package/dist/{recap-GGVCG5VH.js → recap-IDBO3KM5.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-RGZHCQ6M.js} +36 -21
- package/dist/run-RGZHCQ6M.js.map +1 -0
- package/dist/schema/settings.schema.json +171 -11
- package/dist/{shell-W4SBQPTE.js → shell-7ADCDFIV.js} +8 -8
- package/dist/{summary-P2JCIIJO.js → summary-7J2HORFD.js} +21 -19
- package/dist/summary-7J2HORFD.js.map +1 -0
- package/dist/test-SRB7EWU6.js +27 -0
- package/dist/{test-git-2KFFAQ6B.js → test-git-G7ATVIXG.js} +6 -6
- package/dist/{test-jira-FKDKG6CD.js → test-jira-Q2HPA522.js} +8 -8
- package/dist/{test-prefix-GP2DAX37.js → test-prefix-JMDGXR5A.js} +6 -6
- package/dist/{test-tabs-YDWMWTVA.js → test-tabs-NGPTFD5T.js} +2 -2
- package/dist/{test-webserver-QI3QQFZ3.js → test-webserver-GZFVXBGD.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-3I7ISHUU.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-TEJAGQX2.js.map +0 -1
- package/dist/chunk-VMZG66UV.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/cleanup-YOM6PQCN.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-RRGREEZQ.js.map} +0 -0
- /package/dist/{IssueTrackerFactory-XN6MQ4UN.js.map → ClaudeService-LEPW6QAC.js.map} +0 -0
- /package/dist/{MetadataManager-CMQQTFLQ.js.map → GitHubService-UTAYZXL3.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-IC6NAFGY.js.map → IssueTrackerFactory-KE2BDCLC.js.map} +0 -0
- /package/dist/{LoomLauncher-5AZU2F5I.js.map → LoomLauncher-GKQMR5E6.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-KQU7OX7G.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-V3KADFMO.js.map} +0 -0
- /package/dist/{chunk-XXFSOVL3.js.map → chunk-3XEXT35Z.js.map} +0 -0
- /package/dist/{chunk-LE2NOUTN.js.map → chunk-4VQXMEEP.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-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-5PNZBH6V.js.map → chunk-H3T3EPF3.js.map} +0 -0
- /package/dist/{chunk-VNYWBHKR.js.map → chunk-JD3K2344.js.map} +0 -0
- /package/dist/{chunk-6YVJVUR4.js.map → chunk-JDN4SPV3.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-RMLADZRY.js.map → chunk-NTDY5AMO.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-V4STTBQD.js.map → chunk-QED2WB2D.js.map} +0 -0
- /package/dist/{chunk-QNHZM5ZV.js.map → chunk-QXGM32TO.js.map} +0 -0
- /package/dist/{chunk-TZNNJLGT.js.map → chunk-RFCAPHL5.js.map} +0 -0
- /package/dist/{chunk-UDCI3QTS.js.map → chunk-SN4S5CWL.js.map} +0 -0
- /package/dist/{chunk-YETJNRQM.js.map → chunk-WEBMMJKL.js.map} +0 -0
- /package/dist/{chunk-KQFIGI37.js.map → chunk-XCP2WDYA.js.map} +0 -0
- /package/dist/{chunk-HLDY5S4C.js.map → chunk-ZUIFO7B4.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-SUHRUMDE.js.map} +0 -0
- /package/dist/{compile-4NCQECKE.js.map → compile-2MD346PO.js.map} +0 -0
- /package/dist/{installation-detector-HF6QN7KP.js.map → darwin-5K3I4FTH.js.map} +0 -0
- /package/dist/{mcp/darwin-3JFFE3W2.js.map → database-helpers-PRDFNDRO.js.map} +0 -0
- /package/dist/{feedback-BMAZGKRW.js.map → feedback-Q6WG2WX4.js.map} +0 -0
- /package/dist/{neon-helpers-HWIYRKOW.js.map → git-TX2IEMB3.js.map} +0 -0
- /package/dist/{prompt-7LZB4PAT.js.map → ignite-P644W2PK.js.map} +0 -0
- /package/dist/{init-CI43GJHV.js.map → init-5HFY7JG6.js.map} +0 -0
- /package/dist/{install-deps-SRTM5U7D.js.map → install-deps-J4ALTM27.js.map} +0 -0
- /package/dist/{remote-MZTFHHTU.js.map → installation-detector-PYAZ2O6U.js.map} +0 -0
- /package/dist/{lint-BSWRMGPZ.js.map → lint-XIXKU22H.js.map} +0 -0
- /package/dist/{linux-RYLOP2LY.js.map → linux-WUGRYCJY.js.map} +0 -0
- /package/dist/{update-notifier-EYLAXZAA.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/{projects-IUSUXD5D.js.map → projects-L5AHUBGA.js.map} +0 -0
- /package/dist/{rebase-S6OHAOOF.js.map → rebase-MAMWPA2L.js.map} +0 -0
- /package/dist/{recap-GGVCG5VH.js.map → recap-IDBO3KM5.js.map} +0 -0
- /package/dist/{shell-W4SBQPTE.js.map → shell-7ADCDFIV.js.map} +0 -0
- /package/dist/{test-6JH4FE2X.js.map → test-SRB7EWU6.js.map} +0 -0
- /package/dist/{test-git-2KFFAQ6B.js.map → test-git-G7ATVIXG.js.map} +0 -0
- /package/dist/{test-jira-FKDKG6CD.js.map → test-jira-Q2HPA522.js.map} +0 -0
- /package/dist/{test-prefix-GP2DAX37.js.map → test-prefix-JMDGXR5A.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-GZFVXBGD.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-3I7ISHUU.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
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DockerManager
|
|
4
|
+
} from "./chunk-AYLC633W.js";
|
|
5
|
+
import {
|
|
6
|
+
ProcessManager
|
|
7
|
+
} from "./chunk-H3T3EPF3.js";
|
|
8
|
+
import {
|
|
9
|
+
detectPackageManager,
|
|
10
|
+
runScript
|
|
11
|
+
} from "./chunk-VIQOQ463.js";
|
|
12
|
+
import {
|
|
13
|
+
getPackageScripts
|
|
14
|
+
} from "./chunk-K3QGG4O2.js";
|
|
15
|
+
import {
|
|
16
|
+
logger,
|
|
17
|
+
restoreTerminalState
|
|
18
|
+
} from "./chunk-VRPPI6GU.js";
|
|
19
|
+
|
|
20
|
+
// src/lib/DevServerManager.ts
|
|
21
|
+
import path from "path";
|
|
22
|
+
|
|
23
|
+
// src/lib/DockerDevServerStrategy.ts
|
|
24
|
+
import { execa } from "execa";
|
|
25
|
+
import net from "net";
|
|
26
|
+
function tcpProbe(port) {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
const socket = net.createConnection({ port, host: "127.0.0.1" });
|
|
29
|
+
socket.once("connect", () => {
|
|
30
|
+
socket.destroy();
|
|
31
|
+
resolve(true);
|
|
32
|
+
});
|
|
33
|
+
socket.once("error", () => {
|
|
34
|
+
socket.destroy();
|
|
35
|
+
resolve(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
var DockerDevServerStrategy = class {
|
|
40
|
+
constructor(_config, utils) {
|
|
41
|
+
this.utils = utils;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the container port using 3-tier fallback:
|
|
45
|
+
* 1. config.containerPort (explicit)
|
|
46
|
+
* 2. inspectImagePorts(imageName) (from built image)
|
|
47
|
+
* 3. parseDockerfileExpose(dockerfilePath) (from Dockerfile)
|
|
48
|
+
*
|
|
49
|
+
* Throws a clear error if all three return null.
|
|
50
|
+
*
|
|
51
|
+
* @param config - Docker config (may override the constructor config)
|
|
52
|
+
* @param imageName - Name of the built Docker image
|
|
53
|
+
* @param dockerfilePath - Absolute path to the Dockerfile
|
|
54
|
+
*/
|
|
55
|
+
async resolveContainerPort(config, imageName, dockerfilePath) {
|
|
56
|
+
if (config.containerPort !== void 0) {
|
|
57
|
+
return config.containerPort;
|
|
58
|
+
}
|
|
59
|
+
const inspectedPort = await this.utils.inspectImagePorts(imageName);
|
|
60
|
+
if (inspectedPort !== null) {
|
|
61
|
+
logger.debug(`Auto-detected container port ${inspectedPort} from Docker image inspect`);
|
|
62
|
+
return inspectedPort;
|
|
63
|
+
}
|
|
64
|
+
const exposedPort = await this.utils.parseDockerfileExpose(dockerfilePath);
|
|
65
|
+
if (exposedPort !== null) {
|
|
66
|
+
logger.debug(`Auto-detected container port ${exposedPort} from Dockerfile EXPOSE directive`);
|
|
67
|
+
return exposedPort;
|
|
68
|
+
}
|
|
69
|
+
throw new Error(
|
|
70
|
+
"Cannot determine container port. Set `devServer.docker.containerPort` in settings or add an `EXPOSE` directive to your Dockerfile."
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Build a Docker image for the worktree.
|
|
75
|
+
* Build context is always the worktree root directory.
|
|
76
|
+
*
|
|
77
|
+
* @param worktreePath - Absolute path to the worktree (build context)
|
|
78
|
+
* @param config - Docker config with Dockerfile path and build args
|
|
79
|
+
*/
|
|
80
|
+
async buildImage(worktreePath, config) {
|
|
81
|
+
const imageName = this.utils.buildImageName(config.identifier ?? worktreePath);
|
|
82
|
+
const dockerfilePath = config.dockerFile ?? "./Dockerfile";
|
|
83
|
+
const args = ["build", "-t", imageName, "-f", dockerfilePath];
|
|
84
|
+
if (config.buildArgs) {
|
|
85
|
+
for (const [key, value] of Object.entries(config.buildArgs)) {
|
|
86
|
+
args.push("--build-arg", `${key}=${value}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
args.push(".");
|
|
90
|
+
logger.info(`Building Docker image "${imageName}" from ${dockerfilePath}...`);
|
|
91
|
+
try {
|
|
92
|
+
await execa("docker", args, {
|
|
93
|
+
cwd: worktreePath,
|
|
94
|
+
stdio: "inherit"
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
98
|
+
throw new Error(`Docker build failed for image "${imageName}": ${message}`);
|
|
99
|
+
}
|
|
100
|
+
logger.success(`Docker image "${imageName}" built successfully`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Run a container in detached (background) mode.
|
|
104
|
+
* Force-removes any existing container with the same name first.
|
|
105
|
+
* Mounts the worktree at /app and adds an anonymous volume for node_modules.
|
|
106
|
+
* Forwards PORT and any envOverrides into the container.
|
|
107
|
+
*
|
|
108
|
+
* @param worktreePath - Absolute path to the worktree (mounted at /app)
|
|
109
|
+
* @param hostPort - Port on the host to map
|
|
110
|
+
* @param containerPort - Port inside the container
|
|
111
|
+
* @param config - Docker config with run args
|
|
112
|
+
* @param envOverrides - Additional environment variables to set in the container
|
|
113
|
+
* @returns The container name
|
|
114
|
+
*/
|
|
115
|
+
async runContainerDetached(worktreePath, hostPort, containerPort, config, envOverrides) {
|
|
116
|
+
const nameId = config.identifier ?? worktreePath;
|
|
117
|
+
const imageName = this.utils.buildImageName(nameId);
|
|
118
|
+
const containerName = this.utils.buildContainerName(nameId);
|
|
119
|
+
await execa("docker", ["rm", "-f", containerName], { reject: false });
|
|
120
|
+
const args = [
|
|
121
|
+
"run",
|
|
122
|
+
"-d",
|
|
123
|
+
"--name",
|
|
124
|
+
containerName,
|
|
125
|
+
"-p",
|
|
126
|
+
`${hostPort}:${containerPort}`,
|
|
127
|
+
// Mount worktree at /app
|
|
128
|
+
"-v",
|
|
129
|
+
`${worktreePath}:/app`,
|
|
130
|
+
// Anonymous volume for node_modules to prevent host/container conflicts
|
|
131
|
+
"-v",
|
|
132
|
+
"/app/node_modules",
|
|
133
|
+
// Forward PORT as the container port so the app listens where Docker expects.
|
|
134
|
+
// The -p mapping handles host-to-container translation.
|
|
135
|
+
"-e",
|
|
136
|
+
`PORT=${containerPort}`
|
|
137
|
+
];
|
|
138
|
+
if (envOverrides) {
|
|
139
|
+
for (const [key, value] of Object.entries(envOverrides)) {
|
|
140
|
+
args.push("-e", `${key}=${value}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (config.runArgs) {
|
|
144
|
+
args.push(...config.runArgs);
|
|
145
|
+
}
|
|
146
|
+
args.push(imageName);
|
|
147
|
+
logger.info(`Starting Docker container "${containerName}" in background (http://localhost:${hostPort} \u2192 container:${containerPort})...`);
|
|
148
|
+
try {
|
|
149
|
+
await execa("docker", args);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
152
|
+
throw new Error(`Failed to start Docker container "${containerName}": ${message}`);
|
|
153
|
+
}
|
|
154
|
+
logger.success(`Docker container "${containerName}" started on port ${hostPort}`);
|
|
155
|
+
return containerName;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Run a container in foreground (blocking) mode.
|
|
159
|
+
* The container is automatically removed on exit (--rm flag).
|
|
160
|
+
* Traps SIGINT and SIGTERM and forwards them to the container via docker stop.
|
|
161
|
+
*
|
|
162
|
+
* @param worktreePath - Absolute path to the worktree (mounted at /app)
|
|
163
|
+
* @param hostPort - Port on the host to map
|
|
164
|
+
* @param containerPort - Port inside the container
|
|
165
|
+
* @param config - Docker config with run args
|
|
166
|
+
* @param opts - Additional options (redirectToStderr, onProcessStarted, envOverrides)
|
|
167
|
+
* @returns Object with optional pid (Docker containers don't expose host PID)
|
|
168
|
+
*/
|
|
169
|
+
async runContainerForeground(worktreePath, hostPort, containerPort, config, opts = {}) {
|
|
170
|
+
const nameId = config.identifier ?? worktreePath;
|
|
171
|
+
const imageName = this.utils.buildImageName(nameId);
|
|
172
|
+
const containerName = this.utils.buildContainerName(nameId);
|
|
173
|
+
const { redirectToStderr, onProcessStarted, envOverrides } = opts;
|
|
174
|
+
await execa("docker", ["rm", "-f", containerName], { reject: false });
|
|
175
|
+
const args = [
|
|
176
|
+
"run",
|
|
177
|
+
"--rm",
|
|
178
|
+
"--name",
|
|
179
|
+
containerName,
|
|
180
|
+
"-p",
|
|
181
|
+
`${hostPort}:${containerPort}`,
|
|
182
|
+
// Mount worktree at /app
|
|
183
|
+
"-v",
|
|
184
|
+
`${worktreePath}:/app`,
|
|
185
|
+
// Anonymous volume for node_modules to prevent host/container conflicts
|
|
186
|
+
"-v",
|
|
187
|
+
"/app/node_modules",
|
|
188
|
+
// Forward PORT as the container port so the app listens where Docker expects.
|
|
189
|
+
// The -p mapping handles host-to-container translation.
|
|
190
|
+
"-e",
|
|
191
|
+
`PORT=${containerPort}`
|
|
192
|
+
];
|
|
193
|
+
if (envOverrides) {
|
|
194
|
+
for (const [key, value] of Object.entries(envOverrides)) {
|
|
195
|
+
args.push("-e", `${key}=${value}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (config.runArgs) {
|
|
199
|
+
args.push(...config.runArgs);
|
|
200
|
+
}
|
|
201
|
+
args.push(imageName);
|
|
202
|
+
logger.info(`Running Docker container "${containerName}" in foreground (http://localhost:${hostPort} \u2192 container:${containerPort})...`);
|
|
203
|
+
const stdio = redirectToStderr ? [process.stdin, process.stderr, process.stderr] : "inherit";
|
|
204
|
+
const forwardSignal = () => {
|
|
205
|
+
logger.debug(`Stopping container "${containerName}"`);
|
|
206
|
+
void execa("docker", ["stop", containerName], { reject: false });
|
|
207
|
+
};
|
|
208
|
+
const onSigint = () => forwardSignal();
|
|
209
|
+
const onSigterm = () => forwardSignal();
|
|
210
|
+
process.on("SIGINT", onSigint);
|
|
211
|
+
process.on("SIGTERM", onSigterm);
|
|
212
|
+
if (onProcessStarted) {
|
|
213
|
+
onProcessStarted(void 0);
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
await execa("docker", args, { stdio });
|
|
217
|
+
} finally {
|
|
218
|
+
process.removeListener("SIGINT", onSigint);
|
|
219
|
+
process.removeListener("SIGTERM", onSigterm);
|
|
220
|
+
restoreTerminalState();
|
|
221
|
+
}
|
|
222
|
+
return {};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Stop and remove a container by name.
|
|
226
|
+
* Uses docker rm -f which handles both running and stopped containers atomically.
|
|
227
|
+
* Handles already-stopped containers gracefully (no error thrown).
|
|
228
|
+
*
|
|
229
|
+
* @param containerName - Name of the container to stop and remove
|
|
230
|
+
*/
|
|
231
|
+
async stopContainer(containerName) {
|
|
232
|
+
logger.debug(`Stopping and removing container "${containerName}"...`);
|
|
233
|
+
await execa("docker", ["rm", "-f", containerName], { reject: false });
|
|
234
|
+
logger.debug(`Container "${containerName}" stopped and removed`);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check if a named container is currently running.
|
|
238
|
+
* Uses exact name matching with anchored regex to avoid partial name matches.
|
|
239
|
+
*
|
|
240
|
+
* @param containerName - Name of the container to check
|
|
241
|
+
* @returns true if the container is running, false otherwise
|
|
242
|
+
*/
|
|
243
|
+
async isContainerRunning(containerName) {
|
|
244
|
+
try {
|
|
245
|
+
const result = await execa("docker", [
|
|
246
|
+
"ps",
|
|
247
|
+
"--filter",
|
|
248
|
+
`name=^${containerName}$`,
|
|
249
|
+
"--format",
|
|
250
|
+
"{{.Names}}"
|
|
251
|
+
], { reject: false });
|
|
252
|
+
return result.exitCode === 0 && result.stdout.trim() === containerName;
|
|
253
|
+
} catch {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Wait for the dev server to be ready by probing the TCP port.
|
|
259
|
+
* Uses net.createConnection instead of lsof-based detection since Docker port
|
|
260
|
+
* forwarding shows com.docker.backend as the listening process (not the dev server).
|
|
261
|
+
* Exits early if the container has stopped (crash detection).
|
|
262
|
+
*
|
|
263
|
+
* @param port - Host port to probe
|
|
264
|
+
* @param timeout - Maximum time to wait in milliseconds
|
|
265
|
+
* @param interval - Interval between probes in milliseconds
|
|
266
|
+
* @param containerName - Optional container name to monitor for early exit
|
|
267
|
+
* @returns true if the port accepts connections within the timeout, false otherwise
|
|
268
|
+
*/
|
|
269
|
+
async waitForReady(port, timeout, interval, containerName) {
|
|
270
|
+
const startTime = Date.now();
|
|
271
|
+
let attempts = 0;
|
|
272
|
+
while (Date.now() - startTime < timeout) {
|
|
273
|
+
attempts++;
|
|
274
|
+
if (containerName && attempts % 3 === 0) {
|
|
275
|
+
const stillRunning = await this.isContainerRunning(containerName);
|
|
276
|
+
if (!stillRunning) {
|
|
277
|
+
logger.warn(
|
|
278
|
+
`Docker container "${containerName}" exited before becoming ready (after ${attempts} attempts, ${Date.now() - startTime}ms)`
|
|
279
|
+
);
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const isReady = await tcpProbe(port);
|
|
284
|
+
if (isReady) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
await new Promise((resolve) => globalThis.setTimeout(resolve, interval));
|
|
288
|
+
}
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/lib/NativeDevServerStrategy.ts
|
|
294
|
+
import { execa as execa2 } from "execa";
|
|
295
|
+
import { setTimeout } from "timers/promises";
|
|
296
|
+
|
|
297
|
+
// src/utils/dev-server.ts
|
|
298
|
+
async function buildDevServerCommand(workspacePath) {
|
|
299
|
+
const packageManager = await detectPackageManager(workspacePath);
|
|
300
|
+
let devCommand;
|
|
301
|
+
switch (packageManager) {
|
|
302
|
+
case "pnpm":
|
|
303
|
+
devCommand = "pnpm dev";
|
|
304
|
+
break;
|
|
305
|
+
case "npm":
|
|
306
|
+
devCommand = "npm run dev";
|
|
307
|
+
break;
|
|
308
|
+
case "yarn":
|
|
309
|
+
devCommand = "yarn dev";
|
|
310
|
+
break;
|
|
311
|
+
default:
|
|
312
|
+
logger.warn(`Unknown or unsupported package manager: ${packageManager}, defaulting to npm`);
|
|
313
|
+
devCommand = "npm run dev";
|
|
314
|
+
}
|
|
315
|
+
logger.debug(`Dev server command: ${devCommand}`);
|
|
316
|
+
return devCommand;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/lib/NativeDevServerStrategy.ts
|
|
320
|
+
var NativeDevServerStrategy = class {
|
|
321
|
+
constructor(processManager, startupTimeout, checkInterval) {
|
|
322
|
+
this.runningServers = /* @__PURE__ */ new Map();
|
|
323
|
+
this.processManager = processManager;
|
|
324
|
+
this.startupTimeout = startupTimeout;
|
|
325
|
+
this.checkInterval = checkInterval;
|
|
326
|
+
}
|
|
327
|
+
async isRunning(port) {
|
|
328
|
+
const process2 = await this.processManager.detectDevServer(port);
|
|
329
|
+
return process2 !== null;
|
|
330
|
+
}
|
|
331
|
+
async startBackground(worktreePath, port, envOverrides) {
|
|
332
|
+
const scripts = await getPackageScripts(worktreePath);
|
|
333
|
+
if (!scripts["dev"]) {
|
|
334
|
+
logger.warn('Skipping auto-start: no "dev" script found in package.json or package.iloom.json');
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const devCommand = await buildDevServerCommand(worktreePath);
|
|
338
|
+
logger.debug(`Starting dev server with command: ${devCommand}`);
|
|
339
|
+
const serverProcess = execa2("sh", ["-c", devCommand], {
|
|
340
|
+
cwd: worktreePath,
|
|
341
|
+
env: {
|
|
342
|
+
...process.env,
|
|
343
|
+
...envOverrides,
|
|
344
|
+
PORT: port.toString()
|
|
345
|
+
},
|
|
346
|
+
// Important: Don't inherit stdio - server runs in background
|
|
347
|
+
stdio: "ignore",
|
|
348
|
+
// Detach from parent process so it continues running
|
|
349
|
+
detached: true
|
|
350
|
+
});
|
|
351
|
+
this.runningServers.set(port, serverProcess);
|
|
352
|
+
serverProcess.on("exit", () => {
|
|
353
|
+
this.runningServers.delete(port);
|
|
354
|
+
});
|
|
355
|
+
serverProcess.unref();
|
|
356
|
+
logger.info(`Waiting for dev server to start on port ${port}...`);
|
|
357
|
+
const ready = await this.waitForReady(port, serverProcess);
|
|
358
|
+
if (!ready) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`Dev server failed to start within ${this.startupTimeout}ms timeout`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
logger.success(`Dev server started successfully on port ${port}`);
|
|
364
|
+
}
|
|
365
|
+
async startForeground(worktreePath, port, opts) {
|
|
366
|
+
const { redirectToStderr = false, onProcessStarted, envOverrides } = opts;
|
|
367
|
+
logger.debug(`Starting dev server in foreground on port ${port}`);
|
|
368
|
+
if (redirectToStderr) {
|
|
369
|
+
const devCommand = await buildDevServerCommand(worktreePath);
|
|
370
|
+
logger.debug(`Starting dev server with command: ${devCommand}`);
|
|
371
|
+
const serverProcess = execa2("sh", ["-c", devCommand], {
|
|
372
|
+
cwd: worktreePath,
|
|
373
|
+
env: {
|
|
374
|
+
...process.env,
|
|
375
|
+
...envOverrides,
|
|
376
|
+
PORT: port.toString()
|
|
377
|
+
},
|
|
378
|
+
stdio: [process.stdin, process.stderr, process.stderr]
|
|
379
|
+
});
|
|
380
|
+
const processInfo = serverProcess.pid !== void 0 ? { pid: serverProcess.pid } : {};
|
|
381
|
+
if (onProcessStarted) {
|
|
382
|
+
onProcessStarted(processInfo.pid);
|
|
383
|
+
}
|
|
384
|
+
const onSigint = () => {
|
|
385
|
+
};
|
|
386
|
+
process.on("SIGINT", onSigint);
|
|
387
|
+
try {
|
|
388
|
+
await serverProcess;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
const execaError = error;
|
|
391
|
+
if (execaError.signal !== "SIGINT") {
|
|
392
|
+
throw error;
|
|
393
|
+
}
|
|
394
|
+
} finally {
|
|
395
|
+
process.removeListener("SIGINT", onSigint);
|
|
396
|
+
restoreTerminalState();
|
|
397
|
+
}
|
|
398
|
+
return processInfo;
|
|
399
|
+
}
|
|
400
|
+
return await runScript("dev", worktreePath, [], {
|
|
401
|
+
env: {
|
|
402
|
+
...envOverrides,
|
|
403
|
+
PORT: port.toString()
|
|
404
|
+
},
|
|
405
|
+
foreground: true,
|
|
406
|
+
...onProcessStarted && { onStart: onProcessStarted },
|
|
407
|
+
noCi: true
|
|
408
|
+
// Dev servers should not have CI=true
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
async stop(port) {
|
|
412
|
+
const serverProcess = this.runningServers.get(port);
|
|
413
|
+
if (!serverProcess) {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
if (serverProcess.pid) {
|
|
418
|
+
process.kill(-serverProcess.pid, "SIGTERM");
|
|
419
|
+
} else {
|
|
420
|
+
serverProcess.kill();
|
|
421
|
+
}
|
|
422
|
+
this.runningServers.delete(port);
|
|
423
|
+
return true;
|
|
424
|
+
} catch (error) {
|
|
425
|
+
logger.warn(
|
|
426
|
+
`Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
427
|
+
);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Stop all tracked server processes. Called during cleanup.
|
|
433
|
+
*/
|
|
434
|
+
async stopAll() {
|
|
435
|
+
for (const [port] of this.runningServers.entries()) {
|
|
436
|
+
await this.stop(port);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Wait for server to be ready by polling the port.
|
|
441
|
+
* Exits early if the spawned process has already exited (crash detection).
|
|
442
|
+
* Public so DevServerManager can reuse it for Docker mode readiness checks.
|
|
443
|
+
*
|
|
444
|
+
* @param port - Port to poll
|
|
445
|
+
* @param processRef - Optional spawned process to monitor for early exit
|
|
446
|
+
*/
|
|
447
|
+
async waitForReady(port, processRef) {
|
|
448
|
+
const startTime = Date.now();
|
|
449
|
+
let attempts = 0;
|
|
450
|
+
while (Date.now() - startTime < this.startupTimeout) {
|
|
451
|
+
attempts++;
|
|
452
|
+
if (processRef && processRef.exitCode != null) {
|
|
453
|
+
logger.warn(
|
|
454
|
+
`Dev server process exited with code ${processRef.exitCode} before becoming ready (after ${attempts} attempts, ${Date.now() - startTime}ms)`
|
|
455
|
+
);
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
const processInfo = await this.processManager.detectDevServer(port);
|
|
459
|
+
if (processInfo) {
|
|
460
|
+
logger.debug(
|
|
461
|
+
`Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`
|
|
462
|
+
);
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
await setTimeout(this.checkInterval);
|
|
466
|
+
}
|
|
467
|
+
logger.warn(
|
|
468
|
+
`Server did not start on port ${port} after ${this.startupTimeout}ms (${attempts} attempts)`
|
|
469
|
+
);
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// src/lib/DevServerManager.ts
|
|
475
|
+
var DEFAULT_STARTUP_TIMEOUT = 18e4;
|
|
476
|
+
var dockerUtils = {
|
|
477
|
+
parseDockerfileExpose: (filePath) => DockerManager.parseExposeFromDockerfile(filePath),
|
|
478
|
+
inspectImagePorts: (imageName) => DockerManager.inspectImagePorts(imageName),
|
|
479
|
+
buildContainerName: (id) => DockerManager.buildContainerName(id),
|
|
480
|
+
buildImageName: (id) => DockerManager.buildImageName(id),
|
|
481
|
+
assertDockerAvailable: () => DockerManager.assertAvailable()
|
|
482
|
+
};
|
|
483
|
+
function getStartupTimeout() {
|
|
484
|
+
const envTimeout = process.env.ILOOM_DEV_SERVER_TIMEOUT;
|
|
485
|
+
if (envTimeout) {
|
|
486
|
+
const parsed = parseInt(envTimeout, 10);
|
|
487
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
488
|
+
return parsed;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return DEFAULT_STARTUP_TIMEOUT;
|
|
492
|
+
}
|
|
493
|
+
function toStrategyConfig(config) {
|
|
494
|
+
return {
|
|
495
|
+
dockerFile: config.dockerFile,
|
|
496
|
+
containerPort: config.containerPort,
|
|
497
|
+
buildArgs: config.dockerBuildArgs,
|
|
498
|
+
runArgs: config.dockerRunArgs,
|
|
499
|
+
identifier: config.identifier
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
var DevServerManager = class {
|
|
503
|
+
constructor(processManager, options = {}) {
|
|
504
|
+
this.runningDockerContainers = /* @__PURE__ */ new Map();
|
|
505
|
+
this.processManager = processManager ?? new ProcessManager();
|
|
506
|
+
this.options = {
|
|
507
|
+
startupTimeout: options.startupTimeout ?? getStartupTimeout(),
|
|
508
|
+
checkInterval: options.checkInterval ?? 1e3
|
|
509
|
+
};
|
|
510
|
+
this.nativeStrategy = new NativeDevServerStrategy(
|
|
511
|
+
this.processManager,
|
|
512
|
+
this.options.startupTimeout,
|
|
513
|
+
this.options.checkInterval
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Create a DockerDevServerStrategy for the given Docker config.
|
|
518
|
+
* The strategy encapsulates all Docker container lifecycle operations.
|
|
519
|
+
*/
|
|
520
|
+
createDockerStrategy(dockerConfig) {
|
|
521
|
+
return new DockerDevServerStrategy(toStrategyConfig(dockerConfig), dockerUtils);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Ensure dev server is running on the specified port.
|
|
525
|
+
* If not running, start it and wait for it to be ready.
|
|
526
|
+
*
|
|
527
|
+
* @param worktreePath - Path to the worktree
|
|
528
|
+
* @param port - Port the server should run on
|
|
529
|
+
* @param dockerConfig - Optional Docker configuration for container-based server
|
|
530
|
+
* @returns true if server is ready, false if startup failed/timed out
|
|
531
|
+
*/
|
|
532
|
+
async ensureServerRunning(worktreePath, port, dockerConfig) {
|
|
533
|
+
logger.debug(`Checking if dev server is running on port ${port}...`);
|
|
534
|
+
if (dockerConfig) {
|
|
535
|
+
const strategy = this.createDockerStrategy(dockerConfig);
|
|
536
|
+
const containerName = dockerUtils.buildContainerName(dockerConfig.identifier);
|
|
537
|
+
const isRunning = await strategy.isContainerRunning(containerName);
|
|
538
|
+
if (isRunning) {
|
|
539
|
+
logger.debug(`Docker container "${containerName}" already running on port ${port}`);
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
logger.info(`Docker dev server not running on port ${port}, starting...`);
|
|
543
|
+
try {
|
|
544
|
+
await this.startDockerServer(worktreePath, port, dockerConfig, strategy);
|
|
545
|
+
return true;
|
|
546
|
+
} catch (error) {
|
|
547
|
+
logger.error(
|
|
548
|
+
`Failed to start Docker dev server: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
549
|
+
);
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const existingProcess = await this.processManager.detectDevServer(port);
|
|
554
|
+
if (existingProcess) {
|
|
555
|
+
logger.debug(
|
|
556
|
+
`Dev server already running on port ${port} (PID: ${existingProcess.pid})`
|
|
557
|
+
);
|
|
558
|
+
return true;
|
|
559
|
+
}
|
|
560
|
+
logger.info(`Dev server not running on port ${port}, starting...`);
|
|
561
|
+
try {
|
|
562
|
+
await this.nativeStrategy.startBackground(worktreePath, port);
|
|
563
|
+
return true;
|
|
564
|
+
} catch (error) {
|
|
565
|
+
logger.error(
|
|
566
|
+
`Failed to start dev server: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
567
|
+
);
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Start dev server in Docker container (background) and wait for it to be ready.
|
|
573
|
+
* Builds the image, resolves the container port, starts the container detached,
|
|
574
|
+
* and polls the host port for readiness.
|
|
575
|
+
*/
|
|
576
|
+
async startDockerServer(worktreePath, port, dockerConfig, strategy) {
|
|
577
|
+
const strategyConfig = toStrategyConfig(dockerConfig);
|
|
578
|
+
const imageName = dockerUtils.buildImageName(dockerConfig.identifier);
|
|
579
|
+
const dockerfilePath = path.resolve(worktreePath, dockerConfig.dockerFile);
|
|
580
|
+
await strategy.buildImage(worktreePath, strategyConfig);
|
|
581
|
+
const containerPort = await strategy.resolveContainerPort(
|
|
582
|
+
strategyConfig,
|
|
583
|
+
imageName,
|
|
584
|
+
dockerfilePath
|
|
585
|
+
);
|
|
586
|
+
const containerName = await strategy.runContainerDetached(
|
|
587
|
+
worktreePath,
|
|
588
|
+
port,
|
|
589
|
+
containerPort,
|
|
590
|
+
strategyConfig
|
|
591
|
+
);
|
|
592
|
+
this.runningDockerContainers.set(port, containerName);
|
|
593
|
+
logger.info(`Waiting for Docker dev server to start on port ${port}...`);
|
|
594
|
+
const ready = await strategy.waitForReady(
|
|
595
|
+
port,
|
|
596
|
+
this.options.startupTimeout,
|
|
597
|
+
this.options.checkInterval,
|
|
598
|
+
containerName
|
|
599
|
+
);
|
|
600
|
+
if (!ready) {
|
|
601
|
+
await strategy.stopContainer(containerName);
|
|
602
|
+
this.runningDockerContainers.delete(port);
|
|
603
|
+
throw new Error(
|
|
604
|
+
`Docker dev server failed to start within ${this.options.startupTimeout}ms timeout`
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
logger.success(`Docker dev server started successfully on port ${port}`);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Check if a dev server is running on the specified port
|
|
611
|
+
*
|
|
612
|
+
* @param port - Port to check
|
|
613
|
+
* @param dockerConfig - Optional Docker configuration; when provided, checks container status
|
|
614
|
+
* @returns true if server is running, false otherwise
|
|
615
|
+
*/
|
|
616
|
+
async isServerRunning(port, dockerConfig) {
|
|
617
|
+
if (dockerConfig) {
|
|
618
|
+
const strategy = this.createDockerStrategy(dockerConfig);
|
|
619
|
+
const containerName = dockerUtils.buildContainerName(dockerConfig.identifier);
|
|
620
|
+
return strategy.isContainerRunning(containerName);
|
|
621
|
+
}
|
|
622
|
+
const existingProcess = await this.processManager.detectDevServer(port);
|
|
623
|
+
return existingProcess !== null;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Run dev server in foreground mode (blocking).
|
|
627
|
+
* This method blocks until the server is stopped (e.g., via Ctrl+C).
|
|
628
|
+
*
|
|
629
|
+
* @param worktreePath - Path to the worktree
|
|
630
|
+
* @param port - Port the server should run on
|
|
631
|
+
* @param redirectToStderr - If true, redirect stdout/stderr to stderr (useful for JSON output)
|
|
632
|
+
* @param onProcessStarted - Callback called immediately after process starts with PID
|
|
633
|
+
* @returns Process information including PID
|
|
634
|
+
*/
|
|
635
|
+
async runServerForeground(worktreePath, port, redirectToStderr = false, onProcessStarted, envOverrides, dockerConfig) {
|
|
636
|
+
if (dockerConfig) {
|
|
637
|
+
logger.debug(`Starting Docker dev server in foreground on port ${port}`);
|
|
638
|
+
const strategy = this.createDockerStrategy(dockerConfig);
|
|
639
|
+
const strategyConfig = toStrategyConfig(dockerConfig);
|
|
640
|
+
const imageName = dockerUtils.buildImageName(dockerConfig.identifier);
|
|
641
|
+
const containerName = dockerUtils.buildContainerName(dockerConfig.identifier);
|
|
642
|
+
const dockerfilePath = path.resolve(worktreePath, dockerConfig.dockerFile);
|
|
643
|
+
await strategy.buildImage(worktreePath, strategyConfig);
|
|
644
|
+
const containerPort = await strategy.resolveContainerPort(
|
|
645
|
+
strategyConfig,
|
|
646
|
+
imageName,
|
|
647
|
+
dockerfilePath
|
|
648
|
+
);
|
|
649
|
+
if (onProcessStarted) {
|
|
650
|
+
onProcessStarted(void 0);
|
|
651
|
+
}
|
|
652
|
+
this.runningDockerContainers.set(port, containerName);
|
|
653
|
+
try {
|
|
654
|
+
await strategy.runContainerForeground(
|
|
655
|
+
worktreePath,
|
|
656
|
+
port,
|
|
657
|
+
containerPort,
|
|
658
|
+
strategyConfig,
|
|
659
|
+
{ redirectToStderr, envOverrides }
|
|
660
|
+
);
|
|
661
|
+
} finally {
|
|
662
|
+
this.runningDockerContainers.delete(port);
|
|
663
|
+
}
|
|
664
|
+
return {};
|
|
665
|
+
}
|
|
666
|
+
return this.nativeStrategy.startForeground(worktreePath, port, {
|
|
667
|
+
redirectToStderr,
|
|
668
|
+
...onProcessStarted !== void 0 && { onProcessStarted },
|
|
669
|
+
...envOverrides !== void 0 && { envOverrides }
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Clean up all running server processes and Docker containers.
|
|
674
|
+
* This should be called when the manager is being disposed.
|
|
675
|
+
*/
|
|
676
|
+
async cleanup() {
|
|
677
|
+
await this.nativeStrategy.stopAll();
|
|
678
|
+
for (const [port, containerName] of this.runningDockerContainers.entries()) {
|
|
679
|
+
try {
|
|
680
|
+
logger.debug(`Cleaning up Docker container "${containerName}" on port ${port}`);
|
|
681
|
+
const strategy = new DockerDevServerStrategy({}, dockerUtils);
|
|
682
|
+
await strategy.stopContainer(containerName);
|
|
683
|
+
} catch (error) {
|
|
684
|
+
logger.warn(
|
|
685
|
+
`Failed to stop Docker container "${containerName}" on port ${port}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
this.runningDockerContainers.clear();
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
export {
|
|
694
|
+
DevServerManager
|
|
695
|
+
};
|
|
696
|
+
//# sourceMappingURL=chunk-QQULYI2S.js.map
|