@ken-jo/agent-connector 0.4.95 → 0.4.98
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 +202 -202
- package/NOTICE +6 -6
- package/README.md +605 -599
- package/dist/{action-Q7GGO4PA.js → action-5JM23CFJ.js} +16 -16
- package/dist/action-5JM23CFJ.js.map +1 -0
- package/dist/{amazon-q-ETMAGY3D.js → amazon-q-LFZNGN27.js} +6 -6
- package/dist/amazon-q-LFZNGN27.js.map +1 -0
- package/dist/{amp-BQZOL5GR.js → amp-CEWOSWQO.js} +4 -4
- package/dist/amp-CEWOSWQO.js.map +1 -0
- package/dist/{amp-67BZONGF.js → amp-S22XTPEQ.js} +7 -7
- package/dist/amp-S22XTPEQ.js.map +1 -0
- package/dist/{antigravity-EA4L225L.js → antigravity-LHFEFNMC.js} +5 -5
- package/dist/antigravity-LHFEFNMC.js.map +1 -0
- package/dist/antigravity-PZXYAO3X.js +18 -0
- package/dist/{antigravity-cli-B2HXZFYQ.js → antigravity-cli-MOKFSWOU.js} +5 -5
- package/dist/antigravity-cli-MOKFSWOU.js.map +1 -0
- package/dist/{antigravity-cli-OM6SC3PE.js → antigravity-cli-PN474FXM.js} +9 -9
- package/dist/antigravity-cli-PN474FXM.js.map +1 -0
- package/dist/audit-2H7E3Z4N.js +311 -0
- package/dist/audit-2H7E3Z4N.js.map +1 -0
- package/dist/{chunk-KHO5WNTP.js → chunk-4GH2KA7V.js} +1 -1
- package/dist/chunk-4GH2KA7V.js.map +1 -0
- package/dist/{chunk-7F5KHLEP.js → chunk-6XWORQM6.js} +4 -4
- package/dist/chunk-6XWORQM6.js.map +1 -0
- package/dist/{chunk-2Y2MZRLP.js → chunk-7C2IPIIB.js} +3 -3
- package/dist/chunk-7C2IPIIB.js.map +1 -0
- package/dist/{chunk-NLE2J5P4.js → chunk-7HHW23AC.js} +29 -29
- package/dist/chunk-7HHW23AC.js.map +1 -0
- package/dist/{chunk-XD7MY6HB.js → chunk-7PSNXUFK.js} +1 -1
- package/dist/chunk-7PSNXUFK.js.map +1 -0
- package/dist/{chunk-YPAXJ7EW.js → chunk-7VSZXOXJ.js} +13 -13
- package/dist/chunk-7VSZXOXJ.js.map +1 -0
- package/dist/{chunk-ISEJWBFF.js → chunk-B6PKHS5I.js} +2 -2
- package/dist/chunk-B6PKHS5I.js.map +1 -0
- package/dist/{chunk-UM5S7DKK.js → chunk-C747DYNT.js} +1 -1
- package/dist/chunk-C747DYNT.js.map +1 -0
- package/dist/{chunk-PW42ZXCB.js → chunk-DOPFBUCX.js} +3 -3
- package/dist/chunk-DOPFBUCX.js.map +1 -0
- package/dist/{chunk-I5UXHIDT.js → chunk-DWZ5IWF4.js} +8 -8
- package/dist/chunk-DWZ5IWF4.js.map +1 -0
- package/dist/{chunk-6WZODR3Z.js → chunk-FJ6F5U3W.js} +5 -5
- package/dist/chunk-FJ6F5U3W.js.map +1 -0
- package/dist/{chunk-H33M77DD.js → chunk-HATCOSQT.js} +22 -19
- package/dist/chunk-HATCOSQT.js.map +1 -0
- package/dist/{chunk-UMQ6NBQR.js → chunk-ILWHLGIC.js} +2 -2
- package/dist/chunk-ILWHLGIC.js.map +1 -0
- package/dist/{chunk-IVAWP6HH.js → chunk-IOJDZJ72.js} +2 -2
- package/dist/chunk-IOJDZJ72.js.map +1 -0
- package/dist/{chunk-NBYKLUF6.js → chunk-KFPSJRHR.js} +2 -2
- package/dist/chunk-KFPSJRHR.js.map +1 -0
- package/dist/{chunk-O7SDRBVB.js → chunk-KM2YXO6V.js} +1 -1
- package/dist/chunk-KM2YXO6V.js.map +1 -0
- package/dist/{chunk-3NH2ARIS.js → chunk-KTBAB556.js} +6 -6
- package/dist/chunk-KTBAB556.js.map +1 -0
- package/dist/{chunk-5IOTP7LQ.js → chunk-KWC5DQ5Z.js} +7 -5
- package/dist/chunk-KWC5DQ5Z.js.map +1 -0
- package/dist/{chunk-JKKU2WKG.js → chunk-LD5HAN6O.js} +4 -4
- package/dist/chunk-LD5HAN6O.js.map +1 -0
- package/dist/{chunk-OP4KBXUO.js → chunk-LFWYYWLV.js} +1 -1
- package/dist/chunk-LFWYYWLV.js.map +1 -0
- package/dist/{chunk-APZDTY76.js → chunk-LZL2YITN.js} +7 -7
- package/dist/chunk-LZL2YITN.js.map +1 -0
- package/dist/{chunk-H53QZQJI.js → chunk-PSGTHJQU.js} +1 -1
- package/dist/chunk-PSGTHJQU.js.map +1 -0
- package/dist/{chunk-FBJQGRET.js → chunk-Q4ISQHUQ.js} +1 -1
- package/dist/chunk-Q4ISQHUQ.js.map +1 -0
- package/dist/{chunk-6TF7MHG5.js → chunk-Q7PR2WGT.js} +2 -2
- package/dist/chunk-Q7PR2WGT.js.map +1 -0
- package/dist/{chunk-GZGLCCEE.js → chunk-QYOUQCC6.js} +1 -1
- package/dist/chunk-QYOUQCC6.js.map +1 -0
- package/dist/{chunk-Z2MRSS2I.js → chunk-RNVIK5YJ.js} +2 -2
- package/dist/chunk-RNVIK5YJ.js.map +1 -0
- package/dist/{chunk-XC5SJ35F.js → chunk-RPWD5H6Y.js} +5 -5
- package/dist/chunk-RPWD5H6Y.js.map +1 -0
- package/dist/{chunk-PAPMUAR5.js → chunk-S25MVWBP.js} +12 -12
- package/dist/chunk-S25MVWBP.js.map +1 -0
- package/dist/{chunk-FJCUKXGX.js → chunk-THI4PI4H.js} +2 -2
- package/dist/chunk-THI4PI4H.js.map +1 -0
- package/dist/{chunk-D4ELPBB5.js → chunk-TOSNS2BY.js} +43 -43
- package/dist/chunk-TOSNS2BY.js.map +1 -0
- package/dist/{chunk-MGTDQLJJ.js → chunk-UNU2KPYJ.js} +11 -9
- package/dist/chunk-UNU2KPYJ.js.map +1 -0
- package/dist/{chunk-MQPNU2CY.js → chunk-UZZTWWGG.js} +1 -1
- package/dist/chunk-UZZTWWGG.js.map +1 -0
- package/dist/{chunk-4NHXLXSD.js → chunk-W7AGWAMH.js} +2 -2
- package/dist/chunk-W7AGWAMH.js.map +1 -0
- package/dist/{chunk-OPXAP3AC.js → chunk-XN7S44U4.js} +1 -1
- package/dist/chunk-XN7S44U4.js.map +1 -0
- package/dist/{chunk-BEFVJ2OE.js → chunk-XXLCMSD3.js} +1 -1
- package/dist/chunk-XXLCMSD3.js.map +1 -0
- package/dist/{chunk-YT43MUSJ.js → chunk-XZWMJLIT.js} +1 -1
- package/dist/chunk-XZWMJLIT.js.map +1 -0
- package/dist/{chunk-RK6VBLXP.js → chunk-ZSOS2KOR.js} +1 -1
- package/dist/chunk-ZSOS2KOR.js.map +1 -0
- package/dist/{claude-code-NMRKTAP7.js → claude-code-FS42PXZO.js} +4 -4
- package/dist/claude-code-FS42PXZO.js.map +1 -0
- package/dist/{claude-code-GRWO6XBZ.js → claude-code-TA53454O.js} +13 -13
- package/dist/claude-code-TA53454O.js.map +1 -0
- package/dist/cli/sdk.js +9 -8
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{cline-25KW25IN.js → cline-GZFN32BM.js} +6 -6
- package/dist/cline-GZFN32BM.js.map +1 -0
- package/dist/{codebuddy-ZNYQACMF.js → codebuddy-IYS3TQZ3.js} +7 -7
- package/dist/codebuddy-IYS3TQZ3.js.map +1 -0
- package/dist/{codebuff-ETYT5UBL.js → codebuff-6KWBW6CT.js} +4 -4
- package/dist/codebuff-6KWBW6CT.js.map +1 -0
- package/dist/{codebuff-VR6JUDIY.js → codebuff-D3MIKJHC.js} +6 -6
- package/dist/codebuff-D3MIKJHC.js.map +1 -0
- package/dist/{codex-YAORPCOD.js → codex-DKBAAUCO.js} +4 -4
- package/dist/codex-DKBAAUCO.js.map +1 -0
- package/dist/{codex-CPNKTXG3.js → codex-ZKLP5IXZ.js} +9 -9
- package/dist/codex-ZKLP5IXZ.js.map +1 -0
- package/dist/{continue-WU2IB5KS.js → continue-I34FNSTJ.js} +8 -8
- package/dist/continue-I34FNSTJ.js.map +1 -0
- package/dist/{copilot-cli-MZTAWMPW.js → copilot-cli-CLBJACQ5.js} +4 -4
- package/dist/copilot-cli-CLBJACQ5.js.map +1 -0
- package/dist/{copilot-cli-PAP377OM.js → copilot-cli-NWPM5GE6.js} +7 -7
- package/dist/copilot-cli-NWPM5GE6.js.map +1 -0
- package/dist/{crush-QBXLNN7T.js → crush-A5C5USRL.js} +4 -4
- package/dist/crush-A5C5USRL.js.map +1 -0
- package/dist/{crush-3AVQA4YU.js → crush-MDGPZSZU.js} +7 -7
- package/dist/crush-MDGPZSZU.js.map +1 -0
- package/dist/{cursor-DIW43TRZ.js → cursor-D5SWDVSW.js} +3 -3
- package/dist/cursor-D5SWDVSW.js.map +1 -0
- package/dist/cursor-JRVK56QA.js +22 -0
- package/dist/{define-connector-DTWb46UB.d.ts → define-connector-B7tLHVnx.d.ts} +1 -1
- package/dist/{detect-6V4LC3MA.js → detect-FKJC36P4.js} +4 -4
- package/dist/detect-FKJC36P4.js.map +1 -0
- package/dist/{devin-QMEM3OFA.js → devin-TZMRC57O.js} +7 -7
- package/dist/devin-TZMRC57O.js.map +1 -0
- package/dist/{doctor-2YDUVSAU.js → doctor-PGVYUQYG.js} +26 -26
- package/dist/doctor-PGVYUQYG.js.map +1 -0
- package/dist/{droid-U3ZBLQFO.js → droid-PFQ2PZSF.js} +4 -4
- package/dist/droid-PFQ2PZSF.js.map +1 -0
- package/dist/{droid-MOKV53J4.js → droid-SCFWDJR4.js} +7 -7
- package/dist/droid-SCFWDJR4.js.map +1 -0
- package/dist/{gemini-cli-47ZHCOZR.js → gemini-cli-MLDGOR2L.js} +8 -8
- package/dist/gemini-cli-MLDGOR2L.js.map +1 -0
- package/dist/{gemini-cli-NMVVBO3K.js → gemini-cli-Y6RJMU24.js} +4 -4
- package/dist/gemini-cli-Y6RJMU24.js.map +1 -0
- package/dist/{goose-4EI5MYTI.js → goose-5DBHDSJW.js} +9 -9
- package/dist/goose-5DBHDSJW.js.map +1 -0
- package/dist/{goose-64V46Y2W.js → goose-K2HKUTBK.js} +4 -4
- package/dist/goose-K2HKUTBK.js.map +1 -0
- package/dist/{grok-cli-QYQPDSVB.js → grok-cli-LX6Q6RUY.js} +7 -7
- package/dist/grok-cli-LX6Q6RUY.js.map +1 -0
- package/dist/{hermes-F75OSK3Y.js → hermes-LJB3SJKB.js} +7 -7
- package/dist/hermes-LJB3SJKB.js.map +1 -0
- package/dist/{hermes-F3EGTK6N.js → hermes-MF3NX4ZY.js} +4 -4
- package/dist/hermes-MF3NX4ZY.js.map +1 -0
- package/dist/{hook-OEVRDMXD.js → hook-PVGBQUQI.js} +16 -16
- package/dist/hook-PVGBQUQI.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/{install-5NMCUDG5.js → install-HPDIK7F6.js} +192 -28
- package/dist/install-HPDIK7F6.js.map +1 -0
- package/dist/{introspect-dNekqPDY.d.ts → introspect-DWCu0Krk.d.ts} +1 -1
- package/dist/{jetbrains-copilot-ZGIWI6YV.js → jetbrains-copilot-2DSVAJMJ.js} +6 -6
- package/dist/jetbrains-copilot-2DSVAJMJ.js.map +1 -0
- package/dist/{junie-DIFN2P22.js → junie-GUBDRADP.js} +6 -6
- package/dist/junie-GUBDRADP.js.map +1 -0
- package/dist/{kilo-EMZJBEBB.js → kilo-HRLWMENX.js} +8 -8
- package/dist/kilo-HRLWMENX.js.map +1 -0
- package/dist/{kilo-SW7BH6EG.js → kilo-SMHPOHJ5.js} +4 -4
- package/dist/kilo-SMHPOHJ5.js.map +1 -0
- package/dist/{kilo-cli-S3GXBPAE.js → kilo-cli-IQMFMYZF.js} +8 -8
- package/dist/kilo-cli-IQMFMYZF.js.map +1 -0
- package/dist/{kilo-cli-ZF272ZHN.js → kilo-cli-T2SRRRJS.js} +5 -5
- package/dist/kilo-cli-T2SRRRJS.js.map +1 -0
- package/dist/{kimi-IQJOIY6B.js → kimi-EPD46UJK.js} +7 -7
- package/dist/kimi-EPD46UJK.js.map +1 -0
- package/dist/{kimi-5FHEXGZD.js → kimi-MSIDEMCI.js} +4 -4
- package/dist/kimi-MSIDEMCI.js.map +1 -0
- package/dist/{kiro-BYX4HEAJ.js → kiro-A7DL52FX.js} +7 -7
- package/dist/kiro-A7DL52FX.js.map +1 -0
- package/dist/{kiro-WGOI5CGT.js → kiro-NYRRBIKW.js} +4 -4
- package/dist/kiro-NYRRBIKW.js.map +1 -0
- package/dist/{leaderboard-XEKS7B3H.js → leaderboard-KCT7XPCI.js} +7 -7
- package/dist/leaderboard-KCT7XPCI.js.map +1 -0
- package/dist/{mimo-code-7R53QDHB.js → mimo-code-NDGLBXNC.js} +7 -7
- package/dist/mimo-code-NDGLBXNC.js.map +1 -0
- package/dist/{mistral-vibe-LHJ55FSB.js → mistral-vibe-LLWASF5X.js} +6 -6
- package/dist/mistral-vibe-LLWASF5X.js.map +1 -0
- package/dist/{mux-XM6AP35L.js → mux-7PIJ7HUQ.js} +4 -4
- package/dist/mux-7PIJ7HUQ.js.map +1 -0
- package/dist/{mux-NYCNGL43.js → mux-ON4QK3OC.js} +6 -6
- package/dist/mux-ON4QK3OC.js.map +1 -0
- package/dist/{nemoclaw-WSIPSE7U.js → nemoclaw-45R5MFBF.js} +7 -7
- package/dist/nemoclaw-45R5MFBF.js.map +1 -0
- package/dist/{omp-562NK5BJ.js → omp-ROCTFV3A.js} +7 -7
- package/dist/omp-ROCTFV3A.js.map +1 -0
- package/dist/{open-interpreter-I2CNOEXY.js → open-interpreter-V6CN542J.js} +6 -6
- package/dist/open-interpreter-V6CN542J.js.map +1 -0
- package/dist/openclaw-AOKFJGRQ.js +17 -0
- package/dist/{openclaw-5EQFGOWL.js → openclaw-KAFTNLR2.js} +4 -4
- package/dist/openclaw-KAFTNLR2.js.map +1 -0
- package/dist/{opencode-YS4WX2E2.js → opencode-YYWQ45LF.js} +7 -7
- package/dist/opencode-YYWQ45LF.js.map +1 -0
- package/dist/{opencode-QGP4ALQY.js → opencode-Z65JYILL.js} +4 -4
- package/dist/opencode-Z65JYILL.js.map +1 -0
- package/dist/{openhands-QMYIKNOS.js → openhands-OFFMWCQW.js} +7 -7
- package/dist/openhands-OFFMWCQW.js.map +1 -0
- package/dist/{package-G25GVTH2.js → package-TALOSRQ4.js} +15 -15
- package/dist/package-TALOSRQ4.js.map +1 -0
- package/dist/{pi-644FIN3A.js → pi-4W74ETTI.js} +6 -6
- package/dist/pi-4W74ETTI.js.map +1 -0
- package/dist/{pi-GGDQREVG.js → pi-DLKCPOJE.js} +4 -4
- package/dist/pi-DLKCPOJE.js.map +1 -0
- package/dist/{qwen-code-GQILBJ5B.js → qwen-code-26CSFDX6.js} +4 -4
- package/dist/qwen-code-26CSFDX6.js.map +1 -0
- package/dist/{qwen-code-STDMX7EM.js → qwen-code-JOBFNEVT.js} +16 -16
- package/dist/qwen-code-JOBFNEVT.js.map +1 -0
- package/dist/{roo-code-SUWI4BBN.js → roo-code-HSAE2CJU.js} +4 -4
- package/dist/roo-code-HSAE2CJU.js.map +1 -0
- package/dist/{roo-code-DLPIHHQ6.js → roo-code-RHIGJZNY.js} +6 -6
- package/dist/roo-code-RHIGJZNY.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -8
- package/dist/runtime/index.js +14 -14
- package/dist/sdk/index.d.ts +4 -4
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +11 -11
- package/dist/{serve-XTMIUHKK.js → serve-4TEHK726.js} +16 -16
- package/dist/serve-4TEHK726.js.map +1 -0
- package/dist/{status-VJAGO4Z7.js → status-DVD4EHMX.js} +11 -11
- package/dist/status-DVD4EHMX.js.map +1 -0
- package/dist/{statusline-EY2E2UGF.js → statusline-ZVNH7XBK.js} +15 -15
- package/dist/statusline-ZVNH7XBK.js.map +1 -0
- package/dist/{synthetic-6FRA7P5Q.js → synthetic-LUT6V6SD.js} +4 -4
- package/dist/synthetic-LUT6V6SD.js.map +1 -0
- package/dist/{telemetry-OLZQBADT.js → telemetry-NWUJPIK3.js} +10 -10
- package/dist/telemetry-NWUJPIK3.js.map +1 -0
- package/dist/{trae-CPPYASR2.js → trae-SIQI3C66.js} +4 -4
- package/dist/trae-SIQI3C66.js.map +1 -0
- package/dist/{trae-UOYD6JZZ.js → trae-TLAFSQRQ.js} +6 -6
- package/dist/trae-TLAFSQRQ.js.map +1 -0
- package/dist/{types-JyhpJHJa.d.ts → types-C6j18a6R.d.ts} +13 -14
- package/dist/{uninstall-AZEUPAND.js → uninstall-DZVFV7KE.js} +21 -21
- package/dist/uninstall-DZVFV7KE.js.map +1 -0
- package/dist/{upgrade-CAUUHSSC.js → upgrade-OUE4ED52.js} +21 -21
- package/dist/upgrade-OUE4ED52.js.map +1 -0
- package/dist/{usage-3KHZ4RYZ.js → usage-NT3ZXALZ.js} +4 -4
- package/dist/usage-NT3ZXALZ.js.map +1 -0
- package/dist/{usage-event-TZWOZPRJ.js → usage-event-IELZE6WO.js} +15 -15
- package/dist/usage-event-IELZE6WO.js.map +1 -0
- package/dist/{vscode-copilot-NIMH2DGU.js → vscode-copilot-VZ5XYSTK.js} +7 -7
- package/dist/vscode-copilot-VZ5XYSTK.js.map +1 -0
- package/dist/{warp-NRBBJQR2.js → warp-5YBSP7FP.js} +4 -4
- package/dist/warp-5YBSP7FP.js.map +1 -0
- package/dist/{warp-QYJGKURM.js → warp-P2HWXIKT.js} +6 -6
- package/dist/warp-P2HWXIKT.js.map +1 -0
- package/dist/{windsurf-75LLZ37C.js → windsurf-3JC73GZK.js} +6 -6
- package/dist/windsurf-3JC73GZK.js.map +1 -0
- package/dist/{zed-HKAZXEJW.js → zed-6CMUKXLI.js} +7 -7
- package/dist/zed-6CMUKXLI.js.map +1 -0
- package/dist/{zed-XJFOOKCO.js → zed-XXCNYOIN.js} +4 -4
- package/dist/zed-XXCNYOIN.js.map +1 -0
- package/package.json +92 -88
- package/dist/action-Q7GGO4PA.js.map +0 -1
- package/dist/amazon-q-ETMAGY3D.js.map +0 -1
- package/dist/amp-67BZONGF.js.map +0 -1
- package/dist/amp-BQZOL5GR.js.map +0 -1
- package/dist/antigravity-EA4L225L.js.map +0 -1
- package/dist/antigravity-VXLDLTO7.js +0 -18
- package/dist/antigravity-cli-B2HXZFYQ.js.map +0 -1
- package/dist/antigravity-cli-OM6SC3PE.js.map +0 -1
- package/dist/chunk-2Y2MZRLP.js.map +0 -1
- package/dist/chunk-3NH2ARIS.js.map +0 -1
- package/dist/chunk-4NHXLXSD.js.map +0 -1
- package/dist/chunk-5IOTP7LQ.js.map +0 -1
- package/dist/chunk-6TF7MHG5.js.map +0 -1
- package/dist/chunk-6WZODR3Z.js.map +0 -1
- package/dist/chunk-7F5KHLEP.js.map +0 -1
- package/dist/chunk-APZDTY76.js.map +0 -1
- package/dist/chunk-BEFVJ2OE.js.map +0 -1
- package/dist/chunk-D4ELPBB5.js.map +0 -1
- package/dist/chunk-FBJQGRET.js.map +0 -1
- package/dist/chunk-FJCUKXGX.js.map +0 -1
- package/dist/chunk-GZGLCCEE.js.map +0 -1
- package/dist/chunk-H33M77DD.js.map +0 -1
- package/dist/chunk-H53QZQJI.js.map +0 -1
- package/dist/chunk-I5UXHIDT.js.map +0 -1
- package/dist/chunk-ISEJWBFF.js.map +0 -1
- package/dist/chunk-IVAWP6HH.js.map +0 -1
- package/dist/chunk-JKKU2WKG.js.map +0 -1
- package/dist/chunk-KHO5WNTP.js.map +0 -1
- package/dist/chunk-MGTDQLJJ.js.map +0 -1
- package/dist/chunk-MQPNU2CY.js.map +0 -1
- package/dist/chunk-NBYKLUF6.js.map +0 -1
- package/dist/chunk-NLE2J5P4.js.map +0 -1
- package/dist/chunk-O7SDRBVB.js.map +0 -1
- package/dist/chunk-OP4KBXUO.js.map +0 -1
- package/dist/chunk-OPXAP3AC.js.map +0 -1
- package/dist/chunk-PAPMUAR5.js.map +0 -1
- package/dist/chunk-PW42ZXCB.js.map +0 -1
- package/dist/chunk-RK6VBLXP.js.map +0 -1
- package/dist/chunk-UM5S7DKK.js.map +0 -1
- package/dist/chunk-UMQ6NBQR.js.map +0 -1
- package/dist/chunk-XC5SJ35F.js.map +0 -1
- package/dist/chunk-XD7MY6HB.js.map +0 -1
- package/dist/chunk-YPAXJ7EW.js.map +0 -1
- package/dist/chunk-YT43MUSJ.js.map +0 -1
- package/dist/chunk-Z2MRSS2I.js.map +0 -1
- package/dist/claude-code-GRWO6XBZ.js.map +0 -1
- package/dist/claude-code-NMRKTAP7.js.map +0 -1
- package/dist/cline-25KW25IN.js.map +0 -1
- package/dist/codebuddy-ZNYQACMF.js.map +0 -1
- package/dist/codebuff-ETYT5UBL.js.map +0 -1
- package/dist/codebuff-VR6JUDIY.js.map +0 -1
- package/dist/codex-CPNKTXG3.js.map +0 -1
- package/dist/codex-YAORPCOD.js.map +0 -1
- package/dist/continue-WU2IB5KS.js.map +0 -1
- package/dist/copilot-cli-MZTAWMPW.js.map +0 -1
- package/dist/copilot-cli-PAP377OM.js.map +0 -1
- package/dist/crush-3AVQA4YU.js.map +0 -1
- package/dist/crush-QBXLNN7T.js.map +0 -1
- package/dist/cursor-DIW43TRZ.js.map +0 -1
- package/dist/cursor-GSLUET3V.js +0 -22
- package/dist/detect-6V4LC3MA.js.map +0 -1
- package/dist/devin-QMEM3OFA.js.map +0 -1
- package/dist/doctor-2YDUVSAU.js.map +0 -1
- package/dist/droid-MOKV53J4.js.map +0 -1
- package/dist/droid-U3ZBLQFO.js.map +0 -1
- package/dist/gemini-cli-47ZHCOZR.js.map +0 -1
- package/dist/gemini-cli-NMVVBO3K.js.map +0 -1
- package/dist/goose-4EI5MYTI.js.map +0 -1
- package/dist/goose-64V46Y2W.js.map +0 -1
- package/dist/grok-cli-QYQPDSVB.js.map +0 -1
- package/dist/hermes-F3EGTK6N.js.map +0 -1
- package/dist/hermes-F75OSK3Y.js.map +0 -1
- package/dist/hook-OEVRDMXD.js.map +0 -1
- package/dist/install-5NMCUDG5.js.map +0 -1
- package/dist/jetbrains-copilot-ZGIWI6YV.js.map +0 -1
- package/dist/junie-DIFN2P22.js.map +0 -1
- package/dist/kilo-EMZJBEBB.js.map +0 -1
- package/dist/kilo-SW7BH6EG.js.map +0 -1
- package/dist/kilo-cli-S3GXBPAE.js.map +0 -1
- package/dist/kilo-cli-ZF272ZHN.js.map +0 -1
- package/dist/kimi-5FHEXGZD.js.map +0 -1
- package/dist/kimi-IQJOIY6B.js.map +0 -1
- package/dist/kiro-BYX4HEAJ.js.map +0 -1
- package/dist/kiro-WGOI5CGT.js.map +0 -1
- package/dist/leaderboard-XEKS7B3H.js.map +0 -1
- package/dist/mimo-code-7R53QDHB.js.map +0 -1
- package/dist/mistral-vibe-LHJ55FSB.js.map +0 -1
- package/dist/mux-NYCNGL43.js.map +0 -1
- package/dist/mux-XM6AP35L.js.map +0 -1
- package/dist/nemoclaw-WSIPSE7U.js.map +0 -1
- package/dist/omp-562NK5BJ.js.map +0 -1
- package/dist/open-interpreter-I2CNOEXY.js.map +0 -1
- package/dist/openclaw-5EQFGOWL.js.map +0 -1
- package/dist/openclaw-7EYBQS4R.js +0 -17
- package/dist/opencode-QGP4ALQY.js.map +0 -1
- package/dist/opencode-YS4WX2E2.js.map +0 -1
- package/dist/openhands-QMYIKNOS.js.map +0 -1
- package/dist/package-G25GVTH2.js.map +0 -1
- package/dist/pi-644FIN3A.js.map +0 -1
- package/dist/pi-GGDQREVG.js.map +0 -1
- package/dist/qwen-code-GQILBJ5B.js.map +0 -1
- package/dist/qwen-code-STDMX7EM.js.map +0 -1
- package/dist/roo-code-DLPIHHQ6.js.map +0 -1
- package/dist/roo-code-SUWI4BBN.js.map +0 -1
- package/dist/serve-XTMIUHKK.js.map +0 -1
- package/dist/status-VJAGO4Z7.js.map +0 -1
- package/dist/statusline-EY2E2UGF.js.map +0 -1
- package/dist/synthetic-6FRA7P5Q.js.map +0 -1
- package/dist/telemetry-OLZQBADT.js.map +0 -1
- package/dist/trae-CPPYASR2.js.map +0 -1
- package/dist/trae-UOYD6JZZ.js.map +0 -1
- package/dist/uninstall-AZEUPAND.js.map +0 -1
- package/dist/upgrade-CAUUHSSC.js.map +0 -1
- package/dist/usage-3KHZ4RYZ.js.map +0 -1
- package/dist/usage-event-TZWOZPRJ.js.map +0 -1
- package/dist/vscode-copilot-NIMH2DGU.js.map +0 -1
- package/dist/warp-NRBBJQR2.js.map +0 -1
- package/dist/warp-QYJGKURM.js.map +0 -1
- package/dist/windsurf-75LLZ37C.js.map +0 -1
- package/dist/zed-HKAZXEJW.js.map +0 -1
- package/dist/zed-XJFOOKCO.js.map +0 -1
- /package/dist/{antigravity-VXLDLTO7.js.map → antigravity-PZXYAO3X.js.map} +0 -0
- /package/dist/{cursor-GSLUET3V.js.map → cursor-JRVK56QA.js.map} +0 -0
- /package/dist/{openclaw-7EYBQS4R.js.map → openclaw-AOKFJGRQ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/jsonc.ts","../src/core/object-map.ts","../src/adapters/claude-code/render.ts","../src/adapters/base.ts","../src/core/hook-array.ts"],"sourcesContent":["/**\r\n * core/jsonc — tolerant JSONC / JSON5-lite parsing.\r\n *\r\n * Many hosts document their config file as JSONC (or JSON5): // line comments,\r\n * /* *\\/ block comments, and trailing commas are all legal. A strict JSON.parse\r\n * false-fails such a perfectly valid file → null → and a careless `?? {}` then\r\n * OVERWRITES the user's entire config with just our entry (data loss). To avoid\r\n * that, every JSON/JSONC adapter parses through `parseJsonc`, which strips\r\n * comments + trailing commas in ONE string-aware pass before JSON.parse.\r\n *\r\n * The single pass is deliberately string-literal aware: a // or /* inside a\r\n * quoted value (e.g. \"http://x//y\") is NOT a comment, and a comma inside a\r\n * string (e.g. \"a,]\") is NOT a trailing comma — both must survive verbatim.\r\n */\r\n\r\n/**\r\n * Strip // line comments, /* *\\/ block comments, and trailing commas from JSONC\r\n * text in a SINGLE string-aware pass.\r\n *\r\n * Rules:\r\n * - While inside a string literal, every character (including //, /*, and ,)\r\n * is copied verbatim; backslash escapes the next character.\r\n * - Outside a string, // … runs to end-of-line and /* … *\\/ to its close.\r\n * - A comma is dropped ONLY when the next non-whitespace, non-comment token is\r\n * a closing `}` or `]` (a trailing comma). A comma followed by another value\r\n * or by end-of-input is preserved (the latter lets JSON.parse report the\r\n * real syntax error instead of us masking it).\r\n */\r\nexport function stripJsonc(text: string): string {\r\n const n = text.length;\r\n let out = \"\";\r\n let i = 0;\r\n let inString = false;\r\n let quote = \"\";\r\n\r\n while (i < n) {\r\n const ch = text[i] as string;\r\n\r\n if (inString) {\r\n out += ch;\r\n if (ch === \"\\\\\") {\r\n // Copy the escaped character verbatim (covers \\\" \\\\ \\/ etc.).\r\n if (i + 1 < n) {\r\n out += text[i + 1] as string;\r\n i += 2;\r\n continue;\r\n }\r\n } else if (ch === quote) {\r\n inString = false;\r\n }\r\n i += 1;\r\n continue;\r\n }\r\n\r\n const next = i + 1 < n ? (text[i + 1] as string) : \"\";\r\n\r\n // Enter a string literal.\r\n if (ch === '\"' || ch === \"'\") {\r\n inString = true;\r\n quote = ch;\r\n out += ch;\r\n i += 1;\r\n continue;\r\n }\r\n\r\n // Line comment — skip to end of line (keep the newline for line tracking).\r\n if (ch === \"/\" && next === \"/\") {\r\n i += 2;\r\n while (i < n && text[i] !== \"\\n\") i += 1;\r\n continue;\r\n }\r\n\r\n // Block comment — skip to the closing */.\r\n if (ch === \"/\" && next === \"*\") {\r\n i += 2;\r\n while (i < n && !(text[i] === \"*\" && text[i + 1] === \"/\")) i += 1;\r\n i += 2; // consume the closing */\r\n continue;\r\n }\r\n\r\n // Trailing comma — drop it only when the next significant token (skipping\r\n // whitespace AND comments) is a closing } or ]. This stays string-aware\r\n // because we only reach here outside a string.\r\n if (ch === \",\") {\r\n const closer = nextSignificant(text, i + 1);\r\n if (closer === \"}\" || closer === \"]\") {\r\n i += 1; // drop the trailing comma\r\n continue;\r\n }\r\n }\r\n\r\n out += ch;\r\n i += 1;\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Peek the next significant (non-whitespace, non-comment) character at/after\r\n * `from`, returning \"\" at end-of-input. Used only outside string literals.\r\n */\r\nfunction nextSignificant(text: string, from: number): string {\r\n const n = text.length;\r\n let i = from;\r\n while (i < n) {\r\n const ch = text[i] as string;\r\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\r\" || ch === \"\\n\") {\r\n i += 1;\r\n continue;\r\n }\r\n const next = i + 1 < n ? (text[i + 1] as string) : \"\";\r\n if (ch === \"/\" && next === \"/\") {\r\n i += 2;\r\n while (i < n && text[i] !== \"\\n\") i += 1;\r\n continue;\r\n }\r\n if (ch === \"/\" && next === \"*\") {\r\n i += 2;\r\n while (i < n && !(text[i] === \"*\" && text[i + 1] === \"/\")) i += 1;\r\n i += 2;\r\n continue;\r\n }\r\n return ch;\r\n }\r\n return \"\";\r\n}\r\n\r\n/**\r\n * Parse JSONC text tolerantly: strip comments + trailing commas, then JSON.parse.\r\n * Throws (like JSON.parse) on genuinely malformed input — callers that want a\r\n * fail-soft null should wrap in try/catch (BaseAdapter.readJson does).\r\n */\r\nexport function parseJsonc<T = unknown>(text: string): T {\r\n return JSON.parse(stripJsonc(text)) as T;\r\n}\r\n","import type { ChangeRecord } from \"./types.js\";\r\n\r\n/**\r\n * Format-agnostic upsert/remove for a config that stores entries in an object\r\n * map at config[rootKey][entryId]. Extracted from BaseAdapter.upsertServerInJson\r\n * / removeServerFromJson so JSON today (and other formats via a Codec later)\r\n * share ONE create/skip/update + overwrite/malformed-guard orchestration. The\r\n * JSON binding in BaseAdapter is a byte-identical wrapper over this.\r\n */\r\n\r\n/** The only format-specific surface: parse a config file to a record and\r\n * serialize it back. parse() fail-softs to null (absent or unparseable). */\r\nexport interface ObjectMapCodec {\r\n parse(path: string): Record<string, unknown> | null;\r\n serialize(path: string, data: Record<string, unknown>, dryRun: boolean): void;\r\n /** Detection half of the overwrite guard: present, non-empty, still unparseable. */\r\n isPresentButUnparseable(path: string): boolean;\r\n}\r\n\r\n/** What to do when config[rootKey] is present but the wrong type (hand-edited to\r\n * an array / primitive). \"warn-skip\" leaves the user's value untouched (the JSON\r\n * server/hook policy); \"coerce\" replaces it with a fresh {} and proceeds (the\r\n * TOML/YAML host policy, used by a later follow-up). */\r\nexport type MalformedRootPolicy = \"warn-skip\" | \"coerce\";\r\n\r\n/** True when a PRESENT value is not a plain object map (array / primitive).\r\n * null/undefined is NOT malformed — that is the well-formed \"absent\" case the\r\n * engine creates fresh. */\r\nexport function isMalformedRootValue(value: unknown): boolean {\r\n return value != null && (typeof value !== \"object\" || Array.isArray(value));\r\n}\r\n\r\nexport interface ObjectMapUpsertOptions {\r\n codec: ObjectMapCodec;\r\n rootKey: string;\r\n platform: string;\r\n configPath: string;\r\n entryId: string;\r\n entry: unknown;\r\n dryRun?: boolean;\r\n policy?: MalformedRootPolicy;\r\n}\r\n\r\nexport interface ObjectMapRemoveOptions {\r\n codec: ObjectMapCodec;\r\n rootKey: string;\r\n platform: string;\r\n configPath: string;\r\n entryId: string;\r\n dryRun?: boolean;\r\n policy?: MalformedRootPolicy;\r\n}\r\n\r\nfunction unparseableWarn(platform: string, configPath: string): ChangeRecord {\r\n return {\r\n platform: platform as ChangeRecord[\"platform\"],\r\n action: \"warn\",\r\n path: configPath,\r\n detail: `existing ${configPath} is not parseable; left untouched (back it up / fix it, then re-run)`,\r\n };\r\n}\r\n\r\nfunction malformedWarn(platform: string, rootKey: string, configPath: string): ChangeRecord {\r\n return {\r\n platform: platform as ChangeRecord[\"platform\"],\r\n action: \"warn\",\r\n path: configPath,\r\n detail: `existing \"${rootKey}\" in ${configPath} is not an object map; left untouched (fix it, then re-run)`,\r\n };\r\n}\r\n\r\nexport function upsertInObjectMap(o: ObjectMapUpsertOptions): ChangeRecord {\r\n const policy = o.policy ?? \"warn-skip\";\r\n if (o.codec.isPresentButUnparseable(o.configPath)) {\r\n return unparseableWarn(o.platform, o.configPath);\r\n }\r\n const cfg = o.codec.parse(o.configPath) ?? {};\r\n if (isMalformedRootValue(cfg[o.rootKey])) {\r\n if (policy === \"warn-skip\") return malformedWarn(o.platform, o.rootKey, o.configPath);\r\n cfg[o.rootKey] = {}; // coerce\r\n }\r\n const bucket = (cfg[o.rootKey] ?? (cfg[o.rootKey] = {})) as Record<string, unknown>;\r\n const before = JSON.stringify(bucket[o.entryId]);\r\n const after = JSON.stringify(o.entry);\r\n let action: ChangeRecord[\"action\"];\r\n if (before === undefined) action = \"create\";\r\n else if (before === after) action = \"skip\";\r\n else action = \"update\";\r\n if (action !== \"skip\") {\r\n bucket[o.entryId] = o.entry;\r\n o.codec.serialize(o.configPath, cfg, o.dryRun ?? false);\r\n }\r\n return {\r\n platform: o.platform as ChangeRecord[\"platform\"],\r\n action,\r\n path: o.configPath,\r\n detail: `${o.rootKey}.${o.entryId}`,\r\n };\r\n}\r\n\r\nexport function removeFromObjectMap(o: ObjectMapRemoveOptions): ChangeRecord {\r\n const policy = o.policy ?? \"warn-skip\";\r\n if (o.codec.isPresentButUnparseable(o.configPath)) {\r\n return unparseableWarn(o.platform, o.configPath);\r\n }\r\n const cfg = o.codec.parse(o.configPath);\r\n if (cfg && isMalformedRootValue(cfg[o.rootKey])) {\r\n if (policy === \"warn-skip\") return malformedWarn(o.platform, o.rootKey, o.configPath);\r\n // coerce: a malformed root holds nothing of ours to remove → absent skip\r\n return {\r\n platform: o.platform as ChangeRecord[\"platform\"],\r\n action: \"skip\",\r\n path: o.configPath,\r\n detail: `${o.rootKey}.${o.entryId} absent`,\r\n };\r\n }\r\n const bucket = cfg?.[o.rootKey] as Record<string, unknown> | undefined;\r\n if (!cfg || !bucket || !(o.entryId in bucket)) {\r\n return {\r\n platform: o.platform as ChangeRecord[\"platform\"],\r\n action: \"skip\",\r\n path: o.configPath,\r\n detail: `${o.rootKey}.${o.entryId} absent`,\r\n };\r\n }\r\n delete bucket[o.entryId];\r\n o.codec.serialize(o.configPath, cfg, o.dryRun ?? false);\r\n return {\r\n platform: o.platform as ChangeRecord[\"platform\"],\r\n action: \"remove\",\r\n path: o.configPath,\r\n detail: `${o.rootKey}.${o.entryId}`,\r\n };\r\n}\r\n","/**\r\n * adapters/claude-code/render — shared content-surface renderers.\r\n *\r\n * The single source of truth for how a connector's commands / skills / subagents\r\n * are serialized into Claude Code's native `md + YAML-frontmatter` documents.\r\n * BOTH the live claude-code adapter (which writes into ~/.claude or .claude when\r\n * installing) AND `core/package` (which emits a marketplace-installable plugin\r\n * bundle) import these so the two paths produce BYTE-IDENTICAL output — there is\r\n * no second, subtly-different copy to drift.\r\n *\r\n * The frontmatter serializer reuses the `yaml` package (the same serializer\r\n * core/yaml and BaseAdapter.renderFrontmatterMd use): a `---` fence, the YAML\r\n * block, a closing `---`, a blank line, then the markdown body and a trailing\r\n * newline.\r\n */\r\n\r\nimport { stringify as stringifyYaml } from \"yaml\";\r\n\r\nimport type { CommandDef, SkillDef, SubagentDef } from \"../../core/types.js\";\r\n\r\n/**\r\n * Render a YAML-frontmatter + markdown body document:\r\n * \"---\\n\" + <yaml> + \"---\\n\\n\" + <body> + \"\\n\".\r\n * Identical to BaseAdapter.renderFrontmatterMd (which now delegates here).\r\n */\r\nexport function renderFrontmatterMd(\r\n frontmatter: Record<string, unknown>,\r\n body: string,\r\n): string {\r\n return `---\\n${stringifyYaml(frontmatter)}---\\n\\n${body}\\n`;\r\n}\r\n\r\n/**\r\n * Render a command to md+frontmatter\r\n * (description, argument-hint, allowed-tools, model + verbatim extra).\r\n *\r\n * `opts.includeToolsAndModel` (default `true`) controls the allowed-tools and\r\n * model insertions. Hosts whose command frontmatter is only\r\n * (description, argument-hint + verbatim extra) — i.e. they have no native\r\n * allowed-tools/model keys — pass `{ includeToolsAndModel: false }` to suppress\r\n * both; the default reproduces the full shape byte-for-byte.\r\n */\r\nexport function renderCommandMd(\r\n cmd: CommandDef,\r\n opts: { includeToolsAndModel?: boolean } = {},\r\n): string {\r\n const { includeToolsAndModel = true } = opts;\r\n const frontmatter: Record<string, unknown> = {};\r\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\r\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\r\n if (includeToolsAndModel) {\r\n const allow = cmd.tools?.allow;\r\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\r\n if (cmd.model !== undefined) frontmatter.model = cmd.model;\r\n }\r\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\r\n return renderFrontmatterMd(frontmatter, cmd.prompt);\r\n}\r\n\r\n/**\r\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\r\n * allowed-tools, disable-model-invocation, verbatim extra) + body.\r\n */\r\nexport function renderSkillMd(skill: SkillDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n name: skill.name,\r\n description: skill.description,\r\n };\r\n if (skill.model !== undefined) frontmatter.model = skill.model;\r\n const allow = skill.tools?.allow;\r\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\r\n if (skill.disableModelInvocation !== undefined) {\r\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\r\n }\r\n if (skill.extra) Object.assign(frontmatter, skill.extra);\r\n return renderFrontmatterMd(frontmatter, skill.body);\r\n}\r\n\r\n/** Render a subagent to md+frontmatter (name, description, tools, model) + prompt body. */\r\nexport function renderSubagentMd(agent: SubagentDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n name: agent.name,\r\n description: agent.description,\r\n };\r\n const allow = agent.tools?.allow;\r\n if (allow && allow.length > 0) frontmatter.tools = allow.join(\", \");\r\n if (agent.model !== undefined) frontmatter.model = agent.model;\r\n if (agent.extra) Object.assign(frontmatter, agent.extra);\r\n return renderFrontmatterMd(frontmatter, agent.prompt);\r\n}\r\n\r\n/**\r\n * Render a subagent in OpenCode's shape (shared by opencode/kilo/mimo-code):\r\n * frontmatter (description, mode:\"subagent\", model?, permission? + verbatim\r\n * extra) with the system prompt as the body. `name` is NOT a frontmatter\r\n * field — it comes from the filename. `permission` is derived from the coarse\r\n * `readonly` knob: a readonly agent gets a per-tool deny map (edit/bash) so it\r\n * cannot mutate the workspace.\r\n */\r\nexport function renderOpenCodeSubagentMd(agent: SubagentDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n description: agent.description,\r\n mode: \"subagent\",\r\n };\r\n if (agent.model !== undefined) frontmatter.model = agent.model;\r\n if (agent.readonly === true) {\r\n // Per-tool permission map: deny mutating tools for a readonly subagent.\r\n frontmatter.permission = { edit: \"deny\", bash: \"deny\" };\r\n }\r\n if (agent.extra) Object.assign(frontmatter, agent.extra);\r\n return renderFrontmatterMd(frontmatter, agent.prompt);\r\n}\r\n","/**\r\n * adapters/base — shared adapter foundation.\r\n *\r\n * Provides JSON config IO, settings backup, and a default doctor. Per-platform\r\n * specifics (paths, capabilities, native render format, runtime parse/format)\r\n * are abstract and implemented by each adapter. TOML/YAML adapters override the\r\n * JSON helpers entirely.\r\n */\r\n\r\nimport {\r\n chmodSync,\r\n copyFileSync,\r\n existsSync,\r\n readdirSync,\r\n readFileSync,\r\n rmSync,\r\n statSync,\r\n writeFileSync,\r\n} from \"node:fs\";\r\nimport type { Dirent } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\r\n\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n DiagnosticResult,\r\n HealthCheck,\r\n HookParadigm,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PlatformMemoryOverride,\r\n} from \"../core/types.js\";\r\nimport { backupsDir, ensureDir, firstSymlinkInPath } from \"../core/paths.js\";\r\nimport { parseJsonc } from \"../core/jsonc.js\";\r\nimport {\r\n isMalformedRootValue as isMalformedRootValueFn,\r\n removeFromObjectMap,\r\n upsertInObjectMap,\r\n type ObjectMapCodec,\r\n} from \"../core/object-map.js\";\r\nimport { removeFromArray, upsertInArray } from \"../core/hook-array.js\";\r\nimport { buildHomeBinActionCommand, buildHomeBinHookCommand } from \"../core/spawn.js\";\r\nimport {\r\n MEMORY_CONTENT_SOFT_BUDGET_BYTES,\r\n listManagedBlocks,\r\n loadMemoryLedger,\r\n recordMemoryTarget,\r\n removeManagedBlocksFile,\r\n saveMemoryLedger,\r\n upsertManagedBlockFile,\r\n} from \"../core/managed-block.js\";\r\nimport { renderFrontmatterMd } from \"./claude-code/render.js\";\r\nimport type { Adapter, InstallContext, MemoryTarget } from \"./spi.js\";\r\n\r\n/** Content-surface kinds with BaseAdapter default install/uninstall handling. */\r\ntype ContentSurface =\r\n | \"commands\"\r\n | \"skills\"\r\n | \"subagents\"\r\n | \"memory\"\r\n | \"statusline\"\r\n | \"actions\";\r\n\r\n/**\r\n * Per-host policy + observables for the shared object-map hook-array merge\r\n * engine ({@link BaseAdapter.upsertHookEntries} / {@link BaseAdapter.removeHookEntries}).\r\n * `E` is the host's per-event array element type (e.g. claude-code's\r\n * `{ matcher, hooks: [...] }`). EVERY observable string + ownership predicate\r\n * is carried here so the engine body hardcodes none of them and per-host\r\n * wording never drifts; a future host needing divergent details overrides only\r\n * its descriptor, not the engine.\r\n */\r\nexport interface HookMergeDescriptor<E> {\r\n /**\r\n * How to handle a present-but-malformed `hooks` root (an array / primitive\r\n * instead of an object map) on install:\r\n * - \"warn-skip\" (DEFAULT): route through {@link BaseAdapter.malformedHookRootSkip}\r\n * — surface a `warn`, write nothing, leave the user's value untouched. This\r\n * is byte-identical to the pre-axis engine, so existing hosts that omit the\r\n * field are unchanged.\r\n * - \"coerce\": replace a malformed root (and any non-array event bucket) with a\r\n * fresh object map / array, then proceed — matching the container hosts\r\n * (codex, goose) whose server path already coerces a malformed root.\r\n */\r\n malformedPolicy?: \"warn-skip\" | \"coerce\";\r\n /**\r\n * Canonical → host event name. `undefined` = the host has no equivalent for\r\n * this event → the engine emits a warn (via unmappedWarnDetail) and skips it.\r\n * Omit the field entirely for identity hosts (claude-code) — no warn path.\r\n */\r\n mapEvent?(event: string): string | undefined;\r\n /** Warn detail for an event mapEvent returns undefined for. Required iff mapEvent can return undefined. */\r\n unmappedWarnDetail?(event: string): string;\r\n /**\r\n * Severity of the record emitted for an event mapEvent returns undefined for.\r\n * DEFAULT `\"warn\"` (trips a non-zero install exit) — byte-identical to every\r\n * host that omits this. A host may return `\"skip\"` for an event whose drop\r\n * predates the never-silent convention (codex's SessionEnd / Notification), so\r\n * the degradation is reported VISIBLY without flipping that legacy event's\r\n * historical exit-0. Either way the event is NEVER silently dropped.\r\n */\r\n unmappedAction?(event: string): \"warn\" | \"skip\";\r\n /** Render one host entry from the event name, declared matcher, and home-bin command. */\r\n renderEntry(event: string, matcher: string, command: string): E;\r\n /** Upsert find: does `entry` already carry THIS specific command (idempotency check)? */\r\n entryOwnsCommand(entry: E, command: string): boolean;\r\n /**\r\n * Uninstall whole-entry predicate (FLAT hosts): does `entry` belong to us?\r\n * NESTED hosts supplying {@link stripInner} may return a never-true predicate —\r\n * the engine then only ever invokes `stripInner`. Bound to `ctx` because\r\n * ownership is connector-generic (ANY of our commands), wider than the\r\n * install-time specific-command check. The `event` param lets EVENT-SPECIFIC\r\n * hosts (codex, whose ownership is per-event by construction) match the\r\n * canonical event being stripped; hosts whose ownership is event-independent\r\n * (claude-code/droid/cursor/qwen) ignore it — a `(ctx) => …` arrow is assignable\r\n * to this 2-param type (fewer params is fine in TS), so they need no change.\r\n */\r\n ownsEntryForRemove(ctx: InstallContext, event: string): (entry: E) => boolean;\r\n /**\r\n * Uninstall inner-strip (NESTED hosts): strip our owned inner commands from\r\n * `entry`, returning the rebuilt entry (`null` when fully emptied) and the\r\n * count of inner commands removed. Omit for FLAT hosts.\r\n */\r\n stripInner?(ctx: InstallContext): (entry: E) => { next: E | null; removed: number };\r\n /** Idempotent-reinstall skip detail, e.g. `hooks.<event> already registered`. */\r\n skipDetail(event: string): string;\r\n /** Uninstall remove detail, e.g. `hooks.<event> (<n>)`. */\r\n removeDetail(event: string, removed: number): string;\r\n /** Uninstall skip detail when no hooks section is present at all. */\r\n absentDetail: string;\r\n /** Uninstall skip detail when a hooks section exists but nothing matched. */\r\n noMatchDetail: string;\r\n /**\r\n * Uninstall: the exact event keys to scan, in order. Omit (default) to scan\r\n * every key actually present (`Object.keys(hooks)`). EVENT-SPECIFIC hosts whose\r\n * ownership predicate rebuilds a per-event command (codex) MUST pin their fixed\r\n * event set here so a home-bin command hand-placed under a foreign event key is\r\n * left untouched — byte-identical to a fixed-event-list uninstall loop.\r\n */\r\n removeEventKeys?: readonly string[];\r\n /** Optional post-mutation hook on the whole parsed file, before the single write. */\r\n onMutate?(file: Record<string, unknown>): void;\r\n /**\r\n * Native-pass ownership find (EXACT command match, vs the normalized\r\n * entryOwnsCommand). Set only when a `native` list is passed.\r\n */\r\n nativeOwnsCommand?(entry: E, command: string): boolean;\r\n /** Native-pass skip detail, e.g. `hooks.<event> (native) already registered`. */\r\n nativeSkipDetail?(event: string): string;\r\n /** Native-pass create/update detail, e.g. `hooks.<event> (native)`. */\r\n nativeMutateDetail?(event: string): string;\r\n}\r\n\r\n/**\r\n * One resolved action trigger for an EMITTER adapter: the host-native trigger\r\n * the adapter writes runs `command`, which re-enters the home binary at the\r\n * `action` verb. `label`/`description` fall back to the action id when the\r\n * connector declared none. Produced by {@link BaseAdapter.actionTriggers}.\r\n */\r\nexport interface ActionTrigger {\r\n /** The action id — also the per-action file/key name on most hosts. */\r\n id: string;\r\n /** Display label (action.description ?? action.id). */\r\n label: string;\r\n /** One-line description (action.description ?? action.id). */\r\n description: string;\r\n /** `<homeBin> action <host> <id> --connector <connectorId>` (the verb the host runs). */\r\n command: string;\r\n}\r\n\r\n/**\r\n * Documented USER-scope AGENTS.md locations, per host (the AGENTS.md-first\r\n * research matrix). Only hosts with a REAL user/global AGENTS.md file are\r\n * listed. Hosts whose documented user-scope memory lives in a DIFFERENT file\r\n * (qwen-code ~/.qwen/QWEN.md, goose .goosehints, kilo/roo/kiro rules dirs,\r\n * copilot-cli copilot-instructions.md) override memoryTargets in-adapter;\r\n * hosts whose user rules are app/UI/cloud-managed (warp Drive, trae,\r\n * jetbrains/cursor settings UI) deliberately have no row — user-scope memory\r\n * there reports the standard skip-warn (the JetBrains-MCP precedent), never a\r\n * write into a file the host ignores.\r\n */\r\nconst AGENTS_MD_USER_PATHS: Partial<Record<PlatformId, () => MemoryTarget>> = {\r\n // codex resolves its own user path in-adapter ($CODEX_HOME with ~ expansion\r\n // + the AGENTS.override.md shadow probe) — deliberately no row here.\r\n zed: () => ({\r\n path:\r\n process.platform === \"win32\" && process.env.APPDATA\r\n ? join(process.env.APPDATA, \"Zed\", \"AGENTS.md\")\r\n : join(homedir(), \".config\", \"zed\", \"AGENTS.md\"),\r\n reason: \"zed personal instructions file\",\r\n }),\r\n amp: () => ({\r\n path: join(homedir(), \".config\", \"amp\", \"AGENTS.md\"),\r\n reason: \"amp user-scope AGENTS.md\",\r\n }),\r\n mux: () => ({\r\n path: join(homedir(), \".mux\", \"AGENTS.md\"),\r\n reason: \"mux global AGENTS.md\",\r\n }),\r\n pi: () => ({\r\n path: join(homedir(), \".pi\", \"agent\", \"AGENTS.md\"),\r\n reason: \"pi global AGENTS.md\",\r\n }),\r\n droid: () => ({\r\n path: join(homedir(), \".factory\", \"AGENTS.md\"),\r\n reason: \"droid (Factory) personal AGENTS.md\",\r\n }),\r\n opencode: () => ({\r\n path: join(homedir(), \".config\", \"opencode\", \"AGENTS.md\"),\r\n reason: \"opencode global AGENTS.md\",\r\n }),\r\n antigravity: () => ({\r\n path: join(homedir(), \".gemini\", \"AGENTS.md\"),\r\n reason: \"antigravity global rules (~/.gemini/AGENTS.md, shared tree)\",\r\n }),\r\n \"antigravity-cli\": () => ({\r\n path: join(homedir(), \".gemini\", \"AGENTS.md\"),\r\n reason: \"agy shares the IDE's ~/.gemini tree (idempotent upsert dedupes)\",\r\n }),\r\n omp: () => ({\r\n path: join(homedir(), \".omp\", \"agent\", \"AGENTS.md\"),\r\n reason: \"omp global AGENTS.md (pi-parity; verify for your version)\",\r\n }),\r\n};\r\n\r\nexport abstract class BaseAdapter implements Adapter {\r\n abstract readonly id: PlatformId;\r\n abstract readonly name: string;\r\n abstract readonly paradigm: HookParadigm;\r\n abstract readonly capabilities: PlatformCapabilities;\r\n\r\n abstract detectInstalled(projectDir: string): DetectedPlatform;\r\n abstract getConfigDir(ctx: InstallContext): string;\r\n abstract getServerConfigPath(ctx: InstallContext): string;\r\n abstract getHookConfigPath(ctx: InstallContext): string;\r\n abstract installServer(ctx: InstallContext): ChangeRecord[];\r\n abstract uninstallServer(ctx: InstallContext): ChangeRecord[];\r\n abstract installHooks(ctx: InstallContext): ChangeRecord[];\r\n abstract uninstallHooks(ctx: InstallContext): ChangeRecord[];\r\n\r\n // ── Content surfaces (commands / skills / subagents) ─────────────────────\r\n // CONCRETE (overridable) defaults so every adapter inherits all six methods\r\n // and the installer can call them without optional-chaining. Each returns a\r\n // single skip when the connector declares no entries of that surface, else a\r\n // single \"warn\" — mirroring the mcp-only hook handling. Supporting adapters\r\n // override only the surfaces they honor.\r\n\r\n installCommands(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"commands\", ctx.connector.commands.length);\r\n }\r\n uninstallCommands(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"commands\", ctx.connector.commands.length);\r\n }\r\n installSkills(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"skills\", ctx.connector.skills.length);\r\n }\r\n uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"skills\", ctx.connector.skills.length);\r\n }\r\n installSubagents(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"subagents\", ctx.connector.subagents.length);\r\n }\r\n uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"subagents\", ctx.connector.subagents.length);\r\n }\r\n\r\n // ── Memory surface (managed marker blocks; AGENTS.md-first) ───────────────\r\n // ONE generic implementation for every supporting host: the per-adapter\r\n // `memoryTargets()` hook resolves WHERE to write (AGENTS.md defaults below;\r\n // claude-code → CLAUDE.md and gemini-cli → GEMINI.md override it), and the\r\n // core/managed-block engine performs the surgical, hash-stamped block edit.\r\n // Unlike commands/skills/subagents these files are SHARED and user-authored —\r\n // bytes outside this connector's own marker pair are never touched.\r\n\r\n /**\r\n * Resolve the memory/rules file(s) this host actually reads at ctx.scope.\r\n * Base default (AGENTS.md-first, owner mandate):\r\n * - an explicit `platforms[<id>].memory.path` override wins;\r\n * - project scope → `<projectDir>/AGENTS.md` (the agents.md standard);\r\n * - user scope → the host's documented user-scope AGENTS.md, when one\r\n * exists ({@link AGENTS_MD_USER_PATHS}); otherwise [] → skip-warn.\r\n * Exception hosts (claude-code, gemini-cli) override this hook.\r\n */\r\n protected memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n const override = this.memoryOverride(ctx);\r\n if (override?.path) {\r\n const base = ctx.scope === \"project\" ? ctx.projectDir : homedir();\r\n return [\r\n {\r\n path: isAbsolute(override.path) ? override.path : join(base, override.path),\r\n reason: `platforms.${this.id}.memory.path override`,\r\n },\r\n ];\r\n }\r\n if (ctx.scope === \"project\") {\r\n return [\r\n { path: join(ctx.projectDir, \"AGENTS.md\"), reason: \"AGENTS.md standard (project root)\" },\r\n ];\r\n }\r\n if (ctx.scope === \"user\") {\r\n const user = AGENTS_MD_USER_PATHS[this.id]?.();\r\n return user ? [user] : [];\r\n }\r\n return [];\r\n }\r\n\r\n /** The per-platform memory override object, when one is declared. */\r\n protected memoryOverride(ctx: InstallContext): PlatformMemoryOverride | undefined {\r\n const o = ctx.connector.platforms[this.id]?.memory;\r\n return o && typeof o === \"object\" ? o : undefined;\r\n }\r\n\r\n installMemory(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n // `?? []` tolerates pre-resolved connectors from versions before the\r\n // memory surface existed (the installer applies the same guard).\r\n const entries = connector.memory ?? [];\r\n if (connector.platforms[this.id]?.memory === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: `memory disabled for ${this.id}` }];\r\n }\r\n if (entries.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no memory\" }];\r\n }\r\n if (!(this.capabilities.supportsMemory ?? false)) {\r\n return this.unsupportedSurface(ctx, \"memory\", entries.length);\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n const override = this.memoryOverride(ctx);\r\n if (override?.mode && this.id !== \"claude-code\") {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `memory.mode is claude-code-only; ignored on ${this.id}`,\r\n });\r\n }\r\n if (ctx.scope !== \"project\" && ctx.scope !== \"user\") {\r\n // system/profile/managed memory files are admin-owned — out of scope (v1).\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail:\r\n `memory not supported at ${ctx.scope} scope on ${this.id} ` +\r\n `(managed/admin memory files are out of scope); ${entries.length} skipped`,\r\n });\r\n return changes;\r\n }\r\n const targets = this.memoryTargets(ctx);\r\n if (targets.length === 0) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail:\r\n `no ${ctx.scope}-scope memory file on ${this.id} ` +\r\n `(user rules are app/UI-managed or undocumented); ${entries.length} skipped`,\r\n });\r\n return changes;\r\n }\r\n changes.push(...this.writeMemoryBlocks(ctx, targets));\r\n return changes;\r\n }\r\n\r\n /**\r\n * Upsert every declared memory entry's block into every resolved target and\r\n * record the ownership ledger rows (`connectorDir(id)/memory-state.json`).\r\n * Shared by the base implementation and the exception-host overrides.\r\n */\r\n protected writeMemoryBlocks(ctx: InstallContext, targets: MemoryTarget[]): ChangeRecord[] {\r\n const changes: ChangeRecord[] = [];\r\n const ledger = loadMemoryLedger(ctx.connector.id);\r\n let ledgerMutated = false;\r\n\r\n for (const target of targets) {\r\n const symlink = this.symlinkPathWarning(target.path);\r\n if (symlink) {\r\n changes.push(symlink);\r\n continue;\r\n }\r\n\r\n for (const entry of ctx.connector.memory ?? []) {\r\n const blockId = `${ctx.connector.id}/${entry.name ?? \"memory\"}`;\r\n const res = upsertManagedBlockFile(target.path, {\r\n blockId,\r\n connectorId: ctx.connector.id,\r\n content: entry.content,\r\n ...(target.commentStyle ? { commentStyle: target.commentStyle } : {}),\r\n force: ctx.force ?? false,\r\n dryRun: ctx.dryRun,\r\n });\r\n changes.push({\r\n platform: this.id,\r\n action: res.action,\r\n path: target.path,\r\n detail: `memory: ${res.detail} — ${target.reason}`,\r\n });\r\n if (res.backupPath) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"create\",\r\n path: res.backupPath,\r\n detail: \"backed up memory file before destructive change\",\r\n });\r\n }\r\n const bytes = Buffer.byteLength(entry.content, \"utf8\");\r\n if (bytes > MEMORY_CONTENT_SOFT_BUDGET_BYTES) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n path: target.path,\r\n detail:\r\n `memory entry \"${entry.name ?? \"memory\"}\" is ${bytes} bytes ` +\r\n `(soft budget ${MEMORY_CONTENT_SOFT_BUDGET_BYTES}); this file is injected into ` +\r\n `every prompt — keep guidance terse`,\r\n });\r\n }\r\n if (res.action !== \"warn\") {\r\n recordMemoryTarget(ledger, {\r\n platform: this.id,\r\n scope: ctx.scope,\r\n path: target.path,\r\n blockId,\r\n createdFile: res.createdFile,\r\n hash: res.hash,\r\n });\r\n ledgerMutated = true;\r\n }\r\n }\r\n // Per-FILE budget (e.g. codex caps combined project docs at 32 KiB —\r\n // budgetBytes ≈ 28 KiB leaves headroom): warn when the whole target file\r\n // (user content + every block) outgrows what the host will actually load.\r\n if (target.budgetBytes !== undefined && !ctx.dryRun && existsSync(target.path)) {\r\n const fileBytes = statSync(target.path).size;\r\n if (fileBytes > target.budgetBytes) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n path: target.path,\r\n detail:\r\n `memory file is ${fileBytes} bytes — over this host's ~${target.budgetBytes}-byte ` +\r\n `budget; the host may truncate or drop it`,\r\n });\r\n }\r\n }\r\n }\r\n\r\n if (ledgerMutated && !ctx.dryRun) saveMemoryLedger(ctx.connector.id, ledger);\r\n return changes;\r\n }\r\n\r\n uninstallMemory(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (!(this.capabilities.supportsMemory ?? false)) {\r\n // Nothing could ever have been written by a non-supporting adapter.\r\n return this.unsupportedSurface(ctx, \"memory\", (connector.memory ?? []).length);\r\n }\r\n\r\n // Candidate files = union of (a) memoryTargets recomputed NOW (probe re-run\r\n // — catches teammate machines with no ledger; the markers in the committed\r\n // file are the source of truth) and (b) ledger rows for this platform from\r\n // EVERY scope (catches a scope flag that differs from install time).\r\n const ledger = loadMemoryLedger(connector.id);\r\n const mine = ledger.targets.filter((t) => t.platform === this.id);\r\n const candidates = new Map<string, { createdFile: boolean }>();\r\n if (ctx.scope === \"project\" || ctx.scope === \"user\") {\r\n for (const t of this.memoryTargets(ctx)) {\r\n candidates.set(t.path, { createdFile: false });\r\n }\r\n }\r\n for (const row of mine) {\r\n const existing = candidates.get(row.path);\r\n candidates.set(row.path, { createdFile: (existing?.createdFile ?? false) || row.createdFile });\r\n }\r\n if (candidates.size === 0) {\r\n return [\r\n { platform: this.id, action: \"skip\", detail: `no memory targets to clean on ${this.id}` },\r\n ];\r\n }\r\n\r\n // Prefix scan (`<connectorId>/`), NOT the declared entry list: renamed or\r\n // removed entries and stale blocks from older versions are reclaimed too.\r\n const changes: ChangeRecord[] = [];\r\n let sawSymlink = false;\r\n for (const [path, { createdFile }] of candidates) {\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) {\r\n changes.push(symlink);\r\n sawSymlink = true;\r\n continue;\r\n }\r\n\r\n const results = removeManagedBlocksFile(\r\n path,\r\n { blockIdPrefix: `${connector.id}/` },\r\n { dryRun: ctx.dryRun, deleteFileIfCreated: createdFile },\r\n );\r\n for (const r of results) {\r\n changes.push({\r\n platform: this.id,\r\n action: r.action,\r\n path: r.path,\r\n detail: `memory: ${r.detail}`,\r\n });\r\n if (r.backupPath) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"create\",\r\n path: r.backupPath,\r\n detail: \"backed up memory file before block removal\",\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Prune this connector's ledger rows for this platform (the file itself is\r\n // deleted when no rows remain). Markers stay the uninstall source of truth.\r\n if (!ctx.dryRun && mine.length > 0 && !sawSymlink) {\r\n ledger.targets = ledger.targets.filter((t) => t.platform !== this.id);\r\n saveMemoryLedger(connector.id, ledger);\r\n }\r\n return changes;\r\n }\r\n\r\n /**\r\n * Doctor: per-ledger-row memory state for this platform — file present,\r\n * block present, and recorded-vs-actual inner hash (drift → warn, the\r\n * user edited inside our block; sync reports the same drift and never\r\n * clobbers it without --force).\r\n */\r\n protected memoryDiagnostics(ctx: InstallContext): DiagnosticResult[] {\r\n const results: DiagnosticResult[] = [];\r\n const rows = loadMemoryLedger(ctx.connector.id).targets.filter(\r\n (t) => t.platform === this.id,\r\n );\r\n for (const row of rows) {\r\n const check = `${this.name}: memory block ${row.blockId}`;\r\n if (!existsSync(row.path)) {\r\n results.push({\r\n check,\r\n status: \"warn\",\r\n message: `memory file missing: ${row.path}`,\r\n fix: \"agent-connector install (sync) will re-create the block\",\r\n fixable: true,\r\n });\r\n continue;\r\n }\r\n let raw: string;\r\n try {\r\n raw = readFileSync(row.path, \"utf8\");\r\n } catch {\r\n results.push({ check, status: \"warn\", message: `cannot read ${row.path}` });\r\n continue;\r\n }\r\n const block = listManagedBlocks(raw).find((b) => b.blockId === row.blockId);\r\n if (!block) {\r\n results.push({\r\n check,\r\n status: \"warn\",\r\n message: `managed block not found in ${row.path}`,\r\n fix: \"agent-connector install (sync) will re-append it\",\r\n fixable: true,\r\n });\r\n } else if (block.drifted) {\r\n results.push({\r\n check,\r\n status: \"warn\",\r\n message:\r\n `user-edited: inner content hash ${block.actualHash} differs from recorded ` +\r\n `${block.recordedHash} in ${row.path}; sync leaves it intact (use --force to overwrite)`,\r\n });\r\n } else {\r\n results.push({ check, status: \"pass\", message: `intact in ${row.path}` });\r\n }\r\n // Shadow-flip probe: re-run memoryTargets NOW for the row's scope — if\r\n // the host's resolution moved (a WARP.md / AGENTS.override.md / .rules /\r\n // .hermes.md appeared, gemini context.fileName changed), the written\r\n // block sits in a file the host no longer reads. The #1 wrong-file\r\n // risk; doctor is the detection layer.\r\n // (`_shared/` bridge rows deliberately live OUTSIDE memoryTargets —\r\n // e.g. claude-code's @AGENTS.md import in CLAUDE.md — skip those.)\r\n if (\r\n !row.blockId.startsWith(\"_shared/\") &&\r\n row.scope === ctx.scope &&\r\n (ctx.scope === \"project\" || ctx.scope === \"user\")\r\n ) {\r\n const current = this.memoryTargets(ctx);\r\n if (current.length > 0 && !current.some((t) => t.path === row.path)) {\r\n results.push({\r\n check,\r\n status: \"warn\",\r\n message:\r\n `${this.id} now resolves its ${row.scope}-scope memory file to ` +\r\n `${current[0]!.path} (${current[0]!.reason}) — the block in ${row.path} ` +\r\n `may no longer be read`,\r\n fix: \"agent-connector install (sync) re-probes and writes the file the host reads now\",\r\n fixable: true,\r\n });\r\n }\r\n }\r\n }\r\n return results;\r\n }\r\n\r\n // ── Declarative host-config key patches (configPatch) ─────────────────────\r\n // CONCRETE (overridable) defaults, mirroring the content surfaces above: the\r\n // installer additionally guards these behind capabilities.supportsConfigPatch\r\n // (the nativeHooks precedent), so these defaults only fire if a capability-\r\n // flagged adapter forgot to override them — still skip-warn, never silent.\r\n\r\n installConfigPatches(ctx: InstallContext): ChangeRecord[] {\r\n const count = (ctx.connector.platforms[this.id]?.configPatch ?? []).length;\r\n if (count === 0) {\r\n return [\r\n { platform: this.id, action: \"skip\", detail: \"connector declares no configPatch entries\" },\r\n ];\r\n }\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `configPatch not supported on ${this.id}; ${count} skipped`,\r\n },\r\n ];\r\n }\r\n\r\n uninstallConfigPatches(_ctx: InstallContext): ChangeRecord[] {\r\n // Nothing was ever applied by a non-supporting adapter → nothing to release.\r\n return [];\r\n }\r\n\r\n // ── Statusline surface (a HUD/status line) ────────────────────────────────\n // CONCRETE (overridable) defaults, mirroring the content surfaces: the\n // installer calls these unconditionally (BaseAdapter defines them), and they\n // self-skip when the connector declares no statusline, else skip-warn on a\n // non-supporting host. A supporting adapter must override these methods; the\n // fleet invariant test pins that supportsStatusline never relies on this\n // default skip-warn implementation.\n\r\n installStatusline(ctx: InstallContext): ChangeRecord[] {\r\n if (ctx.connector.statusline == null) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no statusline\" }];\r\n }\r\n if (ctx.connector.platforms[this.id]?.statusline === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: `statusline disabled for ${this.id}` }];\r\n }\r\n if (!(this.capabilities.supportsStatusline ?? false)) {\r\n return this.unsupportedSurface(ctx, \"statusline\", 1);\r\n }\r\n // A supporting adapter must override this; the default is the same skip-warn\r\n // safety net the configPatch defaults provide (never silent).\r\n return this.unsupportedSurface(ctx, \"statusline\", 1);\r\n }\r\n\r\n uninstallStatusline(ctx: InstallContext): ChangeRecord[] {\r\n if (ctx.connector.statusline == null) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no statusline\" }];\r\n }\r\n if (!(this.capabilities.supportsStatusline ?? false)) {\r\n // Nothing could ever have been written by a non-supporting adapter.\r\n return this.unsupportedSurface(ctx, \"statusline\", 1);\r\n }\r\n return this.unsupportedSurface(ctx, \"statusline\", 1);\r\n }\r\n\r\n // ── Action surface (a user-invokable action) ──────────────────────────────\n // CONCRETE (overridable) defaults, mirroring the statusline pair. v1 ships\n // the dispatch backbone plus per-host affordance emitters. Adapters that set\n // supportsActions must override these methods; every other host keeps this\n // honest skip-warn default. (`?? []` tolerates pre-resolved connectors from\n // versions before the action surface existed, exactly like installMemory.)\n\r\n installActions(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"actions\", (ctx.connector.actions ?? []).length);\r\n }\r\n uninstallActions(ctx: InstallContext): ChangeRecord[] {\r\n return this.unsupportedSurface(ctx, \"actions\", (ctx.connector.actions ?? []).length);\r\n }\r\n\r\n /**\r\n * Shared, surface-agnostic helper for the action EMITTERS: yield one\r\n * {@link ActionTrigger} per declared action, each carrying the home-bin verb\r\n * command the host trigger must run\r\n * (`<homeBin> action <host> <actionId> --connector <id>`, via\r\n * {@link buildHomeBinActionCommand}) plus a `label`/`description` that fall\r\n * back to the action id. Each supporting adapter iterates this and writes its\r\n * host-native trigger (hermes quick_commands / warp workflow / droid exec\r\n * file) — the per-host file shape is NOT this helper's concern, only the\r\n * common (id, label, description, command) tuple. Callers own the standard\r\n * guards (platforms[id].actions === false / empty actions).\r\n */\r\n protected actionTriggers(ctx: InstallContext): ActionTrigger[] {\r\n return (ctx.connector.actions ?? []).map((action) => ({\r\n id: action.id,\r\n label: action.description ?? action.id,\r\n description: action.description ?? action.id,\r\n command: buildHomeBinActionCommand(\r\n ctx.homeBinPath,\r\n this.id,\r\n action.id,\r\n ctx.connector.id,\r\n ),\r\n }));\r\n }\r\n\r\n /**\r\n * Default response for a content surface this platform cannot honor: a single\r\n * skip when the connector declares none of that surface, else a single \"warn\"\r\n * ChangeRecord noting how many were skipped. Mirrors mcp-only hook handling.\r\n */\r\n protected unsupportedSurface(\r\n _ctx: InstallContext,\r\n surface: ContentSurface,\r\n count: number,\r\n ): ChangeRecord[] {\r\n if (count === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: `connector declares no ${surface}` }];\r\n }\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `${surface} not supported on ${this.id}; ${count} skipped`,\r\n },\r\n ];\r\n }\r\n\r\n // ── Content-file helpers (used by surface-supporting adapters) ────────────\r\n\r\n protected symlinkPathWarning(path: string): ChangeRecord | null {\r\n const symlink = firstSymlinkInPath(path);\r\n if (symlink === null) return null;\r\n return {\r\n platform: this.id,\r\n action: \"warn\",\r\n path,\r\n detail: `${basename(path)} skipped: symbolic link in path (${symlink})`,\r\n };\r\n }\r\n\r\n protected writeManagedFile(\r\n path: string,\r\n contents: string,\r\n dryRun: boolean,\r\n detail = basename(path),\r\n executable?: boolean,\r\n ): ChangeRecord {\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return symlink;\r\n\r\n let action: ChangeRecord[\"action\"];\r\n if (!existsSync(path)) {\r\n action = \"create\";\r\n } else {\r\n let current: string | null = null;\r\n try {\r\n current = readFileSync(path, \"utf8\");\r\n } catch {\r\n current = null;\r\n }\r\n action = current === contents ? \"skip\" : \"update\";\r\n }\r\n if (action !== \"skip\" && !dryRun) {\r\n ensureDir(dirname(path));\r\n writeFileSync(path, contents, \"utf8\");\r\n if (executable !== undefined) chmodSync(path, executable ? 0o755 : 0o644);\r\n }\r\n return { platform: this.id, action, path, detail };\r\n }\r\n\r\n protected removeManagedFile(\r\n path: string,\r\n dryRun: boolean,\r\n detail = basename(path),\r\n absentDetail = `${detail} absent`,\r\n ): ChangeRecord {\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return symlink;\r\n\r\n if (!existsSync(path)) {\r\n return { platform: this.id, action: \"skip\", path, detail: absentDetail };\r\n }\r\n if (!dryRun) {\r\n rmSync(path, { recursive: true, force: true });\r\n }\r\n return { platform: this.id, action: \"remove\", path, detail };\r\n }\r\n\r\n /**\r\n * Write a content file idempotently: \"skip\" when the existing bytes are\r\n * already identical, else \"create\"/\"update\". Creates parent dirs (mkdir -p).\r\n * Honors dryRun (computes the action but writes nothing).\r\n */\r\n protected writeContentFile(path: string, contents: string, dryRun: boolean): ChangeRecord {\r\n return this.writeManagedFile(path, contents, dryRun);\r\n }\r\n\r\n /**\r\n * Remove a content file we wrote; \"skip\" when already absent. Honors dryRun.\r\n * Uses rmSync with `force` to also tolerate a path that is a directory tree\r\n * (e.g. a skill folder removed by the supporting adapter).\r\n */\r\n protected removeContentFile(path: string, dryRun: boolean): ChangeRecord {\r\n return this.removeManagedFile(path, dryRun);\r\n }\r\n\r\n /**\r\n * Defense-in-depth path containment: resolve `rel` against `baseDir` and\r\n * return the absolute path ONLY when it stays inside `baseDir`. Returns null\r\n * when `rel` escapes (absolute path, `..` traversal, etc.) so a caller can\r\n * skip-and-warn rather than write/delete outside the surface dir. This is the\r\n * runtime backstop behind the config-time validation in normalizeSkills.\r\n */\r\n protected resolveWithin(baseDir: string, rel: string): string | null {\r\n const base = resolve(baseDir);\r\n const target = resolve(base, rel);\r\n if (target === base) return null; // rel resolved to the dir itself (e.g. \"\" / \".\")\r\n const rind = relative(base, target);\r\n // Outside when the relative path climbs out (`..`) or is itself absolute.\r\n if (rind === \"\" || rind.startsWith(\"..\") || resolve(base, rind) !== target) {\r\n return null;\r\n }\r\n if (rind === \"..\" || rind.startsWith(`..${sep}`)) return null;\r\n return target;\r\n }\r\n\r\n /**\r\n * Recursively report whether a directory tree contains any regular FILE (vs\r\n * only empty/nested-empty subdirectories). Symlinks count as files (we never\r\n * recurse through them). Used by removeDirIfEmpty to decide if a tree is safe\r\n * to drop. An unreadable entry is treated as \"a file is present\" (conservative).\r\n */\r\n private dirTreeHasFile(dir: string): boolean {\r\n let entries: Dirent[];\r\n try {\r\n entries = readdirSync(dir, { withFileTypes: true });\r\n } catch {\r\n return true; // unreadable → assume it holds data; do not remove\r\n }\r\n for (const e of entries) {\r\n if (e.isDirectory()) {\r\n if (this.dirTreeHasFile(join(dir, e.name))) return true;\r\n } else {\r\n return true; // a file / symlink / special → the tree is not \"empty\"\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Remove a directory ONLY when its tree holds NO regular files — i.e. it is\r\n * empty or contains only (nested) empty directories, such as the intermediate\r\n * dirs our own nested skill resources created. Replaces the unconditional\r\n * `rm -rf <dir>` that uninstallSkills used to call, which destroyed user-added\r\n * files / sibling-tool files / shared skill dirs the connector never wrote.\r\n * When ANY file remains (at any depth) the whole tree is left in place and the\r\n * skip is noted. Honors dryRun (computes the action but removes nothing). A\r\n * missing dir is a no-op \"skip\".\r\n */\r\n protected removeDirIfEmpty(dir: string, dryRun: boolean): ChangeRecord {\r\n const symlink = this.symlinkPathWarning(dir);\r\n if (symlink) return symlink;\r\n\r\n if (!existsSync(dir)) {\r\n return { platform: this.id, action: \"skip\", path: dir, detail: `${basename(dir)} absent` };\r\n }\r\n let stat: ReturnType<typeof statSync>;\r\n try {\r\n stat = statSync(dir);\r\n } catch {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: dir,\r\n detail: `${basename(dir)} unreadable; left in place`,\r\n };\r\n }\r\n if (!stat.isDirectory()) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: dir,\r\n detail: `${basename(dir)} not a directory; left in place`,\r\n };\r\n }\r\n if (this.dirTreeHasFile(dir)) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: dir,\r\n detail: `${basename(dir)} still holds files we did not write; left in place`,\r\n };\r\n }\r\n if (!dryRun) {\r\n try {\r\n // The tree is files-free: only (possibly nested) empty dirs remain, which\r\n // are ours / inert. A recursive remove drops them without touching data.\r\n rmSync(dir, { recursive: true, force: true });\r\n } catch {\r\n // Lost a race or perms — non-fatal; report as a skip.\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: dir,\r\n detail: `${basename(dir)} could not be removed; left in place`,\r\n };\r\n }\r\n }\r\n return { platform: this.id, action: \"remove\", path: dir, detail: basename(dir) };\r\n }\r\n\r\n /**\r\n * Render a YAML-frontmatter + markdown body document:\r\n * \"---\\n\" + <yaml> + \"---\\n\\n\" + <body> + \"\\n\".\r\n * Delegates to the shared renderer (adapters/claude-code/render) so every\r\n * content-file path — adapters AND the plugin packager — emits identical bytes.\r\n */\r\n protected renderFrontmatterMd(\r\n frontmatter: Record<string, unknown>,\r\n body: string,\r\n ): string {\r\n return renderFrontmatterMd(frontmatter, body);\r\n }\r\n\r\n // ── JSON config helpers (used by JSON-format adapters) ───────────────────\r\n\r\n /**\r\n * Read + parse a JSON/JSONC config file, returning null when it is absent OR\r\n * unparseable. Parses TOLERANTLY via parseJsonc (strips // and /* *\\/ comments\r\n * and trailing commas) so a perfectly valid JSONC file never false-fails to\r\n * null — that null is what `?? {}` would otherwise turn into a clobbering\r\n * overwrite of the user's whole config.\r\n */\r\n protected readJson<T = Record<string, unknown>>(path: string): T | null {\r\n if (!existsSync(path)) return null;\r\n try {\r\n return parseJsonc<T>(readFileSync(path, \"utf8\"));\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * True when `path` exists and holds non-whitespace content but readJson cannot\r\n * parse it (even after JSONC stripping). The overwrite guard: writing a\r\n * `{}`-based config over a present-but-broken settings file would silently\r\n * destroy the user's data, so callers warn-and-skip instead.\r\n */\r\n protected isPresentButUnparseable(path: string): boolean {\r\n if (!existsSync(path)) return false;\r\n let raw: string;\r\n try {\r\n if (statSync(path).size === 0) return false;\r\n raw = readFileSync(path, \"utf8\");\r\n } catch {\r\n return false;\r\n }\r\n if (raw.trim() === \"\") return false;\r\n return this.readJson(path) === null;\r\n }\r\n\r\n protected writeJson(path: string, data: unknown, dryRun = false): void {\r\n if (dryRun) return;\r\n const symlink = firstSymlinkInPath(path);\r\n if (symlink !== null) {\r\n throw new Error(`${basename(path)} skipped: symbolic link in path (${symlink})`);\r\n }\r\n ensureDir(dirname(path));\r\n writeFileSync(path, `${JSON.stringify(data, null, 2)}\\n`, \"utf8\");\r\n }\r\n\r\n /**\r\n * True when a PRESENT rootKey value is not a plain object map (the user\r\n * hand-edited it to an array / string / number / boolean). Assigning a server\r\n * entry into such a value would corrupt the file silently (a named property on\r\n * an Array is dropped by JSON.stringify) or throw under strict mode (a property\r\n * write / `in` operator against a primitive), so callers warn-and-skip. A\r\n * `null`/`undefined` value is NOT malformed — it is the well-formed \"absent\"\r\n * case the helpers create fresh.\r\n */\r\n protected isMalformedRootValue(value: unknown): boolean {\r\n return isMalformedRootValueFn(value);\r\n }\r\n\r\n /**\r\n * Warn-skip ChangeRecord when an existing JSON `hooks` config is present-but-\r\n * malformed (root hand-edited to an array/primitive, or an existing event\r\n * bucket is a non-array) — installing a hook into it would silently drop the\r\n * entry (a named property on an Array is dropped by JSON.stringify) or throw\r\n * under strict mode (a `.push`/property write against a primitive or non-array\r\n * bucket). Returns null when the hooks config is well-formed, including the\r\n * absent case the installers create fresh (proceed normally). Mirrors the\r\n * server-root guard (isMalformedRootValue). All targeted hosts use the Claude-\r\n * style `{ Event: Matcher[] }` shape, so every present event bucket must be an\r\n * array; a non-array bucket is the same malformed class as a wrong-typed root.\r\n */\r\n protected malformedHookRootSkip(configPath: string, hooksRoot: unknown): ChangeRecord | null {\r\n if (hooksRoot == null) return null; // absent → installer creates fresh\r\n if (this.isMalformedRootValue(hooksRoot)) {\r\n // array / primitive root\r\n return {\r\n platform: this.id,\r\n action: \"warn\",\r\n path: configPath,\r\n detail: `existing \"hooks\" in ${configPath} is not an object map; left untouched (fix it, then re-run)`,\r\n };\r\n }\r\n for (const v of Object.values(hooksRoot as Record<string, unknown>)) {\r\n if (v !== undefined && !Array.isArray(v)) {\r\n // an existing event bucket is a non-array\r\n return {\r\n platform: this.id,\r\n action: \"warn\",\r\n path: configPath,\r\n detail: `existing \"hooks\" in ${configPath} has a non-array event bucket; left untouched (fix it, then re-run)`,\r\n };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n // ── Shared object-map hook-array merge engine ────────────────────────────\r\n // installHooks/uninstallHooks for every json-stdio host that stores hooks as\r\n // `{ <event>: HookEntry[] }` share ONE create/update/skip + strip/remove\r\n // orchestration. The host supplies a {@link HookMergeDescriptor} carrying\r\n // EVERY observable string and ownership predicate — the engine body hardcodes\r\n // none of them, so per-host wording (skip/remove/absent/no-match details) and\r\n // FLAT-vs-NESTED removal stay host-controlled and never drift to a lowest-\r\n // common-denominator phrasing the suites (which assert by action) would miss.\r\n // The write-gate is the `mutated` bool, matching the migrated host exactly.\r\n\r\n /**\r\n * Install: upsert each `{ event, matcher }` in `pending` into the object-map\r\n * `hooks` root at `configPath`. Reproduces the canonical host's loop: read\r\n * `?? {}`, warn-skip on a malformed `hooks` root, then per pending item render\r\n * the entry, find the owned slot, and create/update/skip. Writes once at the\r\n * end iff anything mutated.\r\n *\r\n * Hosts that fold their `nativeHooks` surface into `pending` (claude-code) pass\r\n * no `native` arg. Hosts that keep the native surface SEPARATE — verbatim\r\n * event keys, EXACT-command ownership, a distinct `(native)` detail — pass it\r\n * as the optional `native` list (cursor); that pass runs after the normalized\r\n * loop and before the single write. Omitting it is byte-identical to before.\r\n */\r\n /**\r\n * Resolve the per-event hook bucket. With \"coerce\" policy a present-but-non-\r\n * array bucket (hand-edited) is replaced by a fresh array; otherwise `??=` is\r\n * used (the warn-skip path already rejected any non-array bucket via\r\n * malformedHookRootSkip, so `??=` only ever fills the absent case).\r\n */\r\n private coerceHookBucket<E>(\r\n hooks: Record<string, E[]>,\r\n event: string,\r\n coerce: boolean,\r\n ): E[] {\r\n if (coerce) {\r\n return Array.isArray(hooks[event]) ? hooks[event] : (hooks[event] = []);\r\n }\r\n return (hooks[event] ??= []);\r\n }\r\n\r\n protected upsertHookEntries<E>(\r\n ctx: InstallContext,\r\n configPath: string,\r\n pending: ReadonlyArray<{ event: string; matcher: string }>,\r\n descriptor: HookMergeDescriptor<E>,\r\n native?: ReadonlyArray<{ event: string; matcher: string }>,\r\n ): ChangeRecord[] {\r\n const symlink = this.symlinkPathWarning(configPath);\r\n if (symlink) return [symlink];\r\n\r\n const file = this.readJson<Record<string, unknown>>(configPath) ?? {};\r\n const coerce = descriptor.malformedPolicy === \"coerce\";\r\n let hooks: Record<string, E[]>;\r\n if (coerce) {\r\n // COERCE policy: a present-but-malformed `hooks` root (array / primitive,\r\n // hand-edited) is replaced by a fresh object map; a well-formed object map\r\n // is kept as-is. Never warn, never throw — matches the container hosts'\r\n // server-path policy.\r\n const existing = file.hooks;\r\n hooks =\r\n existing && typeof existing === \"object\" && !Array.isArray(existing)\r\n ? (existing as Record<string, E[]>)\r\n : ((file.hooks = {}) as Record<string, E[]>);\r\n } else {\r\n const skip = this.malformedHookRootSkip(configPath, file.hooks);\r\n if (skip) return [skip];\r\n hooks = (file.hooks ??= {}) as Record<string, E[]>;\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n let mutated = false;\r\n\r\n for (const { event, matcher } of pending) {\r\n const hostEvent = descriptor.mapEvent ? descriptor.mapEvent(event) : event;\r\n if (hostEvent === undefined) {\r\n changes.push({\r\n platform: this.id,\r\n action: descriptor.unmappedAction ? descriptor.unmappedAction(event) : \"warn\",\r\n path: configPath,\r\n detail: descriptor.unmappedWarnDetail!(event),\r\n });\r\n continue;\r\n }\r\n // Command is built from the CANONICAL `event` (NOT hostEvent) — the home\r\n // binary dispatches on the canonical name; only the host's bucket key,\r\n // detail, and skipDetail use the mapped `hostEvent`.\r\n const command = buildHomeBinHookCommand(\r\n ctx.homeBinPath,\r\n this.id,\r\n event,\r\n ctx.connector.id,\r\n );\r\n const entry = descriptor.renderEntry(hostEvent, matcher, command);\r\n const bucket = this.coerceHookBucket(hooks, hostEvent, coerce);\r\n const r = upsertInArray(bucket, entry, (e) =>\r\n descriptor.entryOwnsCommand(e, command),\r\n );\r\n\r\n if (r.action !== \"skip\") {\r\n hooks[hostEvent] = r.array;\r\n mutated = true;\r\n }\r\n changes.push({\r\n platform: this.id,\r\n action: r.action,\r\n path: configPath,\r\n detail:\r\n r.action === \"skip\"\r\n ? descriptor.skipDetail(hostEvent)\r\n : `hooks.${hostEvent}`,\r\n });\r\n }\r\n\r\n // Native pass (json-stdio hosts with a verbatim `nativeHooks` surface):\r\n // native event-name keys are NOT mapEvent-mapped, are found by EXACT command\r\n // (so a native key coinciding with a normalized event's mapped key adds a\r\n // SECOND distinct command rather than clobbering it), and carry the `(native)`\r\n // detail. Hosts passing no `native` list skip this loop entirely → the\r\n // normalized-only behavior is byte-identical.\r\n for (const { event, matcher } of native ?? []) {\r\n const command = buildHomeBinHookCommand(\r\n ctx.homeBinPath,\r\n this.id,\r\n event,\r\n ctx.connector.id,\r\n );\r\n const entry = descriptor.renderEntry(event, matcher, command);\r\n const bucket = this.coerceHookBucket(hooks, event, coerce);\r\n const r = upsertInArray(bucket, entry, (e) =>\r\n descriptor.nativeOwnsCommand!(e, command),\r\n );\r\n if (r.action !== \"skip\") {\r\n hooks[event] = r.array;\r\n mutated = true;\r\n }\r\n changes.push({\r\n platform: this.id,\r\n action: r.action,\r\n path: configPath,\r\n detail:\r\n r.action === \"skip\"\r\n ? descriptor.nativeSkipDetail!(event)\r\n : descriptor.nativeMutateDetail!(event),\r\n });\r\n }\r\n\r\n if (mutated) {\r\n descriptor.onMutate?.(file);\r\n this.writeJson(configPath, file, ctx.dryRun);\r\n }\r\n return changes;\r\n }\r\n\r\n /**\r\n * Uninstall: strip owned content from every event bucket in the object-map\r\n * `hooks` root at `configPath`. NESTED hosts pass `descriptor.stripInner`\r\n * (strip owned inner commands, drop emptied entries; `removed` = inner\r\n * commands); FLAT hosts omit it (drop whole owned entries). Reproduces the\r\n * canonical host: read (NO `?? {}`), `[skip]` (absentDetail) when no hooks\r\n * section, per-event remove → delete-or-replace bucket, write once iff\r\n * mutated, and a single `[skip]` (noMatchDetail) when nothing matched.\r\n */\r\n protected removeHookEntries<E>(\r\n ctx: InstallContext,\r\n configPath: string,\r\n descriptor: HookMergeDescriptor<E>,\r\n ): ChangeRecord[] {\r\n const symlink = this.symlinkPathWarning(configPath);\r\n if (symlink) return [symlink];\r\n\r\n const file = this.readJson<Record<string, unknown>>(configPath);\r\n const hooks = file?.hooks as Record<string, E[]> | undefined;\r\n if (!file || !hooks) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: descriptor.absentDetail,\r\n },\r\n ];\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n let mutated = false;\r\n // stripInner is event-independent for current hosts → computed once. The\r\n // whole-entry ownership predicate is rebuilt PER EVENT so EVENT-SPECIFIC\r\n // hosts (codex) can match the canonical event being stripped; event-agnostic\r\n // hosts simply ignore the param.\r\n const stripInner = descriptor.stripInner?.(ctx);\r\n\r\n // Default: scan every present key. EVENT-SPECIFIC hosts pin a fixed event set\r\n // (descriptor.removeEventKeys) so a foreign-key bucket is never inspected —\r\n // matching their original fixed-event-list uninstall loop byte-for-byte.\r\n for (const event of descriptor.removeEventKeys ?? Object.keys(hooks)) {\r\n const bucket = hooks[event];\r\n if (!Array.isArray(bucket)) continue;\r\n\r\n const ownsEntry = descriptor.ownsEntryForRemove(ctx, event);\r\n const r = removeFromArray(bucket, ownsEntry, stripInner);\r\n if (r.removed > 0) {\r\n if (r.array.length > 0) hooks[event] = r.array;\r\n else delete hooks[event];\r\n changes.push({\r\n platform: this.id,\r\n action: \"remove\",\r\n path: configPath,\r\n detail: descriptor.removeDetail(event, r.removed),\r\n });\r\n mutated = true;\r\n }\r\n }\r\n\r\n if (mutated) this.writeJson(configPath, file, ctx.dryRun);\r\n if (changes.length === 0) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: descriptor.noMatchDetail,\r\n });\r\n }\r\n return changes;\r\n }\r\n\r\n /** Bind BaseAdapter's JSON leaf IO (readJson/writeJson + the unparseable\r\n * overwrite guard) as a Codec for the object-map engine. */\r\n private jsonObjectMapCodec(): ObjectMapCodec {\r\n return {\r\n parse: (path) => this.readJson<Record<string, unknown>>(path),\r\n serialize: (path, data, dryRun) => this.writeJson(path, data, dryRun),\r\n isPresentButUnparseable: (path) => this.isPresentButUnparseable(path),\r\n };\r\n }\r\n\r\n /**\r\n * Upsert `entry` at `config[rootKey][serverId]` in a JSON file, creating the\r\n * file/object as needed. Returns a ChangeRecord describing create/update/skip.\r\n * Idempotent: an identical entry yields \"skip\".\r\n */\r\n protected upsertServerInJson(\r\n configPath: string,\r\n rootKey: string,\r\n serverId: string,\r\n entry: unknown,\r\n dryRun = false,\r\n ): ChangeRecord {\r\n const symlink = this.symlinkPathWarning(configPath);\r\n if (symlink) return symlink;\r\n\r\n return upsertInObjectMap({\r\n codec: this.jsonObjectMapCodec(),\r\n rootKey,\r\n platform: this.id,\r\n configPath,\r\n entryId: serverId,\r\n entry,\r\n dryRun,\r\n });\r\n }\r\n\r\n /** Remove `config[rootKey][serverId]` from a JSON file. */\r\n protected removeServerFromJson(\r\n configPath: string,\r\n rootKey: string,\r\n serverId: string,\r\n dryRun = false,\r\n ): ChangeRecord {\r\n const symlink = this.symlinkPathWarning(configPath);\r\n if (symlink) return symlink;\r\n\r\n return removeFromObjectMap({\r\n codec: this.jsonObjectMapCodec(),\r\n rootKey,\r\n platform: this.id,\r\n configPath,\r\n entryId: serverId,\r\n dryRun,\r\n });\r\n }\r\n\r\n // ── Backup ───────────────────────────────────────────────────────────────\r\n\r\n backupSettings(ctx: InstallContext): string | null {\r\n const files = [...new Set([this.getServerConfigPath(ctx), this.getHookConfigPath(ctx)])].filter(\r\n (f) => {\r\n if (!existsSync(f)) return false;\r\n try {\r\n return statSync(f).isFile();\r\n } catch {\r\n return false;\r\n }\r\n },\r\n );\r\n if (files.length === 0) return null;\r\n if (ctx.dryRun) return null;\r\n ensureDir(backupsDir());\r\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\r\n let last: string | null = null;\r\n for (const f of files) {\r\n const dest = join(backupsDir(), `${this.id}-${stamp}-${basename(f)}`);\r\n copyFileSync(f, dest);\r\n last = dest;\r\n }\r\n return last;\r\n }\r\n\r\n // ── Diagnostics ─────────────────────────────────────────────────────────\r\n\r\n getHealthChecks?(ctx: InstallContext): readonly HealthCheck[];\r\n\r\n doctor(ctx: InstallContext): DiagnosticResult[] {\r\n const results: DiagnosticResult[] = [];\r\n const cfg = this.getServerConfigPath(ctx);\r\n results.push(\r\n existsSync(cfg)\r\n ? { check: `${this.name}: config present`, status: \"pass\", message: cfg }\r\n : {\r\n check: `${this.name}: config present`,\r\n status: \"warn\",\r\n message: `not found: ${cfg}`,\r\n fix: `agent-connector install --targets ${this.id}`,\r\n // Only sync-recoverable when the connector actually declares a\r\n // server — a re-sync writes the config file only then. For a\r\n // serverless (memory/configPatch-only) connector the file is never\r\n // created, so marking it fixable would loop it into \"still failing\".\r\n fixable: !!ctx.connector.server,\r\n },\r\n );\r\n for (const hc of this.getHealthChecks?.(ctx) ?? []) {\r\n const r = hc.check();\r\n results.push({\r\n check: hc.name,\r\n status: r.status === \"OK\" ? \"pass\" : \"fail\",\r\n message: r.detail ?? r.status,\r\n });\r\n }\r\n // Memory-surface checks are ledger-driven: no installed memory → no rows →\r\n // no noise. Shared by every adapter (the overrides call super.doctor()).\r\n results.push(...this.memoryDiagnostics(ctx));\r\n return results;\r\n }\r\n}\r\n","/** Decision for one inner-array upsert. */\r\nexport type ArrayUpsertAction = \"create\" | \"update\" | \"skip\";\r\n\r\nexport interface ArrayUpsertResult<E> {\r\n array: E[];\r\n action: ArrayUpsertAction;\r\n}\r\n\r\n/**\r\n * Upsert one rendered `candidate` into a per-event hook array.\r\n * - find the FIRST entry the caller OWNS via `ownsEntry`;\r\n * - hit + JSON-equal → skip (array returned unchanged);\r\n * - hit + differs → update (replace that slot);\r\n * - miss → create (push).\r\n */\r\nexport function upsertInArray<E>(\r\n array: E[],\r\n candidate: E,\r\n ownsEntry: (entry: E) => boolean,\r\n): ArrayUpsertResult<E> {\r\n const idx = array.findIndex(ownsEntry);\r\n if (idx >= 0) {\r\n if (JSON.stringify(array[idx]) === JSON.stringify(candidate)) {\r\n return { array, action: \"skip\" };\r\n }\r\n const next = array.slice();\r\n next[idx] = candidate;\r\n return { array: next, action: \"update\" };\r\n }\r\n return { array: [...array, candidate], action: \"create\" };\r\n}\r\n\r\nexport interface ArrayRemoveResult<E> {\r\n array: E[];\r\n removed: number;\r\n}\r\n\r\n/**\r\n * Remove owned content from a per-event hook array.\r\n * - FLAT hosts: omit `stripInner` → drop whole entries matching `ownsEntry`;\r\n * `removed` = whole entries dropped.\r\n * - NESTED hosts: pass `stripInner` → strip owned inner commands and rebuild,\r\n * dropping entries left empty; `removed` = inner commands removed.\r\n */\r\nexport function removeFromArray<E>(\r\n array: E[],\r\n ownsEntry: (entry: E) => boolean,\r\n stripInner?: (entry: E) => { next: E | null; removed: number },\r\n): ArrayRemoveResult<E> {\r\n if (!stripInner) {\r\n const kept = array.filter((e) => !ownsEntry(e));\r\n return { array: kept, removed: array.length - kept.length };\r\n }\r\n const kept: E[] = [];\r\n let removed = 0;\r\n for (const e of array) {\r\n const r = stripInner(e);\r\n removed += r.removed;\r\n if (r.next !== null) kept.push(r.next);\r\n }\r\n return { array: kept, removed };\r\n}\r\n"],"mappings":"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","names":["kept"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/antigravity-shared.ts"],"sourcesContent":["/**\r\n * usage/readers/antigravity-shared — logic shared by the Antigravity IDE\r\n * (`antigravity`) and Antigravity CLI (`antigravity-cli`) native usage readers.\r\n *\r\n * Both surfaces persist per-conversation transcripts as `transcript*.jsonl`\r\n * under a `brain/` subtree of their global dir. Each assistant turn embeds a\r\n * Gemini-style `usage_metadata` block (camelCase, same field names the Gemini\r\n * API returns):\r\n * promptTokenCount → input (cache-INCLUSIVE, like the Gemini API)\r\n * candidatesTokenCount → output\r\n * cachedContentTokenCount → cacheRead (the cached portion already inside prompt)\r\n * thoughtsTokenCount → reasoning\r\n * cacheWrite is not reported by Gemini → always 0.\r\n *\r\n * Because promptTokenCount is cache-inclusive, net input = prompt - cached\r\n * (clamped ≥ 0), mirroring the gemini-cli reader's subtract_cached_overlap.\r\n *\r\n * Confidence is MEDIUM on the native JSONL shape (Antigravity is fast-moving and\r\n * its docs are JS-rendered): the field names above are the documented/observed\r\n * shape but versions may differ, so extraction is BEST-EFFORT and every caller\r\n * fails open to [] when the store is absent or a row does not match. We also\r\n * tolerate the snake_case spellings as a secondary alias set.\r\n *\r\n * The model-alias table is shared with — and kept in sync with — the tokscale\r\n * pricing::aliases::resolve_alias port (sessions/antigravity.rs).\r\n */\r\n\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { inferProvider } from \"../normalize.js\";\r\nimport type { PlatformId } from \"../../core/types.js\";\r\nimport type { UsageRecord } from \"../types.js\";\r\n\r\nconst DEFAULT_MODEL = \"unknown\";\r\nconst DEFAULT_PROVIDER = \"antigravity\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Model alias table (port of tokscale pricing::aliases::resolve_alias).\r\n// Keys are lowercased; lookup lowercases the input. Resolves placeholder /\r\n// reseller model ids (e.g. Antigravity's MODEL_PLACEHOLDER_*) to canonical ids.\r\n// Shared by both Antigravity readers.\r\n// ─────────────────────────────────────────────────────────────────────────\r\nexport const MODEL_ALIASES: ReadonlyMap<string, string> = new Map([\r\n [\"big-pickle\", \"glm-4.7\"],\r\n [\"big pickle\", \"glm-4.7\"],\r\n [\"bigpickle\", \"glm-4.7\"],\r\n [\"k2p5\", \"kimi-k2-thinking\"],\r\n [\"k2-p5\", \"kimi-k2-thinking\"],\r\n [\"k2p6\", \"kimi-k2.6\"],\r\n [\"k2-p6\", \"kimi-k2.6\"],\r\n [\"kimi-k2p6\", \"kimi-k2.6\"],\r\n [\"kimi-k2.5-thinking\", \"kimi-k2-thinking\"],\r\n [\"kimi-for-coding\", \"kimi-k2.5\"],\r\n [\"model_placeholder_m26\", \"claude-opus-4-6\"],\r\n [\"model_placeholder_m35\", \"claude-sonnet-4-6\"],\r\n [\"model_placeholder_m36\", \"gemini-3.1-pro\"],\r\n [\"model_placeholder_m37\", \"gemini-3.1-pro\"],\r\n [\"model_placeholder_m47\", \"gemini-3-flash-preview\"],\r\n [\"model_openai_gpt_oss_120b_medium\", \"gpt-oss-120b-medium\"],\r\n [\"claude-opus-4-6-thinking\", \"claude-opus-4-6\"],\r\n [\"claude-sonnet-4-6-thinking\", \"claude-sonnet-4-6\"],\r\n [\"claude-opus-4.6-thinking\", \"claude-opus-4-6\"],\r\n [\"claude-sonnet-4.6-thinking\", \"claude-sonnet-4-6\"],\r\n [\"claude-opus-4-6\", \"claude-opus-4-6\"],\r\n [\"claude-sonnet-4-6\", \"claude-sonnet-4-6\"],\r\n [\"claude-haiku-4-6\", \"claude-haiku-4-6\"],\r\n [\"claude-opus-4.6\", \"claude-opus-4-6\"],\r\n [\"claude-sonnet-4.6\", \"claude-sonnet-4-6\"],\r\n [\"claude-haiku-4.6\", \"claude-haiku-4-6\"],\r\n [\"anthropic/claude-4-5-opus\", \"claude-opus-4-5\"],\r\n [\"anthropic/claude-4-5-sonnet\", \"claude-sonnet-4-5\"],\r\n [\"anthropic/claude-4-5-haiku\", \"claude-haiku-4-5\"],\r\n [\"anthropic/claude-4-6-opus\", \"claude-opus-4-6\"],\r\n [\"anthropic/claude-4-6-sonnet\", \"claude-sonnet-4-6\"],\r\n [\"anthropic/claude-4-6-haiku\", \"claude-haiku-4-6\"],\r\n [\"gemini-3.1-pro-high\", \"gemini-3.1-pro\"],\r\n [\"gemini-3.1-pro-low\", \"gemini-3.1-pro\"],\r\n [\"gemini-3-pro-high\", \"gemini-3-pro\"],\r\n [\"gemini-3-pro-low\", \"gemini-3-pro\"],\r\n [\"gemini-3-flash\", \"gemini-3-flash-preview\"],\r\n [\"gemini-3-flash-c\", \"gemini-3-flash-preview\"],\r\n [\"kimi-k2.5-nvfp4\", \"kimi-k2.5\"],\r\n [\"kimi-k2-instruct-0905\", \"kimi-k2.5\"],\r\n]);\r\n\r\n/** Resolve a model alias to its canonical id, or undefined when none matches. */\r\nexport function resolveAlias(modelId: string): string | undefined {\r\n return MODEL_ALIASES.get(modelId.toLowerCase());\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Scalar coercion (shared with the tokscale to_safe_i64 contract)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Coerce an unknown to a non-negative i64-safe integer (port of to_safe_i64):\r\n * accepts number or numeric string, floors toward zero, clamps at 0; 0 otherwise.\r\n */\r\nexport function toSafeInt(v: unknown): number {\r\n const n =\r\n typeof v === \"number\"\r\n ? v\r\n : typeof v === \"string\"\r\n ? Number(v.trim())\r\n : NaN;\r\n if (!Number.isFinite(n)) return 0;\r\n return Math.max(0, Math.trunc(n));\r\n}\r\n\r\n/** A non-empty trimmed string, or undefined (port of the `.filter(!is_empty)` guards). */\r\nexport function nonEmptyStr(v: unknown): string | undefined {\r\n if (typeof v !== \"string\") return undefined;\r\n return v.trim() === \"\" ? undefined : v;\r\n}\r\n\r\n/** First key whose value coerces to a positive-or-zero integer (ignoring absent/zero). */\r\nfunction firstInt(obj: Record<string, unknown>, keys: readonly string[]): number {\r\n for (const k of keys) {\r\n const v = obj[k];\r\n if (v === undefined || v === null) continue;\r\n const n = toSafeInt(v);\r\n if (n > 0) return n;\r\n }\r\n return 0;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Native-transcript usage_metadata extraction (best-effort, MEDIUM confidence)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The camelCase Gemini field names + snake_case secondary aliases. */\r\nconst PROMPT_KEYS = [\"promptTokenCount\", \"prompt_token_count\"] as const;\r\nconst CANDIDATES_KEYS = [\"candidatesTokenCount\", \"candidates_token_count\"] as const;\r\nconst CACHED_KEYS = [\"cachedContentTokenCount\", \"cached_content_token_count\"] as const;\r\nconst THOUGHTS_KEYS = [\"thoughtsTokenCount\", \"thoughts_token_count\"] as const;\r\n\r\n/** A `usage_metadata` object pulled off a transcript row (any spelling). */\r\nfunction findUsageMetadata(row: Record<string, unknown>): Record<string, unknown> | undefined {\r\n for (const k of [\"usage_metadata\", \"usageMetadata\"]) {\r\n const v = row[k];\r\n if (typeof v === \"object\" && v !== null && !Array.isArray(v)) {\r\n return v as Record<string, unknown>;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\n/** Pull a model id off a transcript row, tolerant of common spellings. */\r\nfunction findModelId(row: Record<string, unknown>): string | undefined {\r\n return (\r\n nonEmptyStr(row.modelId) ??\r\n nonEmptyStr(row.model) ??\r\n nonEmptyStr(row.model_id) ??\r\n nonEmptyStr(row.modelName) ??\r\n nonEmptyStr(row.model_name)\r\n );\r\n}\r\n\r\n/** Pull a session/conversation id off a row, tolerant of common spellings. */\r\nfunction findSessionId(row: Record<string, unknown>): string | undefined {\r\n return (\r\n nonEmptyStr(row.sessionId) ??\r\n nonEmptyStr(row.session_id) ??\r\n nonEmptyStr(row.conversationId) ??\r\n nonEmptyStr(row.conversation_id)\r\n );\r\n}\r\n\r\n/** Options carried per-file so a transcript with no per-row model/session can borrow them. */\r\nexport interface UsageMetadataContext {\r\n /** Platform attribution for emitted records. */\r\n platformId: PlatformId;\r\n /** Session id to attribute rows to when the row itself carries none. */\r\n fallbackSessionId: string;\r\n /** Per-conversation model fallback (e.g. from a session_meta row), if known. */\r\n fallbackModel?: string;\r\n /** Timestamp (epoch ms) to use when the row carries none — never drops a row for it. */\r\n fallbackTs: number;\r\n}\r\n\r\n/**\r\n * Best-effort parse of one native brain-transcript JSONL row into a usage record,\r\n * or undefined when the row has no `usage_metadata` / no tokens. Mirrors the\r\n * gemini-cli cache-inclusive normalization: net input = prompt - cached (≥ 0).\r\n *\r\n * Fail-soft: any shape that does not match yields undefined (the caller skips it).\r\n */\r\nexport function parseUsageMetadataRow(\r\n row: unknown,\r\n ctx: UsageMetadataContext,\r\n): UsageRecord | undefined {\r\n if (typeof row !== \"object\" || row === null || Array.isArray(row)) return undefined;\r\n const obj = row as Record<string, unknown>;\r\n\r\n const meta = findUsageMetadata(obj);\r\n if (meta === undefined) return undefined;\r\n\r\n const promptTokens = firstInt(meta, PROMPT_KEYS);\r\n const output = firstInt(meta, CANDIDATES_KEYS);\r\n const cacheRead = firstInt(meta, CACHED_KEYS);\r\n const reasoning = firstInt(meta, THOUGHTS_KEYS);\r\n\r\n // promptTokenCount is cache-inclusive → net input = prompt - cached (≥ 0).\r\n const input = Math.max(0, promptTokens - Math.min(cacheRead, promptTokens));\r\n\r\n if (input === 0 && output === 0 && cacheRead === 0 && reasoning === 0) return undefined;\r\n\r\n const rawModel = findModelId(obj) ?? ctx.fallbackModel ?? DEFAULT_MODEL;\r\n const modelId = resolveAlias(rawModel) ?? rawModel;\r\n const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;\r\n\r\n const sessionId = findSessionId(obj) ?? ctx.fallbackSessionId;\r\n\r\n const ts = parseRowTimestamp(obj) ?? ctx.fallbackTs;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = 0;\r\n tokens.reasoning = reasoning;\r\n\r\n const record: UsageRecord = {\r\n platformId: ctx.platformId,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n confidence: \"host-reported\",\r\n };\r\n\r\n const dedupKey = nonEmptyStr(obj.responseId) ?? nonEmptyStr(obj.response_id) ?? nonEmptyStr(obj.id);\r\n if (dedupKey !== undefined) record.dedupKey = `${sessionId}:${dedupKey}`;\r\n\r\n return record;\r\n}\r\n\r\n/** Parse a per-row timestamp (epoch ms / s, or RFC3339 string), else undefined. */\r\nfunction parseRowTimestamp(obj: Record<string, unknown>): number | undefined {\r\n const v = obj.timestamp ?? obj.ts ?? obj.created_at ?? obj.createdAt;\r\n if (typeof v === \"number\" && Number.isFinite(v)) {\r\n const n = Math.trunc(v);\r\n if (n <= 0) return undefined;\r\n return n >= 1_000_000_000_000 ? n : n * 1000;\r\n }\r\n if (typeof v === \"string\") {\r\n const ms = Date.parse(v);\r\n if (!Number.isNaN(ms)) return ms;\r\n const numeric = Number(v.trim());\r\n if (Number.isInteger(numeric) && numeric > 0) {\r\n return numeric >= 1_000_000_000_000 ? numeric : numeric * 1000;\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\n/** A per-conversation model fallback off a `session_meta` row, else undefined. */\r\nexport function sessionMetaModel(row: unknown): string | undefined {\r\n if (typeof row !== \"object\" || row === null || Array.isArray(row)) return undefined;\r\n const obj = row as Record<string, unknown>;\r\n const rowType = nonEmptyStr(obj.type);\r\n if (rowType !== \"session_meta\") return undefined;\r\n return findModelId(obj);\r\n}\r\n"],"mappings":";;;AAyCO,IAAM,gBAA6C,oBAAI,IAAI;AAAA,EAChE,CAAC,cAAc,SAAS;AAAA,EACxB,CAAC,cAAc,SAAS;AAAA,EACxB,CAAC,aAAa,SAAS;AAAA,EACvB,CAAC,QAAQ,kBAAkB;AAAA,EAC3B,CAAC,SAAS,kBAAkB;AAAA,EAC5B,CAAC,QAAQ,WAAW;AAAA,EACpB,CAAC,SAAS,WAAW;AAAA,EACrB,CAAC,aAAa,WAAW;AAAA,EACzB,CAAC,sBAAsB,kBAAkB;AAAA,EACzC,CAAC,mBAAmB,WAAW;AAAA,EAC/B,CAAC,yBAAyB,iBAAiB;AAAA,EAC3C,CAAC,yBAAyB,mBAAmB;AAAA,EAC7C,CAAC,yBAAyB,gBAAgB;AAAA,EAC1C,CAAC,yBAAyB,gBAAgB;AAAA,EAC1C,CAAC,yBAAyB,wBAAwB;AAAA,EAClD,CAAC,oCAAoC,qBAAqB;AAAA,EAC1D,CAAC,4BAA4B,iBAAiB;AAAA,EAC9C,CAAC,8BAA8B,mBAAmB;AAAA,EAClD,CAAC,4BAA4B,iBAAiB;AAAA,EAC9C,CAAC,8BAA8B,mBAAmB;AAAA,EAClD,CAAC,mBAAmB,iBAAiB;AAAA,EACrC,CAAC,qBAAqB,mBAAmB;AAAA,EACzC,CAAC,oBAAoB,kBAAkB;AAAA,EACvC,CAAC,mBAAmB,iBAAiB;AAAA,EACrC,CAAC,qBAAqB,mBAAmB;AAAA,EACzC,CAAC,oBAAoB,kBAAkB;AAAA,EACvC,CAAC,6BAA6B,iBAAiB;AAAA,EAC/C,CAAC,+BAA+B,mBAAmB;AAAA,EACnD,CAAC,8BAA8B,kBAAkB;AAAA,EACjD,CAAC,6BAA6B,iBAAiB;AAAA,EAC/C,CAAC,+BAA+B,mBAAmB;AAAA,EACnD,CAAC,8BAA8B,kBAAkB;AAAA,EACjD,CAAC,uBAAuB,gBAAgB;AAAA,EACxC,CAAC,sBAAsB,gBAAgB;AAAA,EACvC,CAAC,qBAAqB,cAAc;AAAA,EACpC,CAAC,oBAAoB,cAAc;AAAA,EACnC,CAAC,kBAAkB,wBAAwB;AAAA,EAC3C,CAAC,oBAAoB,wBAAwB;AAAA,EAC7C,CAAC,mBAAmB,WAAW;AAAA,EAC/B,CAAC,yBAAyB,WAAW;AACvC,CAAC;AAGM,SAAS,aAAa,SAAqC;AAChE,SAAO,cAAc,IAAI,QAAQ,YAAY,CAAC;AAChD;AAUO,SAAS,UAAU,GAAoB;AAC5C,QAAM,IACJ,OAAO,MAAM,WACT,IACA,OAAO,MAAM,WACX,OAAO,EAAE,KAAK,CAAC,IACf;AACR,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC;AAClC;AAGO,SAAS,YAAY,GAAgC;AAC1D,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,SAAO,EAAE,KAAK,MAAM,KAAK,SAAY;AACvC;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
isNonDefaultDataRoot
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QYOUQCC6.js";
|
|
5
5
|
|
|
6
6
|
// src/core/spawn.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -158,4 +158,4 @@ export {
|
|
|
158
158
|
resolveSpawnCommand,
|
|
159
159
|
detectLaunchMethod
|
|
160
160
|
};
|
|
161
|
-
//# sourceMappingURL=chunk-
|
|
161
|
+
//# sourceMappingURL=chunk-W7AGWAMH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/spawn.ts"],"sourcesContent":["/**\r\n * core/spawn — cross-platform command construction.\r\n *\r\n * Borrowed from context-mode (issues #369/#372/#548/#738): bare `node` is\r\n * unreliable on Windows Git Bash (MSYS) and MSYS rewrites absolute paths on\r\n * non-C: drives. Always use the resolved runtime path, forward slashes, and\r\n * double-quoting. No-ops on macOS/Linux.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\n\r\nimport { isNonDefaultDataRoot } from \"./paths.js\";\r\nimport type { InstallScope, PlatformId, ServerDef } from \"./types.js\";\r\nimport type { InstallContext } from \"../adapters/spi.js\";\r\nimport type {\r\n LaunchMethod,\r\n TelemetryInstallScope,\r\n} from \"../telemetry/types.js\";\r\n\r\n/**\r\n * Narrow the framework's 5-value {@link InstallScope} down to the two telemetry\r\n * slicing buckets: only a `project`-local install is `project`; everything else\r\n * (system/user/profile/managed) is global and reads as `user`.\r\n */\r\nexport function narrowInstallScope(scope: InstallScope): TelemetryInstallScope {\r\n return scope === \"project\" ? \"project\" : \"user\";\r\n}\r\n\r\n/** Build `\"<nodePath>\" \"<scriptPath>\"`. */\r\nexport function buildNodeCommand(\r\n scriptPath: string,\r\n opts?: { nodePath?: string },\r\n): string {\r\n const nodePath = (opts?.nodePath ?? process.execPath).replace(/\\\\/g, \"/\");\r\n const safe = scriptPath.replace(/\\\\/g, \"/\");\r\n return `\"${nodePath}\" \"${safe}\"`;\r\n}\r\n\r\n/**\r\n * Strict inverse of buildNodeCommand. Returns the two quoted tokens, or null if\r\n * `cmd` was not produced by buildNodeCommand (no fragile last-whitespace tail\r\n * grabbing — that was the #548 doubled-path bug when paths contained spaces).\r\n */\r\nexport function parseNodeCommand(\r\n cmd: string,\r\n): { nodePath: string; scriptPath: string } | null {\r\n if (typeof cmd !== \"string\" || cmd.length === 0) return null;\r\n const m = cmd.match(/^\"([^\"]+)\"\\s+\"([^\"]+)\"\\s*$/);\r\n if (!m || !m[1] || !m[2]) return null;\r\n return { nodePath: m[1], scriptPath: m[2] };\r\n}\r\n\r\n/** Quote a single argument for inclusion in a host hook command string. */\r\nexport function quoteArg(arg: string): string {\r\n return `\"${arg.replace(/\\\\/g, \"/\")}\"`;\r\n}\r\n\r\n/**\r\n * True when `hay` (slash-normalized) has the quoted home-bin path IMMEDIATELY\r\n * followed by `verb` — i.e. the verb sits in its command SLOT (right after the\r\n * home binary), not merely somewhere in the argument list. This distinguishes\r\n * `\"<bin>\" statusline …` from `\"<bin>\" action … statusline …`: the action verb\r\n * takes a free-form `actionId` positional that can legitimately equal another\r\n * verb's name (`statusline` / `usage-event` / `hook`), and only the SLOT\r\n * position identifies the real verb. `homeBinNorm` is the slash-normalized\r\n * home-bin path the caller already derived.\r\n */\r\nfunction hasVerbSlot(hay: string, homeBinNorm: string, verb: string): boolean {\r\n return hay.includes(`\"${homeBinNorm}\" ${verb} `);\r\n}\r\n\r\n/**\r\n * Build the universal hook command a host config points at:\r\n * \"<homeBin>\" hook <platformId> <event> --connector <id>\r\n * Pointing every host at the one stable home binary is how a single update\r\n * propagates everywhere (docs/ARCHITECTURE.md §3 R1).\r\n */\r\nexport function buildHomeBinHookCommand(\r\n homeBinPath: string,\r\n platformId: string,\r\n event: string,\r\n connectorId: string,\r\n): string {\r\n return `${quoteArg(homeBinPath)} hook ${platformId} ${event} --connector ${connectorId}`;\r\n}\r\n\r\n/**\r\n * True when `command` is a home-bin hook command for exactly `connectorId`.\r\n *\r\n * Critical: the connector id is the LAST token of the hook command\r\n * (`... --connector <id>`), so a naive `command.includes(\"--connector \" + id)`\r\n * collides on shared-prefix ids — `--connector acme-db` contains\r\n * `--connector acme`, which would let uninstalling `acme` strip `acme-db`'s\r\n * hooks. We anchor the id token: the character after it must be end-of-string,\r\n * whitespace, or a closing double-quote (the JSON-embedded case). Connector ids\r\n * are kebab-case (ID_RE) so they never contain whitespace or quotes themselves.\r\n */\r\nexport function isHomeBinHookCommand(\r\n command: string | undefined,\r\n homeBinPath: string,\r\n connectorId: string,\r\n): boolean {\r\n if (!command) return false;\r\n // The stored command was forward-slashed by quoteArg(); homeBinPath() yields\r\n // NATIVE (back)slashes on Windows (node:path join). Normalize BOTH sides so the\r\n // ownership substring test holds on win32 (without this, detection always\r\n // returns false there → duplicate hooks on re-install + orphans on uninstall).\r\n // No-op on POSIX.\r\n const hay = command.replace(/\\\\/g, \"/\");\r\n if (!hay.includes(homeBinPath.replace(/\\\\/g, \"/\"))) return false;\r\n const token = `--connector ${connectorId}`;\r\n let from = 0;\r\n for (;;) {\r\n const idx = hay.indexOf(token, from);\r\n if (idx < 0) return false;\r\n const after = hay.charAt(idx + token.length);\r\n if (after === \"\" || after === '\"' || /\\s/.test(after)) return true;\r\n from = idx + token.length;\r\n }\r\n}\r\n\r\n/**\r\n * Build the OPT-IN host-native usage-event command an AfterModel / PostInvocation\r\n * hook points at:\r\n * \"<homeBin>\" usage-event <platformId> --connector <id>\r\n * Mirrors {@link buildHomeBinHookCommand} (same anchoring rules apply) but routes\r\n * to the hidden `usage-event` entrypoint, which records a DISTINCT `model_turn`\r\n * row instead of dispatching a connector handler.\r\n */\r\nexport function buildUsageEventCommand(\r\n homeBinPath: string,\r\n platformId: string,\r\n connectorId: string,\r\n): string {\r\n return `${quoteArg(homeBinPath)} usage-event ${platformId} --connector ${connectorId}`;\r\n}\r\n\r\n/**\r\n * True when `command` is OUR host-native usage-event command for exactly\r\n * `connectorId`. Same end-of-token anchoring as {@link isHomeBinHookCommand} so a\r\n * shared-prefix id can't collide; additionally requires the ` usage-event ` verb\r\n * so it is never confused with a plain `hook` command during uninstall.\r\n */\r\nexport function isUsageEventCommand(\r\n command: string | undefined,\r\n homeBinPath: string,\r\n connectorId: string,\r\n): boolean {\r\n if (!command) return false;\r\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\r\n const hay = command.replace(/\\\\/g, \"/\");\r\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\r\n if (!hay.includes(homeBinNorm)) return false;\r\n if (!hasVerbSlot(hay, homeBinNorm, \"usage-event\")) return false;\r\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\r\n}\r\n\r\n/**\r\n * Build the home-bin statusline command a host's status line config points at:\r\n * \"<homeBin>\" statusline <platformId> --connector <id>\r\n * Mirrors {@link buildHomeBinHookCommand} / {@link buildUsageEventCommand} (the\r\n * same single-home-binary indirection) but routes to the `statusline`\r\n * entrypoint, which renders the connector's HUD line for the host.\r\n */\r\nexport function buildHomeBinStatuslineCommand(\r\n homeBinPath: string,\r\n platformId: string,\r\n connectorId: string,\r\n): string {\r\n return `${quoteArg(homeBinPath)} statusline ${platformId} --connector ${connectorId}`;\r\n}\r\n\r\n/**\r\n * True when `command` is OUR home-bin statusline command for exactly\r\n * `connectorId`. Same end-of-token anchoring as {@link isHomeBinHookCommand} so a\r\n * shared-prefix id can't collide; additionally requires the ` statusline ` verb\r\n * so it is never confused with a plain `hook` / `usage-event` command.\r\n */\r\nexport function isHomeBinStatuslineCommand(\r\n command: string | undefined,\r\n homeBinPath: string,\r\n connectorId: string,\r\n): boolean {\r\n if (!command) return false;\r\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\r\n const hay = command.replace(/\\\\/g, \"/\");\r\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\r\n if (!hay.includes(homeBinNorm)) return false;\r\n if (!hasVerbSlot(hay, homeBinNorm, \"statusline\")) return false;\r\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\r\n}\r\n\r\n/**\r\n * Build the home-bin action command a host affordance (workflow, task, slash\n * command, keybinding) points at:\n * \"<homeBin>\" action <platformId> <actionId> --connector <id>\r\n * Mirrors {@link buildHomeBinStatuslineCommand} (the same single-home-binary\r\n * indirection) but routes to the `action` entrypoint, which re-imports the\r\n * connector and runs the named action's run(ctx). Adapters with a verified\n * native trigger surface emit this command into that surface; other hosts can\n * still use the same command manually.\n */\nexport function buildHomeBinActionCommand(\r\n homeBinPath: string,\r\n platformId: string,\r\n actionId: string,\r\n connectorId: string,\r\n): string {\r\n return `${quoteArg(homeBinPath)} action ${platformId} ${actionId} --connector ${connectorId}`;\r\n}\r\n\r\n/**\r\n * True when `command` is OUR home-bin action command for exactly `connectorId`.\r\n * Same end-of-token anchoring as {@link isHomeBinHookCommand} so a shared-prefix\r\n * id can't collide; additionally requires the ` action ` verb so it is never\r\n * confused with a plain `hook` / `usage-event` / `statusline` command.\r\n */\r\nexport function isHomeBinActionCommand(\r\n command: string | undefined,\r\n homeBinPath: string,\r\n connectorId: string,\r\n): boolean {\r\n if (!command) return false;\r\n // Normalize separators like isHomeBinHookCommand (win32 ownership detection).\r\n const hay = command.replace(/\\\\/g, \"/\");\r\n const homeBinNorm = homeBinPath.replace(/\\\\/g, \"/\");\r\n if (!hay.includes(homeBinNorm)) return false;\r\n if (!hasVerbSlot(hay, homeBinNorm, \"action\")) return false;\r\n return isHomeBinHookCommand(command, homeBinPath, connectorId);\r\n}\r\n\r\n/**\r\n * Single source of truth for \"is OPT-IN host-native turn-usage capture enabled\r\n * for this connector?\" — read by the Gemini / Antigravity adapters at install\r\n * time to decide whether to ALSO write the AfterModel / PostInvocation usage hook.\r\n * Enabled when the connector opts in via telemetry.hostNativeUsage OR when the\r\n * install-time env switch AGENT_CONNECTOR_HOST_NATIVE=1 forces it on. Off by\r\n * default (privacy: host-native capture is never installed silently).\r\n */\r\nexport function isHostNativeUsageEnabled(\r\n telemetry: { enabled: boolean; hostNativeUsage?: boolean },\r\n env: NodeJS.ProcessEnv = process.env,\r\n): boolean {\r\n if (telemetry.enabled !== true) return false;\r\n if (env.AGENT_CONNECTOR_HOST_NATIVE === \"1\") return true;\r\n return telemetry.hostNativeUsage === true;\r\n}\r\n\r\n/**\r\n * Single source of truth for \"should this server be wrapped by `serve` for\r\n * telemetry?\" — so every adapter behaves identically even for a server that\r\n * skipped normalizeServer (e.g. a per-platform override). On by default for an\r\n * stdio server with a command, unless explicitly disabled or telemetry is off.\r\n */\r\nexport function shouldWrapForTelemetry(\r\n server: ServerDef,\r\n telemetry: { enabled: boolean },\r\n): boolean {\r\n return (\r\n server.wrapForTelemetry !== false &&\r\n telemetry.enabled === true &&\r\n server.transport === \"stdio\" &&\r\n typeof server.command === \"string\" &&\r\n server.command !== \"\"\r\n );\r\n}\r\n\r\n/**\r\n * Build the telemetry-wrapping server command:\r\n * \"<homeBin>\" serve --connector <id> --scope <scope> --host <platformId> -- <realCommand> <realArgs...>\r\n * Used when a stdio server opts into transparent telemetry capture.\r\n *\r\n * `scope` records the install dimension (global user vs project-local) on every\r\n * telemetry row so usage can be sliced by it later. It is OPTIONAL for backward\r\n * compatibility: when omitted, the `--scope` flag is not emitted and the runtime\r\n * treats the scope as \"unknown\".\r\n *\r\n * `platformId` bakes the install TARGET platform into the wrapper so the proxy\r\n * stamps `hostPlatform` correctly even under a headless spawn where runtime env\r\n * markers are absent (detectRuntimeHost only knows claude-code/cursor/codex and\r\n * otherwise mis-attributes). Emitted as `--host <platformId>` in the FLAG\r\n * section (before `--`). It is OPTIONAL + backward-compatible: when omitted the\r\n * `--host` flag is not emitted and the runtime falls back to env detection.\r\n *\r\n * `dataDir` pins the framework data-root the spawned `serve` child must use to\r\n * resolve the connector record (and write telemetry). Emitted as `--data-dir\r\n * <path>` in the FLAG section. It exists because some hosts (codex strips the\r\n * MCP child's environment) do NOT propagate `AGENT_CONNECTOR_DATA_DIR` to the\r\n * spawned server — so a child that relied on inheriting it would resolve the\r\n * DEFAULT `~/.agent-connector` and die with \"Connector not registered\" when the\r\n * install wrote the record under an OVERRIDDEN root. Passing it explicitly makes\r\n * the wrap env-independent for any env-stripping host. OPTIONAL + backward-\r\n * compatible: callers pass it only for a non-default root (a default-root install\r\n * stays flag-free and relies on the correct fallback), and when omitted the\r\n * `--data-dir` flag is not emitted and the runtime resolves the data-root the\r\n * usual way.\r\n */\r\nexport function buildServeWrapperCommand(\r\n homeBinPath: string,\r\n connectorId: string,\r\n realCommand: string,\r\n realArgs: string[],\r\n scope?: InstallScope,\r\n platformId?: PlatformId,\r\n dataDir?: string,\r\n): { command: string; args: string[] } {\r\n const flags = [\"serve\", \"--connector\", connectorId];\r\n if (scope !== undefined) flags.push(\"--scope\", narrowInstallScope(scope));\r\n if (platformId !== undefined) flags.push(\"--host\", platformId);\r\n if (dataDir !== undefined && dataDir !== \"\") flags.push(\"--data-dir\", dataDir);\r\n return {\r\n command: homeBinPath,\r\n args: [...flags, \"--\", realCommand, ...realArgs],\r\n };\r\n}\r\n\r\n/**\r\n * Telemetry serve-wrap for a stdio command: when the connector opts in, route\r\n * `command`/`args` through `<homeBin> serve --connector <id> -- …`; otherwise\r\n * return them unchanged. Consolidates the per-host wrap snippet — the caller\r\n * keeps its own command/args seeding + downstream env-resolution + entry shaping.\r\n *\r\n * When the install's framework data-root is NON-DEFAULT (overridden via\r\n * AGENT_CONNECTOR_DATA_DIR), the wrap also carries an explicit `--data-dir\r\n * <root>` so the spawned `serve` child resolves the connector record from that\r\n * root even on hosts that strip the child's environment (codex). A default-root\r\n * install emits no flag and relies on the correct runtime fallback.\r\n */\r\nexport function buildWrappedStdio(\r\n ctx: Pick<InstallContext, \"homeBinPath\" | \"connector\" | \"scope\" | \"dataRoot\">,\r\n server: ServerDef,\r\n platformId: PlatformId,\r\n command: string,\r\n args: string[],\r\n): { command: string; args: string[] } {\r\n if (!shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\r\n return { command, args };\r\n }\r\n const dataDir = isNonDefaultDataRoot(ctx.dataRoot) ? ctx.dataRoot : undefined;\r\n return buildServeWrapperCommand(\r\n ctx.homeBinPath,\r\n ctx.connector.id,\r\n command,\r\n args,\r\n ctx.scope,\r\n platformId,\r\n dataDir,\r\n );\r\n}\r\n\r\n/** Injectable deps for {@link resolveSpawnCommand} (so the win32 branch is unit-testable on POSIX). */\r\nexport interface SpawnResolveDeps {\r\n platform?: NodeJS.Platform;\r\n /** PATH value (`;`-separated on Windows). */\r\n pathEnv?: string;\r\n /** PATHEXT value (`;`-separated). */\r\n pathExt?: string;\r\n /** File-existence probe (defaults to fs.existsSync). */\r\n exists?: (p: string) => boolean;\r\n}\r\n\r\n/** How a child command should be handed to spawn() on this platform. */\r\nexport interface SpawnResolution {\r\n /** The command to pass to spawn() (an absolute path on win32 when resolved). */\r\n file: string;\r\n /**\r\n * Whether spawn() MUST use `shell: true`. On native Windows a `.cmd`/`.bat`\r\n * shim (npx.cmd, pnpm.cmd, the agent-connector.cmd launcher) cannot be run by\r\n * raw CreateProcess — Node throws EINVAL since the 2024 security fix unless a\r\n * shell is used. `.exe` resolves directly with no shell.\r\n */\r\n needsShell: boolean;\r\n}\r\n\r\n/**\r\n * Resolve a child command for spawn() across platforms. NO-OP on macOS/Linux\r\n * (returns the command unchanged, no shell). On native Windows it fixes the two\r\n * spawn failure modes for bare package runners:\r\n * 1. raw CreateProcess ignores PATHEXT, so spawn(\"npx\") → ENOENT even though\r\n * `npx.cmd` is on PATH. We search PATH × PATHEXT and return the resolved\r\n * absolute path.\r\n * 2. a resolved `.cmd`/`.bat` still cannot be launched without a shell, so we\r\n * flag `needsShell` for those (and `.exe`/`.com` run directly).\r\n * A bare name that PATH search misses falls back to `{ file: command,\r\n * needsShell: true }` so cmd.exe's own PATHEXT lookup still finds it.\r\n */\r\nexport function resolveSpawnCommand(\r\n command: string,\r\n deps: SpawnResolveDeps = {},\r\n): SpawnResolution {\r\n const platform = deps.platform ?? process.platform;\r\n if (platform !== \"win32\") return { file: command, needsShell: false };\r\n\r\n const isBatch = (s: string): boolean => /\\.(cmd|bat)$/i.test(s);\r\n\r\n // Already a path or already has an extension → don't search; only decide shell.\r\n if (/[\\\\/]/.test(command) || /\\.[a-z0-9]+$/i.test(command)) {\r\n return { file: command, needsShell: isBatch(command) };\r\n }\r\n\r\n const exists = deps.exists ?? existsSync;\r\n const pathEnv = deps.pathEnv ?? process.env.PATH ?? process.env.Path ?? \"\";\r\n const pathExt = deps.pathExt ?? process.env.PATHEXT ?? \".COM;.EXE;.BAT;.CMD\";\r\n const dirs = pathEnv.split(\";\").filter((d) => d !== \"\");\r\n const exts = pathExt.split(\";\").filter((e) => e !== \"\");\r\n for (const dir of dirs) {\r\n for (const ext of exts) {\r\n const candidate = join(dir, command + ext);\r\n if (exists(candidate)) return { file: candidate, needsShell: isBatch(ext) };\r\n }\r\n }\r\n // Not found on PATH — let cmd.exe resolve it (handles shim dirs we may miss).\r\n return { file: command, needsShell: true };\r\n}\r\n\r\n/** Basenames (case-insensitive, sans common extensions) of the ephemeral package runners. */\r\nconst PACKAGE_RUNNERS: Record<string, Extract<LaunchMethod, \"npx\" | \"bunx\" | \"uvx\">> = {\r\n npx: \"npx\",\r\n bunx: \"bunx\",\r\n uvx: \"uvx\",\r\n};\r\n\r\n/** Basenames of language interpreters that launch a local script. */\r\nconst INTERPRETERS: ReadonlySet<string> = new Set([\"node\", \"bun\", \"deno\"]);\r\n\r\n/**\r\n * Strip a directory prefix and a trailing executable extension to get the bare\r\n * program name. Tolerates both POSIX and Windows separators (the wrapped command\r\n * may be an absolute Windows path) and lowercases for case-insensitive matching.\r\n */\r\nfunction commandBasename(realCommand: string): string {\r\n const noDir = realCommand.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? realCommand;\r\n return noDir.replace(/\\.(exe|cmd|bat|com)$/i, \"\").toLowerCase();\r\n}\r\n\r\n/**\r\n * Classify how the real MCP server is launched, for the \"launch-method\" slicing\r\n * dimension. Package runners (npx/bunx/uvx) and interpreters (node/bun/deno) are\r\n * detected by the command basename. A remote (http) server is not launched\r\n * locally, so the caller — which alone knows the transport — passes\r\n * `isRemote: true` to force \"http\". Anything else resolves to \"binary\".\r\n */\r\nexport function detectLaunchMethod(\r\n realCommand: string,\r\n realArgs: string[],\r\n opts?: { isRemote?: boolean },\r\n): LaunchMethod {\r\n void realArgs; // reserved: args may later refine node-vs-script heuristics\r\n if (opts?.isRemote === true) return \"http\";\r\n if (typeof realCommand !== \"string\" || realCommand.trim() === \"\") {\r\n return \"unknown\";\r\n }\r\n const base = commandBasename(realCommand);\r\n if (base === \"\") return \"unknown\";\r\n const runner = PACKAGE_RUNNERS[base];\r\n if (runner !== undefined) return runner;\r\n if (INTERPRETERS.has(base)) return \"node\";\r\n return \"binary\";\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/toml.ts"],"sourcesContent":["/**\r\n * core/toml — minimal TOML string IO.\r\n *\r\n * The TOML analog of core/yaml's read/write helpers. Lifted from the codex\r\n * adapter's private readToml/writeToml so the Group-B command renderers for\r\n * Gemini/Qwen/Codex (which author `.toml` command files) share one\r\n * implementation rather than each re-importing @iarna/toml.\r\n *\r\n * Deliberately tiny and string-oriented: these are pure (de)serializers — no\r\n * filesystem touches, no dryRun, no merge logic. Callers own reading/writing\r\n * and any idempotency/upsert (the shapes differ per platform), exactly as the\r\n * adapters layer their own logic on top of the JSON/YAML helpers.\r\n */\r\n\r\nimport TOML from \"@iarna/toml\";\r\n\r\n/**\r\n * Serialize a plain object to a TOML string.\r\n *\r\n * @iarna/toml's `stringify` is typed to accept its own `JsonMap`; our objects\r\n * are structurally compatible, so we cast at the boundary (same approach the\r\n * codex adapter used). Returns the TOML text — the caller writes it.\r\n */\r\nexport function writeTomlString(obj: Record<string, unknown>): string {\r\n return TOML.stringify(obj as never);\r\n}\r\n\r\n/**\r\n * Parse a TOML string into a typed object. Throws on malformed TOML (callers\r\n * that want fail-soft behavior should wrap in try/catch, mirroring how the\r\n * codex adapter degrades a corrupt config.toml to `{}`).\r\n */\r\nexport function readTomlString<T = Record<string, unknown>>(text: string): T {\r\n return TOML.parse(text) as T;\r\n}\r\n"],"mappings":";;;AAcA,OAAO,UAAU;AASV,SAAS,gBAAgB,KAAsC;AACpE,SAAO,KAAK,UAAU,GAAY;AACpC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/interpolate.ts"],"sourcesContent":["/**\r\n * core/interpolate — universal ${env:VAR} interpolation.\r\n *\r\n * The developer writes one portable syntax in their connector config:\r\n * \"${env:ACME_KEY}\" → value of process.env.ACME_KEY\r\n * \"${env:ACME_URL:-https://x}\" → value, or the default after \":-\" if unset/empty\r\n *\r\n * Two consumers:\r\n * • resolveEnvRefs / resolveEnvRefsDeep — resolve to literals at INSTALL time,\r\n * for hosts with NO native interpolation (e.g. Codex TOML).\r\n * • rewriteEnvRefs — translate to a host's NATIVE interpolation token (e.g.\r\n * Cursor/VS Code \"${env:VAR}\", Claude \"${VAR}\") so secrets are never baked\r\n * into config files. Adapters choose which to use.\r\n */\r\n\r\n/** Matches ${env:NAME} and ${env:NAME:-default}. NAME is [A-Za-z_][A-Za-z0-9_]*. */\r\nexport const ENV_REF_RE = /\\$\\{env:([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\\}/g;\r\n\r\n/** Resolve every ${env:VAR} in `input` to a literal from `env`. */\r\nexport function resolveEnvRefs(\r\n input: string,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string {\r\n return input.replace(ENV_REF_RE, (_m, name: string, def?: string) => {\r\n const v = env[name];\r\n if (v != null && v !== \"\") return v;\r\n return def ?? \"\";\r\n });\r\n}\r\n\r\n/** Recursively resolve ${env:VAR} in all strings of a JSON-ish value. */\r\nexport function resolveEnvRefsDeep<T>(value: T, env: NodeJS.ProcessEnv = process.env): T {\r\n if (typeof value === \"string\") return resolveEnvRefs(value, env) as unknown as T;\r\n if (Array.isArray(value)) {\r\n return value.map((v) => resolveEnvRefsDeep(v, env)) as unknown as T;\r\n }\r\n if (value && typeof value === \"object\") {\r\n const out: Record<string, unknown> = {};\r\n for (const [k, v] of Object.entries(value)) out[k] = resolveEnvRefsDeep(v, env);\r\n return out as T;\r\n }\r\n return value;\r\n}\r\n\r\n/**\r\n * Translate every ${env:VAR(:-default)} via `render` into a host-native token.\r\n * The renderer receives the var name and optional default and returns the\r\n * replacement string (e.g. `(name) => \"${\" + name + \"}\"` for Claude).\r\n */\r\nexport function rewriteEnvRefs(\r\n input: string,\r\n render: (name: string, def?: string) => string,\r\n): string {\r\n return input.replace(ENV_REF_RE, (_m, name: string, def?: string) =>\r\n render(name, def),\r\n );\r\n}\r\n\r\n/** True if the string contains at least one ${env:...} reference. */\r\nexport function hasEnvRef(input: string): boolean {\r\n ENV_REF_RE.lastIndex = 0;\r\n return ENV_REF_RE.test(input);\r\n}\r\n\r\n/**\r\n * Names of every ${env:VAR} reference in a JSON-ish value that\r\n * {@link resolveEnvRefsDeep} would bake to an EMPTY literal — i.e. the var is\r\n * unset/empty in `env` AND the reference carries no `:-default`. These are the\r\n * silent-empty-secret bakes on hosts WITHOUT native interpolation: the install\r\n * succeeds but writes `\"\"` where a secret was meant, surfacing only as a\r\n * runtime auth failure inside the MCP server. Returns deduped names in\r\n * first-seen order; uses the SAME unset/default semantics as resolveEnvRefs so\r\n * the two can never disagree. A ref WITH a `:-default` is intentional and never\r\n * reported (even when the default itself is empty — the dev opted into \"\").\r\n */\r\nexport function findUnsetEnvRefs<T>(\r\n value: T,\r\n env: NodeJS.ProcessEnv = process.env,\r\n): string[] {\r\n const seen = new Set<string>();\r\n const order: string[] = [];\r\n const scanString = (input: string): void => {\r\n // A FRESH regex per scan — the shared ENV_REF_RE carries /g lastIndex state\r\n // (hasEnvRef / matchAll would otherwise start mid-string and miss matches).\r\n const re = new RegExp(ENV_REF_RE.source, \"g\");\r\n for (const m of input.matchAll(re)) {\r\n const name = m[1] as string;\r\n const def = m[2] as string | undefined;\r\n // Mirrors resolveEnvRefs: a present, non-empty value resolves to itself;\r\n // otherwise the default is used (no bake of \"\"). Only an unset/empty var\r\n // WITHOUT a default bakes \"\" — the case we report.\r\n const v = env[name];\r\n if (v != null && v !== \"\") continue;\r\n if (def !== undefined) continue;\r\n if (!seen.has(name)) {\r\n seen.add(name);\r\n order.push(name);\r\n }\r\n }\r\n };\r\n const walk = (v: unknown): void => {\r\n if (typeof v === \"string\") scanString(v);\r\n else if (Array.isArray(v)) v.forEach(walk);\r\n else if (v && typeof v === \"object\") Object.values(v).forEach(walk);\r\n };\r\n walk(value);\r\n return order;\r\n}\r\n"],"mappings":";;;AAgBO,IAAM,aAAa;AAGnB,SAAS,eACd,OACA,MAAyB,QAAQ,KACzB;AACR,SAAO,MAAM,QAAQ,YAAY,CAAC,IAAI,MAAc,QAAiB;AACnE,UAAM,IAAI,IAAI,IAAI;AAClB,QAAI,KAAK,QAAQ,MAAM,GAAI,QAAO;AAClC,WAAO,OAAO;AAAA,EAChB,CAAC;AACH;AAGO,SAAS,mBAAsB,OAAU,MAAyB,QAAQ,KAAQ;AACvF,MAAI,OAAO,UAAU,SAAU,QAAO,eAAe,OAAO,GAAG;AAC/D,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAAA,EACpD;AACA,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,MAA+B,CAAC;AACtC,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,EAAG,KAAI,CAAC,IAAI,mBAAmB,GAAG,GAAG;AAC9E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,eACd,OACA,QACQ;AACR,SAAO,MAAM;AAAA,IAAQ;AAAA,IAAY,CAAC,IAAI,MAAc,QAClD,OAAO,MAAM,GAAG;AAAA,EAClB;AACF;AAmBO,SAAS,iBACd,OACA,MAAyB,QAAQ,KACvB;AACV,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAkB,CAAC;AACzB,QAAM,aAAa,CAAC,UAAwB;AAG1C,UAAM,KAAK,IAAI,OAAO,WAAW,QAAQ,GAAG;AAC5C,eAAW,KAAK,MAAM,SAAS,EAAE,GAAG;AAClC,YAAM,OAAO,EAAE,CAAC;AAChB,YAAM,MAAM,EAAE,CAAC;AAIf,YAAM,IAAI,IAAI,IAAI;AAClB,UAAI,KAAK,QAAQ,MAAM,GAAI;AAC3B,UAAI,QAAQ,OAAW;AACvB,UAAI,CAAC,KAAK,IAAI,IAAI,GAAG;AACnB,aAAK,IAAI,IAAI;AACb,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,CAAC,MAAqB;AACjC,QAAI,OAAO,MAAM,SAAU,YAAW,CAAC;AAAA,aAC9B,MAAM,QAAQ,CAAC,EAAG,GAAE,QAAQ,IAAI;AAAA,aAChC,KAAK,OAAO,MAAM,SAAU,QAAO,OAAO,CAAC,EAAE,QAAQ,IAAI;AAAA,EACpE;AACA,OAAK,KAAK;AACV,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/sqlite.ts"],"sourcesContent":["/**\r\n * usage/sqlite — a lazy, read-only sql.js (WASM) loader for SQLite readers.\r\n *\r\n * Why sql.js: pure WASM, zero native build / node-gyp / prebuilt-binary matrix,\r\n * so it installs identically on Linux/macOS/Windows and in CI (the decisive\r\n * constraint — see docs/research/usage-design.md §2). We never write the host DB:\r\n * we load its bytes and run SELECTs, then discard.\r\n *\r\n * Read-only by construction:\r\n * • open by reading the file into a Uint8Array → new SQL.Database(bytes);\r\n * • if a -wal/-shm sidecar exists, the on-disk file may be a half-flushed\r\n * snapshot, so we copy the db (+ sidecars) into an os.tmpdir temp path,\r\n * open the copy, and clean it up afterward. This avoids reading a torn page\r\n * of a live DB (Crush/OpenCode can be running).\r\n *\r\n * Fail-open: ANY failure (missing wasm, unreadable file, corrupt db, bad SQL)\r\n * returns null / [] — a SQLite reader degrades to zero rows, never throws.\r\n *\r\n * The WASM module is initialized once (lazy singleton) so report runs that touch\r\n * no SQLite reader pay nothing.\r\n */\r\n\r\nimport { copyFileSync, existsSync, mkdtempSync, readFileSync, rmSync } from \"node:fs\";\r\nimport { createRequire } from \"node:module\";\r\nimport { tmpdir } from \"node:os\";\r\nimport { basename, dirname, join } from \"node:path\";\r\n\r\n/** Minimal handle a SQLite reader needs: run a SELECT, then close. */\r\nexport interface SqliteDb {\r\n /** Run a SQL statement and return all rows as plain objects (column → value). */\r\n all(sql: string): Array<Record<string, unknown>>;\r\n /** Release the in-memory database. Idempotent. */\r\n close(): void;\r\n}\r\n\r\n/** The sql.js factory signature we depend on (a tiny structural subset). */\r\ninterface SqlJsStatic {\r\n Database: new (data: Uint8Array) => SqlJsDatabase;\r\n}\r\ninterface SqlJsDatabase {\r\n exec(sql: string): Array<{ columns: string[]; values: unknown[][] }>;\r\n close(): void;\r\n}\r\ntype InitSqlJs = (config?: { locateFile?: (file: string) => string }) => Promise<SqlJsStatic>;\r\n\r\nconst require = createRequire(import.meta.url);\r\n\r\n/** Lazy singleton: the initialized sql.js module (or null if it failed to load). */\r\nlet sqlPromise: Promise<SqlJsStatic | null> | undefined;\r\n\r\n/** Resolve the sql-wasm.wasm next to the resolved sql.js package entry. */\r\nfunction locateWasm(file: string): string {\r\n try {\r\n const entry = require.resolve(\"sql.js\"); // → node_modules/sql.js/dist/sql-wasm.js\r\n return join(dirname(entry), file);\r\n } catch {\r\n return file;\r\n }\r\n}\r\n\r\n/** Initialize sql.js once. Returns null (cached) when the module cannot load. */\r\nfunction loadSqlJs(): Promise<SqlJsStatic | null> {\r\n if (sqlPromise === undefined) {\r\n sqlPromise = (async () => {\r\n try {\r\n // sql.js's default export is the initializer (a CommonJS module).\r\n const mod = require(\"sql.js\") as InitSqlJs | { default: InitSqlJs };\r\n const init: InitSqlJs = typeof mod === \"function\" ? mod : mod.default;\r\n return await init({ locateFile: locateWasm });\r\n } catch {\r\n return null;\r\n }\r\n })();\r\n }\r\n return sqlPromise;\r\n}\r\n\r\n/** SQLite WAL/SHM sidecar suffixes that signal a possibly-live database file. */\r\nconst SIDECAR_SUFFIXES = [\"-wal\", \"-shm\"] as const;\r\n\r\n/**\r\n * Open a SQLite file read-only via sql.js. Returns a small {@link SqliteDb} or\r\n * null on any failure. When a -wal/-shm sidecar is present the db is copied to a\r\n * temp dir first (and the copy is removed when the handle is closed) to avoid\r\n * reading a torn snapshot of a live database.\r\n */\r\nexport async function openSqlite(path: string): Promise<SqliteDb | null> {\r\n if (!existsSync(path)) return null;\r\n\r\n const SQL = await loadSqlJs();\r\n if (SQL === null) return null;\r\n\r\n const hasSidecar = SIDECAR_SUFFIXES.some((s) => existsSync(path + s));\r\n let openPath = path;\r\n let tempDir: string | undefined;\r\n\r\n if (hasSidecar) {\r\n try {\r\n tempDir = mkdtempSync(join(tmpdir(), \"agent-connector-usage-\"));\r\n const dst = join(tempDir, basename(path));\r\n copyFileSync(path, dst);\r\n for (const suffix of SIDECAR_SUFFIXES) {\r\n const side = path + suffix;\r\n if (existsSync(side)) copyFileSync(side, dst + suffix);\r\n }\r\n openPath = dst;\r\n } catch {\r\n // If the copy fails, fall back to opening the original bytes directly.\r\n openPath = path;\r\n if (tempDir) {\r\n cleanupTemp(tempDir);\r\n tempDir = undefined;\r\n }\r\n }\r\n }\r\n\r\n let bytes: Uint8Array;\r\n try {\r\n bytes = readFileSync(openPath);\r\n } catch {\r\n if (tempDir) cleanupTemp(tempDir);\r\n return null;\r\n }\r\n\r\n // Reject anything that is not a SQLite file up front (the 16-byte header magic\r\n // \"SQLite format 3\\0\"). sql.js would otherwise accept arbitrary bytes and only\r\n // fail at query time; this keeps the documented \"null on non-db\" contract.\r\n if (!hasSqliteMagic(bytes)) {\r\n if (tempDir) cleanupTemp(tempDir);\r\n return null;\r\n }\r\n\r\n let db: SqlJsDatabase;\r\n try {\r\n db = new SQL.Database(bytes);\r\n } catch {\r\n if (tempDir) cleanupTemp(tempDir);\r\n return null;\r\n }\r\n\r\n let closed = false;\r\n return {\r\n all(sql: string): Array<Record<string, unknown>> {\r\n if (closed) return [];\r\n let result: Array<{ columns: string[]; values: unknown[][] }>;\r\n try {\r\n result = db.exec(sql);\r\n } catch {\r\n return []; // bad SQL / schema mismatch → no rows\r\n }\r\n const out: Array<Record<string, unknown>> = [];\r\n for (const block of result) {\r\n const { columns, values } = block;\r\n for (const row of values) {\r\n const obj: Record<string, unknown> = {};\r\n for (let i = 0; i < columns.length; i++) {\r\n const col = columns[i];\r\n if (col !== undefined) obj[col] = row[i];\r\n }\r\n out.push(obj);\r\n }\r\n }\r\n return out;\r\n },\r\n close(): void {\r\n if (closed) return;\r\n closed = true;\r\n try {\r\n db.close();\r\n } catch {\r\n /* ignore */\r\n }\r\n if (tempDir) cleanupTemp(tempDir);\r\n },\r\n };\r\n}\r\n\r\n/** The 16-byte SQLite file header: \"SQLite format 3\\0\". */\r\nconst SQLITE_MAGIC = Uint8Array.from([\r\n 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00,\r\n]);\r\n\r\n/** Does `bytes` begin with the SQLite file-header magic? */\r\nfunction hasSqliteMagic(bytes: Uint8Array): boolean {\r\n if (bytes.length < SQLITE_MAGIC.length) return false;\r\n for (let i = 0; i < SQLITE_MAGIC.length; i++) {\r\n if (bytes[i] !== SQLITE_MAGIC[i]) return false;\r\n }\r\n return true;\r\n}\r\n\r\nfunction cleanupTemp(dir: string): void {\r\n try {\r\n rmSync(dir, { recursive: true, force: true });\r\n } catch {\r\n /* best-effort */\r\n }\r\n}\r\n"],"mappings":"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","names":["require"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/jsonl.ts"],"sourcesContent":["/**\r\n * usage/jsonl — tolerant JSONL / JSON readers + a file-mtime helper.\r\n *\r\n * Every reader is fail-open: a malformed line is skipped (never thrown), a\r\n * missing/unreadable file yields no rows. Mirrors the NdjsonStore.query and host\r\n * parser behavior — bad input degrades to empty, it does not crash a report.\r\n *\r\n * Ports tokscale sessions/utils.rs file_modified_timestamp_ms (mtime fallback)\r\n * and the per-line skip-malformed loop used by every JSONL parser.\r\n */\r\n\r\nimport { readFileSync, statSync } from \"node:fs\";\r\n\r\n/**\r\n * Parse a JSONL file into objects, skipping blank/malformed lines. Returns [] on\r\n * any read error (missing file, permissions). Each yielded value is whatever\r\n * `JSON.parse` produced — callers narrow it. Order matches the file.\r\n *\r\n * Returns an array (not a generator) so callers can index/slice; for the file\r\n * sizes here (session logs) a full read is acceptable, matching the Rust\r\n * BufReader-per-file approach.\r\n */\r\nexport function readJsonlLines(path: string): unknown[] {\r\n let text: string;\r\n try {\r\n text = readFileSync(path, \"utf8\");\r\n } catch {\r\n return [];\r\n }\r\n\r\n const out: unknown[] = [];\r\n for (const line of text.split(\"\\n\")) {\r\n const trimmed = line.trim();\r\n if (trimmed === \"\") continue;\r\n try {\r\n out.push(JSON.parse(trimmed));\r\n } catch {\r\n continue; // skip malformed line\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Read and parse a whole JSON file. Returns undefined on any read/parse error\r\n * (the fail-open contract for JSON readers). Caller narrows the unknown result.\r\n */\r\nexport function readJsonFile(path: string): unknown {\r\n let text: string;\r\n try {\r\n text = readFileSync(path, \"utf8\");\r\n } catch {\r\n return undefined;\r\n }\r\n try {\r\n return JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/**\r\n * File modification time in epoch ms, used as a timestamp fallback when a log\r\n * line carries none. Port of file_modified_timestamp_ms: falls back to \"now\"\r\n * when the file cannot be stat'd so a row is never dropped for lack of a ts.\r\n */\r\nexport function fileMtimeMs(path: string): number {\r\n try {\r\n return Math.floor(statSync(path).mtimeMs);\r\n } catch {\r\n return Date.now();\r\n }\r\n}\r\n"],"mappings":";;;AAWA,SAAS,cAAc,gBAAgB;AAWhC,SAAS,eAAe,MAAyB;AACtD,MAAI;AACJ,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;AAAA,EAClC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,MAAiB,CAAC;AACxB,aAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,YAAY,GAAI;AACpB,QAAI;AACF,UAAI,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,IAC9B,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,aAAa,MAAuB;AAClD,MAAI;AACJ,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,YAAY,MAAsB;AAChD,MAAI;AACF,WAAO,KAAK,MAAM,SAAS,IAAI,EAAE,OAAO;AAAA,EAC1C,QAAQ;AACN,WAAO,KAAK,IAAI;AAAA,EAClB;AACF;","names":[]}
|
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
fileMtimeMs,
|
|
4
4
|
readJsonFile,
|
|
5
5
|
readJsonlLines
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZSOS2KOR.js";
|
|
7
7
|
import {
|
|
8
8
|
firstExistingRoot,
|
|
9
9
|
isFile,
|
|
10
10
|
walkFiles
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-KM2YXO6V.js";
|
|
12
12
|
import {
|
|
13
13
|
emptyTokens,
|
|
14
14
|
inferProvider,
|
|
15
15
|
normalizeWorkspaceKey,
|
|
16
16
|
workspaceLabelFromKey
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-7PSNXUFK.js";
|
|
18
18
|
|
|
19
19
|
// src/usage/readers/claude-code.ts
|
|
20
20
|
import { basename, dirname, sep } from "path";
|
|
@@ -649,4 +649,4 @@ var claude_code_default = claudeCodeReader;
|
|
|
649
649
|
export {
|
|
650
650
|
claude_code_default as default
|
|
651
651
|
};
|
|
652
|
-
//# sourceMappingURL=claude-code-
|
|
652
|
+
//# sourceMappingURL=claude-code-FS42PXZO.js.map
|