@ken-jo/agent-connector 0.4.97 → 0.4.99
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 +604 -596
- package/dist/{action-IPFDPOZU.js → action-5OEM3QC4.js} +17 -16
- package/dist/action-5OEM3QC4.js.map +1 -0
- package/dist/{amazon-q-IT44LEWV.js → amazon-q-7DPVJXJN.js} +6 -6
- package/dist/amazon-q-7DPVJXJN.js.map +1 -0
- package/dist/{amp-CEWOSWQO.js → amp-BQZOL5GR.js} +4 -4
- package/dist/amp-BQZOL5GR.js.map +1 -0
- package/dist/{amp-P35FRU2Z.js → amp-VYXZWHXW.js} +7 -7
- package/dist/amp-VYXZWHXW.js.map +1 -0
- package/dist/{antigravity-LHFEFNMC.js → antigravity-EA4L225L.js} +5 -5
- package/dist/antigravity-EA4L225L.js.map +1 -0
- package/dist/antigravity-VXHL6ZPM.js +18 -0
- package/dist/{antigravity-cli-MOKFSWOU.js → antigravity-cli-B2HXZFYQ.js} +5 -5
- package/dist/antigravity-cli-B2HXZFYQ.js.map +1 -0
- package/dist/{antigravity-cli-MPE27LPI.js → antigravity-cli-JHQ7JGNX.js} +10 -9
- package/dist/antigravity-cli-JHQ7JGNX.js.map +1 -0
- package/dist/{audit-3E5JAOP2.js → audit-BO7JQYIH.js} +8 -8
- package/dist/{chunk-7C2IPIIB.js → chunk-2Y2MZRLP.js} +3 -3
- package/dist/chunk-2Y2MZRLP.js.map +1 -0
- package/dist/{chunk-GZZCHJDP.js → chunk-4KIXXJ7B.js} +2 -2
- package/dist/chunk-4KIXXJ7B.js.map +1 -0
- package/dist/chunk-4NFDNY3C.js +34 -0
- package/dist/chunk-4NFDNY3C.js.map +1 -0
- package/dist/{chunk-C63AAXK7.js → chunk-4QXCNZMD.js} +5 -5
- package/dist/chunk-4QXCNZMD.js.map +1 -0
- package/dist/{chunk-Q7PR2WGT.js → chunk-6TF7MHG5.js} +2 -2
- package/dist/chunk-6TF7MHG5.js.map +1 -0
- package/dist/{chunk-7ZFK2WEO.js → chunk-6WN37NVN.js} +113 -10
- package/dist/chunk-6WN37NVN.js.map +1 -0
- package/dist/{chunk-GCPEPUD7.js → chunk-6XMV2OOA.js} +6 -6
- package/dist/chunk-6XMV2OOA.js.map +1 -0
- package/dist/{chunk-XXLCMSD3.js → chunk-BEFVJ2OE.js} +1 -1
- package/dist/chunk-BEFVJ2OE.js.map +1 -0
- package/dist/{chunk-N4ENLZEU.js → chunk-BV5WK6VQ.js} +19 -19
- package/dist/chunk-BV5WK6VQ.js.map +1 -0
- package/dist/{chunk-WPTNMYYM.js → chunk-BXPSDNIB.js} +6 -6
- package/dist/chunk-BXPSDNIB.js.map +1 -0
- package/dist/{chunk-Q4ISQHUQ.js → chunk-FBJQGRET.js} +1 -1
- package/dist/chunk-FBJQGRET.js.map +1 -0
- package/dist/{chunk-THI4PI4H.js → chunk-FJCUKXGX.js} +2 -2
- package/dist/chunk-FJCUKXGX.js.map +1 -0
- package/dist/{chunk-L2C5UMKW.js → chunk-FKW5A6HE.js} +23 -7
- package/dist/chunk-FKW5A6HE.js.map +1 -0
- package/dist/{chunk-NDMNMAKP.js → chunk-G5HAIYRM.js} +43 -43
- package/dist/chunk-G5HAIYRM.js.map +1 -0
- package/dist/{chunk-SLJI5BOM.js → chunk-GDIAHWNY.js} +2 -2
- package/dist/chunk-GDIAHWNY.js.map +1 -0
- package/dist/{chunk-QYOUQCC6.js → chunk-GZGLCCEE.js} +1 -1
- package/dist/chunk-GZGLCCEE.js.map +1 -0
- package/dist/{chunk-PSGTHJQU.js → chunk-H53QZQJI.js} +1 -1
- package/dist/chunk-H53QZQJI.js.map +1 -0
- package/dist/{chunk-7HHW23AC.js → chunk-IRUYJD23.js} +29 -29
- package/dist/chunk-IRUYJD23.js.map +1 -0
- package/dist/{chunk-IOJDZJ72.js → chunk-IVAWP6HH.js} +2 -2
- package/dist/chunk-IVAWP6HH.js.map +1 -0
- package/dist/{chunk-3FINQ2ZF.js → chunk-JTN3AKZO.js} +30 -20
- package/dist/chunk-JTN3AKZO.js.map +1 -0
- package/dist/{chunk-4GH2KA7V.js → chunk-KHO5WNTP.js} +1 -1
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/{chunk-MLU7NDAZ.js → chunk-KLZBRNFP.js} +12 -12
- package/dist/chunk-KLZBRNFP.js.map +1 -0
- package/dist/{chunk-3EP5V2F4.js → chunk-M6OS4OLU.js} +3 -3
- package/dist/chunk-M6OS4OLU.js.map +1 -0
- package/dist/{chunk-UZZTWWGG.js → chunk-MQPNU2CY.js} +1 -1
- package/dist/chunk-MQPNU2CY.js.map +1 -0
- package/dist/{chunk-LQ55E7QI.js → chunk-N4STCQGP.js} +7 -7
- package/dist/chunk-N4STCQGP.js.map +1 -0
- package/dist/{chunk-KFPSJRHR.js → chunk-NBYKLUF6.js} +2 -2
- package/dist/chunk-NBYKLUF6.js.map +1 -0
- package/dist/{chunk-KM2YXO6V.js → chunk-O7SDRBVB.js} +1 -1
- package/dist/chunk-O7SDRBVB.js.map +1 -0
- package/dist/{chunk-LFWYYWLV.js → chunk-OP4KBXUO.js} +1 -1
- package/dist/chunk-OP4KBXUO.js.map +1 -0
- package/dist/{chunk-XN7S44U4.js → chunk-OPXAP3AC.js} +1 -1
- package/dist/chunk-OPXAP3AC.js.map +1 -0
- package/dist/{chunk-TGZFDXNH.js → chunk-PWCBWAM4.js} +6 -4
- package/dist/chunk-PWCBWAM4.js.map +1 -0
- package/dist/{chunk-Y3K6KJMS.js → chunk-QSY74NAP.js} +2 -2
- package/dist/chunk-QSY74NAP.js.map +1 -0
- package/dist/{chunk-ZSOS2KOR.js → chunk-RK6VBLXP.js} +1 -1
- package/dist/chunk-RK6VBLXP.js.map +1 -0
- package/dist/{chunk-FHYR5Q5T.js → chunk-SFY6YLVK.js} +19 -12
- package/dist/chunk-SFY6YLVK.js.map +1 -0
- package/dist/{chunk-C747DYNT.js → chunk-UM5S7DKK.js} +1 -1
- package/dist/chunk-UM5S7DKK.js.map +1 -0
- package/dist/{chunk-ILWHLGIC.js → chunk-UMQ6NBQR.js} +2 -2
- package/dist/chunk-UMQ6NBQR.js.map +1 -0
- package/dist/{chunk-7PSNXUFK.js → chunk-XD7MY6HB.js} +1 -1
- package/dist/chunk-XD7MY6HB.js.map +1 -0
- package/dist/{chunk-XVEJAFKW.js → chunk-XY3N2U6L.js} +5 -5
- package/dist/chunk-XY3N2U6L.js.map +1 -0
- package/dist/{chunk-XZWMJLIT.js → chunk-YT43MUSJ.js} +1 -1
- package/dist/chunk-YT43MUSJ.js.map +1 -0
- package/dist/{claude-code-QBWDT5RT.js → claude-code-LJ6DVXWQ.js} +24 -14
- package/dist/claude-code-LJ6DVXWQ.js.map +1 -0
- package/dist/{claude-code-FS42PXZO.js → claude-code-NMRKTAP7.js} +4 -4
- package/dist/claude-code-NMRKTAP7.js.map +1 -0
- package/dist/cli/sdk.js +7 -7
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{cline-JKEAYWVR.js → cline-JAPJNOZQ.js} +6 -6
- package/dist/cline-JAPJNOZQ.js.map +1 -0
- package/dist/{codebuddy-EB6EYPC3.js → codebuddy-GC7VAE2Y.js} +7 -7
- package/dist/codebuddy-GC7VAE2Y.js.map +1 -0
- package/dist/{codebuff-5RSXFU6G.js → codebuff-3VODFPD4.js} +6 -6
- package/dist/codebuff-3VODFPD4.js.map +1 -0
- package/dist/{codebuff-6KWBW6CT.js → codebuff-ETYT5UBL.js} +4 -4
- package/dist/codebuff-ETYT5UBL.js.map +1 -0
- package/dist/{codex-ART46CDD.js → codex-RXIS5BHM.js} +9 -9
- package/dist/codex-RXIS5BHM.js.map +1 -0
- package/dist/{codex-DKBAAUCO.js → codex-YAORPCOD.js} +4 -4
- package/dist/codex-YAORPCOD.js.map +1 -0
- package/dist/{continue-JHZCMSPH.js → continue-MECVDV4Z.js} +8 -8
- package/dist/continue-MECVDV4Z.js.map +1 -0
- package/dist/{copilot-cli-CLBJACQ5.js → copilot-cli-MZTAWMPW.js} +4 -4
- package/dist/copilot-cli-MZTAWMPW.js.map +1 -0
- package/dist/{copilot-cli-QVAU5CFM.js → copilot-cli-WVWAWNSM.js} +7 -7
- package/dist/copilot-cli-WVWAWNSM.js.map +1 -0
- package/dist/{crush-A5C5USRL.js → crush-QBXLNN7T.js} +4 -4
- package/dist/crush-QBXLNN7T.js.map +1 -0
- package/dist/{crush-7TORBYUL.js → crush-YB3SK6NK.js} +7 -7
- package/dist/crush-YB3SK6NK.js.map +1 -0
- package/dist/{cursor-D5SWDVSW.js → cursor-DIW43TRZ.js} +3 -3
- package/dist/cursor-DIW43TRZ.js.map +1 -0
- package/dist/cursor-RSLHA2CY.js +22 -0
- package/dist/{define-connector-DTWb46UB.d.ts → define-connector-odRHEC4H.d.ts} +1 -1
- package/dist/{detect-JHSA3G3U.js → detect-ALP4G7WG.js} +4 -4
- package/dist/detect-ALP4G7WG.js.map +1 -0
- package/dist/{devin-SSR7S4WX.js → devin-WPDN3MXE.js} +7 -7
- package/dist/devin-WPDN3MXE.js.map +1 -0
- package/dist/{doctor-CQJ7TZPA.js → doctor-YEQWCWZJ.js} +27 -26
- package/dist/doctor-YEQWCWZJ.js.map +1 -0
- package/dist/{droid-45PJ7JGF.js → droid-HS6MX3IL.js} +10 -8
- package/dist/droid-HS6MX3IL.js.map +1 -0
- package/dist/{droid-PFQ2PZSF.js → droid-U3ZBLQFO.js} +4 -4
- package/dist/droid-U3ZBLQFO.js.map +1 -0
- package/dist/{gemini-cli-Y6RJMU24.js → gemini-cli-NMVVBO3K.js} +4 -4
- package/dist/gemini-cli-NMVVBO3K.js.map +1 -0
- package/dist/{gemini-cli-24PFDK7D.js → gemini-cli-VJ6X5DNF.js} +8 -8
- package/dist/gemini-cli-VJ6X5DNF.js.map +1 -0
- package/dist/{goose-U5D3LCPC.js → goose-3X7ID7YW.js} +9 -9
- package/dist/goose-3X7ID7YW.js.map +1 -0
- package/dist/{goose-K2HKUTBK.js → goose-64V46Y2W.js} +4 -4
- package/dist/goose-64V46Y2W.js.map +1 -0
- package/dist/{grok-cli-L2MHAPBY.js → grok-cli-4VFVF2CQ.js} +7 -7
- package/dist/grok-cli-4VFVF2CQ.js.map +1 -0
- package/dist/{hermes-2S5JUTTJ.js → hermes-AIVUE7LX.js} +10 -8
- package/dist/hermes-AIVUE7LX.js.map +1 -0
- package/dist/{hermes-MF3NX4ZY.js → hermes-F3EGTK6N.js} +4 -4
- package/dist/hermes-F3EGTK6N.js.map +1 -0
- package/dist/{hook-VHICXHXL.js → hook-F63I3SD5.js} +17 -16
- package/dist/hook-F63I3SD5.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/{install-WLENR4KF.js → install-23WRRFBY.js} +21 -21
- package/dist/install-23WRRFBY.js.map +1 -0
- package/dist/{introspect-dNekqPDY.d.ts → introspect-gTx6GzpW.d.ts} +1 -1
- package/dist/{jetbrains-copilot-Z4FC3RM3.js → jetbrains-copilot-XBO2JZRO.js} +6 -6
- package/dist/jetbrains-copilot-XBO2JZRO.js.map +1 -0
- package/dist/{junie-ULGJJIHB.js → junie-UCOS6Q37.js} +6 -6
- package/dist/junie-UCOS6Q37.js.map +1 -0
- package/dist/{kilo-SMHPOHJ5.js → kilo-SW7BH6EG.js} +4 -4
- package/dist/kilo-SW7BH6EG.js.map +1 -0
- package/dist/{kilo-WWIJOVWD.js → kilo-T4OXNUYY.js} +8 -8
- package/dist/kilo-T4OXNUYY.js.map +1 -0
- package/dist/{kilo-cli-QKE2EQLS.js → kilo-cli-I2S3W245.js} +8 -8
- package/dist/kilo-cli-I2S3W245.js.map +1 -0
- package/dist/{kilo-cli-T2SRRRJS.js → kilo-cli-ZF272ZHN.js} +5 -5
- package/dist/kilo-cli-ZF272ZHN.js.map +1 -0
- package/dist/{kimi-MSIDEMCI.js → kimi-5FHEXGZD.js} +4 -4
- package/dist/kimi-5FHEXGZD.js.map +1 -0
- package/dist/{kimi-JMUFTVSF.js → kimi-VLSUFLYV.js} +7 -7
- package/dist/kimi-VLSUFLYV.js.map +1 -0
- package/dist/{kiro-UWUCRKR3.js → kiro-AQFXGOJX.js} +10 -8
- package/dist/kiro-AQFXGOJX.js.map +1 -0
- package/dist/{kiro-NYRRBIKW.js → kiro-WGOI5CGT.js} +4 -4
- package/dist/kiro-WGOI5CGT.js.map +1 -0
- package/dist/{leaderboard-NJWKGMXP.js → leaderboard-YBD3IKC2.js} +7 -7
- package/dist/leaderboard-YBD3IKC2.js.map +1 -0
- package/dist/{mimo-code-BPNYYIVM.js → mimo-code-KETL7W7D.js} +7 -7
- package/dist/mimo-code-KETL7W7D.js.map +1 -0
- package/dist/{mistral-vibe-LT3DAJ3L.js → mistral-vibe-3AU7N2CA.js} +6 -6
- package/dist/mistral-vibe-3AU7N2CA.js.map +1 -0
- package/dist/{mux-AHNUAY5Z.js → mux-BO2L5CTW.js} +6 -6
- package/dist/mux-BO2L5CTW.js.map +1 -0
- package/dist/{mux-7PIJ7HUQ.js → mux-XM6AP35L.js} +4 -4
- package/dist/mux-XM6AP35L.js.map +1 -0
- package/dist/{nemoclaw-RE5RZASZ.js → nemoclaw-WA7RSKF2.js} +7 -7
- package/dist/nemoclaw-WA7RSKF2.js.map +1 -0
- package/dist/{omp-D2EXEPH7.js → omp-UDYJ2PYY.js} +9 -7
- package/dist/omp-UDYJ2PYY.js.map +1 -0
- package/dist/{open-interpreter-SSGBEUKX.js → open-interpreter-WMBNM4MQ.js} +6 -6
- package/dist/open-interpreter-WMBNM4MQ.js.map +1 -0
- package/dist/openclaw-3DHVHX5P.js +17 -0
- package/dist/{openclaw-KAFTNLR2.js → openclaw-5EQFGOWL.js} +4 -4
- package/dist/openclaw-5EQFGOWL.js.map +1 -0
- package/dist/{opencode-YKUKZY3J.js → opencode-IKMI3RI7.js} +7 -7
- package/dist/opencode-IKMI3RI7.js.map +1 -0
- package/dist/{opencode-Z65JYILL.js → opencode-QGP4ALQY.js} +4 -4
- package/dist/opencode-QGP4ALQY.js.map +1 -0
- package/dist/{openhands-SEZMCUC3.js → openhands-QGXMQR6I.js} +7 -7
- package/dist/openhands-QGXMQR6I.js.map +1 -0
- package/dist/{package-JECVQEFT.js → package-TAUTPP7Z.js} +15 -15
- package/dist/package-TAUTPP7Z.js.map +1 -0
- package/dist/{pi-YPYV2ULH.js → pi-A2HCGRJG.js} +9 -7
- package/dist/pi-A2HCGRJG.js.map +1 -0
- package/dist/{pi-DLKCPOJE.js → pi-GGDQREVG.js} +4 -4
- package/dist/pi-GGDQREVG.js.map +1 -0
- package/dist/{qwen-code-ZHCLCYMC.js → qwen-code-DNQTGJOF.js} +35 -17
- package/dist/qwen-code-DNQTGJOF.js.map +1 -0
- package/dist/{qwen-code-26CSFDX6.js → qwen-code-GQILBJ5B.js} +4 -4
- package/dist/qwen-code-GQILBJ5B.js.map +1 -0
- package/dist/{roo-code-HSAE2CJU.js → roo-code-SUWI4BBN.js} +4 -4
- package/dist/roo-code-SUWI4BBN.js.map +1 -0
- package/dist/{roo-code-7F4HYB34.js → roo-code-VI2ZKTZC.js} +6 -6
- package/dist/roo-code-VI2ZKTZC.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -8
- package/dist/runtime/index.js +15 -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 +12 -11
- package/dist/{serve-LYSBH43G.js → serve-6MDLRQS2.js} +17 -16
- package/dist/serve-6MDLRQS2.js.map +1 -0
- package/dist/{status-PHKKGEW5.js → status-IUP75XHP.js} +11 -11
- package/dist/status-IUP75XHP.js.map +1 -0
- package/dist/{statusline-ZDD4OZ4F.js → statusline-PRODZV2J.js} +16 -15
- package/dist/statusline-PRODZV2J.js.map +1 -0
- package/dist/{synthetic-LUT6V6SD.js → synthetic-6FRA7P5Q.js} +4 -4
- package/dist/synthetic-6FRA7P5Q.js.map +1 -0
- package/dist/{telemetry-HDGMI2BK.js → telemetry-X4PLZEDB.js} +10 -10
- package/dist/telemetry-X4PLZEDB.js.map +1 -0
- package/dist/{trae-SIQI3C66.js → trae-CPPYASR2.js} +4 -4
- package/dist/trae-CPPYASR2.js.map +1 -0
- package/dist/{trae-Y67HSDOW.js → trae-VOJXUYRN.js} +6 -6
- package/dist/trae-VOJXUYRN.js.map +1 -0
- package/dist/{types-JyhpJHJa.d.ts → types-DWXnnx-N.d.ts} +96 -22
- package/dist/{uninstall-RWO2GM2I.js → uninstall-BSIJ4QXN.js} +21 -21
- package/dist/uninstall-BSIJ4QXN.js.map +1 -0
- package/dist/{upgrade-YJCXNUEE.js → upgrade-ZSICU3NE.js} +21 -21
- package/dist/upgrade-ZSICU3NE.js.map +1 -0
- package/dist/{usage-IWO4RQN6.js → usage-EQUNVSCT.js} +4 -4
- package/dist/usage-EQUNVSCT.js.map +1 -0
- package/dist/{usage-event-AFFKCLHE.js → usage-event-J5CQ6LNT.js} +16 -15
- package/dist/usage-event-J5CQ6LNT.js.map +1 -0
- package/dist/{vscode-copilot-5CI5B3X6.js → vscode-copilot-ZBXRPKGG.js} +7 -7
- package/dist/vscode-copilot-ZBXRPKGG.js.map +1 -0
- package/dist/{warp-5YBSP7FP.js → warp-NRBBJQR2.js} +4 -4
- package/dist/warp-NRBBJQR2.js.map +1 -0
- package/dist/{warp-INAKVGBV.js → warp-S444B2S3.js} +9 -7
- package/dist/warp-S444B2S3.js.map +1 -0
- package/dist/{windsurf-4HM57QAY.js → windsurf-R6D2JUTN.js} +6 -6
- package/dist/windsurf-R6D2JUTN.js.map +1 -0
- package/dist/{zed-YN5X37PQ.js → zed-DQV3ZUCU.js} +10 -8
- package/dist/zed-DQV3ZUCU.js.map +1 -0
- package/dist/{zed-XXCNYOIN.js → zed-XJFOOKCO.js} +4 -4
- package/dist/zed-XJFOOKCO.js.map +1 -0
- package/package.json +88 -88
- package/dist/action-IPFDPOZU.js.map +0 -1
- package/dist/amazon-q-IT44LEWV.js.map +0 -1
- package/dist/amp-CEWOSWQO.js.map +0 -1
- package/dist/amp-P35FRU2Z.js.map +0 -1
- package/dist/antigravity-LHFEFNMC.js.map +0 -1
- package/dist/antigravity-TWIWXTQH.js +0 -18
- package/dist/antigravity-cli-MOKFSWOU.js.map +0 -1
- package/dist/antigravity-cli-MPE27LPI.js.map +0 -1
- package/dist/chunk-3EP5V2F4.js.map +0 -1
- package/dist/chunk-3FINQ2ZF.js.map +0 -1
- package/dist/chunk-4GH2KA7V.js.map +0 -1
- package/dist/chunk-7C2IPIIB.js.map +0 -1
- package/dist/chunk-7HHW23AC.js.map +0 -1
- package/dist/chunk-7PSNXUFK.js.map +0 -1
- package/dist/chunk-7ZFK2WEO.js.map +0 -1
- package/dist/chunk-C63AAXK7.js.map +0 -1
- package/dist/chunk-C747DYNT.js.map +0 -1
- package/dist/chunk-FHYR5Q5T.js.map +0 -1
- package/dist/chunk-GCPEPUD7.js.map +0 -1
- package/dist/chunk-GZZCHJDP.js.map +0 -1
- package/dist/chunk-ILWHLGIC.js.map +0 -1
- package/dist/chunk-IOJDZJ72.js.map +0 -1
- package/dist/chunk-KFPSJRHR.js.map +0 -1
- package/dist/chunk-KM2YXO6V.js.map +0 -1
- package/dist/chunk-L2C5UMKW.js.map +0 -1
- package/dist/chunk-LFWYYWLV.js.map +0 -1
- package/dist/chunk-LQ55E7QI.js.map +0 -1
- package/dist/chunk-MLU7NDAZ.js.map +0 -1
- package/dist/chunk-N4ENLZEU.js.map +0 -1
- package/dist/chunk-NDMNMAKP.js.map +0 -1
- package/dist/chunk-PSGTHJQU.js.map +0 -1
- package/dist/chunk-Q4ISQHUQ.js.map +0 -1
- package/dist/chunk-Q7PR2WGT.js.map +0 -1
- package/dist/chunk-QYOUQCC6.js.map +0 -1
- package/dist/chunk-SLJI5BOM.js.map +0 -1
- package/dist/chunk-TGZFDXNH.js.map +0 -1
- package/dist/chunk-THI4PI4H.js.map +0 -1
- package/dist/chunk-UZZTWWGG.js.map +0 -1
- package/dist/chunk-WPTNMYYM.js.map +0 -1
- package/dist/chunk-XN7S44U4.js.map +0 -1
- package/dist/chunk-XVEJAFKW.js.map +0 -1
- package/dist/chunk-XXLCMSD3.js.map +0 -1
- package/dist/chunk-XZWMJLIT.js.map +0 -1
- package/dist/chunk-Y3K6KJMS.js.map +0 -1
- package/dist/chunk-ZSOS2KOR.js.map +0 -1
- package/dist/claude-code-FS42PXZO.js.map +0 -1
- package/dist/claude-code-QBWDT5RT.js.map +0 -1
- package/dist/cline-JKEAYWVR.js.map +0 -1
- package/dist/codebuddy-EB6EYPC3.js.map +0 -1
- package/dist/codebuff-5RSXFU6G.js.map +0 -1
- package/dist/codebuff-6KWBW6CT.js.map +0 -1
- package/dist/codex-ART46CDD.js.map +0 -1
- package/dist/codex-DKBAAUCO.js.map +0 -1
- package/dist/continue-JHZCMSPH.js.map +0 -1
- package/dist/copilot-cli-CLBJACQ5.js.map +0 -1
- package/dist/copilot-cli-QVAU5CFM.js.map +0 -1
- package/dist/crush-7TORBYUL.js.map +0 -1
- package/dist/crush-A5C5USRL.js.map +0 -1
- package/dist/cursor-D5SWDVSW.js.map +0 -1
- package/dist/cursor-W7I4QUFO.js +0 -22
- package/dist/detect-JHSA3G3U.js.map +0 -1
- package/dist/devin-SSR7S4WX.js.map +0 -1
- package/dist/doctor-CQJ7TZPA.js.map +0 -1
- package/dist/droid-45PJ7JGF.js.map +0 -1
- package/dist/droid-PFQ2PZSF.js.map +0 -1
- package/dist/gemini-cli-24PFDK7D.js.map +0 -1
- package/dist/gemini-cli-Y6RJMU24.js.map +0 -1
- package/dist/goose-K2HKUTBK.js.map +0 -1
- package/dist/goose-U5D3LCPC.js.map +0 -1
- package/dist/grok-cli-L2MHAPBY.js.map +0 -1
- package/dist/hermes-2S5JUTTJ.js.map +0 -1
- package/dist/hermes-MF3NX4ZY.js.map +0 -1
- package/dist/hook-VHICXHXL.js.map +0 -1
- package/dist/install-WLENR4KF.js.map +0 -1
- package/dist/jetbrains-copilot-Z4FC3RM3.js.map +0 -1
- package/dist/junie-ULGJJIHB.js.map +0 -1
- package/dist/kilo-SMHPOHJ5.js.map +0 -1
- package/dist/kilo-WWIJOVWD.js.map +0 -1
- package/dist/kilo-cli-QKE2EQLS.js.map +0 -1
- package/dist/kilo-cli-T2SRRRJS.js.map +0 -1
- package/dist/kimi-JMUFTVSF.js.map +0 -1
- package/dist/kimi-MSIDEMCI.js.map +0 -1
- package/dist/kiro-NYRRBIKW.js.map +0 -1
- package/dist/kiro-UWUCRKR3.js.map +0 -1
- package/dist/leaderboard-NJWKGMXP.js.map +0 -1
- package/dist/mimo-code-BPNYYIVM.js.map +0 -1
- package/dist/mistral-vibe-LT3DAJ3L.js.map +0 -1
- package/dist/mux-7PIJ7HUQ.js.map +0 -1
- package/dist/mux-AHNUAY5Z.js.map +0 -1
- package/dist/nemoclaw-RE5RZASZ.js.map +0 -1
- package/dist/omp-D2EXEPH7.js.map +0 -1
- package/dist/open-interpreter-SSGBEUKX.js.map +0 -1
- package/dist/openclaw-IJ33K45M.js +0 -17
- package/dist/openclaw-KAFTNLR2.js.map +0 -1
- package/dist/opencode-YKUKZY3J.js.map +0 -1
- package/dist/opencode-Z65JYILL.js.map +0 -1
- package/dist/openhands-SEZMCUC3.js.map +0 -1
- package/dist/package-JECVQEFT.js.map +0 -1
- package/dist/pi-DLKCPOJE.js.map +0 -1
- package/dist/pi-YPYV2ULH.js.map +0 -1
- package/dist/qwen-code-26CSFDX6.js.map +0 -1
- package/dist/qwen-code-ZHCLCYMC.js.map +0 -1
- package/dist/roo-code-7F4HYB34.js.map +0 -1
- package/dist/roo-code-HSAE2CJU.js.map +0 -1
- package/dist/serve-LYSBH43G.js.map +0 -1
- package/dist/status-PHKKGEW5.js.map +0 -1
- package/dist/statusline-ZDD4OZ4F.js.map +0 -1
- package/dist/synthetic-LUT6V6SD.js.map +0 -1
- package/dist/telemetry-HDGMI2BK.js.map +0 -1
- package/dist/trae-SIQI3C66.js.map +0 -1
- package/dist/trae-Y67HSDOW.js.map +0 -1
- package/dist/uninstall-RWO2GM2I.js.map +0 -1
- package/dist/upgrade-YJCXNUEE.js.map +0 -1
- package/dist/usage-IWO4RQN6.js.map +0 -1
- package/dist/usage-event-AFFKCLHE.js.map +0 -1
- package/dist/vscode-copilot-5CI5B3X6.js.map +0 -1
- package/dist/warp-5YBSP7FP.js.map +0 -1
- package/dist/warp-INAKVGBV.js.map +0 -1
- package/dist/windsurf-4HM57QAY.js.map +0 -1
- package/dist/zed-XXCNYOIN.js.map +0 -1
- package/dist/zed-YN5X37PQ.js.map +0 -1
- /package/dist/{antigravity-TWIWXTQH.js.map → antigravity-VXHL6ZPM.js.map} +0 -0
- /package/dist/{audit-3E5JAOP2.js.map → audit-BO7JQYIH.js.map} +0 -0
- /package/dist/{cursor-W7I4QUFO.js.map → cursor-RSLHA2CY.js.map} +0 -0
- /package/dist/{openclaw-IJ33K45M.js.map → openclaw-3DHVHX5P.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/openclaw/index.ts"],"sourcesContent":["/**\r\n * adapters/openclaw — OpenClaw (Gateway) platform adapter for agent-connector.\r\n *\r\n * OpenClaw is a **ts-plugin** host, but with a twist no other ts-plugin host\r\n * has: a plugin only delivers its MCP tools to the agent when it is registered\r\n * in TWO places at once (DUAL REGISTRATION):\r\n *\r\n * (a) plugins.entries.<id> = { enabled: true } + plugins.load.paths: [dir]\r\n * — so the gateway DISCOVERS and LOADS the plugin\r\n * module (runs register(api), wiring the hooks).\r\n * NOTE: the entry is { enabled } only — a per-entry\r\n * `module` field is rejected by `openclaw config\r\n * validate`, so discovery goes through the\r\n * plugins.load.paths dir scan instead; and\r\n * (b) mcp.servers.<id> — nested under a top-level \"mcp\" object, so the\r\n * plugin's MCP tools SURFACE to the agent.\r\n *\r\n * If only (a) is present, the plugin loads but ZERO tools reach the agent.\r\n * If only (b) is present, the tools are declared but the hook bridge never\r\n * loads. context-mode's own adapter proved this empirically against OpenClaw\r\n * 2026.4.22 (src/adapters/openclaw/index.ts checkPluginRegistration: \"in\r\n * plugins.entries but missing from mcp.servers — plugin loads but no ctx_*\r\n * tools reach the agent\"). So getHealthChecks() FAILS when the two are\r\n * inconsistent (entries XOR mcp.servers).\r\n *\r\n * Why we BRIDGE instead of importing handlers (mirrors the OpenCode adapter):\r\n * context-mode could load ITS OWN plugin in-process because the handler code\r\n * shipped with the package. agent-connector cannot: the connector's hook\r\n * handlers are arbitrary developer code we must not import into the gateway's\r\n * runtime (wrong cwd, wrong deps, version skew). So installHooks synthesizes a\r\n * tiny, fully self-contained ESM plugin module — { id, name, configSchema,\r\n * register(api) } — that imports NOTHING from agent-connector and, on each\r\n * hook firing, shells out to the ONE stable home binary's universal entrypoint\r\n * <homeBin> hook openclaw <event> --connector <id>\r\n * feeding the event payload on stdin and JSON.parsing the normalized\r\n * HookResponse back from stdout. Fail-open: any bridge error → no-op. The same\r\n * universal json-stdio dispatcher every other host uses thus serves OpenClaw.\r\n *\r\n * Plugin module shape (grounded in context-mode build/adapters/openclaw/plugin.js):\r\n * export default { id, name, configSchema, register(api) }\r\n * register(api) wires typed lifecycle hooks via api.on(event, handler):\r\n * before_tool_call → block (return { block, blockReason }) / rewrite args\r\n * (mutate event.params in place); deny+ask both block.\r\n * after_tool_call → observe (capture result/output).\r\n * session_start → record the real session id.\r\n * before_prompt_build → inject context (fires PER TURN; no blocking). ONE\r\n * handler serves two events via separate state: SessionStart\r\n * additionalContext via { appendSystemContext } ONCE (the\r\n * verified injection point — session_start itself returns no\r\n * context payload) AND UserPromptSubmit additionalContext via\r\n * { appendContext } EVERY turn (context-injection only — a\r\n * block/deny decision degrades to a no-op).\r\n * subagent_spawned / subagent_ended → observe the subagent lifecycle\r\n * (SubagentStart / SubagentStop; observe-only — no\r\n * decision or context payload).\r\n * api.on() is the correct API for typed lifecycle hooks; api.registerHook() is\r\n * for generic command hooks. We register defensively (api.on present check).\r\n *\r\n * Config file (JSON5 / JSONC — PARSE TOLERANTLY):\r\n * user scope → resolveOpenClawConfigPath():\r\n * $OPENCLAW_CONFIG_PATH\r\n * else $OPENCLAW_STATE_DIR/openclaw.json\r\n * else ~/.openclaw/openclaw.json\r\n * (mirrors context-mode openclawConfigPath — the file the\r\n * gateway actually loads, NOT process.cwd()).\r\n * project scope → <projectDir>/openclaw.json (also supported).\r\n * openclaw.json may contain comments + trailing commas (JSON5), so we NEVER\r\n * use strict JSON.parse — readJson is overridden to strip comments/commas\r\n * first via the shared core/jsonc parseJsonc. writes are strict JSON\r\n * (idempotent, comment-free).\r\n *\r\n * Plugin module location (project | user):\r\n * user → <stateDir>/extensions/<id>/index.mjs (stateDir = dir of openclaw.json)\r\n * project → <projectDir>/.openclaw/extensions/<id>/index.mjs\r\n * Beside index.mjs we also emit an openclaw.plugin.json manifest\r\n * { id, name, main, enabled, configSchema }. `configSchema` is REQUIRED —\r\n * `openclaw config validate` rejects a manifest without it (\"plugin manifest\r\n * requires configSchema\"); our plugin takes no user config, so it is the empty\r\n * closed object schema { type: \"object\", additionalProperties: false }. The\r\n * plugin's DIRECTORY (not the file) is added to plugins.load.paths so the\r\n * gateway scans it and loads the module; the plugins.entries.<id> =\r\n * { enabled: true } half then activates it. (There is no per-entry \"module\"\r\n * field — validate rejects it.)\r\n *\r\n * The gateway hot-reloads its config on SIGUSR1 — no action needed here; the\r\n * next reload (or restart) picks up our entries/servers/module.\r\n *\r\n * Capabilities (per OpenClaw hook API):\r\n * preToolUse / postToolUse / sessionStart / userPromptSubmit / subagentStart /\r\n * subagentStop true; supportsNativeHooks true; transports [\"stdio\"].\r\n * before_tool_call mutates event.params → canModifyArgs true.\r\n * after_tool_call cannot rewrite the tool result → canModifyOutput false.\r\n * before_prompt_build injects context → canInjectSessionContext true; it has\r\n * no blocking ability, so userPromptSubmit is context-injection-only.\r\n */\r\n\r\nimport { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { dirname, join, resolve } from \"node:path\";\r\n\r\nimport { BaseAdapter } from \"../base.js\";\r\nimport type {\r\n Adapter,\r\n GeneratedPluginFile,\r\n HookReply,\r\n InstallContext,\r\n MemoryTarget,\r\n NormalizedEvent,\r\n} from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookEventName,\r\n HookParadigm,\r\n HookResponse,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionStartEvent,\r\n SubagentStartEvent,\r\n SubagentStopEvent,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport { parseJsonc } from \"../../core/jsonc.js\";\r\nimport {\r\n buildWrappedStdio,\r\n} from \"../../core/spawn.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\n\r\nconst HOST: PlatformId = \"openclaw\";\r\n\r\n/**\r\n * MCP servers live nested under the top-level \"mcp\" object: mcp.servers.<id>\r\n * (NOT a top-level \"mcpServers\" key). plugins.entries.<id> is the second half of\r\n * the dual registration.\r\n */\r\nconst MCP_ROOT_KEY = \"mcp\";\r\nconst MCP_SERVERS_KEY = \"servers\";\r\nconst PLUGINS_KEY = \"plugins\";\r\nconst PLUGINS_ENTRIES_KEY = \"entries\";\r\n/**\r\n * The gateway discovers a synthesized plugin module by scanning the directories\r\n * listed in plugins.load.paths — it does NOT take a per-entry `module` field\r\n * (that fails `openclaw config validate`). We add the plugin's own dir here.\r\n */\r\nconst PLUGINS_LOAD_KEY = \"load\";\r\nconst PLUGINS_LOAD_PATHS_KEY = \"paths\";\r\n/** Manifest the gateway reads inside a plugins.load.paths directory. */\r\nconst PLUGIN_MANIFEST_FILE = \"openclaw.plugin.json\";\r\n\r\n/**\r\n * Canonical → OpenClaw event name map. A connector hook event is only emitted by\r\n * the generated plugin when it appears here AND is declared by the connector.\r\n *\r\n * SessionStart maps to OpenClaw's session_start (to learn the real session id)\r\n * plus before_prompt_build (the verified context-injection point — session_start\r\n * itself returns no context payload upstream).\r\n *\r\n * UserPromptSubmit also maps to before_prompt_build, which fires PER TURN (every\r\n * prompt build) and can ONLY inject context (prependContext / appendContext /\r\n * *SystemContext) — it has NO blocking ability. So UserPromptSubmit here is\r\n * CONTEXT-INJECTION-ONLY: a connector handler returning a block/deny decision\r\n * DEGRADES to a no-op (the generated bridge injects nothing). The two events\r\n * coexist in one before_prompt_build handler via separate state (the once-only\r\n * SessionStart flag must never suppress the per-turn UserPromptSubmit injection).\r\n */\r\nconst EVENT_TO_OPENCLAW: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: \"before_tool_call\",\r\n PostToolUse: \"after_tool_call\",\r\n SessionStart: \"session_start\",\r\n // Per-turn context injection at prompt assembly (context-only, no blocking).\r\n UserPromptSubmit: \"before_prompt_build\",\r\n // Subagent lifecycle: OpenClaw observes launch + completion (no decision\r\n // control on either). PermissionRequest is deliberately ABSENT — OpenClaw's\r\n // permission gate is the requireApproval RETURN VALUE of before_tool_call,\r\n // not an observable event; PostToolUseFailure is ABSENT too (a failure\r\n // arrives merged into after_tool_call, already surfaced as PostToolUse\r\n // isError). Unmapped declared events are reported as \"unsupported here\".\r\n SubagentStart: \"subagent_spawned\",\r\n SubagentStop: \"subagent_ended\",\r\n};\r\n\r\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\r\ninterface OpenClawBridgePayload {\r\n toolName?: string;\r\n toolInput?: Record<string, unknown>;\r\n toolOutput?: string;\r\n isError?: boolean;\r\n sessionId?: string;\r\n source?: string;\r\n projectDir?: string;\r\n // UserPromptSubmit (before_prompt_build): the current prompt text.\r\n prompt?: string;\r\n // subagent_spawned / subagent_ended. The generated plugin projects the host's\r\n // REAL native fields here (verified against openclaw/openclaw\r\n // src/plugins/hook-types.ts): SubagentStart agentId←e.agentId,\r\n // agentType←e.label (the host's only descriptor); SubagentStop\r\n // agentId←e.targetSessionKey (its ONLY identity). The host emits no agentType\r\n // and no result/output on subagent_ended, so those slots are simply omitted —\r\n // we never post invented field names. Empty strings are dropped.\r\n agentId?: string;\r\n agentType?: string;\r\n lastAssistantMessage?: string;\r\n}\r\n\r\n/**\r\n * Native MCP server entry shapes OpenClaw accepts under mcp.servers.<id>.\r\n *\r\n * A stdio sidecar carries NO `transport` field: OpenClaw's config validator\r\n * only accepts `transport: \"sse\" | \"streamable-http\"` for remote servers and\r\n * REJECTS `transport: \"stdio\"` (verified against OpenClaw 2026.6.1). A stdio\r\n * server is INFERRED from the presence of `command`, so we must never write a\r\n * transport key here.\r\n */\r\ninterface OpenClawStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n enabled?: boolean;\r\n}\r\ninterface OpenClawRemoteServer {\r\n url: string;\r\n transport: \"sse\" | \"streamable-http\";\r\n headers?: Record<string, string>;\r\n enabled?: boolean;\r\n}\r\n\r\n/**\r\n * plugins.entries.<id> reference shape.\r\n *\r\n * `openclaw config validate` REJECTS a `module` field here (it is not part of\r\n * the entry schema), so the entry is `{ enabled: true }` ONLY. Discovery of the\r\n * synthesized module is wired separately via `plugins.load.paths` (the dir that\r\n * holds the module + its openclaw.plugin.json manifest).\r\n */\r\ninterface OpenClawPluginEntry {\r\n enabled: boolean;\r\n}\r\n\r\nexport class OpenClawAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n // Declared as `string` (not the literal \"OpenClaw\") so a fork adapter can\r\n // override it — NemoClaw extends this class (precedent: AntigravityAdapter,\r\n // whose name is likewise typed `string` for AntigravityCliAdapter).\r\n readonly name: string = \"OpenClaw\";\r\n readonly paradigm: HookParadigm = \"ts-plugin\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block. OpenClaw's AGENTS.md\r\n // lives in the AGENT WORKSPACE (default ~/.openclaw/workspace), NOT the\r\n // user's repo — memoryTargets below maps BOTH scopes there (R2:\r\n // platforms force scopes; personal-assistant semantics, no project file).\r\n supportsMemory: true,\r\n preToolUse: true,\r\n postToolUse: true,\r\n // OpenClaw compaction is owned by a context engine, not wired through the\r\n // universal bridge here.\r\n preCompact: false,\r\n sessionStart: true,\r\n sessionEnd: false,\r\n // before_prompt_build fires per-turn and injects context (no blocking), so\r\n // UserPromptSubmit is supported as CONTEXT-INJECTION-ONLY: a block/deny\r\n // decision degrades to a no-op (it cannot stop the prompt here).\r\n userPromptSubmit: true,\r\n stop: false,\r\n notification: false,\r\n // Newer events: OpenClaw observes the full subagent lifecycle via\r\n // subagent_spawned / subagent_ended (observe-only — no decision control,\r\n // so a SubagentStop \"deny\" cannot keep the subagent running here).\r\n // permissionRequest / postToolUseFailure stay unset: the permission gate\r\n // is a RETURN VALUE of before_tool_call (not an event) and tool failures\r\n // arrive merged into after_tool_call. Install reports the standard\r\n // \"unsupported here\" for unmapped declared events.\r\n subagentStart: true,\r\n subagentStop: true,\r\n // before_tool_call mutates event.params in place → input rewrite supported.\r\n canModifyArgs: true,\r\n // after_tool_call observes but cannot rewrite the tool result upstream.\r\n canModifyOutput: false,\r\n // injected via before_prompt_build at prompt assembly.\r\n canInjectSessionContext: true,\r\n // stdio sidecars + remote servers. OpenClaw's validator accepts a remote\r\n // transport of \"sse\" | \"streamable-http\" (AC \"http\" → \"streamable-http\");\r\n // verified against OpenClaw 2026.6.1 + docs.openclaw.ai/gateway/configuration-reference.\r\n transports: [\"stdio\", \"sse\", \"http\"],\r\n // Content surface: OpenClaw follows the AgentSkills spec (dir-per-skill\r\n // SKILL.md with {name, description} frontmatter + body). User scope →\r\n // ~/.openclaw/skills (the `openclaw skills install --global` target);\r\n // project scope → the resolved <workspace>/skills (the highest-priority\r\n // documented skill root, the same workspace the memory surface anchors to).\r\n supportsSkills: true,\r\n // Action surface: each declared action becomes a user-invokable slash\r\n // command registered INSIDE the generated plugin module (api.registerCommand),\r\n // shelling out to the home-bin action verb with the install target baked as\r\n // the host token (this.id), so a fork like NemoClaw emits `action nemoclaw`.\r\n // supportsActions -> the installActions/uninstallActions overrides below.\r\n supportsActions: true,\r\n // Native passthrough: OpenClaw lifecycle hook names with no canonical analog\r\n // (declared on platforms.<id>.nativeHooks) are bridged verbatim by the\r\n // generated plugin via the same on(...) helper → home-bin runNativeHook\r\n // dispatch (mirrors omp/opencode). Independent of hooks:false.\r\n supportsNativeHooks: true,\r\n };\r\n\r\n // ── Tolerant JSON5/JSONC read (override base strict JSON.parse) ──────────\r\n\r\n /**\r\n * openclaw.json is officially JSON5 (comments + trailing commas allowed). A\r\n * strict JSON.parse false-fails a perfectly valid commented file, so we strip\r\n * comments and trailing commas before parsing. Writes remain strict JSON\r\n * (writeJson in BaseAdapter), which is itself valid JSON5 — so round-trips\r\n * stay safe and idempotent.\r\n */\r\n protected override readJson<T = Record<string, unknown>>(path: string): T | null {\r\n if (!existsSync(path)) return null;\r\n let raw: string;\r\n try {\r\n raw = readFileSync(path, \"utf8\");\r\n } catch {\r\n return null;\r\n }\r\n try {\r\n // Shared, string-aware JSONC stripper (the local stripJsonish whose\r\n // trailing-comma regex corrupted in-string \",]\"/\",}\"-like values is gone).\r\n return parseJsonc<T>(raw);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n // ── Memory surface: agent-workspace AGENTS.md (both scopes) ─────────────\r\n /**\r\n * OpenClaw loads AGENTS.md (operating instructions) from its AGENT WORKSPACE\r\n * every session — `agents.defaults.workspace` in openclaw.json when set,\r\n * else `<stateDir>/workspace` (default ~/.openclaw/workspace). That file is\r\n * personal-assistant state, NOT a repo file, so a \"project scope\" write does\r\n * not apply: BOTH scopes map to the workspace (R2: platforms force scopes),\r\n * with the reason string flagging the semantics.\r\n */\r\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n if (this.memoryOverride(ctx)?.path) return super.memoryTargets(ctx);\r\n if (ctx.scope !== \"project\" && ctx.scope !== \"user\") return [];\r\n return [\r\n {\r\n path: join(this.resolveWorkspace(), \"AGENTS.md\"),\r\n reason:\r\n \"openclaw agent-workspace AGENTS.md (workspace-scoped operating instructions, \" +\r\n \"not the project repo — both scopes map here)\",\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Resolve OpenClaw's AGENT WORKSPACE — `agents.defaults.workspace` in\r\n * openclaw.json when set, else `<stateDir>/workspace` (default\r\n * ~/.openclaw/workspace). The same root the memory surface and the\r\n * project-scope skills surface both anchor to, so they never diverge.\r\n */\r\n private resolveWorkspace(): string {\r\n const configPath = resolveOpenClawConfigPath();\r\n const cfg = this.readJson<{ agents?: { defaults?: { workspace?: unknown } } }>(configPath);\r\n const declared = cfg?.agents?.defaults?.workspace;\r\n return typeof declared === \"string\" && declared.trim() !== \"\"\r\n ? declared.startsWith(\"~\")\r\n ? resolve(homedir(), declared.replace(/^~[/\\\\]?/, \"\"))\r\n : resolve(declared)\r\n : join(dirname(configPath), \"workspace\");\r\n }\r\n\r\n // ── Detection ──────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userConfig = resolveOpenClawConfigPath();\r\n const userDir = join(homedir(), \".openclaw\");\r\n const projectConfig = join(projectDir, \"openclaw.json\");\r\n\r\n // Fork-before-parent at DETECTION: NemoClaw DRIVES ~/.openclaw/openclaw.json,\r\n // so on a NemoClaw box (its ~/.nemoclaw/ marker present) the user-scope\r\n // OpenClaw config is nemoclaw-OWNED — defer so the planner does not double-\r\n // target the shared file as two platforms (an `uninstall openclaw` would\r\n // otherwise strip the connector's entries out from under nemoclaw). The\r\n // NemoClaw adapter overrides detectInstalled, so it is unaffected by this.\r\n const deferToNemoClaw = existsSync(join(homedir(), \".nemoclaw\"));\r\n const userInstalled =\r\n !deferToNemoClaw && (existsSync(userConfig) || existsSync(userDir));\r\n const projInstalled = existsSync(projectConfig);\r\n const installed = userInstalled || projInstalled;\r\n\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projectConfig : userConfig;\r\n\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? scope === \"project\"\r\n ? `found project OpenClaw config at ${projectConfig}`\r\n : `found OpenClaw config at ${configPath}`\r\n : `no OpenClaw config at ${userConfig} or ${userDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ───────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? ctx.projectDir\r\n : dirname(resolveOpenClawConfigPath());\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \"openclaw.json\")\r\n : resolveOpenClawConfigPath();\r\n }\r\n\r\n /**\r\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\r\n * OpenClaw additionally needs the plugins.entries reference written into\r\n * openclaw.json (handled in installHooks); this is the module on disk.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.pluginDir(ctx), this.pluginFileName());\r\n }\r\n\r\n /** Extensions directory the synthesized plugin module is written into. */\r\n private pluginDir(ctx: InstallContext): string {\r\n const base =\r\n ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".openclaw\")\r\n : dirname(resolveOpenClawConfigPath());\r\n return join(base, \"extensions\", ctx.connector.id);\r\n }\r\n\r\n /** Plugin module file name (ESM so the gateway loads it without a loader). */\r\n private pluginFileName(): string {\r\n return \"index.mjs\";\r\n }\r\n\r\n // ── MCP server install / uninstall (mcp.servers.<id>) ───────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const server = this.effectiveServer(ctx);\r\n const serverPath = this.getServerConfigPath(ctx);\r\n\r\n if (!server) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: serverPath,\r\n detail: ctx.connector.server\r\n ? \"server registration disabled for openclaw\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\r\n const entry = this.renderServerEntry(ctx, server);\r\n return [this.upsertNestedServer(serverPath, ctx.connector.id, entry, ctx.dryRun)];\r\n }\r\n\r\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\r\n const serverPath = this.getServerConfigPath(ctx);\r\n return [this.removeNestedServer(serverPath, ctx.connector.id, ctx.dryRun)];\r\n }\r\n\r\n /** Resolve the per-platform server override into an effective ServerDef. */\r\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\r\n const override = ctx.connector.platforms[this.id]?.server;\r\n if (override === false) return undefined;\r\n const base = ctx.connector.server;\r\n if (!base) return undefined;\r\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\r\n }\r\n\r\n /**\r\n * Render a normalized ServerDef into OpenClaw's native mcp.servers.<id> entry.\r\n *\r\n * stdio → { command, args?, env? } (NO transport key — a stdio sidecar is\r\n * inferred from `command`; OpenClaw's validator rejects\r\n * transport:\"stdio\" and only accepts \"sse\"/\"streamable-http\")\r\n * remote → { url, transport: \"sse\"|\"streamable-http\", headers? }\r\n *\r\n * OpenClaw documents no native ${env:VAR} token, so refs resolve to literals.\r\n */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): OpenClawStdioServer | OpenClawRemoteServer {\r\n if (server.transport === \"stdio\") {\r\n let command = server.command ?? \"\";\r\n let args = [...(server.args ?? [])];\r\n\r\n // Transparent telemetry wrapping: route the real command through\r\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\r\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n // NO `transport` key: OpenClaw infers a stdio sidecar from `command` and\r\n // its validator rejects transport:\"stdio\" (only \"sse\"/\"streamable-http\").\r\n const entry: OpenClawStdioServer = {\r\n command: resolveEnvRefsDeep(command),\r\n };\r\n const resolvedArgs = resolveEnvRefsDeep(args).filter((s) => s !== \"\");\r\n if (resolvedArgs.length > 0) entry.args = resolvedArgs;\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.env = env;\r\n if (server.enabled === false) entry.enabled = false;\r\n return entry;\r\n }\r\n\r\n // sse / http → OpenClaw registers a remote URL sidecar. AC's canonical\r\n // \"http\" (streamable HTTP) maps to OpenClaw's literal \"streamable-http\" — its\r\n // validator rejects a bare \"http\" transport value.\r\n const transport: \"sse\" | \"streamable-http\" =\r\n server.transport === \"http\" ? \"streamable-http\" : \"sse\";\r\n const entry: OpenClawRemoteServer = {\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n transport,\r\n };\r\n if (server.headers && Object.keys(server.headers).length > 0) {\r\n entry.headers = resolveEnvRefsDeep({ ...server.headers });\r\n }\r\n if (server.enabled === false) entry.enabled = false;\r\n return entry;\r\n }\r\n\r\n /** Resolve every ${env:VAR} in env values to literals (no native token). */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n /** Upsert config.mcp.servers.<id> idempotently. */\r\n private upsertNestedServer(\r\n path: string,\r\n id: string,\r\n entry: unknown,\r\n dryRun: boolean,\r\n ): ChangeRecord {\r\n // OVERWRITE GUARD: never blank a present-but-unparseable openclaw.json.\r\n if (this.isPresentButUnparseable(path)) {\r\n return {\r\n platform: this.id,\r\n action: \"warn\",\r\n path,\r\n detail: `existing ${path} is not parseable; left untouched (back it up / fix it, then re-run)`,\r\n };\r\n }\r\n const cfg = this.readJson<Record<string, unknown>>(path) ?? {};\r\n const servers = this.nestedServersBucket(cfg);\r\n const before = JSON.stringify(servers[id]);\r\n const after = JSON.stringify(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 servers[id] = entry;\r\n this.writeJson(path, cfg, dryRun);\r\n }\r\n return {\r\n platform: this.id,\r\n action,\r\n path,\r\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\r\n };\r\n }\r\n\r\n /** Remove config.mcp.servers.<id>. */\r\n private removeNestedServer(path: string, id: string, dryRun: boolean): ChangeRecord {\r\n const cfg = this.readJson<Record<string, unknown>>(path);\r\n const mcp = cfg?.[MCP_ROOT_KEY];\r\n const servers =\r\n mcp && typeof mcp === \"object\" && !Array.isArray(mcp)\r\n ? ((mcp as Record<string, unknown>)[MCP_SERVERS_KEY] as\r\n | Record<string, unknown>\r\n | undefined)\r\n : undefined;\r\n if (!cfg || !servers || !(id in servers)) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id} absent`,\r\n };\r\n }\r\n delete servers[id];\r\n this.writeJson(path, cfg, dryRun);\r\n return {\r\n platform: this.id,\r\n action: \"remove\",\r\n path,\r\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\r\n };\r\n }\r\n\r\n /** Get-or-create config.mcp.servers as a mutable object. */\r\n private nestedServersBucket(cfg: Record<string, unknown>): Record<string, unknown> {\r\n let mcp = cfg[MCP_ROOT_KEY];\r\n if (!mcp || typeof mcp !== \"object\" || Array.isArray(mcp)) {\r\n mcp = {};\r\n cfg[MCP_ROOT_KEY] = mcp;\r\n }\r\n const mcpObj = mcp as Record<string, unknown>;\r\n let servers = mcpObj[MCP_SERVERS_KEY];\r\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\r\n servers = {};\r\n mcpObj[MCP_SERVERS_KEY] = servers;\r\n }\r\n return servers as Record<string, unknown>;\r\n }\r\n\r\n // ── Hook install / uninstall (ts-plugin + DUAL REGISTRATION) ────────────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n\r\n // `hooks: false` disables only the CANONICAL (normalized) events; nativeHooks\r\n // is a sibling, openclaw-scoped declaration that SURVIVES the opt-out (mirrors\r\n // omp/opencode). The canonicalOff guard in buildPluginSource still suppresses\r\n // the canonical api.on handlers, so a hooks:false + nativeHooks connector\r\n // wires ONLY the native passthrough.\r\n const canonicalDisabled = ctx.connector.platforms[this.id]?.hooks === false;\r\n const hasCanonical = !canonicalDisabled && ctx.connector.hookEvents.length > 0;\r\n const hasNative = this.nativeHookEvents(ctx).length > 0;\r\n\r\n // Empty-events gate: the plugin module is SHARED with the action surface, so\r\n // a connector with actions-but-no-hooks still needs it written + registered —\r\n // but that is installActions' job (it calls ensurePlugin too). installHooks\r\n // only writes when there ARE hooks (canonical or native); its skip detail\r\n // stays honest about why.\r\n if (!hasCanonical && !hasNative) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: pluginPath,\r\n detail: canonicalDisabled\r\n ? `hooks disabled for ${this.id}`\r\n : this.actionTriggers(ctx).length > 0\r\n ? \"no hooks (plugin written for actions)\"\r\n : \"connector declares no hooks\",\r\n },\r\n ];\r\n }\r\n\r\n return this.ensurePlugin(ctx, `openclaw plugin module (${this.hookDetail(ctx)})`);\r\n }\r\n\r\n // ── Action install / uninstall (slash commands in the shared plugin) ────\r\n\r\n /**\r\n * Each declared action becomes an `api.registerCommand(...)` inside the SAME\r\n * synthesized plugin module (see buildPluginSource). So installActions ensures\r\n * that shared module is on disk AND dual-registered: when hooks already wrote\r\n * the identical bytes the content-compare yields \"skip\" (no double material\r\n * write), and an actions-only connector gets the plugin written + registered\r\n * here. Honors platforms.<id>.actions === false and the empty-actions skip.\r\n */\r\n override installActions(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n if (ctx.connector.platforms[this.id]?.actions === false) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: `actions disabled for ${this.id}` },\r\n ];\r\n }\r\n if (this.actionTriggers(ctx).length === 0) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"connector declares no actions\" },\r\n ];\r\n }\r\n return this.ensurePlugin(ctx, \"openclaw plugin module (action commands)\");\r\n }\r\n\r\n /**\r\n * Actions live INSIDE the shared plugin module, which uninstallHooks removes\r\n * (file + manifest + dual-registration entry) unconditionally — it runs last\r\n * in the teardown pass. Removing the plugin here too would race uninstallHooks,\r\n * so this is a single informational skip.\r\n */\r\n override uninstallActions(ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: this.getHookConfigPath(ctx),\r\n detail: \"action commands are embedded in the plugin module; removed by uninstallHooks\",\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Synthesize + content-compare-write the plugin module(s) AND upsert the dual-\r\n * registration entry. Shared by installHooks and installActions: the generator\r\n * is a pure function of ctx, so whichever surface runs second sees byte-\r\n * identical files (and an already-present entry) and reports \"skip\" — no double\r\n * material write. `moduleDetail` flavors the module ChangeRecord per surface.\r\n */\r\n private ensurePlugin(ctx: InstallContext, moduleDetail: string): ChangeRecord[] {\r\n const configPath = this.getServerConfigPath(ctx);\r\n const changes: ChangeRecord[] = [];\r\n\r\n // 1. Write the synthesized plugin module(s).\r\n for (const file of this.synthesizePlugin(ctx)) {\r\n changes.push(\r\n this.writeManagedFile(file.path, file.contents, ctx.dryRun, moduleDetail, file.executable),\r\n );\r\n }\r\n\r\n // 2. DUAL REGISTRATION half (a): enable plugins.entries.<id> AND add the\r\n // plugin DIR to plugins.load.paths so the gateway discovers + loads the\r\n // module. (half (b), mcp.servers.<id>, is written by installServer — both\r\n // are required for tools to reach the agent.)\r\n changes.push(this.upsertPluginEntry(configPath, ctx, this.pluginDir(ctx)));\r\n\r\n return changes;\r\n }\r\n\r\n /**\r\n * Human-facing summary of which declared events the synthesized module ACTUALLY\r\n * wires. Only events present in EVENT_TO_OPENCLAW are mapped/wired; any declared\r\n * event with no OpenClaw mapping (e.g. UserPromptSubmit) is reported separately\r\n * as \"unsupported here\" so the detail never overstates coverage.\r\n */\r\n private hookDetail(ctx: InstallContext): string {\r\n const declared =\r\n ctx.connector.platforms[this.id]?.hooks === false\r\n ? []\r\n : ctx.connector.hookEvents;\r\n const mapped = declared.filter((e) => EVENT_TO_OPENCLAW[e] !== undefined);\r\n const unsupported = declared.filter((e) => EVENT_TO_OPENCLAW[e] === undefined);\r\n const native = this.nativeHookEvents(ctx);\r\n const parts: string[] = [];\r\n if (mapped.length > 0) parts.push(mapped.join(\",\"));\r\n if (native.length > 0) parts.push(`native: ${native.join(\",\")}`);\r\n const base = parts.join(\"; \") || \"no canonical hooks\";\r\n return unsupported.length > 0\r\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\r\n : base;\r\n }\r\n\r\n /**\r\n * OpenClaw-native passthrough events declared on platforms.<id>.nativeHooks\r\n * (host lifecycle hook names with no canonical HookEventName). Emitted as\r\n * generic on(...) bridge registrations and dispatched host-generically by the\r\n * home-bin's runNativeHook. Independent of hooks:false (supportsNativeHooks).\r\n */\r\n private nativeHookEvents(ctx: InstallContext): string[] {\r\n return Object.keys(ctx.connector.platforms[this.id]?.nativeHooks ?? {});\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const configPath = this.getServerConfigPath(ctx);\r\n const changes: ChangeRecord[] = [];\r\n\r\n // 1. Remove the plugins.entries.<id> reference AND drop the plugin dir from\r\n // plugins.load.paths.\r\n changes.push(\r\n this.removePluginEntry(configPath, ctx.connector.id, this.pluginDir(ctx), ctx.dryRun),\r\n );\r\n\r\n // 2. Remove the plugin module + its manifest on disk.\r\n const manifestPath = join(this.pluginDir(ctx), PLUGIN_MANIFEST_FILE);\r\n for (const [path, label] of [\r\n [pluginPath, \"openclaw plugin module\"],\r\n [manifestPath, \"openclaw plugin manifest\"],\r\n ] as const) {\r\n if (existsSync(path)) {\r\n changes.push(this.removeManagedFile(path, ctx.dryRun, label, `no ${label} present`));\r\n } else {\r\n changes.push({\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `no ${label} present`,\r\n });\r\n }\r\n }\r\n\r\n // 3. Drop the now-empty plugin dir (only if WE own its full contents).\r\n changes.push(this.removeDirIfEmpty(this.pluginDir(ctx), ctx.dryRun));\r\n\r\n return changes;\r\n }\r\n\r\n /**\r\n * Upsert plugins.entries.<id> = { enabled: true } AND add `pluginDir` to\r\n * plugins.load.paths idempotently.\r\n *\r\n * `openclaw config validate` rejects a per-entry `module` field, so the entry\r\n * carries ONLY `{ enabled: true }`. The gateway discovers the synthesized\r\n * module by scanning the directories in plugins.load.paths (the dir holding\r\n * index.mjs + openclaw.plugin.json), so the dir is added there.\r\n */\r\n private upsertPluginEntry(\r\n configPath: string,\r\n ctx: InstallContext,\r\n pluginDir: string,\r\n ): ChangeRecord {\r\n // OVERWRITE GUARD: never blank a present-but-unparseable openclaw.json.\r\n if (this.isPresentButUnparseable(configPath)) {\r\n return {\r\n platform: this.id,\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 const cfg = this.readJson<Record<string, unknown>>(configPath) ?? {};\r\n const entries = this.pluginEntriesBucket(cfg);\r\n const id = ctx.connector.id;\r\n const desired: OpenClawPluginEntry = { enabled: true };\r\n const entryBefore = JSON.stringify(entries[id]);\r\n const entryAfter = JSON.stringify(desired);\r\n\r\n // plugins.load.paths: add the plugin dir if absent.\r\n const loadPaths = this.pluginLoadPathsBucket(cfg);\r\n const pathPresent = loadPaths.includes(pluginDir);\r\n\r\n const entryChanged = entryBefore !== entryAfter;\r\n const pathChanged = !pathPresent;\r\n let action: ChangeRecord[\"action\"];\r\n if (entryBefore === undefined) action = \"create\";\r\n else if (!entryChanged && !pathChanged) action = \"skip\";\r\n else action = \"update\";\r\n\r\n if (action !== \"skip\") {\r\n entries[id] = desired;\r\n if (!pathPresent) loadPaths.push(pluginDir);\r\n this.writeJson(configPath, cfg, ctx.dryRun);\r\n }\r\n return {\r\n platform: this.id,\r\n action,\r\n path: configPath,\r\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}`,\r\n };\r\n }\r\n\r\n /** Remove plugins.entries.<id> AND drop `pluginDir` from plugins.load.paths. */\r\n private removePluginEntry(\r\n configPath: string,\r\n id: string,\r\n pluginDir: string,\r\n dryRun: boolean,\r\n ): ChangeRecord {\r\n const cfg = this.readJson<Record<string, unknown>>(configPath);\r\n const plugins = cfg?.[PLUGINS_KEY];\r\n const pluginsObj =\r\n plugins && typeof plugins === \"object\" && !Array.isArray(plugins)\r\n ? (plugins as Record<string, unknown>)\r\n : undefined;\r\n const entries = pluginsObj?.[PLUGINS_ENTRIES_KEY] as\r\n | Record<string, unknown>\r\n | undefined;\r\n const load = pluginsObj?.[PLUGINS_LOAD_KEY] as Record<string, unknown> | undefined;\r\n const loadPaths =\r\n load && Array.isArray(load[PLUGINS_LOAD_PATHS_KEY])\r\n ? (load[PLUGINS_LOAD_PATHS_KEY] as unknown[])\r\n : undefined;\r\n\r\n const entryPresent = Boolean(entries && id in entries);\r\n const pathIdx = loadPaths ? loadPaths.indexOf(pluginDir) : -1;\r\n\r\n if (!cfg || (!entryPresent && pathIdx < 0)) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} absent`,\r\n };\r\n }\r\n if (entryPresent && entries) delete entries[id];\r\n if (loadPaths && pathIdx >= 0) loadPaths.splice(pathIdx, 1);\r\n this.writeJson(configPath, cfg, dryRun);\r\n return {\r\n platform: this.id,\r\n action: \"remove\",\r\n path: configPath,\r\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}`,\r\n };\r\n }\r\n\r\n /** Get-or-create config.plugins.entries as a mutable object. */\r\n private pluginEntriesBucket(cfg: Record<string, unknown>): Record<string, unknown> {\r\n let plugins = cfg[PLUGINS_KEY];\r\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) {\r\n plugins = {};\r\n cfg[PLUGINS_KEY] = plugins;\r\n }\r\n const pluginsObj = plugins as Record<string, unknown>;\r\n let entries = pluginsObj[PLUGINS_ENTRIES_KEY];\r\n if (!entries || typeof entries !== \"object\" || Array.isArray(entries)) {\r\n entries = {};\r\n pluginsObj[PLUGINS_ENTRIES_KEY] = entries;\r\n }\r\n return entries as Record<string, unknown>;\r\n }\r\n\r\n /** Get-or-create config.plugins.load.paths as a mutable string array. */\r\n private pluginLoadPathsBucket(cfg: Record<string, unknown>): string[] {\r\n let plugins = cfg[PLUGINS_KEY];\r\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) {\r\n plugins = {};\r\n cfg[PLUGINS_KEY] = plugins;\r\n }\r\n const pluginsObj = plugins as Record<string, unknown>;\r\n let load = pluginsObj[PLUGINS_LOAD_KEY];\r\n if (!load || typeof load !== \"object\" || Array.isArray(load)) {\r\n load = {};\r\n pluginsObj[PLUGINS_LOAD_KEY] = load;\r\n }\r\n const loadObj = load as Record<string, unknown>;\r\n const existing = loadObj[PLUGINS_LOAD_PATHS_KEY];\r\n // Normalize to a fresh string[] (drop any non-string a user may have placed\r\n // here) and write it back so the caller mutates the live array.\r\n const paths = Array.isArray(existing)\r\n ? existing.filter((p): p is string => typeof p === \"string\")\r\n : [];\r\n loadObj[PLUGINS_LOAD_PATHS_KEY] = paths;\r\n return paths;\r\n }\r\n\r\n // ── Content surface: skills (dir-per-skill SKILL.md) ────────────────────\r\n // CONTENT-ONLY: pure native-file writers, mirroring codex/claude-code\r\n // installSkills + renderSkill. No runtime dispatch, no home-bin pointer, no\r\n // telemetry wrap. Each write is idempotent (byte-identical → skip) via\r\n // writeContentFile and reversible via removeContentFile + removeDirIfEmpty\r\n // (never rm -rf a shared dir). Honors platforms[\"openclaw\"].skills === false.\r\n //\r\n // Native locations (AgentSkills spec — dir-per-skill SKILL.md + resources):\r\n // user → ~/.openclaw/skills/<name>/SKILL.md (`openclaw skills install\r\n // --global` targets this dir)\r\n // project → <workspace>/skills/<name>/SKILL.md (the highest-priority\r\n // documented skill root; <workspace> is the SAME root the memory\r\n // surface resolves, so both content surfaces stay consistent).\r\n\r\n /**\r\n * Per-skill directory for ctx.scope:\r\n * user → ~/.openclaw/skills/<name> (`--global` install target)\r\n * project → <workspace>/skills/<name> (resolved agent workspace —\r\n * consistent with this adapter's memoryTargets resolution).\r\n */\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n const base =\r\n ctx.scope === \"project\"\r\n ? join(this.resolveWorkspace(), \"skills\")\r\n : join(dirname(resolveOpenClawConfigPath()), \"skills\");\r\n return join(base, name);\r\n }\r\n\r\n override installSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[this.id]?.skills === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: `skills disabled for ${this.id}` }];\r\n }\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\r\n );\r\n // Bundle any resource files beside SKILL.md (relative path → contents).\r\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\r\n // (config-time validation already rejects these, but never trust input).\r\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\r\n }\r\n }\r\n return changes;\r\n }\r\n\r\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n // Remove only the files we wrote (SKILL.md + declared resources), then the\r\n // skill dir itself when we own its full contents.\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue; // never delete outside the skill dir\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n // Only remove the skill dir when WE own its full contents — never rm -rf a\r\n // dir that still holds user-added / sibling-tool / shared files.\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n // ── ts-plugin synthesis ────────────────────────────────────────────────\r\n\r\n /**\r\n * Build ONE self-contained ESM plugin module for OpenClaw.\r\n *\r\n * The module imports nothing from agent-connector. It embeds two constants\r\n * (the absolute home-bin path and the connector id) and a `bridge()` helper\r\n * that shells out to the universal hook entrypoint via execFileSync, feeding\r\n * the OpenClaw event payload on stdin and JSON.parsing the normalized\r\n * HookResponse back from stdout (fail-open: any error → null). Its default\r\n * export is the OpenClaw plugin definition { id, name, configSchema,\r\n * register(api) }; register wires api.on(...) handlers for the events this\r\n * connector actually declares.\r\n */\r\n synthesizePlugin(ctx: InstallContext): GeneratedPluginFile[] {\r\n const path = this.getHookConfigPath(ctx);\r\n const contents = this.buildPluginSource(ctx);\r\n // The gateway scans plugins.load.paths dirs for a manifest, so emit an\r\n // openclaw.plugin.json beside index.mjs pointing at the module entry.\r\n const manifestPath = join(this.pluginDir(ctx), PLUGIN_MANIFEST_FILE);\r\n const manifest = this.buildPluginManifest(ctx);\r\n return [\r\n { path, contents, executable: false },\r\n { path: manifestPath, contents: manifest, executable: false },\r\n ];\r\n }\r\n\r\n /**\r\n * Build the openclaw.plugin.json manifest the gateway reads inside a\r\n * plugins.load.paths directory. It names the plugin and points at the ESM\r\n * module entry (index.mjs) so the loader knows what to import.\r\n *\r\n * `configSchema` is REQUIRED: `openclaw config validate` (and `openclaw mcp\r\n * list`) REJECT a manifest without it (\"plugin manifest requires\r\n * configSchema\"). Our plugin takes no user config, so we emit the empty\r\n * closed object schema from openclaw's own minimal manifest example\r\n * ({ type: \"object\", additionalProperties: false }).\r\n */\r\n private buildPluginManifest(ctx: InstallContext): string {\r\n const manifest = {\r\n id: ctx.connector.id,\r\n name: ctx.connector.displayName || ctx.connector.id,\r\n main: this.pluginFileName(),\r\n enabled: true,\r\n configSchema: { type: \"object\", additionalProperties: false },\r\n };\r\n return `${JSON.stringify(manifest, null, 2)}\\n`;\r\n }\r\n\r\n /** Compose the generated plugin source with plain string concatenation. */\r\n private buildPluginSource(ctx: InstallContext): string {\r\n const homeBin = JSON.stringify(ctx.homeBinPath);\r\n const connectorId = JSON.stringify(ctx.connector.id);\r\n const connectorName = JSON.stringify(ctx.connector.displayName || ctx.connector.id);\r\n\r\n // `platforms[host].hooks === false` disables the CANONICAL events. The\r\n // plugin module may still be synthesized for ACTIONS (installActions writes\r\n // it independently of hooks), so the canonical handler set collapses to []\r\n // here rather than letting a live before_tool_call/after_tool_call gate leak\r\n // into a hooks-disabled plugin. Mirrors omp/opencode. Uses this.id so the\r\n // NemoClaw fork checks platforms.nemoclaw.hooks.\r\n const canonicalOff = ctx.connector.platforms[this.id]?.hooks === false;\r\n const events = canonicalOff\r\n ? []\r\n : ctx.connector.hookEvents.filter(\r\n (e): e is HookEventName => EVENT_TO_OPENCLAW[e] !== undefined,\r\n );\r\n const has = (e: HookEventName) => events.includes(e);\r\n\r\n const header =\r\n \"/**\\n\" +\r\n \" * AUTO-GENERATED by agent-connector — DO NOT EDIT.\\n\" +\r\n \" *\\n\" +\r\n \" * Self-contained OpenClaw plugin bridge for connector \" +\r\n ctx.connector.id +\r\n \".\\n\" +\r\n \" * It imports nothing from agent-connector: every hook invocation shells out\\n\" +\r\n \" * to the stable home binary's universal entrypoint and JSON-parses the\\n\" +\r\n \" * normalized response. Fail-open: any bridge error degrades to a no-op.\\n\" +\r\n \" *\\n\" +\r\n \" * Registered via DUAL REGISTRATION in openclaw.json: plugins.entries.<id>\\n\" +\r\n \" * (loads this module) + mcp.servers.<id> (surfaces the MCP tools). The\\n\" +\r\n \" * gateway hot-reloads its config on SIGUSR1.\\n\" +\r\n \" */\\n\" +\r\n 'import { execFileSync, execSync } from \"node:child_process\";\\n\\n' +\r\n \"const HOME_BIN = \" +\r\n homeBin +\r\n \";\\n\" +\r\n \"const CONNECTOR_ID = \" +\r\n connectorId +\r\n \";\\n\\n\" +\r\n \"/**\\n\" +\r\n \" * Invoke the universal hook entrypoint for one canonical event.\\n\" +\r\n \" * @param {string} event canonical (or native passthrough) event name\\n\" +\r\n \" * (PreToolUse|PostToolUse|SessionStart|UserPromptSubmit|SubagentStart|SubagentStop)\\n\" +\r\n \" * @param {object} payload OpenClaw-shaped payload posted on stdin\\n\" +\r\n \" * @returns {object|null} normalized HookResponse, or null on any failure\\n\" +\r\n \" */\\n\" +\r\n \"function bridge(event, payload) {\\n\" +\r\n \" try {\\n\" +\r\n \" // On Windows HOME_BIN is the agent-connector.cmd launcher: Node cannot\\n\" +\r\n \" // execFile a batch file, and shell+args is deprecated (DEP0190), so run\\n\" +\r\n \" // one quoted command line via a shell. POSIX keeps the direct execFile.\\n\" +\r\n ' const args = [\"hook\", ' + JSON.stringify(this.id) + ', event, \"--connector\", CONNECTOR_ID];\\n' +\r\n ' const opts = { input: JSON.stringify(payload), encoding: \"utf8\" };\\n' +\r\n \" const stdout =\\n\" +\r\n ' process.platform === \"win32\"\\n' +\r\n \" ? execSync([HOME_BIN, ...args].map((a) => '\\\"' + a + '\\\"').join(\\\" \\\"), opts)\\n\" +\r\n \" : execFileSync(HOME_BIN, args, opts);\\n\" +\r\n ' const text = (stdout || \"\").trim();\\n' +\r\n ' if (text === \"\") return { decision: \"allow\" };\\n' +\r\n \" return JSON.parse(text);\\n\" +\r\n \" } catch {\\n\" +\r\n \" // Fail-open — never wedge a tool call on a bridge error.\\n\" +\r\n \" return null;\\n\" +\r\n \" }\\n\" +\r\n \"}\\n\\n\" +\r\n \"// Module-scoped context the prompt-build hook injects at session start.\\n\" +\r\n \"// before_prompt_build is the verified injection point (session_start itself\\n\" +\r\n \"// returns no context payload). The flag prevents double-injection.\\n\" +\r\n \"let PROJECT_DIR = process.cwd();\\n\" +\r\n \"let SESSION_ID = \\\"\\\";\\n\" +\r\n \"let pendingContext = null;\\n\" +\r\n \"let contextInjected = false;\\n\\n\";\r\n\r\n // register(api) body — wire only the handlers this connector declares.\r\n const reg: string[] = [];\r\n\r\n reg.push(\r\n \" register(api) {\\n\" +\r\n \" PROJECT_DIR = process.cwd();\\n\" +\r\n \" const on = (event, handler) => {\\n\" +\r\n ' if (typeof api?.on === \"function\") {\\n' +\r\n \" try { api.on(event, handler); return; } catch { /* fall through */ }\\n\" +\r\n \" }\\n\" +\r\n ' if (typeof api?.registerHook === \"function\") {\\n' +\r\n \" try {\\n\" +\r\n ' api.registerHook(event, handler, { name: CONNECTOR_ID + \":\" + event, description: \"agent-connector bridge\" });\\n' +\r\n \" } catch { /* best effort */ }\\n\" +\r\n \" }\\n\" +\r\n \" };\\n\",\r\n );\r\n\r\n if (has(\"PreToolUse\")) {\r\n reg.push(\r\n \"\\n\" +\r\n \" // PreToolUse → before_tool_call: block (return { block, blockReason })\\n\" +\r\n \" // for deny/ask; rewrite args by mutating event.params in place for modify.\\n\" +\r\n ' on(\"before_tool_call\", async (event) => {\\n' +\r\n \" const e = event || {};\\n\" +\r\n \" const toolInput = e.params || {};\\n\" +\r\n \" const res = bridge(\\\"PreToolUse\\\", {\\n\" +\r\n ' toolName: e.toolName || \"\",\\n' +\r\n \" toolInput,\\n\" +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n \" if (!res) return undefined;\\n\" +\r\n \" // OpenClaw has no separate ask gate — deny and ask both block (safe).\\n\" +\r\n ' if (res.decision === \"deny\" || res.decision === \"ask\") {\\n' +\r\n ' return { block: true, blockReason: res.reason || (\"Blocked by \" + CONNECTOR_ID) };\\n' +\r\n \" }\\n\" +\r\n ' if (res.decision === \"modify\" && res.updatedInput && typeof toolInput === \"object\") {\\n' +\r\n \" Object.assign(toolInput, res.updatedInput);\\n\" +\r\n \" }\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n if (has(\"PostToolUse\")) {\r\n reg.push(\r\n \"\\n\" +\r\n \" // PostToolUse → after_tool_call: observe the completed tool call.\\n\" +\r\n \" // OpenClaw exposes the result (v2+) or output (older builds); it cannot\\n\" +\r\n \" // rewrite the tool result, so updatedOutput is intentionally dropped.\\n\" +\r\n ' on(\"after_tool_call\", async (event) => {\\n' +\r\n \" const e = event || {};\\n\" +\r\n \" const rawResult = e.result !== undefined ? e.result : e.output;\\n\" +\r\n \" const toolOutput =\\n\" +\r\n ' typeof rawResult === \"string\"\\n' +\r\n \" ? rawResult\\n\" +\r\n \" : rawResult != null\\n\" +\r\n \" ? JSON.stringify(rawResult)\\n\" +\r\n \" : undefined;\\n\" +\r\n \" bridge(\\\"PostToolUse\\\", {\\n\" +\r\n ' toolName: e.toolName || \"\",\\n' +\r\n \" toolInput: e.params || {},\\n\" +\r\n \" toolOutput,\\n\" +\r\n \" isError: Boolean(e.error || e.isError),\\n\" +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n if (has(\"SubagentStart\")) {\r\n reg.push(\r\n \"\\n\" +\r\n \" // SubagentStart → subagent_spawned: observe-only (OpenClaw exposes no\\n\" +\r\n \" // decision or context-injection payload for subagent launches).\\n\" +\r\n \" // PRIMARY SOURCE (openclaw/openclaw src/plugins/hook-types.ts:720-806,\\n\" +\r\n \" // PluginHookSubagentSpawnedEvent = PluginHookSubagentSpawnBase): the\\n\" +\r\n \" // native event carries `agentId` (the agent identity) + an OPTIONAL\\n\" +\r\n \" // human `label` — and NO subagentId/subagentType/agent/agentType. So we\\n\" +\r\n \" // read the real e.agentId and surface the real e.label as the type-ish\\n\" +\r\n \" // descriptor; the former subagentId/subagentType/agent reads were\\n\" +\r\n \" // false-friends (host emits none). Empty values are omitted so the\\n\" +\r\n \" // dispatcher never matcher-filters on an empty descriptor (fail-open).\\n\" +\r\n ' on(\"subagent_spawned\", async (event) => {\\n' +\r\n \" const e = event || {};\\n\" +\r\n \" bridge(\\\"SubagentStart\\\", {\\n\" +\r\n \" agentId: e.agentId || undefined,\\n\" +\r\n \" agentType: e.label || undefined,\\n\" +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n if (has(\"SubagentStop\")) {\r\n reg.push(\r\n \"\\n\" +\r\n \" // SubagentStop → subagent_ended: observe-only completion. A normalized\\n\" +\r\n \" // 'deny' cannot keep the subagent running on OpenClaw, so the bridge\\n\" +\r\n \" // reply is intentionally ignored.\\n\" +\r\n \" // PRIMARY SOURCE (openclaw/openclaw src/plugins/hook-types.ts:808-818\\n\" +\r\n \" // PluginHookSubagentEndedEvent + wired-hooks-subagent.test.ts:118-126):\\n\" +\r\n \" // the native event's ONLY identity is `targetSessionKey` — it carries\\n\" +\r\n \" // NO agentId/subagentId, NO agentType/subagentType/agent, and NO\\n\" +\r\n \" // result/output. The old e.agentId||e.subagentId / e.agentType||… /\\n\" +\r\n \" // e.result||e.output reads were ALL false-friends (host emits none →\\n\" +\r\n \" // agentId was always undefined). We read the real e.targetSessionKey as\\n\" +\r\n \" // agentId and omit the type/message slots the host never provides.\\n\" +\r\n ' on(\"subagent_ended\", async (event) => {\\n' +\r\n \" const e = event || {};\\n\" +\r\n \" bridge(\\\"SubagentStop\\\", {\\n\" +\r\n \" agentId: e.targetSessionKey || undefined,\\n\" +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n if (has(\"SessionStart\")) {\r\n reg.push(\r\n \"\\n\" +\r\n \" // SessionStart → session_start records the real session id and fetches\\n\" +\r\n \" // the additionalContext to inject; before_prompt_build performs the\\n\" +\r\n \" // injection (the verified context-injection point upstream).\\n\" +\r\n ' on(\"session_start\", async (event) => {\\n' +\r\n \" const e = event || {};\\n\" +\r\n \" SESSION_ID = e.sessionId || e.sessionKey || SESSION_ID;\\n\" +\r\n \" const res = bridge(\\\"SessionStart\\\", {\\n\" +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n ' source: e.resumedFrom ? \"resume\" : \"startup\",\\n' +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n \" contextInjected = false;\\n\" +\r\n \" pendingContext =\\n\" +\r\n ' res && typeof res.additionalContext === \"string\" && res.additionalContext\\n' +\r\n \" ? res.additionalContext\\n\" +\r\n \" : null;\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n // before_prompt_build fires on EVERY prompt build. ONE handler serves both\r\n // context-injecting events that target it — they COEXIST via SEPARATE state\r\n // so the once-only SessionStart flag never suppresses the per-turn injection:\r\n // SessionStart → inject pendingContext ONCE (first build), as system ctx.\r\n // UserPromptSubmit → bridge EVERY turn, append the returned additionalContext.\r\n // before_prompt_build has NO blocking ability, so a UserPromptSubmit block/deny\r\n // decision DEGRADES to a no-op (context-injection only — never claim a block).\r\n if (has(\"SessionStart\") || has(\"UserPromptSubmit\")) {\r\n let body = \"\";\r\n if (has(\"SessionStart\")) {\r\n body +=\r\n \" // SessionStart: inject the session-start context exactly once.\\n\" +\r\n \" if (!contextInjected && pendingContext) {\\n\" +\r\n \" contextInjected = true;\\n\" +\r\n \" out.appendSystemContext = pendingContext;\\n\" +\r\n \" }\\n\";\r\n }\r\n if (has(\"UserPromptSubmit\")) {\r\n body +=\r\n \" // UserPromptSubmit: per-turn context injection. before_prompt_build\\n\" +\r\n \" // cannot block, so a deny/block decision degrades to a no-op.\\n\" +\r\n \" const e = event || {};\\n\" +\r\n \" const ures = bridge(\\\"UserPromptSubmit\\\", {\\n\" +\r\n ' prompt: typeof e.prompt === \"string\" ? e.prompt : \"\",\\n' +\r\n \" sessionId: SESSION_ID,\\n\" +\r\n \" projectDir: PROJECT_DIR,\\n\" +\r\n \" });\\n\" +\r\n ' if (ures && typeof ures.additionalContext === \"string\" && ures.additionalContext) {\\n' +\r\n \" out.appendContext = ures.additionalContext;\\n\" +\r\n \" }\\n\";\r\n }\r\n reg.push(\r\n \"\\n\" +\r\n \" // before_prompt_build → coexisting SessionStart (once) + UserPromptSubmit\\n\" +\r\n \" // (per-turn) context injection. Context-only: it cannot block a prompt.\\n\" +\r\n ' on(\"before_prompt_build\", (event) => {\\n' +\r\n \" const out = {};\\n\" +\r\n body +\r\n \" return Object.keys(out).length > 0 ? out : undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n // NATIVE passthrough events: OpenClaw lifecycle hook names with no canonical\r\n // analog, declared on platforms.<id>.nativeHooks. Each registers an on(...)\r\n // handler that bridges the NATIVE event name verbatim to the home-bin →\r\n // runNativeHook dispatches it host-generically. Read straight off\r\n // platforms.<id>.nativeHooks (independent of hookEvents AND of canonicalOff),\r\n // so they install even with hooks:false. Mirrors omp/opencode.\r\n for (const ev of this.nativeHookEvents(ctx)) {\r\n const key = JSON.stringify(ev);\r\n reg.push(\r\n \"\\n\" +\r\n \" // nativeHooks passthrough → \" + ev + \"\\n\" +\r\n \" on(\" + key + \", (event) => {\\n\" +\r\n \" bridge(\" + key + \", { sessionId: SESSION_ID, projectDir: PROJECT_DIR, raw: event });\\n\" +\r\n \" return undefined;\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n // Action surface: one api.registerCommand per declared action, registered in\r\n // the SAME register(api) body. The command shells out to the home-bin\r\n // `action <host>` verb with the host token baked as this.id (so a NemoClaw\r\n // fork emits `action nemoclaw`, NOT openclaw — exactly like the hook bridge\r\n // above). The win32 branch reuses the hook bridge's quoted-shell form (a .cmd\r\n // launcher throws EINVAL via execFileSync). Both id AND description are\r\n // JSON.stringify'd — descriptions are free-form connector text, so a raw \" /\r\n // backtick would break the generated module.\r\n for (const action of this.actionTriggers(ctx)) {\r\n const id = JSON.stringify(action.id);\r\n const description = JSON.stringify(action.description);\r\n reg.push(\r\n \"\\n\" +\r\n \" // Action /\" + action.id + \" -> run the home-bin action verb directly.\\n\" +\r\n \" api.registerCommand({\\n\" +\r\n \" name: \" + id + \",\\n\" +\r\n \" description: \" + description + \",\\n\" +\r\n \" handler: async (_ctx) => {\\n\" +\r\n \" try {\\n\" +\r\n ' const args = [\"action\", ' + JSON.stringify(this.id) + \", \" + id + ', \"--connector\", CONNECTOR_ID];\\n' +\r\n \" const out =\\n\" +\r\n ' process.platform === \"win32\"\\n' +\r\n \" ? execSync([HOME_BIN, ...args].map((a) => '\\\"' + a + '\\\"').join(\\\" \\\"), { encoding: \\\"utf8\\\" })\\n\" +\r\n ' : execFileSync(HOME_BIN, args, { encoding: \"utf8\" });\\n' +\r\n ' return { text: (out || \"\").trim() };\\n' +\r\n \" } catch (e) {\\n\" +\r\n \" return { text: \\\"action \\\" + \" + id + \" + \\\" failed: \\\" + (e && e.message ? e.message : \\\"error\\\") };\\n\" +\r\n \" }\\n\" +\r\n \" },\\n\" +\r\n \" });\\n\",\r\n );\r\n }\r\n\r\n reg.push(\" },\\n\");\r\n\r\n const definition =\r\n \"const plugin = {\\n\" +\r\n \" id: CONNECTOR_ID,\\n\" +\r\n \" name: \" +\r\n connectorName +\r\n \",\\n\" +\r\n \" configSchema: {\\n\" +\r\n ' type: \"object\",\\n' +\r\n \" properties: {\\n\" +\r\n \" enabled: {\\n\" +\r\n ' type: \"boolean\",\\n' +\r\n \" default: true,\\n\" +\r\n ' description: \"Enable or disable the \" + CONNECTOR_ID + \" plugin.\",\\n' +\r\n \" },\\n\" +\r\n \" },\\n\" +\r\n \" additionalProperties: false,\\n\" +\r\n \" },\\n\" +\r\n reg.join(\"\") +\r\n \"};\\n\\n\" +\r\n \"export default plugin;\\n\";\r\n\r\n return header + definition;\r\n }\r\n\r\n // ── Runtime: parse OUR bridge payload → normalized event ───────────────\r\n\r\n /**\r\n * `raw` is the payload OUR generated plugin posts (NOT a host-native shape):\r\n * { toolName, toolInput, toolOutput?, isError?, sessionId, source?, projectDir }\r\n * so this maps straight through.\r\n */\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as OpenClawBridgePayload;\r\n const base = {\r\n hostPlatform: this.id,\r\n connectorId: \"\",\r\n sessionId: typeof input.sessionId === \"string\" ? input.sessionId : \"\",\r\n raw,\r\n ...(typeof input.projectDir === \"string\" ? { projectDir: input.projectDir } : {}),\r\n } as const;\r\n\r\n switch (event) {\r\n case \"PreToolUse\": {\r\n const ev: PreToolUseEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"PostToolUse\": {\r\n const ev: PostToolUseEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n ...(typeof input.toolOutput === \"string\" ? { toolOutput: input.toolOutput } : {}),\r\n ...(typeof input.isError === \"boolean\" ? { isError: input.isError } : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SessionStart\": {\r\n const source: SessionStartEvent[\"source\"] =\r\n input.source === \"resume\"\r\n ? \"resume\"\r\n : input.source === \"compact\"\r\n ? \"compact\"\r\n : input.source === \"clear\"\r\n ? \"clear\"\r\n : \"startup\";\r\n const ev: SessionStartEvent = { ...base, source };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStart\": {\r\n // Empty strings are dropped so the runtime matcher never filters a\r\n // real spawn on an unknown agent type (fail-open, per the dispatcher).\r\n const ev: SubagentStartEvent = {\r\n ...base,\r\n ...(isNonEmptyString(input.agentId) ? { agentId: input.agentId } : {}),\r\n ...(isNonEmptyString(input.agentType)\r\n ? { agentType: input.agentType }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStop\": {\r\n const ev: SubagentStopEvent = {\r\n ...base,\r\n ...(isNonEmptyString(input.agentId) ? { agentId: input.agentId } : {}),\r\n ...(isNonEmptyString(input.agentType)\r\n ? { agentType: input.agentType }\r\n : {}),\r\n ...(isNonEmptyString(input.lastAssistantMessage)\r\n ? { lastAssistantMessage: input.lastAssistantMessage }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n default:\r\n // Other canonical events are not surfaced by OpenClaw; treat as a\r\n // session-start-shaped no-op so the dispatcher fails open gracefully.\r\n return { ...base, source: \"startup\" } satisfies SessionStartEvent;\r\n }\r\n }\r\n\r\n // ── Runtime: normalized response → reply the generated bridge parses ───\r\n\r\n /**\r\n * Unlike json-stdio hosts (whose reply is the host's NATIVE control payload),\r\n * OUR generated bridge consumes this stdout directly. So the reply body is the\r\n * NORMALIZED HookResponse itself — the bridge JSON.parses it and reads\r\n * decision / updatedInput / additionalContext.\r\n */\r\n formatReply(_event: HookEventName, response: HookResponse): HookReply {\r\n return {\r\n exitCode: 0,\r\n stdout: JSON.stringify(response ?? { decision: \"allow\" }),\r\n };\r\n }\r\n\r\n // ── Diagnostics ────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const configPath = this.getServerConfigPath(ctx);\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const pluginDir = this.pluginDir(ctx);\r\n const id = ctx.connector.id;\r\n // Actions are health-equivalent to hooks: both write the SAME plugin module\r\n // and the SAME dual-registration entry, so an actions-only connector must\r\n // still assert the plugin/extension is present + loaded.\r\n const hasHooks =\r\n ctx.connector.hookEvents.length > 0 ||\r\n this.nativeHookEvents(ctx).length > 0 ||\r\n this.actionTriggers(ctx).length > 0;\r\n const hasServer = Boolean(ctx.connector.server);\r\n\r\n return [\r\n {\r\n name: `${this.name}: openclaw.json present`,\r\n check: () =>\r\n existsSync(configPath)\r\n ? { status: \"OK\", detail: configPath }\r\n : { status: \"FAIL\", detail: `not found: ${configPath}` },\r\n },\r\n {\r\n // HARDEST PART — dual registration must be CONSISTENT. The plugin only\r\n // delivers tools when it is LOADED (plugins.entries.<id> enabled AND its\r\n // dir in plugins.load.paths) AND in mcp.servers. A config with one half\r\n // but not the other is a tool-less (or never-loaded) install, so FAIL on\r\n // loaded XOR mcp.servers. (We assert plugins.load.paths — NOT a per-entry\r\n // `module` field, which openclaw config validate rejects.)\r\n name: `${this.name}: dual registration (plugins.entries+load.paths + mcp.servers.${id})`,\r\n check: () => {\r\n // Only assert what the connector declares: a catalog-only connector\r\n // (no MCP server, no hooks) never writes either half of the dual\r\n // registration, so absence — even of the config file — is healthy.\r\n if (!hasServer && !hasHooks) {\r\n return { status: \"OK\", detail: \"no MCP server or hooks declared\" };\r\n }\r\n const cfg = this.readJson<Record<string, unknown>>(configPath);\r\n if (!cfg) return { status: \"FAIL\", detail: `cannot read ${configPath}` };\r\n\r\n const inEntries = this.hasPluginEntry(cfg, id) && this.hasLoadPath(cfg, pluginDir);\r\n const inMcp = this.hasMcpServer(cfg, id);\r\n\r\n // A hooks-only connector (no MCP server declared) does not need the\r\n // mcp.servers half — the load half alone is correct and complete.\r\n if (!hasServer) {\r\n return inEntries || !hasHooks\r\n ? { status: \"OK\", detail: \"hooks-only connector (no MCP server)\" }\r\n : {\r\n status: \"FAIL\",\r\n detail: `${id} not enabled in ${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY} (plugin will not load)`,\r\n };\r\n }\r\n\r\n if (inEntries && inMcp) {\r\n return {\r\n status: \"OK\",\r\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id}+${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY} + ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\r\n };\r\n }\r\n if (inEntries && !inMcp) {\r\n return {\r\n status: \"FAIL\",\r\n detail: `loaded (${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}+${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) but missing from ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY} — plugin loads but no tools reach the agent`,\r\n };\r\n }\r\n if (!inEntries && inMcp) {\r\n return {\r\n status: \"FAIL\",\r\n detail: `in ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY} but not loaded (missing ${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY} or ${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) — tools declared but plugin never loads`,\r\n };\r\n }\r\n return {\r\n status: \"FAIL\",\r\n detail: `not loaded (${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}+${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) and not in ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}`,\r\n };\r\n },\r\n },\r\n {\r\n name: `${this.name}: plugin module present`,\r\n check: () => {\r\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\r\n return existsSync(pluginPath)\r\n ? { status: \"OK\", detail: pluginPath }\r\n : { status: \"FAIL\", detail: `not found: ${pluginPath}` };\r\n },\r\n },\r\n ];\r\n }\r\n\r\n /** True when config.plugins.entries.<id> exists (and is not disabled). */\r\n private hasPluginEntry(cfg: Record<string, unknown>, id: string): boolean {\r\n const plugins = cfg[PLUGINS_KEY];\r\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) return false;\r\n const entries = (plugins as Record<string, unknown>)[PLUGINS_ENTRIES_KEY];\r\n if (!entries || typeof entries !== \"object\" || Array.isArray(entries)) return false;\r\n const entry = (entries as Record<string, unknown>)[id];\r\n if (entry === undefined) return false;\r\n // An explicit { enabled: false } means the gateway will not load it.\r\n return !(\r\n entry &&\r\n typeof entry === \"object\" &&\r\n (entry as Record<string, unknown>).enabled === false\r\n );\r\n }\r\n\r\n /** True when config.plugins.load.paths includes `pluginDir`. */\r\n private hasLoadPath(cfg: Record<string, unknown>, pluginDir: string): boolean {\r\n const plugins = cfg[PLUGINS_KEY];\r\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) return false;\r\n const load = (plugins as Record<string, unknown>)[PLUGINS_LOAD_KEY];\r\n if (!load || typeof load !== \"object\" || Array.isArray(load)) return false;\r\n const paths = (load as Record<string, unknown>)[PLUGINS_LOAD_PATHS_KEY];\r\n return Array.isArray(paths) && paths.includes(pluginDir);\r\n }\r\n\r\n /** True when config.mcp.servers.<id> exists. */\r\n private hasMcpServer(cfg: Record<string, unknown>, id: string): boolean {\r\n const mcp = cfg[MCP_ROOT_KEY];\r\n if (!mcp || typeof mcp !== \"object\" || Array.isArray(mcp)) return false;\r\n const servers = (mcp as Record<string, unknown>)[MCP_SERVERS_KEY];\r\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) return false;\r\n return id in (servers as Record<string, unknown>);\r\n }\r\n\r\n}\r\n\r\n/**\r\n * Resolve the openclaw.json the gateway actually loads (mirrors context-mode's\r\n * openclawConfigPath): $OPENCLAW_CONFIG_PATH, else $OPENCLAW_STATE_DIR/openclaw.json,\r\n * else ~/.openclaw/openclaw.json. The gateway never loads a CWD/project-local\r\n * openclaw.json for user scope, so this is the canonical user-scope path.\r\n */\r\nfunction resolveOpenClawConfigPath(env: NodeJS.ProcessEnv = process.env): string {\r\n if (env.OPENCLAW_CONFIG_PATH) return resolve(env.OPENCLAW_CONFIG_PATH);\r\n const stateDir = env.OPENCLAW_STATE_DIR\r\n ? resolve(env.OPENCLAW_STATE_DIR)\r\n : resolve(homedir(), \".openclaw\");\r\n return resolve(stateDir, \"openclaw.json\");\r\n}\r\n\r\n/** Narrow to a non-empty string (the bridge omits empties, but stay defensive). */\r\nfunction isNonEmptyString(value: unknown): value is string {\r\n return typeof value === \"string\" && value !== \"\";\r\n}\r\n\r\nexport const adapter = new OpenClawAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/yaml.ts"],"sourcesContent":["/**\r\n * core/yaml — minimal YAML config IO.\r\n *\r\n * The YAML analog of BaseAdapter's JSON helpers (readJson/writeJson). Adapters\r\n * whose native config is YAML (Goose's config.yaml, Hermes's config.yaml) cannot\r\n * use the JSON helpers, so they reach for these two functions instead — same\r\n * existsSync-guard / parse-failure-tolerant / dryRun-respecting contract, just\r\n * over the `yaml` package's parse()/stringify() rather than JSON.parse/stringify.\r\n *\r\n * Deliberately tiny: read-or-null and ensureDir+write. All merge/upsert/idempotency\r\n * logic lives in each adapter (the shapes differ per platform), exactly as the\r\n * JSON adapters layer their own upsert on top of writeJson.\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\r\nimport { dirname } from \"node:path\";\r\n\r\nimport { parse, stringify } from \"yaml\";\r\n\r\nimport type { ObjectMapCodec } from \"./object-map.js\";\r\nimport { ensureDir } from \"./paths.js\";\r\n\r\n/**\r\n * Read and parse a YAML file. Returns `null` when the file is missing OR when it\r\n * fails to parse (mirrors BaseAdapter.readJson's fail-soft behavior so a corrupt\r\n * file degrades to \"treat as absent\" rather than throwing mid-install).\r\n */\r\nexport function readYaml<T = Record<string, unknown>>(path: string): T | null {\r\n if (!existsSync(path)) return null;\r\n try {\r\n const parsed = parse(readFileSync(path, \"utf8\")) as T | null | undefined;\r\n // An empty YAML document parses to null/undefined — normalize to null.\r\n return parsed == null ? null : parsed;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Serialize `data` to YAML and write it to `path`, creating parent dirs as\r\n * needed. Honors `dryRun` (no write). Mirrors BaseAdapter.writeJson's signature.\r\n */\r\nexport function writeYaml(path: string, data: unknown, dryRun = false): void {\r\n if (dryRun) return;\r\n ensureDir(dirname(path));\r\n writeFileSync(path, stringify(data), \"utf8\");\r\n}\r\n\r\n/**\r\n * An ObjectMapCodec over YAML for the core/object-map engine. Shared by the YAML\r\n * object-map server hosts (Goose's `extensions`, Hermes's `mcp_servers`) and any\r\n * future YAML host. `isPresentButUnparseable` is `() => false`: YAML server hosts\r\n * historically coerce/overwrite (readYaml(path) ?? {}) rather than warn-skip on an\r\n * unparseable file — preserved here for byte-identical behavior.\r\n */\r\nexport function yamlObjectMapCodec(): ObjectMapCodec {\r\n return {\r\n parse: (path) => readYaml<Record<string, unknown>>(path),\r\n serialize: (path, data, dryRun) => writeYaml(path, data, dryRun),\r\n isPresentButUnparseable: () => false,\r\n };\r\n}\r\n"],"mappings":";;;;;;AAcA,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,eAAe;AAExB,SAAS,OAAO,iBAAiB;AAU1B,SAAS,SAAsC,MAAwB;AAC5E,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,SAAS,MAAM,aAAa,MAAM,MAAM,CAAC;AAE/C,WAAO,UAAU,OAAO,OAAO;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,UAAU,MAAc,MAAe,SAAS,OAAa;AAC3E,MAAI,OAAQ;AACZ,YAAU,QAAQ,IAAI,CAAC;AACvB,gBAAc,MAAM,UAAU,IAAI,GAAG,MAAM;AAC7C;AASO,SAAS,qBAAqC;AACnD,SAAO;AAAA,IACL,OAAO,CAAC,SAAS,SAAkC,IAAI;AAAA,IACvD,WAAW,CAAC,MAAM,MAAM,WAAW,UAAU,MAAM,MAAM,MAAM;AAAA,IAC/D,yBAAyB,MAAM;AAAA,EACjC;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk/introspect.ts"],"sourcesContent":["/**\r\n * sdk/introspect — host-capability introspection over the adapter registry.\r\n *\r\n * A thin, READ-ONLY query layer above {@link loadAdapter} / {@link allAdapters}:\r\n * \"which hosts can honor surface X?\" and \"what can host Y do?\". It exists so a\r\n * connector author (or a docs/CLI surface) can answer those questions WITHOUT\r\n * reaching into adapter internals or re-deriving the per-surface capability\r\n * rules — the predicates below are the single source of truth for mapping the\r\n * raw {@link PlatformCapabilities} flags onto the developer-facing surface names.\r\n *\r\n * Everything is async because adapters load lazily (one entry per platform in\r\n * the registry, imported only when queried).\r\n */\r\n\r\nimport type {\r\n HookEventName,\r\n PlatformCapabilities,\r\n PlatformId,\r\n} from \"../core/types.js\";\r\nimport { allAdapters, loadAdapter } from \"../adapters/registry.js\";\r\n\r\n/**\r\n * The single source of truth mapping each normalized {@link HookEventName} onto\r\n * the {@link PlatformCapabilities} flag that says \"this host can natively FIRE\r\n * this event\". The optional flags (the newer E1 events + PostCompact) are read\r\n * as `?? false`, mirroring the supportsCommands precedent — a host that leaves a\r\n * flag unset cannot fire that event, so a declared hook for it skip-warns at\r\n * install and `explain` reports it as not honored.\r\n *\r\n * This is the per-event signal {@link explain}'s hooks row evaluates against the\r\n * connector's DECLARED events (so a Stop-only connector on a PreToolUse-only\r\n * host no longer falsely shows `native`), and the same signal `simulate`'s real\r\n * parse→handler→format chain expresses at runtime.\r\n */\r\nexport function hostCanFireEvent(\r\n c: PlatformCapabilities,\r\n event: HookEventName,\r\n): boolean {\r\n switch (event) {\r\n case \"SessionStart\":\r\n return c.sessionStart;\r\n case \"SessionEnd\":\r\n return c.sessionEnd;\r\n case \"UserPromptSubmit\":\r\n return c.userPromptSubmit;\r\n case \"PreToolUse\":\r\n return c.preToolUse;\r\n case \"PostToolUse\":\r\n return c.postToolUse;\r\n case \"PreCompact\":\r\n return c.preCompact;\r\n case \"Stop\":\r\n return c.stop;\r\n case \"Notification\":\r\n return c.notification;\r\n case \"PermissionRequest\":\r\n return c.permissionRequest ?? false;\r\n case \"PostToolUseFailure\":\r\n return c.postToolUseFailure ?? false;\r\n case \"SubagentStart\":\r\n return c.subagentStart ?? false;\r\n case \"SubagentStop\":\r\n return c.subagentStop ?? false;\r\n case \"PostCompact\":\r\n return c.postCompact ?? false;\r\n }\r\n}\r\n\r\n/** The full normalized hook-event union, in canonical order. */\r\nconst ALL_HOOK_EVENTS: HookEventName[] = [\r\n \"SessionStart\",\r\n \"SessionEnd\",\r\n \"UserPromptSubmit\",\r\n \"PreToolUse\",\r\n \"PostToolUse\",\r\n \"PreCompact\",\r\n \"Stop\",\r\n \"Notification\",\r\n \"PermissionRequest\",\r\n \"PostToolUseFailure\",\r\n \"SubagentStart\",\r\n \"SubagentStop\",\r\n \"PostCompact\",\r\n];\r\n\r\n/**\r\n * The developer-facing surface names a connector can declare. These mirror the\r\n * top-level {@link import(\"../core/types.js\").ConnectorConfig} keys (server,\r\n * hooks, commands, …) plus the platform-scoped `configPatch` / `nativeHooks`\r\n * escape hatches — the same vocabulary the install diff and `explain` use.\r\n */\r\nexport type SurfaceName =\r\n | \"server\"\r\n | \"hooks\"\r\n | \"commands\"\r\n | \"skills\"\r\n | \"subagents\"\r\n | \"memory\"\r\n | \"statusline\"\r\n | \"actions\"\r\n | \"configPatch\"\r\n | \"nativeHooks\";\r\n\r\n/**\r\n * Pure capability predicate per surface — `true` when the host can NATIVELY\r\n * honor that surface. The optional capability flags are read as `?? false`\r\n * (the supportsCommands precedent in core/types), so a host that simply leaves\r\n * a flag unset reports the surface as unsupported (the installer skip-warns it).\r\n *\r\n * `hooks` here is the COARSE host-capability predicate: `true` when the host can\r\n * fire AT LEAST ONE normalized event (it derives from {@link hostCanFireEvent},\r\n * the per-event source of truth, so the two never drift). It is the right answer\r\n * for the connector-less queries ({@link hostsSupporting} / {@link surfaceSupport}:\r\n * \"which hosts have a hook runtime at all?\"). It is deliberately NOT used by\r\n * {@link explain}, which must judge the hooks surface against the connector's\r\n * SPECIFIC declared events — a Stop-only connector on a PreToolUse-only host is\r\n * NOT honored even though the host has a hook runtime (see {@link explain}).\r\n */\r\nexport const SURFACE_PREDICATES: Record<\r\n SurfaceName,\r\n (c: PlatformCapabilities) => boolean\r\n> = {\r\n server: (c) => c.transports.length > 0,\r\n hooks: (c) => ALL_HOOK_EVENTS.some((e) => hostCanFireEvent(c, e)),\r\n commands: (c) => c.supportsCommands ?? false,\r\n skills: (c) => c.supportsSkills ?? false,\r\n subagents: (c) => c.supportsSubagents ?? false,\r\n memory: (c) => c.supportsMemory ?? false,\r\n statusline: (c) => c.supportsStatusline ?? false,\r\n // Emitters ship on droid + hermes + warp plus the ts-plugin slash-command\r\n // hosts omp + openclaw (+ the nemoclaw fork) — the hosts with a verifiable\r\n // target. Every other host leaves supportsActions unset, so explain() marks\r\n // actions skip-warn there — the honest state for a host with no emission target.\r\n actions: (c) => c.supportsActions ?? false,\r\n configPatch: (c) => c.supportsConfigPatch ?? false,\r\n nativeHooks: (c) => c.supportsNativeHooks ?? false,\r\n};\r\n\r\n/**\r\n * The {@link PlatformCapabilities} a host advertises, or `undefined` for an id\r\n * that is not in the registry (`\"unknown\"`, a usage-only id like `\"synthetic\"`,\r\n * or a typo) — callers branch on undefined rather than crash.\r\n */\r\nexport async function capabilitiesOf(\r\n host: PlatformId | string,\r\n): Promise<PlatformCapabilities | undefined> {\r\n const adapter = await loadAdapter(host);\r\n return adapter?.capabilities;\r\n}\r\n\r\n/**\r\n * Every registered host that can NATIVELY honor `surface`, as a sorted id list\r\n * (stable output for snapshots/docs). Loads all adapters in parallel and keeps\r\n * only those whose capabilities pass {@link SURFACE_PREDICATES}.\r\n */\r\nexport async function hostsSupporting(surface: SurfaceName): Promise<PlatformId[]> {\r\n const predicate = SURFACE_PREDICATES[surface];\r\n const adapters = await allAdapters();\r\n return adapters\r\n .filter((adapter) => predicate(adapter.capabilities))\r\n .map((adapter) => adapter.id)\r\n .sort();\r\n}\r\n\r\n/**\r\n * Convenience: does `host` natively support `surface`? `false` for an unknown\r\n * id (no capabilities → cannot support anything).\r\n */\r\nexport async function surfaceSupport(\r\n host: PlatformId | string,\r\n surface: SurfaceName,\r\n): Promise<boolean> {\r\n const capabilities = await capabilitiesOf(host);\r\n return capabilities ? SURFACE_PREDICATES[surface](capabilities) : false;\r\n}\r\n"],"mappings":";;;;;;;AAkCO,SAAS,iBACd,GACA,OACS;AACT,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE;AAAA,IACX,KAAK;AACH,aAAO,EAAE,qBAAqB;AAAA,IAChC,KAAK;AACH,aAAO,EAAE,sBAAsB;AAAA,IACjC,KAAK;AACH,aAAO,EAAE,iBAAiB;AAAA,IAC5B,KAAK;AACH,aAAO,EAAE,gBAAgB;AAAA,IAC3B,KAAK;AACH,aAAO,EAAE,eAAe;AAAA,EAC5B;AACF;AAGA,IAAM,kBAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAmCO,IAAM,qBAGT;AAAA,EACF,QAAQ,CAAC,MAAM,EAAE,WAAW,SAAS;AAAA,EACrC,OAAO,CAAC,MAAM,gBAAgB,KAAK,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAAA,EAChE,UAAU,CAAC,MAAM,EAAE,oBAAoB;AAAA,EACvC,QAAQ,CAAC,MAAM,EAAE,kBAAkB;AAAA,EACnC,WAAW,CAAC,MAAM,EAAE,qBAAqB;AAAA,EACzC,QAAQ,CAAC,MAAM,EAAE,kBAAkB;AAAA,EACnC,YAAY,CAAC,MAAM,EAAE,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA,EAK3C,SAAS,CAAC,MAAM,EAAE,mBAAmB;AAAA,EACrC,aAAa,CAAC,MAAM,EAAE,uBAAuB;AAAA,EAC7C,aAAa,CAAC,MAAM,EAAE,uBAAuB;AAC/C;AAOA,eAAsB,eACpB,MAC2C;AAC3C,QAAM,UAAU,MAAM,YAAY,IAAI;AACtC,SAAO,SAAS;AAClB;AAOA,eAAsB,gBAAgB,SAA6C;AACjF,QAAM,YAAY,mBAAmB,OAAO;AAC5C,QAAM,WAAW,MAAM,YAAY;AACnC,SAAO,SACJ,OAAO,CAAC,YAAY,UAAU,QAAQ,YAAY,CAAC,EACnD,IAAI,CAAC,YAAY,QAAQ,EAAE,EAC3B,KAAK;AACV;AAMA,eAAsB,eACpB,MACA,SACkB;AAClB,QAAM,eAAe,MAAM,eAAe,IAAI;AAC9C,SAAO,eAAe,mBAAmB,OAAO,EAAE,YAAY,IAAI;AACpE;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/cursor/index.ts"],"sourcesContent":["/**\r\n * adapters/cursor — Cursor platform adapter for agent-connector.\r\n *\r\n * Generalized from context-mode's proven Cursor adapter: the served identity is\r\n * now `ctx.connector` (not a hardcoded \"context-mode\"), and every hook command\r\n * points at the single stable home binary (the shared hook-merge engine builds\r\n * the command) so one framework update propagates everywhere.\r\n *\r\n * Cursor is a json-stdio host:\r\n * - MCP servers: user scope → ~/.cursor/mcp.json (\"mcpServers\"); project scope\r\n * → <projectDir>/.cursor/mcp.json (\"mcpServers\").\r\n * - Hooks: <configDir>/hooks.json with shape `{ version, hooks: { <cursorEvent>:\r\n * [ { command, matcher? } ] } }`. Unlike Claude, each entry is a FLAT command\r\n * object (no `{ matcher, hooks:[...] }` wrapper).\r\n * - Reply: a JSON object on stdout (exit 0). deny/ask carry `permission` +\r\n * `user_message`; modify carries `updated_input`; context injects via\r\n * `agent_message` (PreToolUse) or `additional_context` (Post/SessionStart).\r\n *\r\n * Cursor supports its own `${env:VAR}` native interpolation, so env/header/url\r\n * values are rewritten to that native token rather than baked into the file.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\n\r\nimport { BaseAdapter, type HookMergeDescriptor } from \"../base.js\";\r\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n CommandDef,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookEventName,\r\n HookParadigm,\r\n HookResponse,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PostToolUseFailureEvent,\r\n PreCompactEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionEndEvent,\r\n SessionStartEvent,\r\n StopEvent,\r\n SubagentDef,\r\n SubagentStartEvent,\r\n SubagentStopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { rewriteEnvRefs } from \"../../core/interpolate.js\";\r\nimport {\r\n buildWrappedStdio,\r\n isHomeBinHookCommand,\r\n} from \"../../core/spawn.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\nimport { normalizeSessionSource } from \"../claude-code/wire.js\";\r\n\r\nconst HOST: PlatformId = \"cursor\";\r\nconst MCP_ROOT_KEY = \"mcpServers\";\r\n\r\n/**\r\n * Native hooks.json version Cursor expects. Exported as the SINGLE source of\r\n * truth for Cursor's hooks-file version, shared with the `cursor-plugin`\r\n * package emitter so the live install + the packaged bundle can never stamp\r\n * different versions (see core/package-formats/cursor.ts).\r\n */\r\nexport const CURSOR_HOOKS_VERSION = 1;\r\n\r\n/**\r\n * Cursor-native hook event names, in the lower-camel form Cursor reads from\r\n * hooks.json. The first four are the events the proven context-mode adapter\r\n * registers; postToolUseFailure / subagentStart / subagentStop are Cursor's\r\n * documented \"Subagent (Task tool) lifecycle\" + tool-failure hooks.\r\n */\r\nconst CURSOR_EVENT = {\r\n PreToolUse: \"preToolUse\",\r\n PostToolUse: \"postToolUse\",\r\n SessionStart: \"sessionStart\",\r\n Stop: \"stop\",\r\n PostToolUseFailure: \"postToolUseFailure\",\r\n SubagentStart: \"subagentStart\",\r\n SubagentStop: \"subagentStop\",\r\n // Lifecycle/prompt events Cursor 1.7+ documents (cursor.com/docs/hooks):\r\n // sessionEnd is fire-and-forget; preCompact is observational (cannot block);\r\n // beforeSubmitPrompt fires before a prompt is sent and CAN prevent submission\r\n // (Cursor itself matches beforeSubmitPrompt against the value \"UserPromptSubmit\").\r\n SessionEnd: \"sessionEnd\",\r\n PreCompact: \"preCompact\",\r\n UserPromptSubmit: \"beforeSubmitPrompt\",\r\n} as const;\r\n\r\n/**\r\n * Map our normalized event names to Cursor's native hook event names. Only the\r\n * events Cursor actually supports are present; everything else has no Cursor\r\n * equivalent and is reported as a skip/warn at install time.\r\n *\r\n * PermissionRequest is deliberately ABSENT: Cursor has no permission-dialog\r\n * event — its permission gate is the OUTPUT field `permission: \"allow\"|\"deny\"|\r\n * \"ask\"` of the before* hooks (beforeShellExecution / beforeMCPExecution /\r\n * beforeReadFile / preToolUse), not an observable event. Install reports the\r\n * standard skip-warn for it.\r\n *\r\n * Exported as the SINGLE source of truth for canonical→Cursor-native event\r\n * mapping, shared with the `cursor-plugin` package emitter (see\r\n * core/package-formats/cursor.ts) so the packaged bundle's hooks.json keys can\r\n * never silently diverge from the live install adapter's.\r\n */\r\nexport const CURSOR_EVENT_MAP: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: CURSOR_EVENT.PreToolUse,\r\n PostToolUse: CURSOR_EVENT.PostToolUse,\r\n SessionStart: CURSOR_EVENT.SessionStart,\r\n Stop: CURSOR_EVENT.Stop,\r\n PostToolUseFailure: CURSOR_EVENT.PostToolUseFailure,\r\n SubagentStart: CURSOR_EVENT.SubagentStart,\r\n SubagentStop: CURSOR_EVENT.SubagentStop,\r\n SessionEnd: CURSOR_EVENT.SessionEnd,\r\n PreCompact: CURSOR_EVENT.PreCompact,\r\n UserPromptSubmit: CURSOR_EVENT.UserPromptSubmit,\r\n};\r\n\r\n/** A single Cursor native hook entry — a flat command object. */\r\ninterface CursorHookEntry {\r\n command: string;\r\n matcher?: string;\r\n}\r\n\r\n/** Native MCP server entry shapes Cursor accepts under `mcpServers`. */\r\ninterface CursorStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n cwd?: string;\r\n}\r\ninterface CursorHttpServer {\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/** Raw Cursor hook stdin payload (snake_case wire fields). */\r\ninterface CursorWireInput {\r\n connector?: unknown;\r\n tool_name?: string;\r\n tool_input?: Record<string, unknown>;\r\n tool_output?: string;\r\n error_message?: string;\r\n cwd?: string;\r\n workspace_roots?: string[];\r\n conversation_id?: string;\r\n session_id?: string;\r\n generation_id?: string;\r\n trigger?: string;\r\n status?: string;\r\n loop_count?: number;\r\n stop_hook_active?: boolean;\r\n\r\n // sessionStart — Cursor's stdin is EXACTLY { session_id, is_background_agent,\r\n // composer_mode } (cursor.com/docs/hooks ~1278-1297): there is NO source/trigger\r\n // start-source discriminator. composer_mode is the editor MODE (agent|ask|edit),\r\n // NOT our normalized SessionStart.source enum (startup|compact|resume|clear), so\r\n // it does not map; surfaced here only so the host shape is documented (no\r\n // normalized field exists for either — see core/types.ts SessionStartEvent).\r\n is_background_agent?: boolean;\r\n composer_mode?: string;\r\n\r\n // beforeSubmitPrompt (UserPromptSubmit) — the submitted prompt text.\r\n // sessionEnd — the documented end reason. Both field names are taken\r\n // verbatim from cursor.com/docs/hooks (snake_case wire).\r\n prompt?: string;\r\n reason?: string;\r\n\r\n // postToolUseFailure — Cursor's existing error vocabulary is error_message;\r\n // the Claude-compatible names are accepted defensively (unverified wire).\r\n error?: string;\r\n tool_use_id?: string;\r\n is_interrupt?: boolean;\r\n // postToolUse / postToolUseFailure carry a BARE `duration` (ms), not\r\n // `duration_ms` (cursor.com/docs/hooks ~870,883,904,918). `duration_ms` is the\r\n // distinct field on sessionEnd (~1315) and subagentStop (~973,994), kept below.\r\n duration?: number;\r\n duration_ms?: number;\r\n\r\n // subagentStart / subagentStop (Task-tool lifecycle). Both name families are\r\n // parsed defensively: agent_* (Claude-compatible) and subagent_* (Cursor-ish).\r\n agent_id?: string;\r\n agent_type?: string;\r\n subagent_id?: string;\r\n subagent_type?: string;\r\n // subagentStop carries the subagent's output text under `summary`, NOT\r\n // last_assistant_message (cursor.com/docs/hooks ~972,993). This is read into\r\n // the normalized lastAssistantMessage.\r\n summary?: string;\r\n}\r\n\r\nexport class CursorAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Cursor\";\r\n readonly paradigm: HookParadigm = \"json-stdio\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\r\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\r\n supportsMemory: true,\r\n // Cursor natively supports pre/post tool-use, session start/end, prompt\r\n // submission, context compaction, and stop (cursor.com/docs/hooks, v1.7+).\r\n preToolUse: true,\r\n postToolUse: true,\r\n preCompact: true,\r\n sessionStart: true,\r\n sessionEnd: true,\r\n userPromptSubmit: true,\r\n stop: true,\r\n notification: false,\r\n // Newer events: Cursor has dedicated postToolUseFailure + subagentStart/\r\n // subagentStop hooks. permissionRequest stays unset — Cursor's permission\r\n // gate is an OUTPUT field of its before* hooks, not an observable event\r\n // (see the EVENT_MAP note).\r\n postToolUseFailure: true,\r\n subagentStart: true,\r\n subagentStop: true,\r\n // Cursor's preToolUse can rewrite tool input (updated_input) but cannot\r\n // rewrite already-emitted tool output.\r\n canModifyArgs: true,\r\n canModifyOutput: false,\r\n canInjectSessionContext: true,\r\n transports: [\"stdio\", \"http\"],\r\n // Server env/url use Cursor's NATIVE ${env:VAR} interpolation (rewriteEnvRefs)\r\n // — the token survives into mcp.json, never a baked literal — so the\r\n // installer's unset-env-ref bake warn does not apply here.\r\n nativeServerEnvInterpolation: true,\r\n // Content surfaces: Cursor supports all three (commands, skills, subagents).\r\n supportsCommands: true,\r\n supportsSkills: true,\r\n supportsSubagents: true,\r\n // Native passthrough hooks: Cursor documents many granular hooks with NO\r\n // canonical analog — beforeShellExecution / afterShellExecution /\r\n // beforeMCPExecution / afterMCPExecution / beforeReadFile / afterFileEdit /\r\n // beforeTabFileRead / afterTabFileEdit / workspaceOpen / afterAgentResponse /\r\n // afterAgentThought (cursor.com/docs/hooks). They are\r\n // host-specific (below the >=3-host core bar; see\r\n // docs/research/host-specific-hook-events-design.md). A connector reaches them\r\n // by declaring platforms[\"cursor\"].nativeHooks; installHooks writes those\r\n // event-name keys verbatim into hooks.json, and the generic uninstall reverses\r\n // them.\r\n supportsNativeHooks: true,\r\n // Cursor has a command-driven status line (`/statusline` → `statusLine` in\r\n // ~/.cursor/cli-config.json, GLOBAL scope only) per the Cursor changelog, but\r\n // the config-key shape + the Claude-parity stdin payload are sourced from a\r\n // community tool (agent-status-pills), not first-party Cursor docs — payload\r\n // field names unverified. Deferred pending a live cursor-agent capture; not a\r\n // permanent gap; user-scope only when wired.\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = join(homedir(), \".cursor\");\r\n const userMcp = join(userDir, \"mcp.json\");\r\n const userHooks = join(userDir, \"hooks.json\");\r\n const projectDirCursor = join(projectDir, \".cursor\");\r\n const installed =\r\n existsSync(userDir) ||\r\n existsSync(userMcp) ||\r\n existsSync(userHooks) ||\r\n existsSync(projectDirCursor);\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath: userMcp,\r\n scope: \"user\",\r\n reason: installed\r\n ? `found Cursor config under ${userDir}`\r\n : `no Cursor config at ${userDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".cursor\")\r\n : join(homedir(), \".cursor\");\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"mcp.json\");\r\n }\r\n\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"hooks.json\");\r\n }\r\n\r\n // ── MCP server install / uninstall ───────────────────────────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n const override = connector.platforms[HOST]?.server;\r\n if (!connector.server || override === false) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: connector.server\r\n ? \"server registration disabled for cursor\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\r\n // Shallow-merge any per-platform server override into the base ServerDef.\r\n const server: ServerDef =\r\n override && typeof override === \"object\"\r\n ? { ...connector.server, ...override }\r\n : connector.server;\r\n\r\n const serverPath = this.getServerConfigPath(ctx);\r\n const entry = this.renderServerEntry(ctx, server);\r\n\r\n return [\r\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\r\n ];\r\n }\r\n\r\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\r\n const serverPath = this.getServerConfigPath(ctx);\r\n return [\r\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\r\n ];\r\n }\r\n\r\n /** Render a normalized ServerDef into Cursor's native mcpServers entry. */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): CursorStdioServer | CursorHttpServer {\r\n const transport: Transport = server.transport;\r\n\r\n if (transport === \"stdio\") {\r\n let command = server.command ?? \"\";\r\n let args = [...(server.args ?? [])];\r\n\r\n // Transparent telemetry wrapping: route the real command through\r\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\r\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n const entry: CursorStdioServer = { command: this.rewrite(command) };\r\n if (args.length > 0) entry.args = args.map((a) => this.rewrite(a));\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.env = env;\r\n if (server.cwd) entry.cwd = this.rewrite(server.cwd);\r\n return entry;\r\n }\r\n\r\n // http (and any other remote transport we surface) — Cursor registers a URL.\r\n const entry: CursorHttpServer = { url: this.rewrite(server.url ?? \"\") };\r\n const headers = this.renderEnv(server.headers);\r\n if (headers) entry.headers = headers;\r\n return entry;\r\n }\r\n\r\n /**\r\n * Render env/header values. Cursor supports its own `${env:VAR}` native\r\n * interpolation, so translate `${env:VAR}` refs to that native token rather\r\n * than baking secrets into the file. Literals pass through unchanged.\r\n */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n const out: Record<string, string> = {};\r\n for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);\r\n return out;\r\n }\r\n\r\n /** Translate `${env:VAR(:-default)}` to Cursor's native `${env:VAR}` token. */\r\n private rewrite(value: string): string {\r\n return rewriteEnvRefs(value, cursorEnvToken);\r\n }\r\n\r\n // ── Hook install / uninstall ─────────────────────────────────────────────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n const override = connector.platforms[HOST];\r\n\r\n // `hooks: false` disables only the NORMALIZED events. nativeHooks is a\r\n // sibling, cursor-scoped declaration on the same override and installs\r\n // regardless.\r\n const normalizedEvents = override?.hooks === false ? [] : connector.hookEvents;\r\n const nativeHooks = override?.nativeHooks ?? {};\r\n const nativeEvents = Object.keys(nativeHooks);\r\n\r\n if (normalizedEvents.length === 0 && nativeEvents.length === 0) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: override?.hooks === false ? \"hooks disabled for cursor\" : \"connector declares no hooks\",\r\n },\r\n ];\r\n }\r\n\r\n // Normalized events go through the engine's mapEvent/warn path; native\r\n // event-name keys ride the separate `native` pass (verbatim keys, EXACT\r\n // command, the `(native)` detail) — see the descriptor + base.upsertHookEntries.\r\n const pending = normalizedEvents.map((event) => ({\r\n event,\r\n matcher: connector.hooks[event]?.matcher ?? \"\",\r\n }));\r\n const native = nativeEvents.map((event) => ({\r\n event,\r\n matcher: nativeHooks[event]?.matcher ?? \"\",\r\n }));\r\n return this.upsertHookEntries(\r\n ctx,\r\n this.getHookConfigPath(ctx),\r\n pending,\r\n this.hookDescriptor(ctx),\r\n native,\r\n );\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));\r\n }\r\n\r\n /**\r\n * Cursor's hook-merge descriptor (FLAT shape `{ command, matcher? }`):\r\n * - mapEvent renames canonical → Cursor's lower-camel native key\r\n * (CURSOR_EVENT_MAP); an unmapped event warn-skips (no Cursor equivalent).\r\n * - renderEntry omits the `matcher` key when the matcher is falsy — this\r\n * `{command}` vs `{command,matcher}` distinction is load-bearing on-disk\r\n * bytes (Cursor's flat entry shape), reproduced exactly here.\r\n * - install find is connector-generic (ANY of our commands at the flat\r\n * `entry.command`); uninstall drops whole owned entries (flat — NO\r\n * stripInner). The version stamp is install-only via onMutate.\r\n * - the native pass uses EXACT-command ownership so a native key coinciding\r\n * with a normalized event's mapped key adds a SECOND distinct command\r\n * rather than clobbering the normalized entry.\r\n */\r\n private hookDescriptor(ctx: InstallContext): HookMergeDescriptor<CursorHookEntry> {\r\n return {\r\n mapEvent: (e) => CURSOR_EVENT_MAP[e as HookEventName],\r\n unmappedWarnDetail: (e) => `${e} has no Cursor hook equivalent — skipped`,\r\n renderEntry: (_event, matcher, command) =>\r\n matcher ? { command, matcher } : { command },\r\n entryOwnsCommand: (entry, _command) => this.isOurCommand(entry.command, ctx),\r\n ownsEntryForRemove: (c) => (entry) => this.isOurCommand(entry.command, c),\r\n skipDetail: (e) => `hooks.${e} already registered`,\r\n removeDetail: (e, n) => `hooks.${e} (${n})`,\r\n absentDetail: \"no hooks section present\",\r\n noMatchDetail: \"no matching hook entries\",\r\n onMutate: (file) => {\r\n (file as { version?: number }).version = CURSOR_HOOKS_VERSION;\r\n },\r\n nativeOwnsCommand: (entry, command) => entry.command === command,\r\n nativeSkipDetail: (e) => `hooks.${e} (native) already registered`,\r\n nativeMutateDetail: (e) => `hooks.${e} (native)`,\r\n };\r\n }\r\n\r\n /** True when a hook command references our home binary AND this connector id\r\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\r\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\r\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\r\n }\r\n\r\n // ── Content surfaces: commands / skills / subagents ──────────────────────\r\n // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,\r\n // agents}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\r\n // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile\r\n // and reversible via removeContentFile. Honors platforms[\"cursor\"] per-surface\r\n // false to skip. Cursor commands are BODY-ONLY markdown (no frontmatter);\r\n // skills are the uniform <name>/SKILL.md + resources; subagents are md+fm.\r\n\r\n private commandsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"commands\");\r\n }\r\n private skillsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"skills\");\r\n }\r\n private agentsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"agents\");\r\n }\r\n\r\n /** Native command file path: <configDir>/commands/<name>.md. */\r\n private commandPath(ctx: InstallContext, name: string): string {\r\n return join(this.commandsDir(ctx), `${name}.md`);\r\n }\r\n /** Native skill dir: <configDir>/skills/<name>. */\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\r\n /** Native subagent file path: <configDir>/agents/<name>.md. */\r\n private subagentPath(ctx: InstallContext, name: string): string {\r\n return join(this.agentsDir(ctx), `${name}.md`);\r\n }\r\n\r\n // ── Commands ──────────────────────────────────────────────────────────────\r\n\r\n override installCommands(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.commands === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for cursor\" }];\r\n }\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.writeContentFile(\r\n this.commandPath(ctx, cmd.name),\r\n this.renderCommand(cmd),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\r\n );\r\n }\r\n\r\n /**\r\n * Render a Cursor command: BODY-ONLY markdown (no frontmatter). Cursor reads\r\n * the file as the command prompt verbatim. We prepend the one-line description\r\n * as an HTML comment header when present so authoring intent survives the\r\n * round-trip without leaking into the rendered prompt. A description containing\r\n * \"-->\" would prematurely CLOSE the HTML comment and leak the remainder into\r\n * the prompt, so we neutralize that sequence before embedding it.\r\n */\r\n private renderCommand(cmd: CommandDef): string {\r\n if (!cmd.description) return `${cmd.prompt}\\n`;\r\n // Break any literal comment-close so it cannot terminate our header early.\r\n const safe = cmd.description.replace(/--+>/g, (m) => m.replace(/>/g, \">\"));\r\n return `<!-- ${safe} -->\\n\\n${cmd.prompt}\\n`;\r\n }\r\n\r\n // ── Skills ────────────────────────────────────────────────────────────────\r\n\r\n override installSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.skills === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for cursor\" }];\r\n }\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\r\n );\r\n // Bundle any resource files beside SKILL.md (relative path → contents).\r\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\r\n // (config-time validation already rejects these, but never trust input).\r\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\r\n }\r\n }\r\n return changes;\r\n }\r\n\r\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n // Remove only the files we wrote (SKILL.md + declared resources), then the\r\n // skill dir itself when we own its full contents.\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue; // never delete outside the skill dir\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n // Only remove the skill dir when WE own its full contents — never rm -rf a\r\n // dir that still holds user-added / sibling-tool / shared files.\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n // ── Subagents ───────────────────────────────────────────────────────────────\r\n\r\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.subagents === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for cursor\" }];\r\n }\r\n if (connector.subagents.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\r\n }\r\n return connector.subagents.map((agent) =>\r\n this.writeContentFile(\r\n this.subagentPath(ctx, agent.name),\r\n this.renderSubagent(agent),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.subagents.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\r\n }\r\n return connector.subagents.map((agent) =>\r\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\r\n );\r\n }\r\n\r\n /** Render a Cursor subagent to md+frontmatter (name, description, model, readonly) + prompt body. */\r\n private renderSubagent(agent: SubagentDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n name: agent.name,\r\n description: agent.description,\r\n };\r\n if (agent.model !== undefined) frontmatter.model = agent.model;\r\n if (agent.readonly !== undefined) frontmatter.readonly = agent.readonly;\r\n if (agent.extra) Object.assign(frontmatter, agent.extra);\r\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const mcpPath = this.getServerConfigPath(ctx);\r\n const hooksPath = this.getHookConfigPath(ctx);\r\n const checks: HealthCheck[] = [\r\n {\r\n name: `${this.name}: mcp.json present`,\r\n check: () =>\r\n existsSync(mcpPath)\r\n ? { status: \"OK\", detail: mcpPath }\r\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\r\n },\r\n {\r\n name: `${this.name}: hooks.json present`,\r\n check: () => {\r\n // Same \"only assert what the connector declares\" rule as the\r\n // content-surface checks below: a hookless connector never writes\r\n // hooks.json, so its absence is healthy, not a failure.\r\n if (ctx.connector.hookEvents.length === 0) {\r\n return { status: \"OK\", detail: \"no hooks declared\" };\r\n }\r\n return existsSync(hooksPath)\r\n ? { status: \"OK\", detail: hooksPath }\r\n : { status: \"FAIL\", detail: `not found: ${hooksPath}` };\r\n },\r\n },\r\n ];\r\n\r\n // Content-surface checks: only assert presence of the files this connector\r\n // declares (skip silently for surfaces it never asked for).\r\n for (const cmd of ctx.connector.commands) {\r\n const p = this.commandPath(ctx, cmd.name);\r\n checks.push({\r\n name: `${this.name}: command ${cmd.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n for (const skill of ctx.connector.skills) {\r\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\r\n checks.push({\r\n name: `${this.name}: skill ${skill.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n for (const agent of ctx.connector.subagents) {\r\n const p = this.subagentPath(ctx, agent.name);\r\n checks.push({\r\n name: `${this.name}: subagent ${agent.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n return checks;\r\n }\r\n\r\n // ── Runtime: parse Cursor stdin JSON → normalized event ──────────────────\r\n\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as CursorWireInput;\r\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\r\n const sessionId = extractSessionId(input);\r\n const projectDir = this.getProjectDir(input);\r\n\r\n const base = {\r\n hostPlatform: HOST,\r\n connectorId,\r\n sessionId,\r\n raw,\r\n ...(projectDir !== undefined ? { projectDir } : {}),\r\n } as const;\r\n\r\n switch (event) {\r\n case \"PreToolUse\": {\r\n const ev: PreToolUseEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"PostToolUse\": {\r\n const toolOutput = input.tool_output ?? input.error_message;\r\n const ev: PostToolUseEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n ...(toolOutput !== undefined ? { toolOutput } : {}),\r\n ...(input.error_message ? { isError: true } : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SessionStart\": {\r\n // Cursor's sessionStart stdin is exactly { session_id, is_background_agent,\r\n // composer_mode } — there is NO source/trigger start-source discriminator\r\n // (cursor.com/docs/hooks ~1278-1297). composer_mode is the editor MODE\r\n // (agent|ask|edit), a different concept from our normalized source enum\r\n // (startup|compact|resume|clear), so it does NOT map. With no discriminator\r\n // available, the normalized source stays at its 'startup' default (via\r\n // normalizeSessionSource(undefined)). is_background_agent / composer_mode\r\n // ride along on base.raw; there is no normalized field for either.\r\n const ev: SessionStartEvent = {\r\n ...base,\r\n source: normalizeSessionSource(undefined),\r\n };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n const ev: StopEvent = {\r\n ...base,\r\n ...(typeof input.stop_hook_active === \"boolean\"\r\n ? { stopHookActive: input.stop_hook_active }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SessionEnd\": {\r\n // Cursor sessionEnd: { session_id, reason, duration_ms, ... }. session_id\r\n // is already folded into base.sessionId via extractSessionId; only the\r\n // documented `reason` enum maps onto the normalized SessionEnd shape.\r\n const ev: SessionEndEvent = {\r\n ...base,\r\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\r\n };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n // Cursor beforeSubmitPrompt: { prompt, attachments }. attachments has no\r\n // normalized field and is preserved via base.raw; only `prompt` maps.\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"PreCompact\": {\r\n // Cursor preCompact: { trigger: \"auto\"|\"manual\", context_*… }. Only the\r\n // documented `trigger` enum maps onto the normalized PreCompact shape.\r\n const ev: PreCompactEvent = {\r\n ...base,\r\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\r\n ? { trigger: input.trigger }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"PostToolUseFailure\": {\r\n // Cursor's established error field is error_message; fall back to the\r\n // Claude-compatible `error` defensively.\r\n const error = input.error_message ?? input.error ?? \"\";\r\n const ev: PostToolUseFailureEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n error,\r\n ...(typeof input.tool_use_id === \"string\"\r\n ? { toolUseId: input.tool_use_id }\r\n : {}),\r\n ...(typeof input.is_interrupt === \"boolean\"\r\n ? { isInterrupt: input.is_interrupt }\r\n : {}),\r\n // postToolUseFailure reports a BARE `duration` (ms), not `duration_ms`\r\n // (cursor.com/docs/hooks ~904,918). duration_ms only exists on\r\n // sessionEnd/subagentStop.\r\n ...(typeof input.duration === \"number\"\r\n ? { durationMs: input.duration }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStart\": {\r\n const agentId = input.agent_id ?? input.subagent_id;\r\n const agentType = input.agent_type ?? input.subagent_type;\r\n const ev: SubagentStartEvent = {\r\n ...base,\r\n ...(typeof agentId === \"string\" ? { agentId } : {}),\r\n ...(typeof agentType === \"string\" ? { agentType } : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStop\": {\r\n const agentId = input.agent_id ?? input.subagent_id;\r\n const agentType = input.agent_type ?? input.subagent_type;\r\n const ev: SubagentStopEvent = {\r\n ...base,\r\n ...(typeof agentId === \"string\" ? { agentId } : {}),\r\n ...(typeof agentType === \"string\" ? { agentType } : {}),\r\n // Cursor's subagentStop carries the subagent's output text under\r\n // `summary`, NOT last_assistant_message (cursor.com/docs/hooks ~972,993).\r\n ...(typeof input.summary === \"string\"\r\n ? { lastAssistantMessage: input.summary }\r\n : {}),\r\n ...(typeof input.stop_hook_active === \"boolean\"\r\n ? { stopHookActive: input.stop_hook_active }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n default: {\r\n // Cursor never delivers Notification / PermissionRequest (no native\r\n // equivalent — permission is an OUTPUT field of its before* hooks, not\r\n // an event). If the runtime dispatches one anyway, fail loudly.\r\n throw new Error(`unsupported cursor hook event: ${String(event)}`);\r\n }\r\n }\r\n }\r\n\r\n private getProjectDir(input: CursorWireInput): string | undefined {\r\n return input.cwd ?? input.workspace_roots?.[0] ?? undefined;\r\n }\r\n\r\n // ── Runtime: normalized response → Cursor native hook reply ──────────────\r\n\r\n formatReply(event: HookEventName, response: HookResponse): HookReply {\r\n const decision = response.decision ?? \"allow\";\r\n\r\n // postToolUseFailure (feedback beside the error) and subagentStart (context\r\n // injected into the SUBAGENT's conversation) are observe/context-only on\r\n // Cursor: \"context\" emits additional_context, and a \"deny\" DEGRADES to the\r\n // same shape carrying the reason (the tool already failed / the spawn is\r\n // not blockable). Everything else is a minimal no-op payload (Cursor\r\n // rejects empty stdout as \"no valid response\").\r\n if (event === \"PostToolUseFailure\" || event === \"SubagentStart\") {\r\n const context =\r\n decision === \"context\"\r\n ? response.additionalContext\r\n : decision === \"deny\"\r\n ? response.reason ?? response.additionalContext\r\n : undefined;\r\n return this.stdout({ additional_context: context ?? \"\" });\r\n }\r\n\r\n // beforeSubmitPrompt (UserPromptSubmit) is a BLOCK gate, not a permission/\r\n // context surface: its only documented output is { continue, user_message }\r\n // (cursor.com/docs/hooks). A \"deny\" prevents submission (continue:false +\r\n // reason); it cannot inject context (no additional_context/agent_message\r\n // field), so every non-deny decision is a no-op continue:true.\r\n if (event === \"UserPromptSubmit\") {\r\n if (decision === \"deny\") {\r\n return this.stdout({\r\n continue: false,\r\n user_message: response.reason ?? \"Blocked by hook\",\r\n });\r\n }\r\n return this.stdout({ continue: true });\r\n }\r\n\r\n // sessionEnd is fire-and-forget (the response is logged but not used) and\r\n // preCompact is observational (cannot block or modify compaction) per\r\n // cursor.com/docs/hooks — neither carries a decision Cursor honors, so both\r\n // are an unconditional no-op passthrough (mirrors Stop).\r\n if (event === \"SessionEnd\" || event === \"PreCompact\") {\r\n return { exitCode: 0 };\r\n }\r\n\r\n // deny → block the action with a user-facing message. (On SubagentStop\r\n // this follows the adapter's Stop idiom — the deny carries Stop semantics.)\r\n if (decision === \"deny\") {\r\n return this.stdout({\r\n permission: \"deny\",\r\n user_message: response.reason ?? \"Blocked by hook\",\r\n });\r\n }\r\n\r\n // ask → prompt the user to confirm.\r\n if (decision === \"ask\") {\r\n return this.stdout({\r\n permission: \"ask\",\r\n user_message: response.reason ?? \"Confirmation required by hook\",\r\n });\r\n }\r\n\r\n // modify → rewrite PreToolUse input (only where Cursor supports it).\r\n if (decision === \"modify\") {\r\n if (event === \"PreToolUse\" && response.updatedInput) {\r\n return this.stdout({ updated_input: response.updatedInput });\r\n }\r\n // Output rewrite is unsupported on Cursor; fall through to allow.\r\n }\r\n\r\n // context → inject soft guidance. PreToolUse uses `agent_message`; Post and\r\n // SessionStart use `additional_context`.\r\n if (decision === \"context\" && response.additionalContext) {\r\n return event === \"PreToolUse\"\r\n ? this.stdout({ agent_message: response.additionalContext })\r\n : this.stdout({ additional_context: response.additionalContext });\r\n }\r\n\r\n // SessionStart always emits valid JSON even on a no-op (Cursor rejects empty\r\n // stdout as \"no valid response\").\r\n if (event === \"SessionStart\") {\r\n return this.stdout({ additional_context: response.additionalContext ?? \"\" });\r\n }\r\n\r\n // allow / void → minimal no-op payload (Cursor rejects empty stdout).\r\n if (event === \"PreToolUse\") return this.stdout({ agent_message: \"\" });\r\n if (event === \"PostToolUse\") return this.stdout({ additional_context: \"\" });\r\n return { exitCode: 0 };\r\n }\r\n\r\n private stdout(payload: unknown): HookReply {\r\n return { exitCode: 0, stdout: JSON.stringify(payload) };\r\n }\r\n}\r\n\r\n/** Cursor native interpolation token: `${env:VAR}` → `${env:VAR}` (passthrough). */\r\nfunction cursorEnvToken(name: string): string {\r\n return `\\${env:${name}}`;\r\n}\r\n\r\nfunction extractSessionId(input: CursorWireInput): string {\r\n if (typeof input.conversation_id === \"string\") return input.conversation_id;\r\n if (typeof input.session_id === \"string\") return input.session_id;\r\n return \"\";\r\n}\r\n\r\nexport const adapter = new CursorAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|
|
@@ -1 +0,0 @@
|
|
|
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 future host affordance (slash command /\r\n * keybinding) points at:\r\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). v1 ships only this command\r\n * builder + the runtime verb; no adapter EMITS the affordance yet.\r\n */\r\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":[]}
|