@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
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SettingsMigrationManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AUYSAMXV.js";
|
|
5
5
|
import {
|
|
6
6
|
ShellCompletion
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QXGM32TO.js";
|
|
8
8
|
import {
|
|
9
9
|
TelemetryService
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MY2Q3FJ3.js";
|
|
11
11
|
import {
|
|
12
12
|
FirstRunManager
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EGNUOALL.js";
|
|
14
14
|
import {
|
|
15
15
|
AgentManager
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import
|
|
16
|
+
} from "./chunk-JD3K2344.js";
|
|
17
|
+
import "./chunk-4VQXMEEP.js";
|
|
18
|
+
import {
|
|
19
|
+
PromptTemplateManager
|
|
20
|
+
} from "./chunk-7RCUWU3I.js";
|
|
21
|
+
import "./chunk-NPVA65KS.js";
|
|
19
22
|
import {
|
|
20
23
|
parseGitRemotes
|
|
21
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-BZ7KTXPB.js";
|
|
22
25
|
import {
|
|
23
26
|
detectClaudeCli,
|
|
24
27
|
launchClaude
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import {
|
|
27
|
-
PromptTemplateManager
|
|
28
|
-
} from "./chunk-WG4MLJ6J.js";
|
|
28
|
+
} from "./chunk-DDHWZNGL.js";
|
|
29
29
|
import {
|
|
30
30
|
getRepoRoot,
|
|
31
31
|
isFileGitignored
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-QNPJXO53.js";
|
|
33
|
+
import "./chunk-WGUGB54H.js";
|
|
34
|
+
import "./chunk-4JZEQBWV.js";
|
|
35
|
+
import "./chunk-FTYWGQFM.js";
|
|
36
36
|
import {
|
|
37
37
|
logger
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-VRPPI6GU.js";
|
|
39
39
|
|
|
40
40
|
// src/commands/init.ts
|
|
41
41
|
import chalk from "chalk";
|
|
@@ -461,4 +461,4 @@ var InitCommand = class {
|
|
|
461
461
|
export {
|
|
462
462
|
InitCommand
|
|
463
463
|
};
|
|
464
|
-
//# sourceMappingURL=init-
|
|
464
|
+
//# sourceMappingURL=init-5HFY7JG6.js.map
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ScriptCommandBase
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-QED2WB2D.js";
|
|
5
|
+
import "./chunk-SN4S5CWL.js";
|
|
6
6
|
import {
|
|
7
7
|
installDependencies
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-VIQOQ463.js";
|
|
9
|
+
import "./chunk-4VQXMEEP.js";
|
|
10
|
+
import "./chunk-K3QGG4O2.js";
|
|
11
|
+
import "./chunk-QNPJXO53.js";
|
|
12
|
+
import "./chunk-WGUGB54H.js";
|
|
13
|
+
import "./chunk-4JZEQBWV.js";
|
|
14
|
+
import "./chunk-FTYWGQFM.js";
|
|
15
15
|
import {
|
|
16
16
|
logger
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-VRPPI6GU.js";
|
|
18
18
|
|
|
19
19
|
// src/commands/install-deps.ts
|
|
20
20
|
var InstallDepsCommand = class extends ScriptCommandBase {
|
|
@@ -40,4 +40,4 @@ var InstallDepsCommand = class extends ScriptCommandBase {
|
|
|
40
40
|
export {
|
|
41
41
|
InstallDepsCommand
|
|
42
42
|
};
|
|
43
|
-
//# sourceMappingURL=install-deps-
|
|
43
|
+
//# sourceMappingURL=install-deps-J4ALTM27.js.map
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
detectInstallationMethod,
|
|
4
4
|
shouldShowUpdateNotification
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-LOAYWTJJ.js";
|
|
6
|
+
import "./chunk-VRPPI6GU.js";
|
|
7
7
|
export {
|
|
8
8
|
detectInstallationMethod,
|
|
9
9
|
shouldShowUpdateNotification
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=installation-detector-
|
|
11
|
+
//# sourceMappingURL=installation-detector-PYAZ2O6U.js.map
|
|
@@ -4,28 +4,28 @@ import {
|
|
|
4
4
|
} from "./chunk-4232AHNQ.js";
|
|
5
5
|
import {
|
|
6
6
|
IssueTrackerFactory
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NUUFP53X.js";
|
|
8
8
|
import {
|
|
9
|
-
|
|
9
|
+
JiraIssueTracker,
|
|
10
10
|
fetchLinearIssueList
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-DMSL5BAP.js";
|
|
12
|
+
import "./chunk-D4Q7T5KD.js";
|
|
13
13
|
import {
|
|
14
14
|
fetchGitHubIssueList,
|
|
15
15
|
fetchGitHubPRList
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-KV4NU3RP.js";
|
|
17
|
+
import "./chunk-NPVA65KS.js";
|
|
18
18
|
import {
|
|
19
19
|
findMainWorktreePathWithSettings
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QNPJXO53.js";
|
|
21
21
|
import {
|
|
22
22
|
SettingsManager
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-WGUGB54H.js";
|
|
24
|
+
import "./chunk-4JZEQBWV.js";
|
|
25
25
|
import {
|
|
26
26
|
getLogger
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-
|
|
27
|
+
} from "./chunk-FTYWGQFM.js";
|
|
28
|
+
import "./chunk-VRPPI6GU.js";
|
|
29
29
|
|
|
30
30
|
// src/commands/issues.ts
|
|
31
31
|
import os from "os";
|
|
@@ -68,7 +68,7 @@ var IssuesCommand = class {
|
|
|
68
68
|
* @returns Array of issue list items
|
|
69
69
|
*/
|
|
70
70
|
async execute(options) {
|
|
71
|
-
var _a, _b, _c, _d, _e;
|
|
71
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
72
72
|
const logger = getLogger();
|
|
73
73
|
const limit = (options == null ? void 0 : options.limit) ?? 100;
|
|
74
74
|
const sprint = options == null ? void 0 : options.sprint;
|
|
@@ -116,55 +116,68 @@ var IssuesCommand = class {
|
|
|
116
116
|
...mine ? { mine } : {}
|
|
117
117
|
});
|
|
118
118
|
} else if (provider === "jira") {
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
const apiToken = jiraSettings == null ? void 0 : jiraSettings.apiToken;
|
|
133
|
-
if (!apiToken) {
|
|
134
|
-
throw new Error(
|
|
135
|
-
"Jira API token not configured. Set issueManagement.jira.apiToken in your settings.json or settings.local.json."
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
const projectKey = jiraSettings == null ? void 0 : jiraSettings.projectKey;
|
|
139
|
-
if (!projectKey) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
"Jira project key not configured. Set issueManagement.jira.projectKey in your settings.json."
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
const doneStatuses = jiraSettings == null ? void 0 : jiraSettings.doneStatuses;
|
|
145
|
-
const client = new JiraApiClient({ host, username, apiToken });
|
|
146
|
-
results = await fetchJiraIssueList(client, { host, projectKey, doneStatuses, limit, sprint, mine });
|
|
119
|
+
const tracker = JiraIssueTracker.fromSettings(settings);
|
|
120
|
+
const trackerConfig = tracker.getConfig();
|
|
121
|
+
const doneStatuses = (_f = (_e = settings.issueManagement) == null ? void 0 : _e.jira) == null ? void 0 : _f.doneStatuses;
|
|
122
|
+
results = await fetchJiraIssueList(tracker.getApiClient(), {
|
|
123
|
+
host: trackerConfig.host,
|
|
124
|
+
projectKey: trackerConfig.projectKey,
|
|
125
|
+
...doneStatuses ? { doneStatuses } : {},
|
|
126
|
+
limit,
|
|
127
|
+
sprint,
|
|
128
|
+
mine
|
|
129
|
+
});
|
|
147
130
|
} else {
|
|
148
131
|
throw new Error(`Unsupported issue tracker provider: ${provider}`);
|
|
149
132
|
}
|
|
150
133
|
results.forEach((item) => {
|
|
151
134
|
item.type = "issue";
|
|
152
135
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
const vcsProvider = ((_g = settings.versionControl) == null ? void 0 : _g.provider) ?? "github";
|
|
137
|
+
if (vcsProvider === "bitbucket") {
|
|
138
|
+
try {
|
|
139
|
+
const bbSettings = (_h = settings.versionControl) == null ? void 0 : _h.bitbucket;
|
|
140
|
+
if (!(bbSettings == null ? void 0 : bbSettings.username) || !(bbSettings == null ? void 0 : bbSettings.apiToken)) {
|
|
141
|
+
logger.warn("BitBucket username or API token not configured. Skipping PR fetch.");
|
|
142
|
+
} else {
|
|
143
|
+
const { BitBucketVCSProvider } = await import("./BitBucketVCSProvider-5X64IXXW.js");
|
|
144
|
+
const bbProvider = BitBucketVCSProvider.fromSettings(settings);
|
|
145
|
+
const bbPRs = await bbProvider.listPullRequests(resolvedProjectPath);
|
|
146
|
+
const prItems = bbPRs.map((pr) => ({
|
|
147
|
+
id: String(pr.id),
|
|
148
|
+
title: `[PR] ${pr.title}`,
|
|
149
|
+
updatedAt: pr.updated_on,
|
|
150
|
+
url: pr.links.html.href,
|
|
151
|
+
state: pr.state.toLowerCase(),
|
|
152
|
+
type: "pr"
|
|
153
|
+
}));
|
|
154
|
+
results = [...results, ...prItems];
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
const isExpectedError = error instanceof Error && (error.message.includes("BitBucket API error (401)") || error.message.includes("BitBucket API error (403)") || error.message.includes("BitBucket API request failed") || error.message.includes("Could not determine BitBucket workspace/repository") || error.message.includes("ETIMEDOUT") || error.message.includes("ECONNREFUSED"));
|
|
158
|
+
if (isExpectedError) {
|
|
159
|
+
logger.warn(`BitBucket PR fetch failed (non-fatal), continuing with issues only: ${error.message}`);
|
|
160
|
+
} else {
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
try {
|
|
166
|
+
const prs = await fetchGitHubPRList({
|
|
167
|
+
limit,
|
|
168
|
+
cwd: resolvedProjectPath,
|
|
169
|
+
...mine ? { mine } : {}
|
|
170
|
+
});
|
|
171
|
+
const prItems = prs.map((pr) => ({ ...pr, type: "pr" }));
|
|
172
|
+
results = [...results, ...prItems];
|
|
173
|
+
} catch (error) {
|
|
174
|
+
const stderr = error.stderr ?? "";
|
|
175
|
+
const isExpectedError = error instanceof Error && (error.message.includes("not logged in") || error.message.includes("auth login") || error.message.includes("rate limit") || error.message.includes("ETIMEDOUT") || error.message.includes("ECONNREFUSED") || error.message.includes("no git remotes found") || stderr.includes("not logged in") || stderr.includes("rate limit"));
|
|
176
|
+
if (isExpectedError) {
|
|
177
|
+
logger.warn(`PR fetch failed (non-fatal), continuing with issues only: ${error.message}`);
|
|
178
|
+
} else {
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
168
181
|
}
|
|
169
182
|
}
|
|
170
183
|
results.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
@@ -176,4 +189,4 @@ var IssuesCommand = class {
|
|
|
176
189
|
export {
|
|
177
190
|
IssuesCommand
|
|
178
191
|
};
|
|
179
|
-
//# sourceMappingURL=issues-
|
|
192
|
+
//# sourceMappingURL=issues-LZMIF22U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/issues.ts"],"sourcesContent":["import os from 'os'\nimport path from 'path'\nimport fs from 'fs-extra'\nimport crypto from 'crypto'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { IssueTrackerFactory } from '../lib/IssueTrackerFactory.js'\nimport { findMainWorktreePathWithSettings } from '../utils/git.js'\nimport { fetchGitHubIssueList, fetchGitHubPRList } from '../utils/github.js'\nimport { fetchLinearIssueList } from '../utils/linear.js'\nimport { fetchJiraIssueList } from '../utils/jira.js'\nimport { JiraIssueTracker } from '../lib/providers/jira/JiraIssueTracker.js'\nimport { getLogger } from '../utils/logger-context.js'\n\n/**\n * Unified output interface for issues from any provider\n */\nexport interface IssueListItem {\n id: string\n title: string\n updatedAt: string\n url: string\n state: string\n type?: 'issue' | 'pr'\n}\n\n/**\n * File-based cache structure (follows UpdateNotifier pattern)\n */\ninterface IssuesCacheFile {\n timestamp: number // Date.now() when cached\n projectPath: string // for verification\n provider: string // 'github' | 'linear' | 'jira'\n data: IssueListItem[]\n}\n\n// Cache configuration\nconst CACHE_TTL_MS = 2 * 60 * 1000 // 2 minutes\nconst CACHE_DIR = path.join(os.homedir(), '.config', 'iloom-ai', 'cache')\n\n/**\n * Generate a deterministic cache file path from project path + provider\n */\nfunction getCacheFilePath(projectPath: string, provider: string, limit: number, sprint?: string, mine?: boolean): string {\n const hash = crypto.createHash('md5').update(`${projectPath}:${provider}:${limit}:${sprint ?? ''}:${mine ? 'mine' : ''}`).digest('hex').slice(0, 12)\n return path.join(CACHE_DIR, `issues-${hash}.json`)\n}\n\n/**\n * Read cache file, return null if missing/expired/corrupted\n * Follows UpdateNotifier.getCachedCheck pattern\n */\nasync function readCacheFile(cacheFilePath: string): Promise<IssueListItem[] | null> {\n try {\n if (!fs.existsSync(cacheFilePath)) return null\n const content = await fs.readFile(cacheFilePath, 'utf8')\n const cache = JSON.parse(content) as IssuesCacheFile\n if (Date.now() - cache.timestamp < CACHE_TTL_MS) return cache.data\n return null // expired\n } catch {\n return null // corrupted or unreadable, treat as cache miss\n }\n}\n\n/**\n * Write cache file following UpdateNotifier.saveCacheFile pattern\n */\nasync function writeCacheFile(\n cacheFilePath: string,\n data: IssueListItem[],\n projectPath: string,\n provider: string,\n): Promise<void> {\n try {\n await fs.ensureDir(CACHE_DIR)\n const cache: IssuesCacheFile = { timestamp: Date.now(), projectPath, provider, data }\n await fs.writeFile(cacheFilePath, JSON.stringify(cache, null, 2), 'utf8')\n } catch {\n // Cache write failure is non-fatal, just log debug\n getLogger().debug(`Failed to write issues cache to ${cacheFilePath}`)\n }\n}\n\nexport interface IssuesCommandOptions {\n projectPath?: string | undefined\n limit?: number | undefined\n sprint?: string | undefined\n mine?: boolean | undefined\n}\n\n/**\n * IssuesCommand: List open issues from the configured issue tracker\n *\n * Returns JSON array of issues. Uses file-based caching with ~2 minute TTL.\n * Follows the ProjectsCommand pattern for structure.\n */\nexport class IssuesCommand {\n private readonly settingsManager: SettingsManager\n\n constructor(settingsManager?: SettingsManager) {\n this.settingsManager = settingsManager ?? new SettingsManager()\n }\n\n /**\n * Execute the issues command\n * @param options - Command options\n * @returns Array of issue list items\n */\n async execute(options?: IssuesCommandOptions): Promise<IssueListItem[]> {\n const logger = getLogger()\n const limit = options?.limit ?? 100\n const sprint = options?.sprint\n const mine = options?.mine\n\n // 1. Resolve project root\n let resolvedProjectPath: string\n if (options?.projectPath) {\n resolvedProjectPath = options.projectPath\n } else {\n try {\n resolvedProjectPath = await findMainWorktreePathWithSettings()\n } catch {\n logger.debug('Failed to resolve worktree path, falling back to cwd')\n resolvedProjectPath = process.cwd()\n }\n }\n\n // 2. Load settings from resolved root\n const settings = await this.settingsManager.loadSettings(resolvedProjectPath)\n\n // 3. Determine provider\n const provider = IssueTrackerFactory.getProviderName(settings)\n\n // Warn if Jira-only flags used with non-Jira provider (--sprint is Jira-only; --mine works across all providers)\n if (provider !== 'jira' && sprint) {\n logger.warn('--sprint flag is only supported with the Jira issue tracker. Ignoring.')\n }\n\n // 4. Check file-based cache\n const cacheFilePath = getCacheFilePath(resolvedProjectPath, provider, limit, sprint, mine)\n const cached = await readCacheFile(cacheFilePath)\n if (cached !== null) {\n logger.debug(`Returning cached issues (${cached.length} items)`)\n // Backfill type field for cache entries from before PR support was added\n return cached.map(item => ({ type: 'issue' as const, ...item }))\n }\n\n // 5. Fetch issues based on provider\n let results: IssueListItem[]\n\n if (provider === 'github') {\n results = await fetchGitHubIssueList({\n limit,\n cwd: resolvedProjectPath,\n ...(mine ? { mine } : {}),\n })\n } else if (provider === 'linear') {\n const teamId = settings.issueManagement?.linear?.teamId\n if (!teamId) {\n throw new Error(\n 'Linear team ID not configured. Set issueManagement.linear.teamId in your settings.json.',\n )\n }\n const apiToken = settings.issueManagement?.linear?.apiToken ?? process.env.LINEAR_API_TOKEN\n results = await fetchLinearIssueList(teamId, {\n limit,\n ...(apiToken ? { apiToken } : {}),\n ...(mine ? { mine } : {}),\n })\n } else if (provider === 'jira') {\n const tracker = JiraIssueTracker.fromSettings(settings)\n const trackerConfig = tracker.getConfig()\n const doneStatuses = settings.issueManagement?.jira?.doneStatuses\n results = await fetchJiraIssueList(tracker.getApiClient(), {\n host: trackerConfig.host,\n projectKey: trackerConfig.projectKey,\n ...(doneStatuses ? { doneStatuses } : {}),\n limit,\n sprint,\n mine,\n })\n } else {\n throw new Error(`Unsupported issue tracker provider: ${provider}`)\n }\n\n // Tag issues with type\n results.forEach(item => { item.type = 'issue' })\n\n // 6. Fetch PRs from VCS provider (GitHub or BitBucket)\n const vcsProvider = settings.versionControl?.provider ?? 'github'\n\n if (vcsProvider === 'bitbucket') {\n try {\n const bbSettings = settings.versionControl?.bitbucket\n if (!bbSettings?.username || !bbSettings?.apiToken) {\n logger.warn('BitBucket username or API token not configured. Skipping PR fetch.')\n } else {\n const { BitBucketVCSProvider } = await import('../lib/providers/bitbucket/BitBucketVCSProvider.js')\n const bbProvider = BitBucketVCSProvider.fromSettings(settings)\n const bbPRs = await bbProvider.listPullRequests(resolvedProjectPath)\n const prItems: IssueListItem[] = bbPRs.map(pr => ({\n id: String(pr.id),\n title: `[PR] ${pr.title}`,\n updatedAt: pr.updated_on,\n url: pr.links.html.href,\n state: pr.state.toLowerCase(),\n type: 'pr' as const,\n }))\n results = [...results, ...prItems]\n }\n } catch (error) {\n // Only catch expected, non-fatal BitBucket errors\n const isExpectedError = error instanceof Error && (\n error.message.includes('BitBucket API error (401)') ||\n error.message.includes('BitBucket API error (403)') ||\n error.message.includes('BitBucket API request failed') ||\n error.message.includes('Could not determine BitBucket workspace/repository') ||\n error.message.includes('ETIMEDOUT') ||\n error.message.includes('ECONNREFUSED')\n )\n if (isExpectedError) {\n logger.warn(`BitBucket PR fetch failed (non-fatal), continuing with issues only: ${error.message}`)\n } else {\n throw error\n }\n }\n } else {\n try {\n const prs = await fetchGitHubPRList({\n limit,\n cwd: resolvedProjectPath,\n ...(mine ? { mine } : {}),\n })\n const prItems: IssueListItem[] = prs.map(pr => ({ ...pr, type: 'pr' as const }))\n results = [...results, ...prItems]\n } catch (error) {\n // Only catch expected, non-fatal errors from gh CLI\n // Per CLAUDE.md: \"DO NOT SWALLOW ERRORS\" -- must check specifically\n const stderr = (error as NodeJS.ErrnoException & { stderr?: string }).stderr ?? ''\n const isExpectedError = error instanceof Error && (\n error.message.includes('not logged in') ||\n error.message.includes('auth login') ||\n error.message.includes('rate limit') ||\n error.message.includes('ETIMEDOUT') ||\n error.message.includes('ECONNREFUSED') ||\n error.message.includes('no git remotes found') ||\n stderr.includes('not logged in') ||\n stderr.includes('rate limit')\n )\n if (isExpectedError) {\n logger.warn(`PR fetch failed (non-fatal), continuing with issues only: ${error.message}`)\n } else {\n throw error // Re-throw unexpected errors -- do not swallow\n }\n }\n }\n\n // 7. Sort by updatedAt descending and apply limit\n results.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())\n results = results.slice(0, limit)\n\n // 8. Write results to cache file\n await writeCacheFile(cacheFilePath, results, resolvedProjectPath, provider)\n\n return results\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ScriptCommandBase
|
|
4
|
+
} from "./chunk-QED2WB2D.js";
|
|
5
|
+
import "./chunk-SN4S5CWL.js";
|
|
6
|
+
import "./chunk-VIQOQ463.js";
|
|
7
|
+
import "./chunk-4VQXMEEP.js";
|
|
8
|
+
import "./chunk-K3QGG4O2.js";
|
|
9
|
+
import "./chunk-QNPJXO53.js";
|
|
10
|
+
import "./chunk-WGUGB54H.js";
|
|
11
|
+
import "./chunk-4JZEQBWV.js";
|
|
12
|
+
import "./chunk-FTYWGQFM.js";
|
|
13
|
+
import "./chunk-VRPPI6GU.js";
|
|
14
|
+
|
|
15
|
+
// src/commands/lint.ts
|
|
16
|
+
var LintCommand = class extends ScriptCommandBase {
|
|
17
|
+
getScriptName() {
|
|
18
|
+
return "lint";
|
|
19
|
+
}
|
|
20
|
+
getScriptDisplayName() {
|
|
21
|
+
return "Lint";
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
LintCommand
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=lint-XIXKU22H.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
buildCommandSequence,
|
|
4
4
|
logger
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VRPPI6GU.js";
|
|
6
6
|
|
|
7
7
|
// src/utils/terminal-backends/linux.ts
|
|
8
8
|
import { execa } from "execa";
|
|
@@ -100,4 +100,4 @@ export {
|
|
|
100
100
|
LinuxBackend,
|
|
101
101
|
detectLinuxTerminal
|
|
102
102
|
};
|
|
103
|
-
//# sourceMappingURL=linux-
|
|
103
|
+
//# sourceMappingURL=linux-WUGRYCJY.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/terminal-backends/darwin.ts","../../src/utils/terminal-backends/command-builder.ts","../../src/utils/env.ts","../../src/utils/logger.ts","../../src/utils/terminal.ts","../../src/utils/platform-detect.ts"],"sourcesContent":["import { execa } from 'execa'\nimport { existsSync } from 'node:fs'\nimport type { TerminalWindowOptions } from '../terminal.js'\nimport type { TerminalBackend } from './types.js'\nimport { buildCommandSequence } from './command-builder.js'\n\n/**\n * Detect if iTerm2 is installed on macOS.\n */\nexport function detectITerm2(): boolean {\n\treturn existsSync('/Applications/iTerm.app')\n}\n\n/**\n * Escape command string for embedding inside an AppleScript `do script \"...\"`.\n */\nfunction escapeForAppleScript(command: string): string {\n\treturn command\n\t\t.replace(/\\\\/g, '\\\\\\\\')\n\t\t.replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Build AppleScript for macOS Terminal.app (single tab).\n *\n * Delegates to the shared buildCommandSequence for command construction,\n * then wraps the result with AppleScript escaping for `do script \"...\"`.\n */\nasync function buildTerminalAppScript(options: TerminalWindowOptions): Promise<string> {\n\tconst command = await buildCommandSequence(options)\n\n\tlet script = `tell application \"Terminal\"\\n`\n\tscript += ` set newTab to do script \"${escapeForAppleScript(command)}\"\\n`\n\n\tif (options.backgroundColor) {\n\t\tconst { r, g, b } = options.backgroundColor\n\t\tscript += ` set background color of newTab to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += `end tell`\n\treturn script\n}\n\n/**\n * Build iTerm2 AppleScript for a single tab in a new window.\n */\nasync function buildITerm2SingleTabScript(options: TerminalWindowOptions): Promise<string> {\n\tconst command = await buildCommandSequence(options)\n\n\tlet script = 'tell application id \"com.googlecode.iterm2\"\\n'\n\tscript += ' create window with default profile\\n'\n\tscript += ' set s1 to current session of current window\\n\\n'\n\n\tif (options.backgroundColor) {\n\t\tconst { r, g, b } = options.backgroundColor\n\t\tscript += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += ` tell s1 to write text \"${escapeForAppleScript(command)}\"\\n\\n`\n\n\tif (options.title) {\n\t\tscript += ` set name of s1 to \"${escapeForAppleScript(options.title)}\"\\n\\n`\n\t}\n\n\tscript += ' activate\\n'\n\tscript += 'end tell'\n\treturn script\n}\n\n/**\n * Build iTerm2 AppleScript for multiple tabs (2+) in a single window.\n */\nasync function buildITerm2MultiTabScript(\n\toptionsArray: TerminalWindowOptions[]\n): Promise<string> {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('buildITerm2MultiTabScript requires at least 2 terminal options')\n\t}\n\n\tlet script = 'tell application id \"com.googlecode.iterm2\"\\n'\n\tscript += ' create window with default profile\\n'\n\tscript += ' set newWindow to current window\\n'\n\n\tconst options1 = optionsArray[0]\n\tif (!options1) {\n\t\tthrow new Error('First terminal option is undefined')\n\t}\n\tconst command1 = await buildCommandSequence(options1)\n\n\tscript += ' set s1 to current session of newWindow\\n\\n'\n\n\tif (options1.backgroundColor) {\n\t\tconst { r, g, b } = options1.backgroundColor\n\t\tscript += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += ` tell s1 to write text \"${escapeForAppleScript(command1)}\"\\n\\n`\n\n\tif (options1.title) {\n\t\tscript += ` set name of s1 to \"${escapeForAppleScript(options1.title)}\"\\n\\n`\n\t}\n\n\tfor (let i = 1; i < optionsArray.length; i++) {\n\t\tconst options = optionsArray[i]\n\t\tif (!options) {\n\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t}\n\t\tconst command = await buildCommandSequence(options)\n\t\tconst sessionVar = `s${i + 1}`\n\n\t\tscript += ' tell newWindow\\n'\n\t\tscript += ` set newTab${i} to (create tab with default profile)\\n`\n\t\tscript += ' end tell\\n'\n\t\tscript += ` set ${sessionVar} to current session of newTab${i}\\n\\n`\n\n\t\tif (options.backgroundColor) {\n\t\t\tconst { r, g, b } = options.backgroundColor\n\t\t\tscript += ` set background color of ${sessionVar} to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t\t}\n\n\t\tscript += ` tell ${sessionVar} to write text \"${escapeForAppleScript(command)}\"\\n\\n`\n\n\t\tif (options.title) {\n\t\t\tscript += ` set name of ${sessionVar} to \"${escapeForAppleScript(options.title)}\"\\n\\n`\n\t\t}\n\t}\n\n\tscript += ' activate\\n'\n\tscript += 'end tell'\n\treturn script\n}\n\n/**\n * macOS terminal backend — supports Terminal.app and iTerm2.\n */\nexport class DarwinBackend implements TerminalBackend {\n\treadonly name = 'darwin'\n\n\tasync openSingle(options: TerminalWindowOptions): Promise<void> {\n\t\tconst hasITerm2 = detectITerm2()\n\n\t\tconst applescript = hasITerm2\n\t\t\t? await buildITerm2SingleTabScript(options)\n\t\t\t: await buildTerminalAppScript(options)\n\n\t\ttry {\n\t\t\tawait execa('osascript', ['-e', applescript])\n\n\t\t\tif (!hasITerm2) {\n\t\t\t\tawait execa('osascript', ['-e', 'tell application \"Terminal\" to activate'])\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to open terminal window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\tasync openMultiple(optionsArray: TerminalWindowOptions[]): Promise<void> {\n\t\tconst hasITerm2 = detectITerm2()\n\n\t\tif (hasITerm2) {\n\t\t\tconst applescript = await buildITerm2MultiTabScript(optionsArray)\n\n\t\t\ttry {\n\t\t\t\tawait execa('osascript', ['-e', applescript])\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to open iTerm2 window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\tfor (let i = 0; i < optionsArray.length; i++) {\n\t\t\t\tconst options = optionsArray[i]\n\t\t\t\tif (!options) {\n\t\t\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t\t\t}\n\t\t\t\tawait this.openSingle(options)\n\n\t\t\t\tif (i < optionsArray.length - 1) {\n\t\t\t\t\tawait new Promise<void>((resolve) => globalThis.setTimeout(resolve, 1000))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import { existsSync } from 'node:fs'\nimport type { TerminalWindowOptions } from '../terminal.js'\nimport { buildEnvSourceCommands } from '../env.js'\n\n/**\n * Build the shell command sequence from TerminalWindowOptions.\n *\n * The returned string is a chain of commands joined by ` && `, prefixed with\n * a space to prevent shell history pollution (HISTCONTROL=ignorespace).\n *\n * This logic is shared across all backends — each backend applies its own\n * escaping on top of the raw command string.\n */\nexport async function buildCommandSequence(options: TerminalWindowOptions): Promise<string> {\n\tconst {\n\t\tworkspacePath,\n\t\tcommand,\n\t\tport,\n\t\tincludeEnvSetup,\n\t\tincludePortExport,\n\t} = options\n\n\tconst commands: string[] = []\n\n\tif (workspacePath) {\n\t\tcommands.push(`cd '${escapeSingleQuotes(workspacePath)}'`)\n\t}\n\n\tif (includeEnvSetup && workspacePath) {\n\t\tconst sourceCommands = await buildEnvSourceCommands(\n\t\t\tworkspacePath,\n\t\t\tasync (p) => existsSync(p)\n\t\t)\n\t\tcommands.push(...sourceCommands)\n\t}\n\n\tif (includePortExport && port !== undefined) {\n\t\tcommands.push(`export PORT=${port}`)\n\t}\n\n\tif (command) {\n\t\tcommands.push(command)\n\t}\n\n\tconst fullCommand = commands.join(' && ')\n\n\t// Prefix with space to prevent shell history pollution\n\treturn ` ${fullCommand}`\n}\n\n/**\n * Escape single quotes for use inside a single-quoted shell string.\n * 'it'\\''s' → ends quote, adds escaped quote, resumes quote\n */\nexport function escapeSingleQuotes(s: string): string {\n\treturn s.replace(/'/g, \"'\\\\''\")\n}\n\n/**\n * Convert {r, g, b} (0–255) to a hex color string \"#RRGGBB\".\n */\nexport function rgbToHex(rgb: { r: number; g: number; b: number }): string {\n\tconst toHex = (n: number): string => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, '0')\n\treturn `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`\n}\n","import path from 'path'\nimport dotenvFlow, { type DotenvFlowConfigOptions } from 'dotenv-flow'\nimport { logger } from './logger.js'\n\n/**\n * Parse .env file content into key-value map\n * Handles comments, empty lines, quoted/unquoted values, multiline values\n */\nexport function parseEnvFile(content: string): Map<string, string> {\n const envMap = new Map<string, string>()\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n\n // Skip empty lines and comments\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n continue\n }\n\n // Remove 'export ' prefix if present\n const cleanLine = trimmedLine.startsWith('export ')\n ? trimmedLine.substring(7)\n : trimmedLine\n\n // Find the first equals sign\n const equalsIndex = cleanLine.indexOf('=')\n if (equalsIndex === -1) {\n continue\n }\n\n const key = cleanLine.substring(0, equalsIndex).trim()\n let value = cleanLine.substring(equalsIndex + 1)\n\n // Handle quoted values\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.substring(1, value.length - 1)\n // Unescape quotes\n value = value.replace(/\\\\\"/g, '\"').replace(/\\\\'/g, \"'\")\n // Unescape newlines\n value = value.replace(/\\\\n/g, '\\n')\n }\n\n if (key) {\n envMap.set(key, value)\n }\n }\n\n return envMap\n}\n\n/**\n * Format environment variable as line for .env file\n * Always quotes values and escapes internal quotes\n */\nexport function formatEnvLine(key: string, value: string): string {\n // Escape quotes and newlines in the value\n const escapedValue = value\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n\n return `${key}=\"${escapedValue}\"`\n}\n\n/**\n * Validate environment variable name and value\n */\nexport function validateEnvVariable(\n key: string,\n _value?: string\n): { valid: boolean; error?: string } {\n if (!key || key.length === 0) {\n return {\n valid: false,\n error: 'Environment variable key cannot be empty',\n }\n }\n\n if (!isValidEnvKey(key)) {\n return {\n valid: false,\n error: `Invalid environment variable name: ${key}. Must start with a letter or underscore and contain only letters, numbers, and underscores.`,\n }\n }\n\n // Values can be any string, including empty\n return { valid: true }\n}\n\n/**\n * Normalize line endings for cross-platform compatibility\n */\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n')\n}\n\n/**\n * Extract port from .env file if present\n */\nexport function extractPort(envContent: Map<string, string>): number | null {\n const portValue = envContent.get('PORT')\n if (!portValue) {\n return null\n }\n\n const port = parseInt(portValue, 10)\n if (isNaN(port)) {\n return null\n }\n\n return port\n}\n\n/**\n * Check if environment variable key is valid\n */\nexport function isValidEnvKey(key: string): boolean {\n if (!key || key.length === 0) {\n return false\n }\n\n // Must start with letter or underscore, followed by letters, numbers, or underscores\n const validKeyRegex = /^[A-Za-z_][A-Za-z0-9_]*$/\n return validKeyRegex.test(key)\n}\n\n/**\n * Load environment variables using dotenv-flow\n * Supports environment-specific files (.env.development, .env.production, etc.)\n * and local overrides (.env.local, .env.development.local)\n */\nexport function loadEnvIntoProcess(options?: {\n path?: string\n nodeEnv?: string\n defaultNodeEnv?: string\n}): { parsed?: Record<string, string>; error?: Error } {\n logger.debug('Loading environment variables with dotenv-flow', {\n options: {\n path: options?.path ?? 'current working directory',\n nodeEnv: options?.nodeEnv ?? 'not specified',\n defaultNodeEnv: options?.defaultNodeEnv ?? 'development (default)'\n }\n })\n\n const configOptions: Partial<DotenvFlowConfigOptions> = {\n silent: true, // Don't throw errors if .env files are missing\n }\n\n // Only add defined values to avoid TypeScript strict type issues\n if (options?.path !== undefined) {\n configOptions.path = options.path\n logger.debug(`Using custom path: ${options.path}`)\n }\n if (options?.nodeEnv !== undefined) {\n configOptions.node_env = options.nodeEnv\n logger.debug(`Using NODE_ENV: ${options.nodeEnv}`)\n }\n if (options?.defaultNodeEnv !== undefined) {\n configOptions.default_node_env = options.defaultNodeEnv\n logger.debug(`Using default NODE_ENV: ${options.defaultNodeEnv}`)\n } else {\n configOptions.default_node_env = 'development'\n logger.debug('Using default NODE_ENV: development')\n }\n\n logger.debug('dotenv-flow config options:', configOptions)\n\n const result = dotenvFlow.config(configOptions)\n\n const returnValue: { parsed?: Record<string, string>; error?: Error } = {}\n\n if (result.parsed) {\n returnValue.parsed = result.parsed as Record<string, string>\n const variableCount = Object.keys(result.parsed).length\n logger.debug(`Successfully loaded ${variableCount} environment variables`)\n } else {\n logger.debug('No environment variables were parsed')\n }\n\n if (result.error) {\n returnValue.error = result.error\n logger.debug('dotenv-flow returned an error', {\n error: result.error.message,\n name: result.error.name\n })\n } else {\n logger.debug('dotenv-flow completed without errors')\n }\n\n return returnValue\n}\n\n/**\n * Check if an error from loadEnvIntoProcess indicates no .env files were found\n * This is a harmless condition that shouldn't be logged as a warning\n */\nexport function isNoEnvFilesFoundError(error: Error): boolean {\n return error.message.startsWith('no \".env*\" files matching pattern')\n}\n\n/**\n * Load environment variables for a specific workspace\n * Automatically determines environment based on NODE_ENV or defaults to development\n */\nexport function loadWorkspaceEnv(workspacePath: string): {\n parsed?: Record<string, string>\n error?: Error\n} {\n const nodeEnv = process.env.NODE_ENV ?? 'development'\n\n logger.debug('Loading workspace environment variables', {\n workspacePath,\n detectedNodeEnv: nodeEnv,\n processNodeEnv: process.env.NODE_ENV ?? 'not set'\n })\n\n return loadEnvIntoProcess({\n path: workspacePath,\n nodeEnv: nodeEnv,\n defaultNodeEnv: 'development'\n })\n}\n\n// CONSTANT: Always use 'development' per critical constraint, unless overridden\nconst DOTENV_FLOW_NODE_ENV = process.env.DOTENV_FLOW_NODE_ENV ?? 'development'\n\n/**\n * Get dotenv-flow files in precedence order (lowest to highest)\n * Always uses 'development' as NODE_ENV per constraint\n */\nexport function getDotenvFlowFiles(): string[] {\n return [\n '.env',\n '.env.local',\n `.env.${DOTENV_FLOW_NODE_ENV}`,\n `.env.${DOTENV_FLOW_NODE_ENV}.local`\n ]\n}\n\n/**\n * Map a file to its \"local\" equivalent for git-safe writes\n * .env -> .env.local\n * .env.{NODE_ENV} -> .env.{NODE_ENV}.local\n * Already local files return unchanged\n */\nexport function getLocalEquivalent(filename: string): string {\n // Already a .local file\n if (filename.endsWith('.local')) {\n return filename\n }\n return `${filename}.local`\n}\n\n/**\n * Find the appropriate env file to write a database URL variable to\n * Considers dotenv-flow precedence and git tracking status\n * Returns path relative to workspacePath\n *\n * Algorithm:\n * 1. Search files in reverse precedence order (highest first)\n * 2. Find first file containing the variable\n * 3. If tracked by git, return its .local equivalent\n * 4. If not tracked, return the file itself\n * 5. If not found anywhere, return '.env.local' (safe default)\n */\nexport async function findEnvFileForDatabaseUrl(\n workspacePath: string,\n variableName: string,\n isFileTracked: (filePath: string, cwd: string) => Promise<boolean>,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string> {\n // Find the highest-precedence file containing the variable\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n\n if (file === null) {\n // Variable not found anywhere - use safe default\n return '.env.local'\n }\n\n // Found the variable - check git tracking\n const isTracked = await isFileTracked(file, workspacePath)\n if (isTracked) {\n // Return .local equivalent for git safety\n return getLocalEquivalent(file)\n }\n\n return file\n}\n\n/**\n * Build shell source commands for all existing dotenv-flow files\n * Returns commands in precedence order (later overrides earlier)\n */\nexport async function buildEnvSourceCommands(\n workspacePath: string,\n fileExists: (filePath: string) => Promise<boolean>\n): Promise<string[]> {\n const files = getDotenvFlowFiles()\n const commands: string[] = []\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n const exists = await fileExists(fullPath)\n if (exists) {\n commands.push(`source ${file}`)\n }\n }\n\n return commands\n}\n\n/**\n * Find the highest-precedence env file containing a variable\n * Searches all dotenv-flow files in reverse precedence order (highest first)\n * Returns the relative filename if found, null otherwise\n */\nexport async function findEnvFileContainingVariable(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string | null> {\n const files = getDotenvFlowFiles().reverse() // highest precedence first\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n\n // Skip if file doesn't exist\n if (!(await fileExists(fullPath))) {\n continue\n }\n\n // Check if file contains the variable\n const value = await getEnvVariable(fullPath, variableName)\n if (value !== null) {\n return file\n }\n }\n\n return null\n}\n\n/**\n * Check if a variable exists in any dotenv-flow file\n * Searches all dotenv-flow files (.env, .env.local, .env.{NODE_ENV}, .env.{NODE_ENV}.local)\n * Returns true if variable is found in any file, false otherwise\n */\nexport async function hasVariableInAnyEnvFile(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<boolean> {\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n return file !== null\n}\n","// Lines 1-5: Imports\nimport chalk, { Chalk } from 'chalk'\nimport { detectDarkMode, type ThemeMode } from './terminal.js'\n\n// Lines 7-17: Type definitions\nexport interface LoggerOptions {\n prefix?: string\n timestamp?: boolean\n silent?: boolean\n forceColor?: boolean | undefined | null\n debug?: boolean\n}\n\nexport interface Logger {\n info: (message: string, ...args: unknown[]) => void\n success: (message: string, ...args: unknown[]) => void\n warn: (message: string, ...args: unknown[]) => void\n error: (message: string, ...args: unknown[]) => void\n debug: (message: string, ...args: unknown[]) => void\n setDebug: (enabled: boolean) => void\n isDebugEnabled: () => boolean\n stdout: NodeJS.WriteStream // Stream for progress output (stdout normally, stderr in JSON mode)\n}\n\n// Lines 19-29: Stream-specific chalk instances\nconst stdoutChalk = new Chalk({ level: chalk.level })\nconst stderrChalk = new Chalk({ level: chalk.level })\n\n// Lines 31-60: Theme-aware color selection\nlet currentThemeMode: ThemeMode = 'light'\n\n/**\n * Initialize theme mode detection\n * This is called automatically on module load\n */\nasync function initializeThemeMode(): Promise<void> {\n try {\n currentThemeMode = await detectDarkMode()\n } catch {\n // Default to light mode on error\n currentThemeMode = 'light'\n }\n}\n\n// Initialize theme mode on module load (non-blocking)\nvoid initializeThemeMode()\n\n/**\n * Get color function based on current theme mode\n * Light mode uses standard colors, dark mode uses brighter/more saturated variants\n */\nfunction getInfoColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.cyan : chalkInstance.blue\n}\n\nfunction getSuccessColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.greenBright : chalkInstance.green\n}\n\nfunction getWarnColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.yellowBright : chalkInstance.yellow\n}\n\nfunction getErrorColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.redBright : chalkInstance.red\n}\n\nfunction getDebugColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.gray : chalkInstance.gray\n}\n\n// Lines 31-45: Helper functions\nfunction formatMessage(message: string, ...args: unknown[]): string {\n // Convert args to strings and append to message\n const formattedArgs = args.map(arg =>\n typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)\n )\n return formattedArgs.length > 0 ? `${message} ${formattedArgs.join(' ')}` : message\n}\n\nfunction formatWithEmoji(message: string, emoji: string, colorFn: (str: string) => string): string {\n if (message.trim()) {\n return colorFn(`${emoji} ${message}`)\n } else {\n return ''\n }\n}\n\nlet globalDebugEnabled = false\n\n// Lines 47-96: Main logger implementation\n/* eslint-disable no-console */\nexport const logger: Logger = {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🗂️ ', getInfoColor(stdoutChalk))\n console.log(output)\n },\n\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '✅', getSuccessColor(stdoutChalk))\n console.log(output)\n },\n\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '⚠️ ', getWarnColor(stderrChalk))\n console.error(output)\n },\n\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '❌', getErrorColor(stderrChalk))\n console.error(output)\n },\n\n debug: (message: string, ...args: unknown[]): void => {\n if (globalDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🔍', getDebugColor(stdoutChalk))\n console.log(output)\n }\n },\n\n setDebug: (enabled: boolean): void => {\n globalDebugEnabled = enabled\n },\n\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n\n stdout: process.stdout\n}\n/* eslint-enable no-console */\n\n// Lines 98-145: Factory function for custom logger instances\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { prefix = '', timestamp = false, silent = false, forceColor, debug = globalDebugEnabled } = options\n\n // Local debug flag for this logger instance\n let localDebugEnabled = debug\n\n // Create chalk instances with forced color if needed\n const customStdoutChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stdoutChalk\n const customStderrChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stderrChalk\n\n const prefixStr = prefix ? `[${prefix}] ` : ''\n const getTimestamp = (): string => timestamp ? `[${new Date().toISOString()}] ` : ''\n\n if (silent) {\n // Return no-op logger when silent\n return {\n info: (): void => {},\n success: (): void => {},\n warn: (): void => {},\n error: (): void => {},\n debug: (): void => {},\n setDebug: (): void => {},\n isDebugEnabled: (): boolean => {\n return false\n },\n stdout: process.stdout\n }\n }\n\n /* eslint-disable no-console */\n return {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🗂️ ', getInfoColor(customStdoutChalk))\n console.log(output)\n },\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '✅', getSuccessColor(customStdoutChalk))\n console.log(output)\n },\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '⚠️ ', getWarnColor(customStderrChalk))\n console.error(output)\n },\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '❌', getErrorColor(customStderrChalk))\n console.error(output)\n },\n debug: (message: string, ...args: unknown[]): void => {\n if (localDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🔍', getDebugColor(customStdoutChalk))\n console.log(output)\n }\n },\n setDebug: (enabled: boolean): void => {\n localDebugEnabled = enabled\n },\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n stdout: process.stdout\n }\n /* eslint-enable no-console */\n}\n\n// Lines 147-200: Factory function for stderr-only logger (for JSON mode)\n/**\n * Creates a logger that redirects all output to stderr.\n * Use this in JSON mode so progress messages don't pollute stdout.\n * The JSON output can then be cleanly piped.\n */\nexport function createStderrLogger(options: LoggerOptions = {}): Logger {\n const { prefix = '', timestamp = false, forceColor, debug = globalDebugEnabled } = options\n\n // Local debug flag for this logger instance\n let localDebugEnabled = debug\n\n // Create chalk instances with forced color if needed\n const customChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stderrChalk\n\n const prefixStr = prefix ? `[${prefix}] ` : ''\n const getTimestamp = (): string => timestamp ? `[${new Date().toISOString()}] ` : ''\n\n return {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🗂️ ', getInfoColor(customChalk))\n console.error(output) // Redirect to stderr\n },\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '✅', getSuccessColor(customChalk))\n console.error(output) // Redirect to stderr\n },\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '⚠️ ', getWarnColor(customChalk))\n console.error(output)\n },\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '❌', getErrorColor(customChalk))\n console.error(output)\n },\n debug: (message: string, ...args: unknown[]): void => {\n if (localDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🔍', getDebugColor(customChalk))\n console.error(output) // Redirect to stderr\n }\n },\n setDebug: (enabled: boolean): void => {\n localDebugEnabled = enabled\n },\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n stdout: process.stderr // Use stderr for progress output in JSON mode\n }\n}\n\n/**\n * Set the theme mode for logger colors\n * This is useful for testing or overriding auto-detection\n *\n * @param mode - Theme mode to use ('light' or 'dark')\n */\nexport function setThemeMode(mode: ThemeMode): void {\n currentThemeMode = mode\n}\n\n/**\n * Get the current theme mode\n *\n * @returns Current theme mode\n */\nexport function getThemeMode(): ThemeMode {\n return currentThemeMode\n}\n\n// Default export\nexport default logger\n","import { execa } from 'execa'\nimport type { Platform } from '../types/index.js'\nimport { getTerminalBackend } from './terminal-backends/index.js'\nimport { detectITerm2 as darwinDetectITerm2 } from './terminal-backends/darwin.js'\nimport { detectTerminalEnvironment } from './platform-detect.js'\n\nexport interface TerminalWindowOptions {\n\tworkspacePath?: string\n\tcommand?: string\n\tbackgroundColor?: { r: number; g: number; b: number }\n\tport?: number\n\tincludeEnvSetup?: boolean // source .env\n\tincludePortExport?: boolean // export PORT=<port>\n\ttitle?: string // Terminal tab title\n}\n\n/**\n * Detect current platform.\n *\n * Delegates to detectTerminalEnvironment() from platform-detect.ts,\n * mapping 'wsl' back to 'linux' to preserve the Platform return type.\n */\nexport function detectPlatform(): Platform {\n\tconst env = detectTerminalEnvironment()\n\tif (env === 'wsl') return 'linux'\n\treturn env\n}\n\n/**\n * Theme mode for color palette selection\n */\nexport type ThemeMode = 'light' | 'dark'\n\n/**\n * Detect macOS dark mode using defaults command\n * Returns 'light' as default for non-macOS platforms or detection failures\n *\n * Uses `defaults read -g AppleInterfaceStyle` which returns \"Dark\" in dark mode\n * and errors (exit code 1) in light mode. This approach doesn't require\n * System Events permission unlike AppleScript.\n */\nexport async function detectDarkMode(): Promise<ThemeMode> {\n\tconst platform = detectPlatform()\n\tif (platform !== 'darwin') {\n\t\treturn 'light'\n\t}\n\n\ttry {\n\t\tconst result = await execa('defaults', ['read', '-g', 'AppleInterfaceStyle'])\n\t\treturn result.stdout.trim().toLowerCase() === 'dark' ? 'dark' : 'light'\n\t} catch {\n\t\t// defaults command errors when AppleInterfaceStyle is not set (light mode)\n\t\treturn 'light'\n\t}\n}\n\n/**\n * Detect if iTerm2 is installed on macOS.\n * Returns false on non-macOS platforms.\n *\n * Delegates to the canonical implementation in darwin.ts.\n */\nexport async function detectITerm2(): Promise<boolean> {\n\tif (detectPlatform() !== 'darwin') return false\n\treturn darwinDetectITerm2()\n}\n\n/**\n * Open new terminal window with specified options.\n * Supports macOS (Terminal.app/iTerm2), WSL (Windows Terminal),\n * Linux GUI terminals (gnome-terminal/konsole/xterm), and tmux for headless.\n */\nexport async function openTerminalWindow(\n\toptions: TerminalWindowOptions\n): Promise<void> {\n\tconst backend = await getTerminalBackend()\n\tawait backend.openSingle(options)\n}\n\n/**\n * Open multiple terminal windows/tabs (2+) with specified options.\n * On macOS with iTerm2, creates a single window with multiple tabs.\n * On WSL, creates multiple Windows Terminal tabs.\n * On Linux, uses the detected terminal emulator or tmux.\n */\nexport async function openMultipleTerminalWindows(\n\toptionsArray: TerminalWindowOptions[]\n): Promise<void> {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('openMultipleTerminalWindows requires at least 2 terminal options. Use openTerminalWindow for single terminal.')\n\t}\n\n\tconst backend = await getTerminalBackend()\n\tawait backend.openMultiple(optionsArray)\n}\n\n/**\n * Open dual terminal windows/tabs with specified options\n * If iTerm2 is available on macOS, creates single window with two tabs\n * Otherwise falls back to two separate Terminal.app windows\n */\nexport async function openDualTerminalWindow(\n\toptions1: TerminalWindowOptions,\n\toptions2: TerminalWindowOptions\n): Promise<void> {\n\tawait openMultipleTerminalWindows([options1, options2])\n}\n","import { readFileSync } from 'node:fs'\n\n/**\n * Terminal environment types.\n * 'darwin' = macOS, 'wsl' = Windows Subsystem for Linux, 'linux' = native Linux, 'win32' = native Windows\n */\nexport type TerminalEnvironment = 'darwin' | 'wsl' | 'linux' | 'win32' | 'unsupported'\n\nlet cachedIsWSL: boolean | undefined\n\n/**\n * Detect if running inside Windows Subsystem for Linux.\n *\n * Detection strategy (in order):\n * 1. Check WSL_DISTRO_NAME env var (always set in WSL2, most reliable)\n * 2. Fallback: read /proc/version for \"microsoft\" or \"WSL\" signature\n *\n * Result is cached to avoid repeated /proc reads.\n */\nexport function isWSL(): boolean {\n\tif (cachedIsWSL !== undefined) {\n\t\treturn cachedIsWSL\n\t}\n\n\tif (process.platform !== 'linux') {\n\t\tcachedIsWSL = false\n\t\treturn false\n\t}\n\n\t// Most reliable: WSL_DISTRO_NAME is always set in WSL2\n\tif (process.env.WSL_DISTRO_NAME) {\n\t\tcachedIsWSL = true\n\t\treturn true\n\t}\n\n\t// Fallback: check /proc/version for WSL signature\n\ttry {\n\t\tconst procVersion = readFileSync('/proc/version', 'utf-8')\n\t\tcachedIsWSL = /microsoft|wsl/i.test(procVersion)\n\t\treturn cachedIsWSL\n\t} catch (error: unknown) {\n\t\t// /proc/version not found — not WSL\n\t\tif (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tcachedIsWSL = false\n\t\t\treturn false\n\t\t}\n\t\t// Unexpected error — assume not WSL\n\t\tcachedIsWSL = false\n\t\treturn false\n\t}\n}\n\n/**\n * Detect the terminal environment, distinguishing WSL from plain Linux.\n */\nexport function detectTerminalEnvironment(): TerminalEnvironment {\n\tconst platform = process.platform\n\tif (platform === 'darwin') return 'darwin'\n\tif (platform === 'win32') return 'win32'\n\tif (platform === 'linux') {\n\t\treturn isWSL() ? 'wsl' : 'linux'\n\t}\n\treturn 'unsupported'\n}\n\n/**\n * Get the WSL distribution name from the environment.\n * Returns undefined when not running in WSL or when the variable is not set.\n */\nexport function detectWSLDistro(): string | undefined {\n\tconst distro = process.env.WSL_DISTRO_NAME\n\t// Empty string means unset; nullish coalescing won't catch it\n\tif (!distro) return undefined\n\treturn distro\n}\n\n/**\n * Reset the cached WSL detection result.\n * Exposed for testing only.\n */\nexport function _resetWSLCache(): void {\n\tcachedIsWSL = undefined\n}\n"],"mappings":"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","names":["execa","existsSync","existsSync","execa"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/terminal-backends/darwin.ts","../../src/utils/terminal-backends/command-builder.ts","../../src/utils/env.ts","../../src/utils/logger.ts","../../src/utils/terminal.ts","../../src/utils/platform-detect.ts"],"sourcesContent":["import { execa } from 'execa'\nimport { existsSync } from 'node:fs'\nimport type { TerminalWindowOptions } from '../terminal.js'\nimport type { TerminalBackend } from './types.js'\nimport { buildCommandSequence } from './command-builder.js'\n\n/**\n * Detect if iTerm2 is installed on macOS.\n */\nexport function detectITerm2(): boolean {\n\treturn existsSync('/Applications/iTerm.app')\n}\n\n/**\n * Escape command string for embedding inside an AppleScript `do script \"...\"`.\n */\nfunction escapeForAppleScript(command: string): string {\n\treturn command\n\t\t.replace(/\\\\/g, '\\\\\\\\')\n\t\t.replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Build AppleScript for macOS Terminal.app (single tab).\n *\n * Delegates to the shared buildCommandSequence for command construction,\n * then wraps the result with AppleScript escaping for `do script \"...\"`.\n */\nasync function buildTerminalAppScript(options: TerminalWindowOptions): Promise<string> {\n\tconst command = await buildCommandSequence(options)\n\n\tlet script = `tell application \"Terminal\"\\n`\n\tscript += ` set newTab to do script \"${escapeForAppleScript(command)}\"\\n`\n\n\tif (options.backgroundColor) {\n\t\tconst { r, g, b } = options.backgroundColor\n\t\tscript += ` set background color of newTab to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += `end tell`\n\treturn script\n}\n\n/**\n * Build iTerm2 AppleScript for a single tab in a new window.\n */\nasync function buildITerm2SingleTabScript(options: TerminalWindowOptions): Promise<string> {\n\tconst command = await buildCommandSequence(options)\n\n\tlet script = 'tell application id \"com.googlecode.iterm2\"\\n'\n\tscript += ' create window with default profile\\n'\n\tscript += ' set s1 to current session of current window\\n\\n'\n\n\tif (options.backgroundColor) {\n\t\tconst { r, g, b } = options.backgroundColor\n\t\tscript += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += ` tell s1 to write text \"${escapeForAppleScript(command)}\"\\n\\n`\n\n\tif (options.title) {\n\t\tscript += ` set name of s1 to \"${escapeForAppleScript(options.title)}\"\\n\\n`\n\t}\n\n\tscript += ' activate\\n'\n\tscript += 'end tell'\n\treturn script\n}\n\n/**\n * Build iTerm2 AppleScript for multiple tabs (2+) in a single window.\n */\nasync function buildITerm2MultiTabScript(\n\toptionsArray: TerminalWindowOptions[]\n): Promise<string> {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('buildITerm2MultiTabScript requires at least 2 terminal options')\n\t}\n\n\tlet script = 'tell application id \"com.googlecode.iterm2\"\\n'\n\tscript += ' create window with default profile\\n'\n\tscript += ' set newWindow to current window\\n'\n\n\tconst options1 = optionsArray[0]\n\tif (!options1) {\n\t\tthrow new Error('First terminal option is undefined')\n\t}\n\tconst command1 = await buildCommandSequence(options1)\n\n\tscript += ' set s1 to current session of newWindow\\n\\n'\n\n\tif (options1.backgroundColor) {\n\t\tconst { r, g, b } = options1.backgroundColor\n\t\tscript += ` set background color of s1 to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t}\n\n\tscript += ` tell s1 to write text \"${escapeForAppleScript(command1)}\"\\n\\n`\n\n\tif (options1.title) {\n\t\tscript += ` set name of s1 to \"${escapeForAppleScript(options1.title)}\"\\n\\n`\n\t}\n\n\tfor (let i = 1; i < optionsArray.length; i++) {\n\t\tconst options = optionsArray[i]\n\t\tif (!options) {\n\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t}\n\t\tconst command = await buildCommandSequence(options)\n\t\tconst sessionVar = `s${i + 1}`\n\n\t\tscript += ' tell newWindow\\n'\n\t\tscript += ` set newTab${i} to (create tab with default profile)\\n`\n\t\tscript += ' end tell\\n'\n\t\tscript += ` set ${sessionVar} to current session of newTab${i}\\n\\n`\n\n\t\tif (options.backgroundColor) {\n\t\t\tconst { r, g, b } = options.backgroundColor\n\t\t\tscript += ` set background color of ${sessionVar} to {${Math.round(r * 257)}, ${Math.round(g * 257)}, ${Math.round(b * 257)}}\\n`\n\t\t}\n\n\t\tscript += ` tell ${sessionVar} to write text \"${escapeForAppleScript(command)}\"\\n\\n`\n\n\t\tif (options.title) {\n\t\t\tscript += ` set name of ${sessionVar} to \"${escapeForAppleScript(options.title)}\"\\n\\n`\n\t\t}\n\t}\n\n\tscript += ' activate\\n'\n\tscript += 'end tell'\n\treturn script\n}\n\n/**\n * macOS terminal backend — supports Terminal.app and iTerm2.\n */\nexport class DarwinBackend implements TerminalBackend {\n\treadonly name = 'darwin'\n\n\tasync openSingle(options: TerminalWindowOptions): Promise<void> {\n\t\tconst hasITerm2 = detectITerm2()\n\n\t\tconst applescript = hasITerm2\n\t\t\t? await buildITerm2SingleTabScript(options)\n\t\t\t: await buildTerminalAppScript(options)\n\n\t\ttry {\n\t\t\tawait execa('osascript', ['-e', applescript])\n\n\t\t\tif (!hasITerm2) {\n\t\t\t\tawait execa('osascript', ['-e', 'tell application \"Terminal\" to activate'])\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to open terminal window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t}\n\t}\n\n\tasync openMultiple(optionsArray: TerminalWindowOptions[]): Promise<void> {\n\t\tconst hasITerm2 = detectITerm2()\n\n\t\tif (hasITerm2) {\n\t\t\tconst applescript = await buildITerm2MultiTabScript(optionsArray)\n\n\t\t\ttry {\n\t\t\t\tawait execa('osascript', ['-e', applescript])\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to open iTerm2 window: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\tfor (let i = 0; i < optionsArray.length; i++) {\n\t\t\t\tconst options = optionsArray[i]\n\t\t\t\tif (!options) {\n\t\t\t\t\tthrow new Error(`Terminal option at index ${i} is undefined`)\n\t\t\t\t}\n\t\t\t\tawait this.openSingle(options)\n\n\t\t\t\tif (i < optionsArray.length - 1) {\n\t\t\t\t\tawait new Promise<void>((resolve) => globalThis.setTimeout(resolve, 1000))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import { existsSync } from 'node:fs'\nimport type { TerminalWindowOptions } from '../terminal.js'\nimport { buildEnvSourceCommands } from '../env.js'\n\n/**\n * Build the shell command sequence from TerminalWindowOptions.\n *\n * The returned string is a chain of commands joined by ` && `, prefixed with\n * a space to prevent shell history pollution (HISTCONTROL=ignorespace).\n *\n * This logic is shared across all backends — each backend applies its own\n * escaping on top of the raw command string.\n */\nexport async function buildCommandSequence(options: TerminalWindowOptions): Promise<string> {\n\tconst {\n\t\tworkspacePath,\n\t\tcommand,\n\t\tport,\n\t\tincludeEnvSetup,\n\t\tincludePortExport,\n\t} = options\n\n\tconst commands: string[] = []\n\n\tif (workspacePath) {\n\t\tcommands.push(`cd '${escapeSingleQuotes(workspacePath)}'`)\n\t}\n\n\tif (includeEnvSetup && workspacePath) {\n\t\tconst sourceCommands = await buildEnvSourceCommands(\n\t\t\tworkspacePath,\n\t\t\tasync (p) => existsSync(p)\n\t\t)\n\t\tcommands.push(...sourceCommands)\n\t}\n\n\tif (includePortExport && port !== undefined) {\n\t\tcommands.push(`export PORT=${port}`)\n\t}\n\n\tif (command) {\n\t\tcommands.push(command)\n\t}\n\n\tconst fullCommand = commands.join(' && ')\n\n\t// Prefix with space to prevent shell history pollution\n\treturn ` ${fullCommand}`\n}\n\n/**\n * Escape single quotes for use inside a single-quoted shell string.\n * 'it'\\''s' → ends quote, adds escaped quote, resumes quote\n */\nexport function escapeSingleQuotes(s: string): string {\n\treturn s.replace(/'/g, \"'\\\\''\")\n}\n\n/**\n * Convert {r, g, b} (0–255) to a hex color string \"#RRGGBB\".\n */\nexport function rgbToHex(rgb: { r: number; g: number; b: number }): string {\n\tconst toHex = (n: number): string => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, '0')\n\treturn `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`\n}\n","import path from 'path'\nimport dotenvFlow, { type DotenvFlowConfigOptions } from 'dotenv-flow'\nimport { logger } from './logger.js'\n\n/**\n * Parse .env file content into key-value map\n * Handles comments, empty lines, quoted/unquoted values, multiline values\n */\nexport function parseEnvFile(content: string): Map<string, string> {\n const envMap = new Map<string, string>()\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n\n // Skip empty lines and comments\n if (!trimmedLine || trimmedLine.startsWith('#')) {\n continue\n }\n\n // Remove 'export ' prefix if present\n const cleanLine = trimmedLine.startsWith('export ')\n ? trimmedLine.substring(7)\n : trimmedLine\n\n // Find the first equals sign\n const equalsIndex = cleanLine.indexOf('=')\n if (equalsIndex === -1) {\n continue\n }\n\n const key = cleanLine.substring(0, equalsIndex).trim()\n let value = cleanLine.substring(equalsIndex + 1)\n\n // Handle quoted values\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.substring(1, value.length - 1)\n // Unescape quotes\n value = value.replace(/\\\\\"/g, '\"').replace(/\\\\'/g, \"'\")\n // Unescape newlines\n value = value.replace(/\\\\n/g, '\\n')\n }\n\n if (key) {\n envMap.set(key, value)\n }\n }\n\n return envMap\n}\n\n/**\n * Format environment variable as line for .env file\n * Always quotes values and escapes internal quotes\n */\nexport function formatEnvLine(key: string, value: string): string {\n // Escape quotes and newlines in the value\n const escapedValue = value\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n\n return `${key}=\"${escapedValue}\"`\n}\n\n/**\n * Validate environment variable name and value\n */\nexport function validateEnvVariable(\n key: string,\n _value?: string\n): { valid: boolean; error?: string } {\n if (!key || key.length === 0) {\n return {\n valid: false,\n error: 'Environment variable key cannot be empty',\n }\n }\n\n if (!isValidEnvKey(key)) {\n return {\n valid: false,\n error: `Invalid environment variable name: ${key}. Must start with a letter or underscore and contain only letters, numbers, and underscores.`,\n }\n }\n\n // Values can be any string, including empty\n return { valid: true }\n}\n\n/**\n * Normalize line endings for cross-platform compatibility\n */\nexport function normalizeLineEndings(content: string): string {\n return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n')\n}\n\n/**\n * Extract port from .env file if present\n */\nexport function extractPort(envContent: Map<string, string>): number | null {\n const portValue = envContent.get('PORT')\n if (!portValue) {\n return null\n }\n\n const port = parseInt(portValue, 10)\n if (isNaN(port)) {\n return null\n }\n\n return port\n}\n\n/**\n * Check if environment variable key is valid\n */\nexport function isValidEnvKey(key: string): boolean {\n if (!key || key.length === 0) {\n return false\n }\n\n // Must start with letter or underscore, followed by letters, numbers, or underscores\n const validKeyRegex = /^[A-Za-z_][A-Za-z0-9_]*$/\n return validKeyRegex.test(key)\n}\n\n/**\n * Load environment variables using dotenv-flow\n * Supports environment-specific files (.env.development, .env.production, etc.)\n * and local overrides (.env.local, .env.development.local)\n */\nexport function loadEnvIntoProcess(options?: {\n path?: string\n nodeEnv?: string\n defaultNodeEnv?: string\n}): { parsed?: Record<string, string>; error?: Error } {\n logger.debug('Loading environment variables with dotenv-flow', {\n options: {\n path: options?.path ?? 'current working directory',\n nodeEnv: options?.nodeEnv ?? 'not specified',\n defaultNodeEnv: options?.defaultNodeEnv ?? 'development (default)'\n }\n })\n\n const configOptions: Partial<DotenvFlowConfigOptions> = {\n silent: true, // Don't throw errors if .env files are missing\n }\n\n // Only add defined values to avoid TypeScript strict type issues\n if (options?.path !== undefined) {\n configOptions.path = options.path\n logger.debug(`Using custom path: ${options.path}`)\n }\n if (options?.nodeEnv !== undefined) {\n configOptions.node_env = options.nodeEnv\n logger.debug(`Using NODE_ENV: ${options.nodeEnv}`)\n }\n if (options?.defaultNodeEnv !== undefined) {\n configOptions.default_node_env = options.defaultNodeEnv\n logger.debug(`Using default NODE_ENV: ${options.defaultNodeEnv}`)\n } else {\n configOptions.default_node_env = 'development'\n logger.debug('Using default NODE_ENV: development')\n }\n\n logger.debug('dotenv-flow config options:', configOptions)\n\n const result = dotenvFlow.config(configOptions)\n\n const returnValue: { parsed?: Record<string, string>; error?: Error } = {}\n\n if (result.parsed) {\n returnValue.parsed = result.parsed as Record<string, string>\n const variableCount = Object.keys(result.parsed).length\n logger.debug(`Successfully loaded ${variableCount} environment variables`)\n } else {\n logger.debug('No environment variables were parsed')\n }\n\n if (result.error) {\n returnValue.error = result.error\n logger.debug('dotenv-flow returned an error', {\n error: result.error.message,\n name: result.error.name\n })\n } else {\n logger.debug('dotenv-flow completed without errors')\n }\n\n return returnValue\n}\n\n/**\n * Check if an error from loadEnvIntoProcess indicates no .env files were found\n * This is a harmless condition that shouldn't be logged as a warning\n */\nexport function isNoEnvFilesFoundError(error: Error): boolean {\n return error.message.startsWith('no \".env*\" files matching pattern')\n}\n\n/**\n * Load environment variables for a specific workspace\n * Automatically determines environment based on NODE_ENV or defaults to development\n */\nexport function loadWorkspaceEnv(workspacePath: string): {\n parsed?: Record<string, string>\n error?: Error\n} {\n const nodeEnv = process.env.NODE_ENV ?? 'development'\n\n logger.debug('Loading workspace environment variables', {\n workspacePath,\n detectedNodeEnv: nodeEnv,\n processNodeEnv: process.env.NODE_ENV ?? 'not set'\n })\n\n return loadEnvIntoProcess({\n path: workspacePath,\n nodeEnv: nodeEnv,\n defaultNodeEnv: 'development'\n })\n}\n\n// CONSTANT: Always use 'development' per critical constraint, unless overridden\nconst DOTENV_FLOW_NODE_ENV = process.env.DOTENV_FLOW_NODE_ENV ?? 'development'\n\n/**\n * Get dotenv-flow files in precedence order (lowest to highest)\n * Always uses 'development' as NODE_ENV per constraint\n */\nexport function getDotenvFlowFiles(): string[] {\n return [\n '.env',\n '.env.local',\n `.env.${DOTENV_FLOW_NODE_ENV}`,\n `.env.${DOTENV_FLOW_NODE_ENV}.local`\n ]\n}\n\n/**\n * Map a file to its \"local\" equivalent for git-safe writes\n * .env -> .env.local\n * .env.{NODE_ENV} -> .env.{NODE_ENV}.local\n * Already local files return unchanged\n */\nexport function getLocalEquivalent(filename: string): string {\n // Already a .local file\n if (filename.endsWith('.local')) {\n return filename\n }\n return `${filename}.local`\n}\n\n/**\n * Find the appropriate env file to write a database URL variable to\n * Considers dotenv-flow precedence and git tracking status\n * Returns path relative to workspacePath\n *\n * Algorithm:\n * 1. Search files in reverse precedence order (highest first)\n * 2. Find first file containing the variable\n * 3. If tracked by git, return its .local equivalent\n * 4. If not tracked, return the file itself\n * 5. If not found anywhere, return '.env.local' (safe default)\n */\nexport async function findEnvFileForDatabaseUrl(\n workspacePath: string,\n variableName: string,\n isFileTracked: (filePath: string, cwd: string) => Promise<boolean>,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string> {\n // Find the highest-precedence file containing the variable\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n\n if (file === null) {\n // Variable not found anywhere - use safe default\n return '.env.local'\n }\n\n // Found the variable - check git tracking\n const isTracked = await isFileTracked(file, workspacePath)\n if (isTracked) {\n // Return .local equivalent for git safety\n return getLocalEquivalent(file)\n }\n\n return file\n}\n\n/**\n * Build shell source commands for all existing dotenv-flow files\n * Returns commands in precedence order (later overrides earlier)\n */\nexport async function buildEnvSourceCommands(\n workspacePath: string,\n fileExists: (filePath: string) => Promise<boolean>\n): Promise<string[]> {\n const files = getDotenvFlowFiles()\n const commands: string[] = []\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n const exists = await fileExists(fullPath)\n if (exists) {\n commands.push(`source ${file}`)\n }\n }\n\n return commands\n}\n\n/**\n * Find the highest-precedence env file containing a variable\n * Searches all dotenv-flow files in reverse precedence order (highest first)\n * Returns the relative filename if found, null otherwise\n */\nexport async function findEnvFileContainingVariable(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<string | null> {\n const files = getDotenvFlowFiles().reverse() // highest precedence first\n\n for (const file of files) {\n const fullPath = path.join(workspacePath, file)\n\n // Skip if file doesn't exist\n if (!(await fileExists(fullPath))) {\n continue\n }\n\n // Check if file contains the variable\n const value = await getEnvVariable(fullPath, variableName)\n if (value !== null) {\n return file\n }\n }\n\n return null\n}\n\n/**\n * Check if a variable exists in any dotenv-flow file\n * Searches all dotenv-flow files (.env, .env.local, .env.{NODE_ENV}, .env.{NODE_ENV}.local)\n * Returns true if variable is found in any file, false otherwise\n */\nexport async function hasVariableInAnyEnvFile(\n workspacePath: string,\n variableName: string,\n fileExists: (filePath: string) => Promise<boolean>,\n getEnvVariable: (filePath: string, varName: string) => Promise<string | null>\n): Promise<boolean> {\n const file = await findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable)\n return file !== null\n}\n","// Lines 1-5: Imports\nimport chalk, { Chalk } from 'chalk'\nimport { detectDarkMode, type ThemeMode } from './terminal.js'\n\n// Lines 7-17: Type definitions\nexport interface LoggerOptions {\n prefix?: string\n timestamp?: boolean\n silent?: boolean\n forceColor?: boolean | undefined | null\n debug?: boolean\n}\n\nexport interface Logger {\n info: (message: string, ...args: unknown[]) => void\n success: (message: string, ...args: unknown[]) => void\n warn: (message: string, ...args: unknown[]) => void\n error: (message: string, ...args: unknown[]) => void\n debug: (message: string, ...args: unknown[]) => void\n setDebug: (enabled: boolean) => void\n isDebugEnabled: () => boolean\n stdout: NodeJS.WriteStream // Stream for progress output (stdout normally, stderr in JSON mode)\n}\n\n// Lines 19-29: Stream-specific chalk instances\nconst stdoutChalk = new Chalk({ level: chalk.level })\nconst stderrChalk = new Chalk({ level: chalk.level })\n\n// Lines 31-60: Theme-aware color selection\nlet currentThemeMode: ThemeMode = 'light'\n\n/**\n * Initialize theme mode detection\n * This is called automatically on module load\n */\nasync function initializeThemeMode(): Promise<void> {\n try {\n currentThemeMode = await detectDarkMode()\n } catch {\n // Default to light mode on error\n currentThemeMode = 'light'\n }\n}\n\n// Initialize theme mode on module load (non-blocking)\nvoid initializeThemeMode()\n\n/**\n * Get color function based on current theme mode\n * Light mode uses standard colors, dark mode uses brighter/more saturated variants\n */\nfunction getInfoColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.cyan : chalkInstance.blue\n}\n\nfunction getSuccessColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.greenBright : chalkInstance.green\n}\n\nfunction getWarnColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.yellowBright : chalkInstance.yellow\n}\n\nfunction getErrorColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.redBright : chalkInstance.red\n}\n\nfunction getDebugColor(chalkInstance: InstanceType<typeof Chalk>): (str: string) => string {\n return currentThemeMode === 'dark' ? chalkInstance.gray : chalkInstance.gray\n}\n\n// Lines 31-45: Helper functions\nfunction formatMessage(message: string, ...args: unknown[]): string {\n // Convert args to strings and append to message\n const formattedArgs = args.map(arg =>\n typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)\n )\n return formattedArgs.length > 0 ? `${message} ${formattedArgs.join(' ')}` : message\n}\n\nfunction formatWithEmoji(message: string, emoji: string, colorFn: (str: string) => string): string {\n if (message.trim()) {\n return colorFn(`${emoji} ${message}`)\n } else {\n return ''\n }\n}\n\nlet globalDebugEnabled = false\n\n// Lines 47-96: Main logger implementation\n/* eslint-disable no-console */\nexport const logger: Logger = {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🗂️ ', getInfoColor(stdoutChalk))\n console.log(output)\n },\n\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '✅', getSuccessColor(stdoutChalk))\n console.log(output)\n },\n\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '⚠️ ', getWarnColor(stderrChalk))\n console.error(output)\n },\n\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '❌', getErrorColor(stderrChalk))\n console.error(output)\n },\n\n debug: (message: string, ...args: unknown[]): void => {\n if (globalDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const output = formatWithEmoji(formatted, '🔍', getDebugColor(stdoutChalk))\n console.log(output)\n }\n },\n\n setDebug: (enabled: boolean): void => {\n globalDebugEnabled = enabled\n },\n\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n\n stdout: process.stdout\n}\n/* eslint-enable no-console */\n\n// Lines 98-145: Factory function for custom logger instances\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { prefix = '', timestamp = false, silent = false, forceColor, debug = globalDebugEnabled } = options\n\n // Local debug flag for this logger instance\n let localDebugEnabled = debug\n\n // Create chalk instances with forced color if needed\n const customStdoutChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stdoutChalk\n const customStderrChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stderrChalk\n\n const prefixStr = prefix ? `[${prefix}] ` : ''\n const getTimestamp = (): string => timestamp ? `[${new Date().toISOString()}] ` : ''\n\n if (silent) {\n // Return no-op logger when silent\n return {\n info: (): void => {},\n success: (): void => {},\n warn: (): void => {},\n error: (): void => {},\n debug: (): void => {},\n setDebug: (): void => {},\n isDebugEnabled: (): boolean => {\n return false\n },\n stdout: process.stdout\n }\n }\n\n /* eslint-disable no-console */\n return {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🗂️ ', getInfoColor(customStdoutChalk))\n console.log(output)\n },\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '✅', getSuccessColor(customStdoutChalk))\n console.log(output)\n },\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '⚠️ ', getWarnColor(customStderrChalk))\n console.error(output)\n },\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '❌', getErrorColor(customStderrChalk))\n console.error(output)\n },\n debug: (message: string, ...args: unknown[]): void => {\n if (localDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🔍', getDebugColor(customStdoutChalk))\n console.log(output)\n }\n },\n setDebug: (enabled: boolean): void => {\n localDebugEnabled = enabled\n },\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n stdout: process.stdout\n }\n /* eslint-enable no-console */\n}\n\n// Lines 147-200: Factory function for stderr-only logger (for JSON mode)\n/**\n * Creates a logger that redirects all output to stderr.\n * Use this in JSON mode so progress messages don't pollute stdout.\n * The JSON output can then be cleanly piped.\n */\nexport function createStderrLogger(options: LoggerOptions = {}): Logger {\n const { prefix = '', timestamp = false, forceColor, debug = globalDebugEnabled } = options\n\n // Local debug flag for this logger instance\n let localDebugEnabled = debug\n\n // Create chalk instances with forced color if needed\n const customChalk = forceColor !== undefined\n ? new Chalk({ level: forceColor ? 3 : 0 })\n : stderrChalk\n\n const prefixStr = prefix ? `[${prefix}] ` : ''\n const getTimestamp = (): string => timestamp ? `[${new Date().toISOString()}] ` : ''\n\n return {\n info: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🗂️ ', getInfoColor(customChalk))\n console.error(output) // Redirect to stderr\n },\n success: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '✅', getSuccessColor(customChalk))\n console.error(output) // Redirect to stderr\n },\n warn: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '⚠️ ', getWarnColor(customChalk))\n console.error(output)\n },\n error: (message: string, ...args: unknown[]): void => {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '❌', getErrorColor(customChalk))\n console.error(output)\n },\n debug: (message: string, ...args: unknown[]): void => {\n if (localDebugEnabled) {\n const formatted = formatMessage(message, ...args)\n const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`\n const output = formatWithEmoji(fullMessage, '🔍', getDebugColor(customChalk))\n console.error(output) // Redirect to stderr\n }\n },\n setDebug: (enabled: boolean): void => {\n localDebugEnabled = enabled\n },\n isDebugEnabled: (): boolean => {\n return globalDebugEnabled\n },\n stdout: process.stderr // Use stderr for progress output in JSON mode\n }\n}\n\n/**\n * Set the theme mode for logger colors\n * This is useful for testing or overriding auto-detection\n *\n * @param mode - Theme mode to use ('light' or 'dark')\n */\nexport function setThemeMode(mode: ThemeMode): void {\n currentThemeMode = mode\n}\n\n/**\n * Get the current theme mode\n *\n * @returns Current theme mode\n */\nexport function getThemeMode(): ThemeMode {\n return currentThemeMode\n}\n\n// Default export\nexport default logger\n","import { execSync } from 'child_process'\nimport { execa } from 'execa'\nimport type { Platform } from '../types/index.js'\nimport { getTerminalBackend } from './terminal-backends/index.js'\nimport { detectITerm2 as darwinDetectITerm2 } from './terminal-backends/darwin.js'\nimport { detectTerminalEnvironment } from './platform-detect.js'\n\nexport interface TerminalWindowOptions {\n\tworkspacePath?: string\n\tcommand?: string\n\tbackgroundColor?: { r: number; g: number; b: number }\n\tport?: number\n\tincludeEnvSetup?: boolean // source .env\n\tincludePortExport?: boolean // export PORT=<port>\n\ttitle?: string // Terminal tab title\n}\n\n/**\n * Detect current platform.\n *\n * Delegates to detectTerminalEnvironment() from platform-detect.ts,\n * mapping 'wsl' back to 'linux' to preserve the Platform return type.\n */\nexport function detectPlatform(): Platform {\n\tconst env = detectTerminalEnvironment()\n\tif (env === 'wsl') return 'linux'\n\treturn env\n}\n\n/**\n * Theme mode for color palette selection\n */\nexport type ThemeMode = 'light' | 'dark'\n\n/**\n * Detect macOS dark mode using defaults command\n * Returns 'light' as default for non-macOS platforms or detection failures\n *\n * Uses `defaults read -g AppleInterfaceStyle` which returns \"Dark\" in dark mode\n * and errors (exit code 1) in light mode. This approach doesn't require\n * System Events permission unlike AppleScript.\n */\nexport async function detectDarkMode(): Promise<ThemeMode> {\n\tconst platform = detectPlatform()\n\tif (platform !== 'darwin') {\n\t\treturn 'light'\n\t}\n\n\ttry {\n\t\tconst result = await execa('defaults', ['read', '-g', 'AppleInterfaceStyle'])\n\t\treturn result.stdout.trim().toLowerCase() === 'dark' ? 'dark' : 'light'\n\t} catch {\n\t\t// defaults command errors when AppleInterfaceStyle is not set (light mode)\n\t\treturn 'light'\n\t}\n}\n\n/**\n * Detect if iTerm2 is installed on macOS.\n * Returns false on non-macOS platforms.\n *\n * Delegates to the canonical implementation in darwin.ts.\n */\nexport async function detectITerm2(): Promise<boolean> {\n\tif (detectPlatform() !== 'darwin') return false\n\treturn darwinDetectITerm2()\n}\n\n/**\n * Open new terminal window with specified options.\n * Supports macOS (Terminal.app/iTerm2), WSL (Windows Terminal),\n * Linux GUI terminals (gnome-terminal/konsole/xterm), and tmux for headless.\n */\nexport async function openTerminalWindow(\n\toptions: TerminalWindowOptions\n): Promise<void> {\n\tconst backend = await getTerminalBackend()\n\tawait backend.openSingle(options)\n}\n\n/**\n * Open multiple terminal windows/tabs (2+) with specified options.\n * On macOS with iTerm2, creates a single window with multiple tabs.\n * On WSL, creates multiple Windows Terminal tabs.\n * On Linux, uses the detected terminal emulator or tmux.\n */\nexport async function openMultipleTerminalWindows(\n\toptionsArray: TerminalWindowOptions[]\n): Promise<void> {\n\tif (optionsArray.length < 2) {\n\t\tthrow new Error('openMultipleTerminalWindows requires at least 2 terminal options. Use openTerminalWindow for single terminal.')\n\t}\n\n\tconst backend = await getTerminalBackend()\n\tawait backend.openMultiple(optionsArray)\n}\n\n/**\n * Open dual terminal windows/tabs with specified options\n * If iTerm2 is available on macOS, creates single window with two tabs\n * Otherwise falls back to two separate Terminal.app windows\n */\nexport async function openDualTerminalWindow(\n\toptions1: TerminalWindowOptions,\n\toptions2: TerminalWindowOptions\n): Promise<void> {\n\tawait openMultipleTerminalWindows([options1, options2])\n}\n\n/**\n * Restore terminal state after a child process may have left it in a bad state.\n *\n * Uses `stty sane` which resets terminal line settings to reasonable defaults.\n * This is more reliable than Node's `setRawMode(false)` because child processes\n * (e.g., dev servers) may change tty settings directly on the shared fd, and\n * Node's API doesn't reliably undo those changes.\n *\n * This function never throws — terminal restoration is best-effort.\n */\nexport function restoreTerminalState(): void {\n\tif (!process.stdin.isTTY) {\n\t\treturn\n\t}\n\ttry {\n\t\texecSync('stty sane', { stdio: 'ignore' })\n\t} catch {\n\t\t// Best-effort: if stty fails, there's nothing more we can do\n\t}\n}\n","import { readFileSync } from 'node:fs'\n\n/**\n * Terminal environment types.\n * 'darwin' = macOS, 'wsl' = Windows Subsystem for Linux, 'linux' = native Linux, 'win32' = native Windows\n */\nexport type TerminalEnvironment = 'darwin' | 'wsl' | 'linux' | 'win32' | 'unsupported'\n\nlet cachedIsWSL: boolean | undefined\n\n/**\n * Detect if running inside Windows Subsystem for Linux.\n *\n * Detection strategy (in order):\n * 1. Check WSL_DISTRO_NAME env var (always set in WSL2, most reliable)\n * 2. Fallback: read /proc/version for \"microsoft\" or \"WSL\" signature\n *\n * Result is cached to avoid repeated /proc reads.\n */\nexport function isWSL(): boolean {\n\tif (cachedIsWSL !== undefined) {\n\t\treturn cachedIsWSL\n\t}\n\n\tif (process.platform !== 'linux') {\n\t\tcachedIsWSL = false\n\t\treturn false\n\t}\n\n\t// Most reliable: WSL_DISTRO_NAME is always set in WSL2\n\tif (process.env.WSL_DISTRO_NAME) {\n\t\tcachedIsWSL = true\n\t\treturn true\n\t}\n\n\t// Fallback: check /proc/version for WSL signature\n\ttry {\n\t\tconst procVersion = readFileSync('/proc/version', 'utf-8')\n\t\tcachedIsWSL = /microsoft|wsl/i.test(procVersion)\n\t\treturn cachedIsWSL\n\t} catch (error: unknown) {\n\t\t// /proc/version not found — not WSL\n\t\tif (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tcachedIsWSL = false\n\t\t\treturn false\n\t\t}\n\t\t// Unexpected error — assume not WSL\n\t\tcachedIsWSL = false\n\t\treturn false\n\t}\n}\n\n/**\n * Detect the terminal environment, distinguishing WSL from plain Linux.\n */\nexport function detectTerminalEnvironment(): TerminalEnvironment {\n\tconst platform = process.platform\n\tif (platform === 'darwin') return 'darwin'\n\tif (platform === 'win32') return 'win32'\n\tif (platform === 'linux') {\n\t\treturn isWSL() ? 'wsl' : 'linux'\n\t}\n\treturn 'unsupported'\n}\n\n/**\n * Get the WSL distribution name from the environment.\n * Returns undefined when not running in WSL or when the variable is not set.\n */\nexport function detectWSLDistro(): string | undefined {\n\tconst distro = process.env.WSL_DISTRO_NAME\n\t// Empty string means unset; nullish coalescing won't catch it\n\tif (!distro) return undefined\n\treturn distro\n}\n\n/**\n * Reset the cached WSL detection result.\n * Exposed for testing only.\n */\nexport function _resetWSLCache(): void {\n\tcachedIsWSL = undefined\n}\n"],"mappings":"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","names":["execa","existsSync","existsSync","execa"]}
|