@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/usage/readers/kilo.ts"],"sourcesContent":["/**\r\n * usage/readers/kilo — Kilo Code (VS Code extension) task-log reader.\r\n *\r\n * Faithful port of tokscale sessions/kilocode.rs, which is a one-line wrapper\r\n * around roocode.rs `parse_roo_kilo_file(path, \"kilocode\")` — Kilo Code shares\r\n * the EXACT same task-log format as Roo Code, differing only in its VS Code\r\n * extension id (`kilocode.kilo-code`) and the source label. This is the Kilo\r\n * VS Code extension usage (distinct from the kilo-cli SQLite reader, platformId\r\n * \"kilo-cli\", which lands separately).\r\n *\r\n * Kilo Code (kilocode.kilo-code) persists per-task logs under its VS Code\r\n * globalStorage:\r\n * <vscodeUserDir>/globalStorage/kilocode.kilo-code/tasks/<taskId>/\r\n * ui_messages.json (the UI message stream — token source)\r\n * api_conversation_history.json (sibling — model/agent source)\r\n * The Rust scanner additionally discovers a remote-host server path under\r\n * ~/.vscode-server/data/User/globalStorage/kilocode.kilo-code/tasks, so we scan\r\n * both the desktop and server tasks roots that exist.\r\n *\r\n * kilo is NOT in paths.ts hostRoots (that per-platform table targets CLIs with\r\n * ~/.<tool> roots, not VS Code extension globalStorage), so this reader resolves\r\n * the cross-OS VS Code \"User\" dir itself, mirroring readers/roo-code.ts:\r\n * - macOS → ~/Library/Application Support/Code/User\r\n * - Windows → %APPDATA%/Code/User (else ~/AppData/Roaming/Code/User)\r\n * - Linux → ~/.config/Code/User\r\n * An AGENT_CONNECTOR_KILO_DIR override (verbatim, non-empty, ~-expanded, resolved\r\n * against CWD when relative) points directly at a single `tasks` parent when set,\r\n * matching the env convention in paths.ts hostRoots.\r\n *\r\n * Tokens (ui_messages.json): the file is a JSON ARRAY of entries; only entries\r\n * with type==\"say\" AND say==\"api_req_started\" carry usage. Each such entry's\r\n * `text` field is a JSON-in-string payload (SAME shape as Roo Code):\r\n * tokensIn → input\r\n * tokensOut → output\r\n * cacheReads → cacheRead\r\n * cacheWrites → cacheWrite\r\n * cost (f64) → cost\r\n * apiProtocol → providerId (preserved verbatim, e.g. \"azure/openai\")\r\n * reasoning is ALWAYS 0 (Kilo Code does not report it). A malformed text payload,\r\n * a missing text, or an unparseable `ts` skips just that entry.\r\n *\r\n * model / agent (api_conversation_history.json): scan every\r\n * <environment_details>…</environment_details> block for <model>, <slug>, <name>\r\n * tags; the LAST <model> wins (default \"unknown\"); agent prefers <slug> then\r\n * <name> (optional). When the sibling file is absent/unreadable: model \"unknown\",\r\n * no agent — exactly the Rust read_task_metadata fallback.\r\n *\r\n * session id is the taskId — the parent directory name of ui_messages.json\r\n * (port of extract_session_id), defaulting to \"unknown\". provider from\r\n * apiProtocol (trimmed, default \"unknown\"). No project attribution (Kilo Code's\r\n * logs carry no cwd). No dedup — one row per api_req_started event (file\r\n * isolation is the implicit unique context). Confidence is \"host-reported\"\r\n * (real host-logged token counts; the design rates this medium qualitatively).\r\n *\r\n * Fail-open: no root → []; unreadable/malformed file, entry, or payload → skipped\r\n * (never throws). Read-only.\r\n */\r\n\r\nimport { existsSync, readFileSync } from \"node:fs\";\r\nimport { homedir, platform as osPlatform } from \"node:os\";\r\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\r\n\r\nimport type { UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { readJsonFile } from \"../jsonl.js\";\r\nimport { expandHome, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"kilo\" as const;\r\nconst DEFAULT_MODEL = \"unknown\";\r\nconst DEFAULT_PROVIDER = \"unknown\";\r\nconst DEFAULT_SESSION = \"unknown\";\r\n\r\n/** Kilo Code extension id → its VS Code globalStorage folder. */\r\nconst KILO_EXTENSION_ID = \"kilocode.kilo-code\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Storage-root resolution (mirrors readers/roo-code.ts vscodeUserDir + the\r\n// AGENT_CONNECTOR_<PLATFORM>_DIR env convention in paths.ts hostRoots, plus the\r\n// remote .vscode-server server path the Rust scanner adds for KiloCode)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Resolve the cross-OS VS Code per-user \"User\" dir (the globalStorage parent). */\r\nfunction vscodeUserDir(): string {\r\n const home = homedir();\r\n switch (osPlatform()) {\r\n case \"darwin\":\r\n return join(home, \"Library\", \"Application Support\", \"Code\", \"User\");\r\n case \"win32\": {\r\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\r\n return join(appData, \"Code\", \"User\");\r\n }\r\n default:\r\n return join(home, \".config\", \"Code\", \"User\");\r\n }\r\n}\r\n\r\n/**\r\n * The `tasks` roots holding per-task subdirectories. An\r\n * AGENT_CONNECTOR_KILO_DIR override (verbatim, non-empty, ~-expanded, resolved\r\n * against CWD when relative) short-circuits to that single root. Otherwise we\r\n * return the desktop globalStorage tasks dir and the remote-host\r\n * ~/.vscode-server tasks dir (the two roots the Rust scanner discovers for\r\n * KiloCode); the caller scans whichever exist.\r\n */\r\nfunction tasksRoots(): string[] {\r\n const raw = process.env.AGENT_CONNECTOR_KILO_DIR;\r\n if (raw != null && raw.trim() !== \"\") {\r\n const expanded = expandHome(raw.trim());\r\n return [isAbsolute(expanded) ? expanded : resolve(expanded)];\r\n }\r\n const home = homedir();\r\n return [\r\n join(vscodeUserDir(), \"globalStorage\", KILO_EXTENSION_ID, \"tasks\"),\r\n join(home, \".vscode-server\", \"data\", \"User\", \"globalStorage\", KILO_EXTENSION_ID, \"tasks\"),\r\n ];\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Value coercion (ports of utils.rs extract_i64 / extract_f64 / parse_timestamp_str)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Port of extract_i64: number / numeric-string → integer, else undefined. */\r\nfunction extractI64(v: unknown): number | undefined {\r\n if (typeof v === \"number\") {\r\n if (!Number.isFinite(v)) return undefined;\r\n return Math.trunc(v);\r\n }\r\n if (typeof v === \"string\") {\r\n const trimmed = v.trim();\r\n if (!/^[+-]?\\d+$/.test(trimmed)) return undefined; // Rust parses as i64 (integer-only)\r\n const n = Number(trimmed);\r\n return Number.isFinite(n) ? Math.trunc(n) : undefined;\r\n }\r\n return undefined;\r\n}\r\n\r\n/** A non-negative integer from a payload field (0 on absence/garbage, clamped ≥ 0). */\r\nfunction tokenField(v: unknown): number {\r\n const n = extractI64(v);\r\n return n === undefined ? 0 : Math.max(0, n);\r\n}\r\n\r\n/** Port of extract_f64: number / numeric-string → f64, else undefined. */\r\nfunction extractF64(v: unknown): number | undefined {\r\n if (typeof v === \"number\") return Number.isFinite(v) ? v : undefined;\r\n if (typeof v === \"string\") {\r\n const n = Number(v.trim());\r\n return Number.isFinite(n) ? n : undefined;\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Port of utils.rs parse_timestamp_str / parse_entry_timestamp: an RFC3339 string\r\n * → epoch ms; an integer (string or number) → ms (×1000 when below the 1e12 ms\r\n * threshold); rejects ≤ 0. Returns null when unusable so the entry is skipped.\r\n */\r\nfunction parseEntryTimestamp(v: unknown): number | null {\r\n let s: string;\r\n if (typeof v === \"string\") s = v;\r\n else if (typeof v === \"number\" && Number.isFinite(v)) s = String(Math.trunc(v));\r\n else return null;\r\n\r\n return parseTimestampStr(s);\r\n}\r\n\r\nfunction parseTimestampStr(value: string): number | null {\r\n const ms = Date.parse(value);\r\n if (!Number.isNaN(ms)) return ms; // RFC3339 / any Date-parseable form\r\n\r\n if (/^[+-]?\\d+$/.test(value.trim())) {\r\n const numeric = Number(value.trim());\r\n if (!Number.isFinite(numeric) || numeric <= 0) return null;\r\n return numeric >= 1_000_000_000_000 ? numeric : numeric * 1000;\r\n }\r\n return null;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// session id (port of extract_session_id)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Session id = the parent directory (taskId) of ui_messages.json, else \"unknown\". */\r\nfunction extractSessionId(path: string): string {\r\n const parent = basename(dirname(path));\r\n return parent !== \"\" ? parent : DEFAULT_SESSION;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// model / agent (ports of read_task_metadata / extract_model_and_agent / extract_tag_value)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface TaskMetadata {\r\n model: string;\r\n agent?: string;\r\n}\r\n\r\n/** Read the sibling api_conversation_history.json for model/agent (fail-open). */\r\nfunction readTaskMetadata(uiMessagesPath: string): TaskMetadata {\r\n const historyPath = join(dirname(uiMessagesPath), \"api_conversation_history.json\");\r\n let content: string;\r\n try {\r\n content = readFileSync(historyPath, \"utf8\");\r\n } catch {\r\n return { model: DEFAULT_MODEL }; // missing/unreadable → (\"unknown\", None)\r\n }\r\n return extractModelAndAgent(content);\r\n}\r\n\r\n/**\r\n * Scan every <environment_details>…</environment_details> block, extracting\r\n * <model>, <slug>, <name>. The LAST non-empty value of each tag wins (port of the\r\n * Rust last_* accumulation). model defaults to \"unknown\"; agent prefers slug then\r\n * name (and is omitted when neither is present).\r\n */\r\nfunction extractModelAndAgent(content: string): TaskMetadata {\r\n const ENV_START = \"<environment_details>\";\r\n const ENV_END = \"</environment_details>\";\r\n\r\n let offset = 0;\r\n let lastModel: string | undefined;\r\n let lastSlug: string | undefined;\r\n let lastName: string | undefined;\r\n\r\n for (;;) {\r\n const startRel = content.indexOf(ENV_START, offset);\r\n if (startRel < 0) break;\r\n const startIdx = startRel + ENV_START.length;\r\n\r\n const endRel = content.indexOf(ENV_END, startIdx);\r\n if (endRel < 0) break;\r\n\r\n const block = content.slice(startIdx, endRel);\r\n\r\n const model = extractTagValue(block, \"model\");\r\n if (model !== undefined) lastModel = model;\r\n const slug = extractTagValue(block, \"slug\");\r\n if (slug !== undefined) lastSlug = slug;\r\n const name = extractTagValue(block, \"name\");\r\n if (name !== undefined) lastName = name;\r\n\r\n offset = endRel + ENV_END.length;\r\n }\r\n\r\n const agent = lastSlug ?? lastName;\r\n const result: TaskMetadata = { model: lastModel ?? DEFAULT_MODEL };\r\n if (agent !== undefined) result.agent = agent;\r\n return result;\r\n}\r\n\r\n/** First <tag>…</tag> value in `block`, trimmed; undefined when absent or empty. */\r\nfunction extractTagValue(block: string, tag: string): string | undefined {\r\n const open = `<${tag}>`;\r\n const close = `</${tag}>`;\r\n\r\n const openIdx = block.indexOf(open);\r\n if (openIdx < 0) return undefined;\r\n const start = openIdx + open.length;\r\n const endRel = block.indexOf(close, start);\r\n if (endRel < 0) return undefined;\r\n\r\n const value = block.slice(start, endRel).trim();\r\n return value === \"\" ? undefined : value;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// api_req_started payload (port of parse_api_req_started_payload + provider_from_api_protocol)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface ApiReqStartedPayload {\r\n cost: number;\r\n tokensIn: number;\r\n tokensOut: number;\r\n cacheReads: number;\r\n cacheWrites: number;\r\n apiProtocol?: string;\r\n}\r\n\r\n/** Parse the JSON-in-string `text` payload of an api_req_started entry. */\r\nfunction parseApiReqStartedPayload(text: string): ApiReqStartedPayload | undefined {\r\n let value: unknown;\r\n try {\r\n value = JSON.parse(text);\r\n } catch {\r\n return undefined;\r\n }\r\n if (typeof value !== \"object\" || value === null) return undefined;\r\n const obj = value as Record<string, unknown>;\r\n\r\n // cost: extract_f64(.cost).unwrap_or(0.0).max(0.0)\r\n const cost = Math.max(0, extractF64(obj[\"cost\"]) ?? 0);\r\n const apiProtocolRaw = typeof obj[\"apiProtocol\"] === \"string\" ? (obj[\"apiProtocol\"] as string) : undefined;\r\n\r\n const payload: ApiReqStartedPayload = {\r\n cost,\r\n tokensIn: tokenField(obj[\"tokensIn\"]),\r\n tokensOut: tokenField(obj[\"tokensOut\"]),\r\n cacheReads: tokenField(obj[\"cacheReads\"]),\r\n cacheWrites: tokenField(obj[\"cacheWrites\"]),\r\n };\r\n if (apiProtocolRaw !== undefined) payload.apiProtocol = apiProtocolRaw;\r\n return payload;\r\n}\r\n\r\n/** Provider from apiProtocol: trimmed, non-empty, else \"unknown\" (verbatim — no inference). */\r\nfunction providerFromApiProtocol(apiProtocol: string | undefined): string {\r\n if (apiProtocol === undefined) return DEFAULT_PROVIDER;\r\n const trimmed = apiProtocol.trim();\r\n return trimmed === \"\" ? DEFAULT_PROVIDER : trimmed;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// File parse (port of parse_roo_kilo_file with source \"kilocode\")\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The fields we read off a ui_messages.json entry (all optional / unknown). */\r\ninterface UiMessageEntry {\r\n type?: unknown;\r\n say?: unknown;\r\n text?: unknown;\r\n ts?: unknown;\r\n}\r\n\r\n/** Parse one task's ui_messages.json into usage records. */\r\nfunction parseKiloFile(path: string): UsageRecord[] {\r\n const data = readJsonFile(path);\r\n if (!Array.isArray(data)) return []; // malformed / non-array → no rows\r\n\r\n const sessionId = extractSessionId(path);\r\n const { model, agent } = readTaskMetadata(path);\r\n\r\n const out: UsageRecord[] = [];\r\n for (const raw of data) {\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const entry = raw as UiMessageEntry;\r\n\r\n if (entry.type !== \"say\" || entry.say !== \"api_req_started\") continue;\r\n\r\n if (typeof entry.text !== \"string\") continue; // None => skip\r\n const ts = parseEntryTimestamp(entry.ts);\r\n if (ts === null) continue; // unparseable ts => skip\r\n\r\n const payload = parseApiReqStartedPayload(entry.text);\r\n if (payload === undefined) continue; // malformed payload => skip\r\n\r\n const providerId = providerFromApiProtocol(payload.apiProtocol);\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = payload.tokensIn;\r\n tokens.output = payload.tokensOut;\r\n tokens.cacheRead = payload.cacheReads;\r\n tokens.cacheWrite = payload.cacheWrites;\r\n // reasoning stays 0 (Kilo Code does not report it).\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId: model,\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 if (payload.cost > 0) record.cost = payload.cost;\r\n if (agent !== undefined) record.agent = agent;\r\n out.push(record);\r\n }\r\n\r\n return out;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Reader singleton\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The Kilo Code (VS Code extension) usage reader singleton. */\r\nconst kiloReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const roots = tasksRoots().filter((root) => existsSync(root));\r\n if (roots.length === 0) return []; // no tasks dir → fail-open\r\n\r\n const records: UsageRecord[] = [];\r\n for (const root of roots) {\r\n // <root>/<taskId>/ui_messages.json\r\n const files = walkFiles(root, (name, abs) => {\r\n return name === \"ui_messages.json\" && /[\\\\/]ui_messages\\.json$/.test(abs);\r\n });\r\n\r\n for (const file of files) {\r\n let rows: UsageRecord[];\r\n try {\r\n rows = parseKiloFile(file);\r\n } catch {\r\n continue; // fail-open per file\r\n }\r\n for (const row of rows) {\r\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\r\n records.push(row);\r\n }\r\n }\r\n }\r\n return records;\r\n },\r\n};\r\n\r\nexport default kiloReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/kilo/index.ts"],"sourcesContent":["/**\r\n * adapters/kilo — Kilo Code (VS Code extension) platform adapter.\r\n *\r\n * Kilo Code (`kilocode.kilo-code`) is a Roo/Cline-fork VS Code extension that\r\n * as of vsix 7.x was REBUILT on the Kilo CLI server and shares ONE backend with\r\n * the Kilo CLI (adapter id \"kilo-cli\"). Paradigm: **ts-plugin** (same plugin\r\n * layer the CLI uses).\r\n *\r\n * MCP config (vsix 7.3.28 — delegated to the kilo backend):\r\n * - user scope → ~/.config/kilo/kilo.json (XDG: $XDG_CONFIG_HOME/kilo)\r\n * - project scope → <projectDir>/.kilo/kilo.json\r\n * Both are JSON, root key **\"mcp\"**, entry shape\r\n * { type:\"local\", command:[exe,...args], environment:{} } (array command).\r\n * The legacy globalStorage `<vscodeUserDir>/globalStorage/kilocode.kilo-code/\r\n * settings/mcp_settings.json` (root \"mcpServers\") is MIGRATION-ONLY in 7.3.28\r\n * and is no longer the live write target — detectInstalled() still probes it so\r\n * an older install is recognized, but we install into kilo.json.\r\n *\r\n * SHARED BACKEND NOTE: kilo.json (VS Code ext) AND kilo.jsonc (CLI) are MERGED\r\n * by the ONE shared backend at user / project-root / .kilo/ levels — 3-way merge\r\n * verified live. The two platform IDs remain distinct for collision tracking, but\r\n * they share the same config dir and the backend dedupes across both files.\r\n *\r\n * Env interpolation: {env:VARIABLE_NAME} is documented by the pi/kilo backend.\r\n * We still resolve env refs to literals at install time (the conservative path,\r\n * consistent with kilo-cli) to avoid any version dependency on the interpolation\r\n * feature being present at runtime.\r\n *\r\n * Hooks (ts-plugin — same layer as kilo-cli):\r\n * The plugins doc banner reads \"applies to current VSCode extension & CLI\".\r\n * Plugin dirs: project → <projectDir>/.kilo/plugin/, user → ~/.config/kilo/plugin/.\r\n * Auto-discovery applies (as in the CLI ≥ 7.3.16), and we ALSO register the\r\n * module path in kilo.json's `plugin` array for explicit load (both loaded).\r\n * Event names: same as kilo-cli (\"tool.execute.before\", \"tool.execute.after\",\r\n * \"experimental.chat.system.transform\"). Bridge shims to \"kilo\" (not \"kilo-cli\").\r\n *\r\n * Content surfaces:\r\n * Commands → .kilo/commands (project) / ~/.config/kilo/commands (user)\r\n * Skills → .kilo/skills/<name>/SKILL.md (project) / ~/.kilo/skills (user)\r\n * Subagents → .kilo/agents (project) / ~/.config/kilo/agents (user)\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { homedir, platform as osPlatform } from \"node:os\";\r\nimport { join } 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 CommandDef,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookEventName,\r\n HookParadigm,\r\n HookResponse,\r\n PermissionRequestEvent,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionStartEvent,\r\n StopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport { renderBridgePrelude } from \"../../core/ts-plugin-bridge.js\";\r\nimport { xdgConfigHome } from \"../../core/host-paths.js\";\r\nimport {\r\n buildWrappedStdio,\r\n} from \"../../core/spawn.js\";\r\nimport { renderOpenCodeSubagentMd, renderSkillMd } from \"../claude-code/render.js\";\r\n\r\nconst HOST: PlatformId = \"kilo\";\r\n/** vsix 7.3.28 root key in kilo.json (delegated kilo backend). */\r\nconst MCP_ROOT_KEY = \"mcp\";\r\n/** kilo.json array of plugin module paths (also supports auto-discovery). */\r\nconst PLUGIN_ARRAY_KEY = \"plugin\";\r\n/** Live config filename for the VS Code ext (DISTINCT from the CLI's kilo.jsonc). */\r\nconst CONFIG_FILE = \"kilo.json\";\r\n\r\n/** Kilo Code extension id → its (legacy, migration-only) VS Code globalStorage folder. */\r\nconst KILO_EXTENSION_ID = \"kilocode.kilo-code\";\r\n/**\r\n * Legacy globalStorage MCP settings filenames (MIGRATION-ONLY in 7.3.28). The\r\n * Cline-family alternative is probed during detection so an older install is\r\n * still recognized; we no longer WRITE there.\r\n */\r\nconst LEGACY_MCP_SETTINGS_FILE = \"mcp_settings.json\";\r\nconst LEGACY_CLINE_SETTINGS_FILE = \"cline_mcp_settings.json\";\r\n\r\n/**\r\n * Canonical → Kilo (shared ts-plugin layer) event name map. Identical to the\r\n * kilo-cli mapping: the extension and CLI share the same plugin event model.\r\n */\r\nconst EVENT_TO_KILO: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: \"tool.execute.before\",\r\n PostToolUse: \"tool.execute.after\",\r\n SessionStart: \"experimental.chat.system.transform\",\r\n // chat.message fires when a new user message arrives (inspect/modify parts) →\r\n // canonical UserPromptSubmit (mirrors the mimo-code OpenCode fork).\r\n UserPromptSubmit: \"chat.message\",\r\n // permission.ask is the decision-capable gate (auto-allow/auto-deny). The\r\n // handler MUTATES output.status (\"ask\"|\"deny\"|\"allow\") — mirrors OpenCode.\r\n PermissionRequest: \"permission.ask\",\r\n // session.idle (\"session finished responding\") → canonical Stop. NOT a direct\r\n // hook key — dispatched through the generic `event` hook (event.type switch).\r\n // session.idle is doc-listed for the VS Code extension & CLI but its runtime\r\n // firing on a given Kilo build is not separately verified (an upstream FR for\r\n // session-lifecycle hooks exists); if it never fires, Stop is a silent no-op\r\n // (an acceptable degrade — it never mis-fires), so coverage may be optimistic.\r\n Stop: \"session.idle\",\r\n};\r\n\r\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\r\ninterface KiloBridgePayload {\r\n toolName?: string;\r\n toolInput?: Record<string, unknown>;\r\n toolOutput?: string;\r\n isError?: boolean;\r\n prompt?: string;\r\n sessionId?: string;\r\n projectDir?: string;\r\n}\r\n\r\n/**\r\n * Native MCP server entry shapes kilo.json accepts under `mcp` (the delegated\r\n * kilo backend). Local (stdio) servers use a SINGLE array command that folds the\r\n * executable and its args together; env lives under `environment`.\r\n */\r\ninterface KiloLocalServer {\r\n type: \"local\";\r\n command: string[];\r\n environment: Record<string, string>;\r\n}\r\ninterface KiloRemoteServer {\r\n type: \"remote\";\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Resolve the kilo backend user config dir: `$XDG_CONFIG_HOME/kilo` when set,\r\n * else `~/.config/kilo`. This is the SAME backend dir kilo-cli uses (the two\r\n * differ only by filename — kilo.json here vs kilo.jsonc for the CLI).\r\n */\r\nfunction kiloConfigDir(): string {\r\n return join(xdgConfigHome(), \"kilo\");\r\n}\r\n\r\n/**\r\n * Resolve the cross-OS VS Code per-user data directory (the \"User\" folder that\r\n * contains `globalStorage`) — used ONLY to probe the legacy migration-only MCP\r\n * settings file during detection. See module header for the per-platform mapping.\r\n */\r\nfunction vscodeUserDir(): string {\r\n const home = homedir();\r\n switch (osPlatform()) {\r\n case \"darwin\":\r\n return join(home, \"Library\", \"Application Support\", \"Code\", \"User\");\r\n case \"win32\": {\r\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\r\n return join(appData, \"Code\", \"User\");\r\n }\r\n default:\r\n // Linux / other POSIX: XDG-style config dir.\r\n return join(home, \".config\", \"Code\", \"User\");\r\n }\r\n}\r\n\r\nexport class KiloAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Kilo Code\";\r\n readonly paradigm: HookParadigm = \"ts-plugin\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md\r\n // via the base default; user scope → ~/.kilocode/rules/agent-connector.md below).\r\n supportsMemory: true,\r\n // Kilo Code 7.x shares the ts-plugin layer with the Kilo CLI — same events.\r\n preToolUse: true,\r\n postToolUse: true,\r\n preCompact: false,\r\n sessionStart: true,\r\n sessionEnd: false,\r\n // chat.message backs UserPromptSubmit; session.idle (via the generic `event`\r\n // hook) backs Stop.\r\n userPromptSubmit: true,\r\n stop: true,\r\n notification: false,\r\n // Decision-capable permission gate (permission.ask) — mutates output.status.\r\n permissionRequest: true,\r\n canModifyArgs: true,\r\n canModifyOutput: true,\r\n canInjectSessionContext: true,\r\n // Kilo Code registers stdio, SSE, and Streamable HTTP MCP servers.\r\n transports: [\"stdio\", \"sse\", \"http\"],\r\n // Content surfaces: commands, skills (since 7.x rebuild), and subagents.\r\n supportsCommands: true,\r\n supportsSkills: true,\r\n supportsSubagents: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userConfig = this.userConfigPath();\r\n const userBackendDir = kiloConfigDir();\r\n // Probe the legacy (migration-only) globalStorage MCP settings too so an\r\n // older install is still recognized; we never WRITE there anymore.\r\n const legacyExtDir = join(vscodeUserDir(), \"globalStorage\", KILO_EXTENSION_ID);\r\n const legacySettings = join(legacyExtDir, \"settings\", LEGACY_MCP_SETTINGS_FILE);\r\n const legacyClineSettings = join(\r\n legacyExtDir,\r\n \"settings\",\r\n LEGACY_CLINE_SETTINGS_FILE,\r\n );\r\n const projectConfig = join(projectDir, \".kilo\", CONFIG_FILE);\r\n\r\n const userMatch =\r\n existsSync(userConfig) ||\r\n existsSync(userBackendDir) ||\r\n existsSync(legacySettings) ||\r\n existsSync(legacyClineSettings) ||\r\n existsSync(legacyExtDir);\r\n const projectMatch = existsSync(projectConfig);\r\n const installed = userMatch || projectMatch;\r\n\r\n // Prefer the user scope/path when present; otherwise surface the project one.\r\n const scope = userMatch || !projectMatch ? \"user\" : \"project\";\r\n const configPath = scope === \"user\" ? userConfig : projectConfig;\r\n const reason = installed\r\n ? userMatch\r\n ? `found Kilo Code config under ${userBackendDir}`\r\n : `found Kilo Code project config at ${projectConfig}`\r\n : `no Kilo Code config at ${userBackendDir} or ${projectConfig}`;\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,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n /** Absolute path to the user-scope kilo.json (kilo backend, XDG dir). */\r\n private userConfigPath(): string {\r\n return join(kiloConfigDir(), CONFIG_FILE);\r\n }\r\n\r\n // ── Memory surface: global rules dir at user scope ──────────────────────\r\n // Project scope stays on the AGENTS.md base default. User scope targets a\r\n // dedicated agent-connector.md in the legacy-compatible ~/.kilocode/rules/\r\n // dir (always loaded; avoids JSONC `instructions` edits in kilo.jsonc; the\r\n // AC-created file is cleanly deletable on uninstall). Shared backend with\r\n // kilo-cli — the convergent write dedupes via the content hash.\r\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"user\") {\r\n return super.memoryTargets(ctx);\r\n }\r\n return [\r\n {\r\n path: join(homedir(), \".kilocode\", \"rules\", \"agent-connector.md\"),\r\n reason: \"kilo global rules dir (~/.kilocode/rules; agent-connector-owned file)\",\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * MCP config dir. Note the project surface is `.kilo/` (kilo backend), NOT the\r\n * extension's `.kilocode/` content tree (which still hosts commands/subagents).\r\n */\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\")\r\n : kiloConfigDir();\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", CONFIG_FILE)\r\n : this.userConfigPath();\r\n }\r\n\r\n /**\r\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\r\n * The backend also supports auto-discovery from the plugin dir, but we ALSO\r\n * register the path in kilo.json's `plugin` array for explicit load (idempotent).\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.pluginDir(ctx), this.pluginFileName(ctx));\r\n }\r\n\r\n /** Plugin directory the synthesized module is written into, per scope. */\r\n private pluginDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", \"plugin\")\r\n : join(kiloConfigDir(), \"plugin\");\r\n }\r\n\r\n /** Plugin module file name (one per connector, kebab-case id). */\r\n private pluginFileName(ctx: InstallContext): string {\r\n return `${ctx.connector.id}.js`;\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 kilo\"\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 /**\r\n * Render a normalized ServerDef into kilo.json's native `mcp` entry. Local\r\n * (stdio) servers fold the executable + args into a SINGLE `command` array and\r\n * carry env under `environment`; remote servers use a `type:\"remote\"` URL entry.\r\n */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): KiloLocalServer | KiloRemoteServer {\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 // Resolve ${env:VAR} to literals at install time (conservative; consistent\r\n // with kilo-cli even though {env:VARIABLE_NAME} is documented).\r\n const argv: string[] = [\r\n resolveEnvRefsDeep(command),\r\n ...resolveEnvRefsDeep(args),\r\n ];\r\n const entry: KiloLocalServer = {\r\n type: \"local\",\r\n command: argv,\r\n environment: this.renderEnv(server.env) ?? {},\r\n };\r\n return entry;\r\n }\r\n\r\n // sse / http (and any other remote transport) — kilo registers a remote URL.\r\n const entry: KiloRemoteServer = {\r\n type: \"remote\",\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n };\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. Resolve `${env:VAR}` references to literals at\r\n * install time for consistency with kilo-cli.\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 return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n // ── Hook install / uninstall (ts-plugin + explicit `plugin` array) ────────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const configPath = this.getServerConfigPath(ctx);\r\n\r\n if (ctx.connector.platforms[HOST]?.hooks === false) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"hooks disabled for kilo\" },\r\n ];\r\n }\r\n if (ctx.connector.hookEvents.length === 0) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"connector declares no hooks\" },\r\n ];\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n\r\n // 1. Write the synthesized plugin module.\r\n for (const file of this.synthesizePlugin(ctx)) {\r\n changes.push(\r\n this.writeManagedFile(\r\n file.path,\r\n file.contents,\r\n ctx.dryRun,\r\n `kilo plugin module (${this.hookDetail(ctx)})`,\r\n file.executable,\r\n ),\r\n );\r\n }\r\n\r\n // 2. Register the module path in kilo.json's `plugin` array. The backend also\r\n // auto-discovers from the plugin dir, but explicit registration is idempotent\r\n // and ensures loading even if auto-discovery is disabled.\r\n changes.push(this.upsertPluginInArray(configPath, pluginPath, ctx.dryRun));\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_KILO are mapped/wired; any declared\r\n * event with no Kilo mapping is reported separately as \"unsupported here\".\r\n */\r\n private hookDetail(ctx: InstallContext): string {\r\n const declared = ctx.connector.hookEvents;\r\n const mapped = declared.filter((e) => EVENT_TO_KILO[e] !== undefined);\r\n const unsupported = declared.filter((e) => EVENT_TO_KILO[e] === undefined);\r\n const base = mapped.join(\",\");\r\n return unsupported.length > 0\r\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\r\n : base;\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. Deregister the module path from kilo.json's `plugin` array.\r\n changes.push(this.removePluginFromArray(configPath, pluginPath, ctx.dryRun));\r\n\r\n // 2. Remove the plugin module on disk.\r\n changes.push(\r\n this.removeManagedFile(pluginPath, ctx.dryRun, \"kilo plugin module\", \"no kilo plugin module present\"),\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 /** Upsert the module path into kilo.json's top-level `plugin` array (idempotent). */\r\n private upsertPluginInArray(\r\n configPath: string,\r\n modulePath: string,\r\n dryRun: boolean,\r\n ): ChangeRecord {\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 plugins = this.pluginArrayBucket(cfg);\r\n if (plugins.includes(modulePath)) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] already includes module`,\r\n };\r\n }\r\n plugins.push(modulePath);\r\n this.writeJson(configPath, cfg, dryRun);\r\n return {\r\n platform: this.id,\r\n action: \"create\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] += module`,\r\n };\r\n }\r\n\r\n /** Remove the module path from kilo.json's `plugin` array. */\r\n private removePluginFromArray(\r\n configPath: string,\r\n modulePath: string,\r\n dryRun: boolean,\r\n ): ChangeRecord {\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 raw = cfg?.[PLUGIN_ARRAY_KEY];\r\n const plugins = Array.isArray(raw) ? (raw as unknown[]) : undefined;\r\n const idx = plugins ? plugins.indexOf(modulePath) : -1;\r\n if (!cfg || !plugins || idx < 0) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] does not include module`,\r\n };\r\n }\r\n plugins.splice(idx, 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: `${PLUGIN_ARRAY_KEY}[] -= module`,\r\n };\r\n }\r\n\r\n /** Get-or-create the top-level `plugin` array as a mutable string array. */\r\n private pluginArrayBucket(cfg: Record<string, unknown>): string[] {\r\n const existing = cfg[PLUGIN_ARRAY_KEY];\r\n const plugins = Array.isArray(existing)\r\n ? existing.filter((p): p is string => typeof p === \"string\")\r\n : [];\r\n cfg[PLUGIN_ARRAY_KEY] = plugins;\r\n return plugins;\r\n }\r\n\r\n // ── ts-plugin synthesis ────────────────────────────────────────────────\r\n\r\n /**\r\n * Build ONE self-contained ESM plugin module for Kilo Code (the VS Code\r\n * extension). Structurally identical to the kilo-cli plugin but bridges to\r\n * \"kilo\" (not \"kilo-cli\") so the dispatcher routes to the correct adapter.\r\n */\r\n synthesizePlugin(ctx: InstallContext): GeneratedPluginFile[] {\r\n const path = this.getHookConfigPath(ctx);\r\n const contents = this.buildPluginSource(ctx);\r\n return [{ path, contents, executable: false }];\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 events = ctx.connector.hookEvents.filter(\r\n (e): e is HookEventName => EVENT_TO_KILO[e] !== undefined,\r\n );\r\n const has = (e: HookEventName) => events.includes(e);\r\n\r\n const header = `/**\r\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\r\n *\r\n * Self-contained Kilo Code (VS Code extension) plugin bridge for connector ${ctx.connector.id}.\r\n * It imports nothing from agent-connector: every hook invocation shells out to\r\n * the stable home binary's universal entrypoint and JSON-parses the normalized\r\n * response. Fail-open: any bridge error degrades to \"allow\".\r\n *\r\n * Default export is the @kilocode/plugin PluginModule shape\r\n * ({ id, server: async (input) => Hooks }); the extension loads it via the\r\n * plugin dir auto-discovery and/or the \"plugin\" array in kilo.json.\r\n */\r\nimport { execFileSync, execSync } from \"node:child_process\";\r\n\r\n${renderBridgePrelude({\r\n homeBin: ctx.homeBinPath,\r\n connectorId: ctx.connector.id,\r\n hookSlug: \"kilo\",\r\n payloadNoun: \"Kilo\",\r\n eventDoc: \" (PreToolUse|PostToolUse|SessionStart)\",\r\n failOpenComment: \"Fail-open — never wedge a tool call on a bridge error.\",\r\n})}\r\n`;\r\n\r\n const handlers: string[] = [];\r\n\r\n if (has(\"PreToolUse\")) {\r\n handlers.push(` // PreToolUse → block (throw) / rewrite args (mutate output.args).\r\n \"tool.execute.before\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: (output && output.args) ?? {},\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PreToolUse\", payload);\r\n if (!res) return;\r\n // Kilo has no \"ask\" gate — degrade \"ask\" to a block (safe direction).\r\n if (res.decision === \"deny\" || res.decision === \"ask\") {\r\n throw new Error(res.reason || \"Blocked by ${ctx.connector.id}\");\r\n }\r\n if (res.updatedInput && output && output.args) {\r\n Object.assign(output.args, res.updatedInput);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"PostToolUse\")) {\r\n handlers.push(` // PostToolUse → observe / rewrite tool output (mutate output.output).\r\n \"tool.execute.after\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: input.args ?? {},\r\n toolOutput: output ? output.output : undefined,\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PostToolUse\", payload);\r\n if (!res) return;\r\n if (typeof res.updatedOutput === \"string\" && output) {\r\n output.output = res.updatedOutput;\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"SessionStart\")) {\r\n handlers.push(` // SessionStart surrogate → inject context into the system prompt.\r\n // The extension has no real SessionStart hook; the system-prompt transform is\r\n // the verified injection point (mirrors OpenCode and kilo-cli).\r\n \"experimental.chat.system.transform\": async (input, output) => {\r\n const payload = {\r\n sessionId: (input && input.sessionID) ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"SessionStart\", payload);\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.system)) {\r\n // Insert at index 1 (after the header) to preserve the prompt-cache fold\r\n // (header must remain system[0]).\r\n output.system.splice(1, 0, res.additionalContext);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"UserPromptSubmit\")) {\r\n handlers.push(` // UserPromptSubmit → context injection on prompt submission.\r\n // chat.message fires when a new user message arrives; output.parts holds the\r\n // prompt parts. Inject context by PUSHING a text part onto output.parts.\r\n // chat.message has NO documented block/abort, so a \"deny\" decision degrades\r\n // to a NO-OP (best-effort) — mirrors the mimo-code OpenCode fork.\r\n \"chat.message\": async (input, output) => {\r\n const promptText =\r\n output && Array.isArray(output.parts)\r\n ? output.parts\r\n .filter((p) => p && p.type === \"text\" && typeof p.text === \"string\")\r\n .map((p) => p.text)\r\n .join(\"\\\\n\")\r\n : \"\";\r\n const res = bridge(\"UserPromptSubmit\", {\r\n prompt: promptText,\r\n sessionId: (input && input.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.parts)) {\r\n output.parts.push({ type: \"text\", text: res.additionalContext });\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"PermissionRequest\")) {\r\n handlers.push(` // PermissionRequest → decision-capable permission gate.\r\n // permission.ask MUTATES output.status (\"ask\"|\"deny\"|\"allow\") — it does NOT\r\n // return a value (mirrors tool.execute.before mutating output.args). A\r\n // normalized \"deny\" maps to output.status \"deny\"; \"ask\" to \"ask\"; allow/void\r\n // leave the default status untouched.\r\n \"permission.ask\": async (input, output) => {\r\n const payload = {\r\n toolName: (input && (input.type || input.tool)) ?? \"\",\r\n toolInput: (input && (input.metadata || input.args)) ?? {},\r\n sessionId: (input && input.sessionID) ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PermissionRequest\", payload);\r\n if (!res || !output) return;\r\n if (res.decision === \"deny\") output.status = \"deny\";\r\n else if (res.decision === \"ask\") output.status = \"ask\";\r\n },`);\r\n }\r\n\r\n if (has(\"Stop\")) {\r\n handlers.push(` // Stop → session.idle (\"session finished responding\"). session.idle is NOT a\r\n // direct hook key — it is dispatched through the generic \\`event\\` hook\r\n // switching on event.type. A block decision throws to halt (Kilo has no\r\n // Stop-gate return value).\r\n event: async ({ event }) => {\r\n if (!event || event.type !== \"session.idle\") return;\r\n const res = bridge(\"Stop\", {\r\n sessionId: (event.properties && event.properties.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (res && res.decision === \"deny\") {\r\n throw new Error(res.reason || \"Stop blocked by ${ctx.connector.id}\");\r\n }\r\n },`);\r\n }\r\n\r\n const definition = `\r\nconst plugin = {\r\n id: CONNECTOR_ID,\r\n // @kilocode/plugin PluginModule: server(input) returns the Hooks object keyed\r\n // by the fork's event names. ctx.directory is the project root; fall back to cwd.\r\n server: async (input) => {\r\n const PROJECT_DIR =\r\n (input && (input.directory || (input.worktree && input.worktree.path))) ||\r\n process.cwd();\r\n\r\n return {\r\n${handlers.join(\"\\n\")}\r\n };\r\n },\r\n};\r\n\r\nexport default plugin;\r\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, projectDir }\r\n * so this maps straight through.\r\n */\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as KiloBridgePayload;\r\n const base = {\r\n hostPlatform: HOST,\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 ev: SessionStartEvent = { ...base, source: \"startup\" };\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 \"PermissionRequest\": {\r\n const ev: PermissionRequestEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n const ev: StopEvent = { ...base };\r\n return ev;\r\n }\r\n default:\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 * OUR generated bridge consumes this stdout directly. The reply body IS the\r\n * normalized HookResponse itself — the bridge JSON.parses it and reads\r\n * decision / updatedInput / updatedOutput / 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 // ── Content surfaces: commands / skills / subagents ───────────────────\r\n // CONTENT-ONLY: pure native-file writers. No runtime dispatch, no home-bin\r\n // pointer, no telemetry wrap. Each method is idempotent (byte-identical →\r\n // skip) via BaseAdapter.writeContentFile and reversible via removeContentFile.\r\n // Honors platforms[\"kilo\"] per-surface false to skip.\r\n //\r\n // NOTE on dirs: the CURRENT kilo backend (7.x, shared with kilo-cli) reads\r\n // commands, subagents, and skills from the .kilo/ tree (project) + the XDG\r\n // backend config dir ~/.config/kilo (user) — NOT the .kilocode/ VS Code\r\n // extension legacy tree (which only carries legacy workflows). Verified against\r\n // kilo.ai/docs/customize/{custom-subagents,workflows,skills} (2026-06-16):\r\n // commands → <projectDir>/.kilo/commands | ~/.config/kilo/commands\r\n // subagents → <projectDir>/.kilo/agents | ~/.config/kilo/agents\r\n // skills → <projectDir>/.kilo/skills | ~/.kilo/skills (skills keep the\r\n // ~/.kilo user root per the docs — surface-specific).\r\n\r\n /** Skills root: project → <projectDir>/.kilo/skills; user → ~/.kilo/skills. */\r\n private skillsRootDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", \"skills\")\r\n : join(homedir(), \".kilo\", \"skills\");\r\n }\r\n\r\n /** Commands root: project → <projectDir>/.kilo/commands; user → ~/.config/kilo/commands. */\r\n private commandsDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", \"commands\")\r\n : join(kiloConfigDir(), \"commands\");\r\n }\r\n\r\n /** Subagents root: project → <projectDir>/.kilo/agents; user → ~/.config/kilo/agents. */\r\n private agentsDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", \"agents\")\r\n : join(kiloConfigDir(), \"agents\");\r\n }\r\n\r\n /** Native command file path: <commandsDir>/<name>.md. */\r\n private commandPath(ctx: InstallContext, name: string): string {\r\n return join(this.commandsDir(ctx), `${name}.md`);\r\n }\r\n\r\n /** Native skill dir: <skillsRootDir>/<name>. */\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsRootDir(ctx), name);\r\n }\r\n\r\n /** Native subagent file path: <agentsDir>/<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 kilo\" }];\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 /** Render a command to md+frontmatter (description, argument-hint, mode, model). */\r\n private renderCommand(cmd: CommandDef): string {\r\n const frontmatter: Record<string, unknown> = {};\r\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\r\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\r\n if (cmd.model !== undefined) frontmatter.model = cmd.model;\r\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\r\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\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 kilo\" }];\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 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 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;\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\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 kilo\" }];\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 renderOpenCodeSubagentMd(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 // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const mcpPath = this.getServerConfigPath(ctx);\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const connectorId = ctx.connector.id;\r\n const hasHooks = ctx.connector.hookEvents.length > 0;\r\n\r\n const checks: HealthCheck[] = [\r\n {\r\n name: `${this.name}: kilo.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 // The backend merges kilo.json AND kilo.jsonc at user/project/.kilo/ levels.\r\n name: `${this.name}: MCP delegated to kilo backend`,\r\n check: () => ({\r\n status: \"OK\",\r\n detail:\r\n ctx.scope === \"user\"\r\n ? `using ${CONFIG_FILE} under ${kiloConfigDir()} (merged with kilo.jsonc by shared backend)`\r\n : `project scope uses .kilo/${CONFIG_FILE} (merged with kilo.jsonc by shared backend)`,\r\n }),\r\n },\r\n {\r\n name: `${this.name}: server entry registered`,\r\n check: () => {\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\r\n const bucket = cfg?.[MCP_ROOT_KEY];\r\n if (!cfg || !bucket) {\r\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\r\n }\r\n return connectorId in bucket\r\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\r\n : {\r\n status: \"FAIL\",\r\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\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 name: `${this.name}: plugin registered in ${PLUGIN_ARRAY_KEY}[]`,\r\n check: () => {\r\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\r\n const cfg = this.readJson<Record<string, unknown>>(mcpPath);\r\n const raw = cfg?.[PLUGIN_ARRAY_KEY];\r\n const plugins = Array.isArray(raw) ? (raw as unknown[]) : undefined;\r\n return plugins && plugins.includes(pluginPath)\r\n ? { status: \"OK\", detail: `${PLUGIN_ARRAY_KEY}[] includes module` }\r\n : {\r\n status: \"FAIL\",\r\n detail: `module not in ${PLUGIN_ARRAY_KEY}[] of ${mcpPath}`,\r\n };\r\n },\r\n },\r\n ];\r\n\r\n // Content-surface checks.\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 /** Read a file, returning undefined on any error (idempotency compare). */\r\n}\r\n\r\nexport const adapter = new KiloAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/kilo-cli/index.ts"],"sourcesContent":["/**\r\n * adapters/kilo-cli — Kilo CLI platform adapter for agent-connector.\r\n *\r\n * The Kilo CLI (the `kilo` binary) is a **live-confirmed OpenCode fork**: a\r\n * SQLite-backed command-line agent (storage `~/.local/share/kilo/kilo.db`) that\r\n * loads `@kilocode/plugin` modules. It is DISTINCT from the Kilo Code VS Code\r\n * extension (adapter id \"kilo\", a Roo/Cline fork) — the two products carry\r\n * different platformIds so their config and usage never merge.\r\n *\r\n * Paradigm — **ts-plugin** (mirrors the OpenCode adapter):\r\n * The fork has no JSON hook table. Instead it loads JS/TS plugin modules whose\r\n * default export is a `@kilocode/plugin` PluginModule:\r\n * { id?, server: async (input) => Hooks }\r\n * where the returned `Hooks` object is keyed by the fork's event names\r\n * (\"tool.execute.before\", \"tool.execute.after\", a session/system event). The\r\n * `server` factory runs in-process inside Kilo and is handed mutable args/output\r\n * objects; it throws to block a tool call.\r\n *\r\n * Why we BRIDGE instead of importing handlers (identical rationale to OpenCode):\r\n * the connector's hook handlers are arbitrary developer code we must not import\r\n * into Kilo's runtime (wrong cwd, wrong deps, version skew). So instead of\r\n * importing handlers we synthesize a tiny, fully self-contained ESM plugin\r\n * module that imports NOTHING from agent-connector and, on each hook firing,\r\n * shells out to the ONE stable home binary's universal entrypoint\r\n * <homeBin> hook kilo-cli <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.\r\n *\r\n * User config dir (XDG): the kilo backend honors `$XDG_CONFIG_HOME`, so the user\r\n * scope resolves to `$XDG_CONFIG_HOME/kilo` when that env var is set & non-empty,\r\n * else `~/.config/kilo` (the default). This is the SAME backend dir the kilo\r\n * extension uses — every user-scope path below (writer, detection probe, plugin\r\n * dir, content surfaces) flows through `kiloCliConfigDir()` so they cannot\r\n * disagree with where the Kilo CLI actually reads.\r\n *\r\n * Registration (hooks — array + auto-discovery both work):\r\n * Since kilo v7.3.16 the fork auto-discovers every file in its plugin dir\r\n * (.kilo/plugin/*.js, ~/.config/kilo/plugin/*.js), so writing the file is\r\n * sufficient for discovery. We ALSO register the path in kilo.jsonc's `plugin`\r\n * array because both loading mechanisms coexist and the array write is harmless\r\n * (idempotent); older versions relied on it exclusively.\r\n *\r\n * Plugin module location (project | user):\r\n * user → ~/.config/kilo/plugin/<id>.js (XDG: $XDG_CONFIG_HOME/kilo/plugin/<id>.js)\r\n * project → <projectDir>/.kilo/plugin/<id>.js\r\n *\r\n * MCP config (the CLI's new-gen dialect — already correct, KEPT verbatim):\r\n * - user scope → ~/.config/kilo/kilo.jsonc (XDG: $XDG_CONFIG_HOME/kilo/kilo.jsonc)\r\n * - project scope → <projectDir>/.kilo/kilo.jsonc (project overrides global)\r\n * Both are JSON/JSONC; we write plain JSON, which is valid JSONC. The root key\r\n * is \"mcp\" (NOT the extension's \"mcpServers\").\r\n *\r\n * Server entry shape (mirrors OpenCode's new-gen dialect):\r\n * - stdio → { type: \"local\", command: [exe, ...args], environment: {...} }\r\n * NOTE the command is a single ARRAY (exe + args together), unlike\r\n * Claude/Cursor's scalar `command` + `args[]` split.\r\n * - remote → { type: \"remote\", url }\r\n *\r\n * The Kilo CLI documents no native `${env:VAR}` interpolation token, so env/url\r\n * refs are resolved to literals at install time (the no-native-token path).\r\n *\r\n * Content surfaces (live-confirmed, kilo v7.3.16; user dir is XDG-resolved):\r\n * - commands → .kilo/command/<name>.md (user ~/.config/kilo/command/)\r\n * - skills → .kilo/skills/<name>/SKILL.md (user ~/.config/kilo/skills/ or ~/.agents/skills)\r\n * - subagents → .kilo/agent/<name>.md with frontmatter mode:subagent\r\n *\r\n * Capability degradations (documented, never thrown):\r\n * - The fork has no \"ask\" gate. A decision of \"ask\" degrades to a block (throw\r\n * with the reason) in tool.execute.before — the safe direction.\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 } from \"../base.js\";\r\nimport { renderCommandMd, renderSkillMd } from \"../claude-code/render.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 PermissionRequestEvent,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionStartEvent,\r\n StopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport { renderBridgePrelude } from \"../../core/ts-plugin-bridge.js\";\r\nimport { xdgConfigHome } from \"../../core/host-paths.js\";\r\nimport {\r\n buildWrappedStdio,\r\n} from \"../../core/spawn.js\";\r\n\r\nconst HOST: PlatformId = \"kilo-cli\";\r\n/** New-generation root key for MCP servers — \"mcp\", not the extension's \"mcpServers\". */\r\nconst MCP_ROOT_KEY = \"mcp\";\r\n/** kilo.jsonc array of plugin module paths the fork loads (NOT auto-discovery). */\r\nconst PLUGIN_ARRAY_KEY = \"plugin\";\r\n/** New-generation config filename (JSON/JSONC). */\r\nconst CONFIG_FILE = \"kilo.jsonc\";\r\n/** The Kilo CLI's SQLite session store — a CLI-exclusive detection marker. */\r\nconst CLI_DB_RELPATH = [\".local\", \"share\", \"kilo\", \"kilo.db\"] as const;\r\n\r\n/**\r\n * Canonical → Kilo (OpenCode-fork) event name map. A connector hook event is\r\n * only emitted by the generated plugin when it appears here AND is declared by\r\n * the connector.\r\n *\r\n * The fork inherits OpenCode's tool-execution events; like OpenCode it has no\r\n * real SessionStart hook, so SessionStart maps to the same system-prompt\r\n * transform surrogate (the verified context-injection point) — we inject\r\n * additionalContext into the system prompt there.\r\n */\r\nconst EVENT_TO_KILO: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: \"tool.execute.before\",\r\n PostToolUse: \"tool.execute.after\",\r\n SessionStart: \"experimental.chat.system.transform\",\r\n // chat.message fires when a new user message arrives (inspect/modify parts) →\r\n // canonical UserPromptSubmit (mirrors the mimo-code OpenCode fork).\r\n UserPromptSubmit: \"chat.message\",\r\n // permission.ask is the decision-capable gate (auto-allow/auto-deny). The\r\n // handler MUTATES output.status (\"ask\"|\"deny\"|\"allow\") — mirrors OpenCode.\r\n PermissionRequest: \"permission.ask\",\r\n // session.idle (\"session finished responding\") → canonical Stop. NOT a direct\r\n // hook key — dispatched through the generic `event` hook (event.type switch).\r\n // session.idle is doc-listed for the VS Code extension & CLI but its runtime\r\n // firing on a given Kilo build is not separately verified (an upstream FR for\r\n // session-lifecycle hooks exists); if it never fires, Stop is a silent no-op\r\n // (an acceptable degrade — it never mis-fires), so coverage may be optimistic.\r\n Stop: \"session.idle\",\r\n};\r\n\r\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\r\ninterface KiloBridgePayload {\r\n toolName?: string;\r\n toolInput?: Record<string, unknown>;\r\n toolOutput?: string;\r\n isError?: boolean;\r\n prompt?: string;\r\n sessionId?: string;\r\n projectDir?: string;\r\n}\r\n\r\n/**\r\n * Native MCP server entry shapes the Kilo CLI's new-gen config accepts under\r\n * `mcp`. QUIRK: a local (stdio) server keys its whole invocation as\r\n * `command: [...]` — a single array of [executable, ...args] — and env as\r\n * `environment`.\r\n */\r\ninterface KiloLocalServer {\r\n type: \"local\";\r\n command: string[];\r\n environment?: Record<string, string>;\r\n}\r\ninterface KiloRemoteServer {\r\n type: \"remote\";\r\n url: string;\r\n}\r\n\r\n/**\r\n * Resolve the kilo backend user config dir: `$XDG_CONFIG_HOME/kilo` when set,\r\n * else `~/.config/kilo`. This is the SAME backend dir the kilo extension uses\r\n * (kilo's own `kiloConfigDir()`), so the CLI writer, detection probe, and\r\n * content surfaces all agree with where the XDG-honoring Kilo CLI reads. When\r\n * `$XDG_CONFIG_HOME` is unset this is byte-identical to `~/.config/kilo`.\r\n */\r\nfunction kiloCliConfigDir(): string {\r\n return join(xdgConfigHome(), \"kilo\");\r\n}\r\n\r\nexport class KiloCliAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Kilo CLI\";\r\n readonly paradigm: HookParadigm = \"ts-plugin\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md\r\n // via the base default; user scope → ~/.kilocode/rules/agent-connector.md below).\r\n supportsMemory: true,\r\n // Matches the OpenCode capability surface — the fork inherits its plugin\r\n // event model.\r\n preToolUse: true,\r\n postToolUse: true,\r\n // The fork's compaction hook is experimental and not wired here.\r\n preCompact: false,\r\n sessionStart: true,\r\n sessionEnd: false,\r\n // chat.message backs UserPromptSubmit; session.idle (via the generic `event`\r\n // hook) backs Stop.\r\n userPromptSubmit: true,\r\n stop: true,\r\n notification: false,\r\n // Newer events: the fork's decision-capable `permission.ask` plugin hook is\r\n // now wired (PermissionRequest → permission.ask, mutating output.status), and\r\n // session.idle (\"session finished responding\") backs Stop via the generic\r\n // `event` hook. subagents run as child sessions (bus events only) and tool\r\n // failure is merged into tool.execute.after / session.error, so\r\n // postToolUseFailure / subagentStart / subagentStop stay unset — the\r\n // generated bridge never references them and install reports them as\r\n // \"unsupported here\".\r\n permissionRequest: true,\r\n // tool.execute.before mutates output.args → input rewrite supported.\r\n canModifyArgs: true,\r\n // tool.execute.after mutates output.output → output rewrite supported.\r\n canModifyOutput: true,\r\n // injected via the system-prompt transform at session start.\r\n canInjectSessionContext: true,\r\n // The Kilo CLI registers stdio (local), SSE, and Streamable HTTP MCP servers.\r\n transports: [\"stdio\", \"sse\", \"http\"],\r\n // Content surfaces: live-confirmed on kilo v7.3.16 (see header).\r\n supportsCommands: true,\r\n supportsSkills: true,\r\n supportsSubagents: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = kiloCliConfigDir();\r\n const userConfig = join(userDir, CONFIG_FILE);\r\n const projectConfig = join(projectDir, \".kilo\", CONFIG_FILE);\r\n // The SQLite session DB is a CLI-exclusive marker (the VS Code extension\r\n // never writes it), so it disambiguates the CLI from the \"kilo\" extension\r\n // even when neither writes a kilo.jsonc yet.\r\n const cliDb = join(homedir(), ...CLI_DB_RELPATH);\r\n const userInstalled = existsSync(userDir) || existsSync(cliDb);\r\n const projInstalled = existsSync(projectConfig);\r\n const installed = userInstalled || projInstalled;\r\n // Report the scope/path/reason for the marker that actually matched, so a\r\n // project-only install isn't misreported as a (non-existent) user install.\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projectConfig : userConfig;\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 Kilo CLI config at ${projectConfig}`\r\n : existsSync(cliDb)\r\n ? `found Kilo CLI session store at ${cliDb}`\r\n : `found Kilo CLI config under ${userDir}`\r\n : `no Kilo CLI config at ${userDir} or session store at ${cliDb}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Memory surface: global rules dir at user scope ──────────────────────\r\n // Project scope stays on the AGENTS.md base default. User scope targets a\r\n // dedicated agent-connector.md in the legacy-compatible ~/.kilocode/rules/\r\n // dir (always loaded; avoids JSONC `instructions` edits in kilo.jsonc; the\r\n // AC-created file is cleanly deletable on uninstall). Shared backend with\r\n // the kilo extension — the convergent write dedupes via the content hash.\r\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"user\") {\r\n return super.memoryTargets(ctx);\r\n }\r\n return [\r\n {\r\n path: join(homedir(), \".kilocode\", \"rules\", \"agent-connector.md\"),\r\n reason: \"kilo global rules dir (~/.kilocode/rules; agent-connector-owned file)\",\r\n },\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, \".kilo\")\r\n : kiloCliConfigDir();\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), CONFIG_FILE);\r\n }\r\n\r\n /**\r\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\r\n * Unlike OpenCode, writing the file is NOT sufficient: the fork loads only the\r\n * module paths listed in kilo.jsonc's `plugin` array, so installHooks also\r\n * registers this path there.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.pluginDir(ctx), this.pluginFileName(ctx));\r\n }\r\n\r\n /** Plugin directory the synthesized module is written into, per scope. */\r\n private pluginDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kilo\", \"plugin\")\r\n : join(kiloCliConfigDir(), \"plugin\");\r\n }\r\n\r\n /** Plugin module file name (one per connector, kebab-case id). */\r\n private pluginFileName(ctx: InstallContext): string {\r\n return `${ctx.connector.id}.js`;\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 kilo-cli\"\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 the Kilo CLI's new-gen `mcp` entry. */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): KiloLocalServer | KiloRemoteServer {\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 // QUIRK: the Kilo CLI's new-gen local server keys its whole invocation as\r\n // a single `command` ARRAY (executable + args together), like OpenCode.\r\n // The CLI has no documented native interpolation token, so resolve every\r\n // ${env:VAR} to a literal at install time.\r\n const entry: KiloLocalServer = {\r\n type: \"local\",\r\n command: resolveEnvRefsDeep([command, ...args]),\r\n };\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.environment = env;\r\n return entry;\r\n }\r\n\r\n // sse / http (and any other remote transport) — the Kilo CLI registers a URL.\r\n const entry: KiloRemoteServer = {\r\n type: \"remote\",\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n };\r\n return entry;\r\n }\r\n\r\n /**\r\n * Render env values. The Kilo CLI documents no native interpolation token, so\r\n * resolve `${env:VAR}` references to literals at install time.\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 return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n // ── Hook install / uninstall (ts-plugin + explicit `plugin` array) ────────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const configPath = this.getServerConfigPath(ctx);\r\n\r\n if (ctx.connector.platforms[HOST]?.hooks === false) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"hooks disabled for kilo-cli\" },\r\n ];\r\n }\r\n if (ctx.connector.hookEvents.length === 0) {\r\n return [\r\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"connector declares no hooks\" },\r\n ];\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n\r\n // 1. Write the synthesized plugin module.\r\n for (const file of this.synthesizePlugin(ctx)) {\r\n changes.push(\r\n this.writeManagedFile(\r\n file.path,\r\n file.contents,\r\n ctx.dryRun,\r\n `kilo plugin module (${this.hookDetail(ctx)})`,\r\n file.executable,\r\n ),\r\n );\r\n }\r\n\r\n // 2. Register the module path in kilo.jsonc's `plugin` array (the fork does\r\n // NOT auto-discover by directory — it reads this array).\r\n changes.push(this.upsertPluginInArray(configPath, pluginPath, ctx.dryRun));\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_KILO are mapped/wired; any declared\r\n * event with no Kilo mapping is reported separately as \"unsupported here\" so\r\n * the detail never overstates coverage.\r\n */\r\n private hookDetail(ctx: InstallContext): string {\r\n const declared = ctx.connector.hookEvents;\r\n const mapped = declared.filter((e) => EVENT_TO_KILO[e] !== undefined);\r\n const unsupported = declared.filter((e) => EVENT_TO_KILO[e] === undefined);\r\n const base = mapped.join(\",\");\r\n return unsupported.length > 0\r\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\r\n : base;\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. Deregister the module path from kilo.jsonc's `plugin` array.\r\n changes.push(this.removePluginFromArray(configPath, pluginPath, ctx.dryRun));\r\n\r\n // 2. Remove the plugin module on disk.\r\n changes.push(\r\n this.removeManagedFile(pluginPath, ctx.dryRun, \"kilo plugin module\", \"no kilo plugin module present\"),\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 /** Upsert the module path into kilo.jsonc's top-level `plugin` array (idempotent). */\r\n private upsertPluginInArray(\r\n configPath: string,\r\n modulePath: string,\r\n dryRun: boolean,\r\n ): ChangeRecord {\r\n // OVERWRITE GUARD: never blank a present-but-unparseable kilo.jsonc.\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 plugins = this.pluginArrayBucket(cfg);\r\n if (plugins.includes(modulePath)) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] already includes module`,\r\n };\r\n }\r\n plugins.push(modulePath);\r\n this.writeJson(configPath, cfg, dryRun);\r\n return {\r\n platform: this.id,\r\n action: \"create\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] += module`,\r\n };\r\n }\r\n\r\n /** Remove the module path from kilo.jsonc's `plugin` array. */\r\n private removePluginFromArray(\r\n configPath: string,\r\n modulePath: string,\r\n dryRun: boolean,\r\n ): ChangeRecord {\r\n // OVERWRITE GUARD: a present-but-unparseable file would round-trip to `{}`.\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 raw = cfg?.[PLUGIN_ARRAY_KEY];\r\n const plugins = Array.isArray(raw) ? (raw as unknown[]) : undefined;\r\n const idx = plugins ? plugins.indexOf(modulePath) : -1;\r\n if (!cfg || !plugins || idx < 0) {\r\n return {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: configPath,\r\n detail: `${PLUGIN_ARRAY_KEY}[] does not include module`,\r\n };\r\n }\r\n plugins.splice(idx, 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: `${PLUGIN_ARRAY_KEY}[] -= module`,\r\n };\r\n }\r\n\r\n /** Get-or-create the top-level `plugin` array as a mutable string array. */\r\n private pluginArrayBucket(cfg: Record<string, unknown>): string[] {\r\n const existing = cfg[PLUGIN_ARRAY_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 plugins = Array.isArray(existing)\r\n ? existing.filter((p): p is string => typeof p === \"string\")\r\n : [];\r\n cfg[PLUGIN_ARRAY_KEY] = plugins;\r\n return plugins;\r\n }\r\n\r\n // ── Content surfaces: commands / skills / subagents ─────────────────────\r\n // CONTENT-ONLY: pure native-file writers under the kilo config dir.\r\n // No runtime dispatch, no home-bin pointer, no telemetry wrap. Each method\r\n // is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\r\n // reversible via removeContentFile. Honors platforms[\"kilo-cli\"] per-surface\r\n // false opt-outs.\r\n //\r\n // Dirs (live-confirmed kilo v7.3.16 — kilo-pi-ground-truth.md):\r\n // commands → <kiloDir>/command/<name>.md\r\n // skills → <kiloDir>/skills/<name>/SKILL.md\r\n // subagents → <kiloDir>/agent/<name>.md (frontmatter mode:subagent)\r\n //\r\n // <kiloDir> (via getConfigDir):\r\n // project scope → <projectDir>/.kilo\r\n // user scope → ~/.config/kilo (XDG: $XDG_CONFIG_HOME/kilo)\r\n\r\n private commandsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"command\");\r\n }\r\n private skillsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"skills\");\r\n }\r\n private agentDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"agent\");\r\n }\r\n\r\n private commandPath(ctx: InstallContext, name: string): string {\r\n return join(this.commandsDir(ctx), `${name}.md`);\r\n }\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\r\n private subagentPath(ctx: InstallContext, name: string): string {\r\n return join(this.agentDir(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 kilo-cli\" }];\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(this.commandPath(ctx, cmd.name), renderCommandMd(cmd), ctx.dryRun),\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 // ── 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 kilo-cli\" }];\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 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 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;\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\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 kilo-cli\" }];\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.renderKiloSubagent(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 /**\r\n * Render a subagent to md+frontmatter for kilo-cli.\r\n * Kilo's shape is (description, mode:\"subagent\", model, permission) with the\r\n * system prompt as the body — mirrors the opencode adapter's renderSubagent.\r\n * `name` is NOT a frontmatter field — it comes from the filename.\r\n * `permission` is derived from the coarse `readonly` knob.\r\n */\r\n private renderKiloSubagent(agent: import(\"../../core/types.js\").SubagentDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n description: agent.description,\r\n mode: \"subagent\",\r\n };\r\n if (agent.model !== undefined) frontmatter.model = agent.model;\r\n if (agent.readonly === true) {\r\n frontmatter.permission = { edit: \"deny\", bash: \"deny\" };\r\n }\r\n if (agent.extra) Object.assign(frontmatter, agent.extra);\r\n // renderFrontmatterMd is inherited from BaseAdapter (delegates to render.ts).\r\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\r\n }\r\n\r\n // ── ts-plugin synthesis ────────────────────────────────────────────────\r\n\r\n /**\r\n * Build ONE self-contained ESM plugin module for the Kilo CLI fork.\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 Kilo payload on stdin and JSON.parsing the normalized HookResponse back\r\n * from stdout (fail-open: any error → null). Its default export is the\r\n * `@kilocode/plugin` PluginModule shape — { id, server: async (input) =>\r\n * ({ \"tool.execute.before\": …, \"tool.execute.after\": …, … }) } — keyed only by\r\n * the fork event names for the events this 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 return [{ path, contents, executable: false }];\r\n }\r\n\r\n /** Compose the generated plugin source with plain string concatenation. */\r\n private buildPluginSource(ctx: InstallContext): string {\r\n // The Kilo event keys this connector declares (and that we can map).\r\n const events = ctx.connector.hookEvents.filter(\r\n (e): e is HookEventName => EVENT_TO_KILO[e] !== undefined,\r\n );\r\n const has = (e: HookEventName) => events.includes(e);\r\n\r\n const header = `/**\r\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\r\n *\r\n * Self-contained Kilo CLI plugin bridge for connector ${ctx.connector.id}.\r\n * It imports nothing from agent-connector: every hook invocation shells out to\r\n * the stable home binary's universal entrypoint and JSON-parses the normalized\r\n * response. Fail-open: any bridge error degrades to \"allow\".\r\n *\r\n * Default export is the @kilocode/plugin PluginModule shape\r\n * ({ id, server: async (input) => Hooks }); the fork loads it because its path\r\n * is registered in kilo.jsonc's \"plugin\" array.\r\n */\r\nimport { execFileSync, execSync } from \"node:child_process\";\r\n\r\n${renderBridgePrelude({\r\n homeBin: ctx.homeBinPath,\r\n connectorId: ctx.connector.id,\r\n hookSlug: \"kilo-cli\",\r\n payloadNoun: \"Kilo\",\r\n eventDoc: \" (PreToolUse|PostToolUse|SessionStart)\",\r\n failOpenComment: \"Fail-open — never wedge a tool call on a bridge error.\",\r\n})}\r\n`;\r\n\r\n const handlers: string[] = [];\r\n\r\n if (has(\"PreToolUse\")) {\r\n handlers.push(` // PreToolUse → block (throw) / rewrite args (mutate output.args).\r\n \"tool.execute.before\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: (output && output.args) ?? {},\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PreToolUse\", payload);\r\n if (!res) return;\r\n // Kilo has no \"ask\" gate — degrade \"ask\" to a block (safe direction).\r\n if (res.decision === \"deny\" || res.decision === \"ask\") {\r\n throw new Error(res.reason || \"Blocked by ${ctx.connector.id}\");\r\n }\r\n if (res.updatedInput && output && output.args) {\r\n Object.assign(output.args, res.updatedInput);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"PostToolUse\")) {\r\n handlers.push(` // PostToolUse → observe / rewrite tool output (mutate output.output).\r\n \"tool.execute.after\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: input.args ?? {},\r\n toolOutput: output ? output.output : undefined,\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PostToolUse\", payload);\r\n if (!res) return;\r\n if (typeof res.updatedOutput === \"string\" && output) {\r\n output.output = res.updatedOutput;\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"SessionStart\")) {\r\n handlers.push(` // SessionStart surrogate → inject context into the system prompt.\r\n // The fork has no real SessionStart hook; the system-prompt transform is the\r\n // verified injection point (mirrors OpenCode).\r\n \"experimental.chat.system.transform\": async (input, output) => {\r\n const payload = {\r\n sessionId: (input && input.sessionID) ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"SessionStart\", payload);\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.system)) {\r\n // Insert at index 1 (after the header) to preserve the prompt-cache fold\r\n // (header must remain system[0]).\r\n output.system.splice(1, 0, res.additionalContext);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"UserPromptSubmit\")) {\r\n handlers.push(` // UserPromptSubmit → context injection on prompt submission.\r\n // chat.message fires when a new user message arrives; output.parts holds the\r\n // prompt parts. Inject context by PUSHING a text part onto output.parts.\r\n // chat.message has NO documented block/abort, so a \"deny\" decision degrades\r\n // to a NO-OP (best-effort) — mirrors the mimo-code OpenCode fork.\r\n \"chat.message\": async (input, output) => {\r\n const promptText =\r\n output && Array.isArray(output.parts)\r\n ? output.parts\r\n .filter((p) => p && p.type === \"text\" && typeof p.text === \"string\")\r\n .map((p) => p.text)\r\n .join(\"\\\\n\")\r\n : \"\";\r\n const res = bridge(\"UserPromptSubmit\", {\r\n prompt: promptText,\r\n sessionId: (input && input.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.parts)) {\r\n output.parts.push({ type: \"text\", text: res.additionalContext });\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"PermissionRequest\")) {\r\n handlers.push(` // PermissionRequest → decision-capable permission gate.\r\n // permission.ask MUTATES output.status (\"ask\"|\"deny\"|\"allow\") — it does NOT\r\n // return a value (mirrors tool.execute.before mutating output.args). A\r\n // normalized \"deny\" maps to output.status \"deny\"; \"ask\" to \"ask\"; allow/void\r\n // leave the default status untouched.\r\n \"permission.ask\": async (input, output) => {\r\n const payload = {\r\n toolName: (input && (input.type || input.tool)) ?? \"\",\r\n toolInput: (input && (input.metadata || input.args)) ?? {},\r\n sessionId: (input && input.sessionID) ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PermissionRequest\", payload);\r\n if (!res || !output) return;\r\n if (res.decision === \"deny\") output.status = \"deny\";\r\n else if (res.decision === \"ask\") output.status = \"ask\";\r\n },`);\r\n }\r\n\r\n if (has(\"Stop\")) {\r\n handlers.push(` // Stop → session.idle (\"session finished responding\"). session.idle is NOT a\r\n // direct hook key — it is dispatched through the generic \\`event\\` hook\r\n // switching on event.type. A block decision throws to halt (Kilo has no\r\n // Stop-gate return value).\r\n event: async ({ event }) => {\r\n if (!event || event.type !== \"session.idle\") return;\r\n const res = bridge(\"Stop\", {\r\n sessionId: (event.properties && event.properties.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (res && res.decision === \"deny\") {\r\n throw new Error(res.reason || \"Stop blocked by ${ctx.connector.id}\");\r\n }\r\n },`);\r\n }\r\n\r\n const definition = `\r\nconst plugin = {\r\n id: CONNECTOR_ID,\r\n // @kilocode/plugin PluginModule: server(input) returns the Hooks object keyed\r\n // by the fork's event names. ctx.directory is the project root; fall back to cwd.\r\n server: async (input) => {\r\n const PROJECT_DIR =\r\n (input && (input.directory || (input.worktree && input.worktree.path))) ||\r\n process.cwd();\r\n\r\n return {\r\n${handlers.join(\"\\n\")}\r\n };\r\n },\r\n};\r\n\r\nexport default plugin;\r\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, projectDir }\r\n * so this maps straight through.\r\n */\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as KiloBridgePayload;\r\n const base = {\r\n hostPlatform: HOST,\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 ev: SessionStartEvent = { ...base, source: \"startup\" };\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 \"PermissionRequest\": {\r\n const ev: PermissionRequestEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n const ev: StopEvent = { ...base };\r\n return ev;\r\n }\r\n default:\r\n // Other canonical events are not surfaced by Kilo; 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 / updatedOutput / 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 connectorId = ctx.connector.id;\r\n const hasHooks = ctx.connector.hookEvents.length > 0;\r\n\r\n return [\r\n {\r\n name: `${this.name}: ${CONFIG_FILE} 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 name: `${this.name}: server entry registered`,\r\n check: () => {\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(configPath);\r\n const bucket = cfg?.[MCP_ROOT_KEY];\r\n if (!cfg || !bucket) {\r\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${configPath}` };\r\n }\r\n return connectorId in bucket\r\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\r\n : {\r\n status: \"FAIL\",\r\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${configPath}`,\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 name: `${this.name}: plugin registered in ${PLUGIN_ARRAY_KEY}[]`,\r\n check: () => {\r\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\r\n const cfg = this.readJson<Record<string, unknown>>(configPath);\r\n const raw = cfg?.[PLUGIN_ARRAY_KEY];\r\n const plugins = Array.isArray(raw) ? (raw as unknown[]) : undefined;\r\n return plugins && plugins.includes(pluginPath)\r\n ? { status: \"OK\", detail: `${PLUGIN_ARRAY_KEY}[] includes module` }\r\n : {\r\n status: \"FAIL\",\r\n detail: `module not in ${PLUGIN_ARRAY_KEY}[] of ${configPath} (fork will not load it)`,\r\n };\r\n },\r\n },\r\n ];\r\n }\r\n\r\n /** Read a file, returning undefined on any error (idempotency compare). */\r\n}\r\n\r\nexport const adapter = new KiloCliAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/usage/readers/kilo-cli.ts"],"sourcesContent":["/**\r\n * usage/readers/kilo-cli — Kilo CLI SQLite session reader.\r\n *\r\n * Faithful port of tokscale sessions/kilo.rs (parse_kilo_sqlite /\r\n * parse_kilo_sqlite_with_fallback, lines 53-155). The Kilo CLI stores every\r\n * message as one row in a `message` table whose `data` column is the raw message\r\n * JSON (TEXT) — the same shape OpenCode uses. This reader opens that DB read-only\r\n * and reports the assistant rows' token usage.\r\n *\r\n * This is the SQLite Kilo CLI reader and is DISTINCT from the already-shipped\r\n * `kilo` reader (sessions/kilocode.rs), which parses the VS Code KiloCode task\r\n * logs (`ui_messages.json`, the Roo/Kilo `api_req_started` JSON format). They are\r\n * different products with different storage and carry different platformIds\r\n * (`kilo-cli` here vs `kilo` there) so their rows never merge.\r\n *\r\n * DB path: ~/.local/share/kilo/kilo.db (XDG_DATA_HOME and the\r\n * AGENT_CONNECTOR_KILO_CLI_DIR override are honored via paths.ts hostRoots).\r\n *\r\n * SQL (port of the Rust `query`):\r\n * SELECT m.id, m.session_id, m.data\r\n * FROM message m\r\n * WHERE json_valid(m.data)\r\n * AND json_extract(m.data, '$.role') = 'assistant'\r\n * AND json_extract(m.data, '$.tokens') IS NOT NULL\r\n *\r\n * Tokens (off the parsed `data` JSON, each clamped ≥ 0 — the Rust `.max(0)` on\r\n * the i64 fields; KiloTokens makes input/output/cache.read/cache.write required\r\n * and reasoning optional, so a row missing one of the required fields fails the\r\n * serde deserialize and is skipped — replicated here):\r\n * tokens.input → input\r\n * tokens.output → output\r\n * tokens.cache.read → cacheRead\r\n * tokens.cache.write → cacheWrite\r\n * tokens.reasoning → reasoning (optional; 0 when absent)\r\n * cost is `data.$.cost` (clamped ≥ 0), emitted only when > 0.\r\n *\r\n * model / provider: data.$.modelID is REQUIRED — a row without it is skipped\r\n * (the Rust `match msg.model_id { None => continue }`). provider prefers\r\n * data.$.providerID, then inferProvider(modelId), then the \"kilo\" default.\r\n *\r\n * agent: data.$.agent then data.$.mode (Rust `msg.agent.or(msg.mode)` — note this\r\n * is the OPPOSITE precedence to the OpenCode reader's mode-then-agent).\r\n *\r\n * session: data.$.session_id (preferred) else the m.session_id column.\r\n *\r\n * project: NONE — the Kilo CLI log carries no cwd/workspace, so no projectKey\r\n * is emitted (matches the spec's \"projectAttribution: None\").\r\n *\r\n * timestamp: data.$.time.created (Unix MILLISECONDS, float, truncated to int).\r\n * When the `time` block is absent the fallback is the DB file's mtime (port of\r\n * file_modified_timestamp_ms). A `time` block present but with a non-numeric\r\n * `created` fails the serde deserialize, so the row is skipped (not fallen back).\r\n *\r\n * DEDUP — dedupKey = data.$.id (the embedded message id) else the m.id row id\r\n * (Rust `msg.id.or(Some(row_id))`). No fingerprint merge: the Kilo CLI is a\r\n * single source of record, so a row-id backstop is sufficient.\r\n *\r\n * confidence: \"host-reported\" (Kilo logs real token counts).\r\n *\r\n * Fail-open: DB missing/locked/unreadable/corrupt → openSqlite() returns null →\r\n * []; a malformed row → skipped. Never throws. Read-only.\r\n */\r\n\r\nimport type { SqliteDb } from \"../sqlite.js\";\r\nimport type { UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { fileMtimeMs } from \"../jsonl.js\";\r\nimport { inferProvider } from \"../normalize.js\";\r\nimport { firstExistingRoot } from \"../paths.js\";\r\nimport { openSqlite } from \"../sqlite.js\";\r\n\r\nconst PLATFORM_ID = \"kilo-cli\" as const;\r\nconst DEFAULT_PROVIDER = \"kilo\";\r\n\r\nconst QUERY = `\r\n SELECT m.id, m.session_id, m.data\r\n FROM message m\r\n WHERE json_valid(m.data)\r\n AND json_extract(m.data, '$.role') = 'assistant'\r\n AND json_extract(m.data, '$.tokens') IS NOT NULL\r\n`;\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Value coercion\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** A non-negative integer token field (port of `.max(0)` on an i64). */\r\nfunction tokenField(v: unknown): number {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : 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 finite number (the serde i64/f64 required-field semantics), or undefined. */\r\nfunction asFiniteNumber(v: unknown): number | undefined {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\r\n return Number.isFinite(n) ? n : undefined;\r\n}\r\n\r\n/** A non-empty string, or undefined. */\r\nfunction asNonEmptyString(v: unknown): string | undefined {\r\n return typeof v === \"string\" && v !== \"\" ? v : undefined;\r\n}\r\n\r\n/** A SELECT column that may come back as Uint8Array (BLOB) / number — to string. */\r\nfunction asString(v: unknown): string | undefined {\r\n if (typeof v === \"string\") return v;\r\n if (typeof v === \"number\" && Number.isFinite(v)) return String(v);\r\n return undefined;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// The parsed `data` column (the KiloMessage subset we read)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface KiloTokens {\r\n input: number;\r\n output: number;\r\n reasoning: number;\r\n cacheRead: number;\r\n cacheWrite: number;\r\n}\r\n\r\ninterface ParsedMessage {\r\n /** Embedded message id (preferred dedup key); undefined when absent. */\r\n id: string | undefined;\r\n /** Embedded session id (preferred over the row column); undefined when absent. */\r\n sessionId: string | undefined;\r\n modelId: string;\r\n providerId: string;\r\n agent: string | undefined;\r\n tokens: KiloTokens;\r\n cost: number;\r\n /** Truncated time.created (ms), or undefined → caller uses the mtime fallback. */\r\n ts: number | undefined;\r\n}\r\n\r\n/**\r\n * Parse the `data` JSON of a row (port of the KiloMessage deserialize + the\r\n * post-deserialize checks). Returns undefined for any row the Rust would skip:\r\n * • not a JSON object / not parseable;\r\n * • role != \"assistant\" (redundant with the SQL filter, but the Rust re-checks);\r\n * • no tokens block, or a tokens block missing a REQUIRED field\r\n * (input / output / cache.read / cache.write — serde would fail the struct);\r\n * • a `time` block present but with a non-numeric `created` (serde fails);\r\n * • no modelID (the Rust `match msg.model_id { None => continue }`).\r\n */\r\nfunction parseData(dataJson: string): ParsedMessage | undefined {\r\n let value: unknown;\r\n try {\r\n value = JSON.parse(dataJson);\r\n } catch {\r\n return undefined;\r\n }\r\n if (typeof value !== \"object\" || value === null) return undefined;\r\n const obj = value as Record<string, unknown>;\r\n\r\n if (obj[\"role\"] !== \"assistant\") return undefined;\r\n\r\n // tokens — required block; input/output/cache.{read,write} are required fields\r\n // (KiloTokens / KiloCache), reasoning is optional. A missing required field\r\n // would fail serde, so we reject the row rather than coerce it to 0.\r\n const tokensRaw = obj[\"tokens\"];\r\n if (typeof tokensRaw !== \"object\" || tokensRaw === null) return undefined;\r\n const t = tokensRaw as Record<string, unknown>;\r\n const input = asFiniteNumber(t[\"input\"]);\r\n const output = asFiniteNumber(t[\"output\"]);\r\n if (input === undefined || output === undefined) return undefined;\r\n\r\n const cacheRaw = t[\"cache\"];\r\n if (typeof cacheRaw !== \"object\" || cacheRaw === null) return undefined;\r\n const cache = cacheRaw as Record<string, unknown>;\r\n const cacheRead = asFiniteNumber(cache[\"read\"]);\r\n const cacheWrite = asFiniteNumber(cache[\"write\"]);\r\n if (cacheRead === undefined || cacheWrite === undefined) return undefined;\r\n\r\n // modelID — required (the Rust skips a row that lacks it).\r\n const modelId = asNonEmptyString(obj[\"modelID\"]);\r\n if (modelId === undefined) return undefined;\r\n\r\n // time — optional block; when present, `created` is a required f64 (serde\r\n // would fail an absent/non-numeric created), so a malformed time skips the row.\r\n const timeRaw = obj[\"time\"];\r\n let ts: number | undefined;\r\n if (timeRaw !== undefined && timeRaw !== null) {\r\n if (typeof timeRaw !== \"object\") return undefined;\r\n const created = asFiniteNumber((timeRaw as Record<string, unknown>)[\"created\"]);\r\n if (created === undefined) return undefined;\r\n ts = Math.trunc(created);\r\n }\r\n\r\n // provider: data.$.providerID, then inferred from model, then the \"kilo\" default.\r\n const providerId =\r\n asNonEmptyString(obj[\"providerID\"]) ?? inferProvider(modelId) ?? DEFAULT_PROVIDER;\r\n\r\n // agent prefers agent then mode (Rust: msg.agent.or(msg.mode)).\r\n const agent = asNonEmptyString(obj[\"agent\"]) ?? asNonEmptyString(obj[\"mode\"]);\r\n\r\n return {\r\n id: asNonEmptyString(obj[\"id\"]),\r\n sessionId: asNonEmptyString(obj[\"session_id\"]),\r\n modelId,\r\n providerId,\r\n agent,\r\n tokens: {\r\n input: tokenField(input),\r\n output: tokenField(output),\r\n reasoning: tokenField(t[\"reasoning\"]),\r\n cacheRead: tokenField(cacheRead),\r\n cacheWrite: tokenField(cacheWrite),\r\n },\r\n cost: Math.max(0, asFiniteNumber(obj[\"cost\"]) ?? 0),\r\n ts,\r\n };\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// DB read\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The three selected columns of one row. */\r\ninterface Row {\r\n id: string;\r\n sessionId: string;\r\n data: string;\r\n}\r\n\r\n/** Select the assistant rows that carry a tokens block. */\r\nfunction selectRows(db: SqliteDb): Row[] {\r\n const rows: Row[] = [];\r\n for (const r of db.all(QUERY)) {\r\n const id = asString(r[\"id\"]);\r\n const sessionId = asString(r[\"session_id\"]);\r\n const data = asString(r[\"data\"]);\r\n if (id === undefined || sessionId === undefined || data === undefined) continue;\r\n rows.push({ id, sessionId, data });\r\n }\r\n return rows;\r\n}\r\n\r\n/** Parse the Kilo CLI SQLite DB into usage records (fallbackTs = DB file mtime). */\r\nfunction parseDb(db: SqliteDb, fallbackTs: number): UsageRecord[] {\r\n const records: UsageRecord[] = [];\r\n\r\n for (const row of selectRows(db)) {\r\n const msg = parseData(row.data);\r\n if (msg === undefined) continue;\r\n\r\n // dedupKey prefers the embedded message id; falls back to the row id.\r\n const dedupKey = msg.id ?? row.id;\r\n // session prefers the embedded id; falls back to the m.session_id column.\r\n const sessionId = msg.sessionId ?? row.sessionId;\r\n // timestamp prefers time.created; falls back to the DB file mtime.\r\n const ts = msg.ts ?? fallbackTs;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = msg.tokens.input;\r\n tokens.output = msg.tokens.output;\r\n tokens.cacheRead = msg.tokens.cacheRead;\r\n tokens.cacheWrite = msg.tokens.cacheWrite;\r\n tokens.reasoning = msg.tokens.reasoning;\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId: msg.modelId,\r\n providerId: msg.providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n dedupKey,\r\n confidence: \"host-reported\",\r\n };\r\n if (msg.cost > 0) record.cost = msg.cost;\r\n if (msg.agent !== undefined) record.agent = msg.agent;\r\n\r\n records.push(record);\r\n }\r\n\r\n return records;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Reader singleton\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The Kilo CLI usage reader singleton. */\r\nconst kiloCliReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const dbPath = firstExistingRoot(PLATFORM_ID);\r\n if (dbPath === undefined) return []; // no kilo.db → fail-open\r\n\r\n const db = await openSqlite(dbPath);\r\n if (db === null) return []; // missing/locked/unreadable/corrupt → fail-open\r\n\r\n try {\r\n const fallbackTs = fileMtimeMs(dbPath);\r\n const rows = parseDb(db, fallbackTs);\r\n if (sinceMs === undefined) return rows;\r\n return rows.filter((r) => r.ts >= sinceMs);\r\n } catch {\r\n return []; // any unexpected error → fail-open\r\n } finally {\r\n db.close();\r\n }\r\n },\r\n};\r\n\r\nexport default kiloCliReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/kimi/index.ts"],"sourcesContent":["/**\r\n * adapters/kimi — Kimi CLI (Moonshot) platform adapter for agent-connector.\r\n *\r\n * Kimi CLI is a json-stdio host: the runner pipes a JSON payload to a command on\r\n * stdin and reads an exit code (and optional reason) back. Two native config\r\n * files back the install. Their scope-resolution DIFFERS (verified against the\r\n * kimi-code source, MIT/public — see the Native paths section):\r\n * - mcp.json → `mcpServers.<id>` MCP registration (JSON, stdio shape:\r\n * {command,args,env}). Project-local at `<projectDir>/.kimi-code/mcp.json`\r\n * under project scope, else the user base dir (`$KIMI_CODE_HOME` ||\r\n * `~/.kimi-code`). Handled via BaseAdapter's JSON helpers.\r\n * - config.toml → `[[hooks]]` array-of-tables (TOML), each table — ALWAYS the\r\n * user base dir (Kimi reads no project-local config.toml).\r\n * { event, matcher, command }. Parsed/serialized with @iarna/toml: every\r\n * config VALUE (unrelated sections, sibling hooks, scalars) is preserved,\r\n * but a parse→stringify round-trip does NOT preserve user COMMENTS or the\r\n * original key ordering/formatting in config.toml (values survive; comments\r\n * and layout do not).\r\n *\r\n * Hook surface is intentionally narrow: Kimi CLI only honors a PreToolUse DENY.\r\n * It cannot rewrite tool args, rewrite tool output, or inject session context —\r\n * so every other decision degrades to a silent allow (exit 0). Kimi Code uses\r\n * the Claude/Codex reply shape: a PreToolUse deny is signalled with EXIT 0 plus\r\n * a `hookSpecificOutput` JSON object on stdout carrying\r\n * permissionDecision:\"deny\" + permissionDecisionReason — that is how Kimi's\r\n * runner blocks the pending tool call. An allow is exit 0 with empty stdout.\r\n *\r\n * E1 extension events (verified against moonshotai.github.io/kimi-cli hooks):\r\n * - PostToolUseFailure — native (tool_name, tool_input, error; tool-name\r\n * matcher). Feedback-only: Kimi's exit-0 protocol adds non-empty stdout to\r\n * context, so \"context\" (and a degraded \"deny\") emit plain-text stdout.\r\n * - SubagentStart / SubagentStop — native, but with Kimi-specific wire\r\n * fields: agent_name (→ normalized agentType; there is no agent_id) plus\r\n * prompt (start) / response (stop → lastAssistantMessage). SubagentStop\r\n * deny uses Kimi's generic block protocol: EXIT 2 with the reason on\r\n * stderr (fed back to the model as correction).\r\n * - PermissionRequest — fired just before Kimi waits for user approval\r\n * (observation only). Wired; its return value does not affect the flow.\r\n * - The remaining canonical events (PostToolUse, UserPromptSubmit, Stop,\r\n * SessionStart, SessionEnd, PreCompact, PostCompact, Notification) are all\r\n * documented Kimi hooks and now wired 1:1 (PascalCase). Of these only\r\n * UserPromptSubmit + Stop are BLOCKABLE — they share SubagentStop's exit-2\r\n * block protocol (deny → EXIT 2 + stderr reason); the rest are observation\r\n * only. Verified against the kimi-code hooks docs (kimi.com/code/docs/en/\r\n * kimi-code-cli/customization/hooks.html): \"Only blockable events\r\n * (PreToolUse, Stop, UserPromptSubmit) have return values that affect the\r\n * main flow. All other events are observation-only.\"\r\n *\r\n * Path confidence: the `~/.kimi-code` base + mcp.json (`mcpServers`) layout is\r\n * PRIMARY-DOC-CONFIRMED against the official Kimi Code CLI docs (config dir\r\n * `~/.kimi-code/`, override `$KIMI_CODE_HOME` — there is NO `$KIMI_HOME`;\r\n * moonshotai.github.io/kimi-code/en/configuration/config-files.html +\r\n * .../customization/mcp.html) and corroborated by a live `kimi doctor config`\r\n * probe of `@moonshot-ai/kimi-code` v0.18.0 (reads `~/.kimi-code`, honors\r\n * `$KIMI_CODE_HOME`, ignores `KIMI_HOME`). We still install + doctor-report\r\n * presence so a future path move surfaces as a FAIL rather than silently\r\n * misbehaving.\r\n *\r\n * NOT YET COVERED: three observation-only Kimi-only events — StopFailure,\r\n * PermissionResult, Interrupt — are documented but NOT promoted to the core\r\n * normalized model (each is below the ≥3-host bar for a core HookEventName).\r\n * A connector that needs them on Kimi can declare them via the nativeHooks\r\n * passthrough. Kimi also has a PLUGIN system (`<base>/plugins/<name>/\r\n * kimi.plugin.json`), not yet surfaced.\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { dirname, join, resolve } from \"node:path\";\r\n\r\nimport TOML from \"@iarna/toml\";\r\n\r\nimport { BaseAdapter } from \"../base.js\";\r\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } 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 NotificationEvent,\r\n PermissionRequestEvent,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PostToolUseFailureEvent,\r\n PostCompactEvent,\r\n PreCompactEvent,\r\n PreToolUseEvent,\r\n SessionEndEvent,\r\n SessionStartEvent,\r\n ServerDef,\r\n SkillDef,\r\n StopEvent,\r\n SubagentStartEvent,\r\n SubagentStopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\nimport { ensureDir } from \"../../core/paths.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport {\r\n buildHomeBinHookCommand,\r\n buildWrappedStdio,\r\n isHomeBinHookCommand,\r\n} from \"../../core/spawn.js\";\r\nimport { normalizeSessionSource } from \"../claude-code/wire.js\";\r\n\r\nconst HOST: PlatformId = \"kimi\";\r\nconst MCP_ROOT_KEY = \"mcpServers\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Native shapes\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Raw Kimi CLI hook payload (Claude-style: PascalCase event, snake_case fields). */\r\ninterface KimiHookInput {\r\n tool_name?: string;\r\n tool_input?: Record<string, unknown>;\r\n // PostToolUse (success) — tool output as a string (kimi turn/index.ts:739,\r\n // toolOutputText(output).slice(0,2000)). kimi has NO `tool_response` field\r\n // (0 hits repo-wide; that key is a Claude-Code false-friend); the EVENT TYPE\r\n // (PostToolUse vs PostToolUseFailure, chosen at turn/index.ts:731) encodes\r\n // success/failure, so there is also no `is_error` field on the wire.\r\n tool_output?: string;\r\n session_id?: string;\r\n cwd?: string;\r\n hook_event_name?: string;\r\n source?: string;\r\n // UserPromptSubmit — kimi sends `readonly ContentPart[]` (turn/index.ts:571,\r\n // sole call site; a text prompt is [{type:'text', text}], kosong\r\n // message.ts:3-6). SubagentStart sends a plain string. Accept both.\r\n prompt?: unknown;\r\n is_error?: boolean;\r\n stop_hook_active?: boolean;\r\n trigger?: string;\r\n message?: string;\r\n reason?: string;\r\n // PostToolUseFailure — kimi sends a KimiErrorPayload OBJECT\r\n // {code, message, name?, details?, retryable} (turn/index.ts:738 via\r\n // toKimiErrorPayload; agent-core errors/serialize.ts:22-27), NOT a string.\r\n error?: unknown;\r\n // SubagentStart / SubagentStop — Kimi sends agent_name (NOT agent_id /\r\n // agent_type) plus prompt (start) / response (stop).\r\n agent_name?: string;\r\n response?: string;\r\n connector?: string;\r\n}\r\n\r\n/** One `[[hooks]]` array-of-tables entry as Kimi stores it in config.toml. */\r\ninterface KimiTomlHook {\r\n event: string;\r\n matcher?: string;\r\n command: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Parsed config.toml shape we care about (rest preserved verbatim). */\r\ninterface KimiConfigToml {\r\n hooks?: KimiTomlHook[];\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Native stdio MCP server entry under `mcpServers`. */\r\ninterface KimiStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n}\r\n\r\n/** Native remote MCP server entry under `mcpServers`. */\r\ninterface KimiHttpServer {\r\n url: string;\r\n /**\r\n * Present only for a legacy SSE endpoint. Per the kimi mcp docs a bare `url`\r\n * (no transport) IS an HTTP server; `transport:\"sse\"` selects the older\r\n * HTTP+SSE transport.\r\n */\r\n transport?: \"sse\";\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Kimi CLI hook events agent-connector registers: every canonical event in the\r\n * core model — Kimi documents all of them as native hooks (PascalCase 1:1). The\r\n * PreToolUse matcher below is charset-clean (Rust-regex safe: no look-around) so\r\n * Kimi's matcher accepts it; copied in spirit from the Codex/context-mode\r\n * matchers. Order mirrors the core ALL_EVENTS sequence.\r\n */\r\nconst KIMI_HOOK_EVENTS = [\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] as const;\r\ntype KimiHookEventName = (typeof KIMI_HOOK_EVENTS)[number];\r\n\r\n/**\r\n * Canonical events with NO Kimi analog. Kimi documents a native hook for EVERY\r\n * current core event, so this is empty today. It stays as the seam: if a future\r\n * core HookEventName lands that Kimi cannot fire, add it here and declared hooks\r\n * for it warn-skip at install — the degradation is reported, never silent.\r\n */\r\nconst WARN_SKIP_EVENTS: ReadonlySet<HookEventName> = new Set<HookEventName>([]);\r\n\r\nconst PRE_TOOL_USE_MATCHER =\r\n \"Bash|Shell|shell|exec_command|Read|Edit|Write|WebFetch|Agent|mcp__\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Adapter\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\nexport class KimiAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Kimi CLI\";\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 // Kimi documents a native hook for EVERY canonical event. BLOCKABLE decisions\r\n // (deny that affects the flow) are honored only for PreToolUse, Stop and\r\n // UserPromptSubmit per the docs; the rest fire observation-only, but we still\r\n // register them so a connector's handler runs (e.g. for telemetry/context).\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: true,\r\n permissionRequest: true,\r\n postToolUseFailure: true,\r\n subagentStart: true,\r\n subagentStop: true,\r\n postCompact: true,\r\n // Kimi cannot rewrite args/output nor inject session context — deny-only.\r\n canModifyArgs: false,\r\n canModifyOutput: false,\r\n canInjectSessionContext: false,\r\n // Kimi documents three MCP transports: stdio, HTTP and (legacy) SSE — a\r\n // url entry with transport:\"sse\" (kimi.com/code/docs/en/kimi-code-cli/\r\n // customization/mcp.html: \"supports three MCP server connection methods\").\r\n transports: [\"stdio\", \"http\", \"sse\"],\r\n // Skills surface: Kimi reads SKILL.md from ~/.kimi-code/skills/<name>/SKILL.md\r\n // (user scope) and <projectDir>/.kimi-code/skills/<name>/SKILL.md (project\r\n // scope). Both are documented scan dirs (docs/en/customization/skills.md;\r\n // \"Project > User\" priority). Project-local mcp.json is likewise read\r\n // (docs/en/customization/mcp.md); config.toml/hooks are user-only.\r\n supportsSkills: true,\r\n // Native passthrough hooks: Kimi's observation-only single-host events —\r\n // StopFailure, PermissionResult, Interrupt — have NO normalized HookEventName\r\n // (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[\"kimi\"].nativeHooks; installHooks writes those\r\n // event-name [[hooks]] entries verbatim, and the generic uninstall reverses them.\r\n supportsNativeHooks: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(_projectDir: string): DetectedPlatform {\r\n const baseDir = this.baseDir();\r\n const mcpPath = join(baseDir, \"mcp.json\");\r\n const configPath = join(baseDir, \"config.toml\");\r\n const installed = existsSync(baseDir) || existsSync(mcpPath) || existsSync(configPath);\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: mcpPath,\r\n scope: \"user\",\r\n reason: installed\r\n ? `found Kimi CLI config under ${baseDir}`\r\n : `no Kimi CLI config at ${baseDir}`,\r\n // Path confidence is high: the ~/.kimi-code base (override $KIMI_CODE_HOME) is\r\n // the primary-doc-verified shape (moonshotai.github.io/kimi-code/en/\r\n // configuration/config-files.html) and live-confirmed via `kimi doctor config`\r\n // on @moonshot-ai/kimi-code v0.18.0.\r\n confidence: \"high\",\r\n };\r\n }\r\n\r\n // ── Native paths ───────────────────────────────────────────────────────\r\n //\r\n // Kimi's config surfaces are NOT uniformly project-aware — each one resolves\r\n // from a different root, verified against the kimi-code source (MIT, public):\r\n // - mcp.json (MCP) → project-local SUPPORTED. config-loader.ts loads\r\n // three sources and `project: join(cwd, '.kimi-code', 'mcp.json')` wins\r\n // over user (`~/.kimi-code/mcp.json`). Doc: docs/en/customization/mcp.md\r\n // (\"Project level: .kimi-code/mcp.json\").\r\n // - skills → project-local SUPPORTED (.kimi-code/skills/, scanned\r\n // above the user dir). Doc: docs/en/customization/skills.md.\r\n // - config.toml (hooks) → USER-ONLY. config/path.ts resolveConfigPath()\r\n // resolves it solely from resolveKimiHome (KIMI_CODE_HOME ?? ~/.kimi-code);\r\n // config/toml.ts loadRuntimeConfigSafe reads that SINGLE file with no\r\n // cwd/project merge. There is no project-local config.toml — so a\r\n // project-scope install must still write hooks to the user base dir or\r\n // Kimi never loads them.\r\n // Hence getConfigDir() (the project-aware root) drives MCP + skills, while\r\n // getHookConfigPath() stays pinned to baseDir() regardless of scope.\r\n\r\n /**\r\n * Project-aware config dir: `<projectDir>/.kimi-code` for project scope, else\r\n * the user base dir. Mirrors codex's getConfigDir. Drives the surfaces Kimi\r\n * reads project-locally (mcp.json + skills) — NOT config.toml (see below).\r\n */\r\n getConfigDir(ctx: InstallContext): string {\r\n if (ctx.scope === \"project\") return join(ctx.projectDir, \".kimi-code\");\r\n return this.baseDir();\r\n }\r\n\r\n /** MCP registration file (JSON) — project-local under project scope. */\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"mcp.json\");\r\n }\r\n\r\n /**\r\n * Hook registration file (TOML) — ALWAYS the user base dir. Kimi resolves\r\n * config.toml only from KIMI_CODE_HOME ?? ~/.kimi-code (no project-local\r\n * variant), so this intentionally ignores ctx.scope: a project-scope install\r\n * writes hooks here so Kimi actually fires them.\r\n */\r\n getHookConfigPath(_ctx: InstallContext): string {\r\n return join(this.baseDir(), \"config.toml\");\r\n }\r\n\r\n /**\r\n * `$KIMI_CODE_HOME` (with `~` expansion, then resolved) when set & non-empty,\r\n * else `~/.kimi-code`. This mirrors `codexConfigHome()` in core/host-paths.ts\r\n * (tilde-expand-then-default) so the writer and any probe agree on the dir.\r\n *\r\n * Per the official Kimi Code CLI docs the config dir is `~/.kimi-code/`,\r\n * overridable ONLY by `$KIMI_CODE_HOME` — there is NO `$KIMI_HOME` env var, so\r\n * the old `$KIMI_HOME`-first resolution was the bug (with `$KIMI_HOME` set the\r\n * adapter wrote where Kimi never reads). Doc:\r\n * moonshotai.github.io/kimi-code/en/configuration/config-files.html;\r\n * live-confirmed by `kimi doctor config` on @moonshot-ai/kimi-code v0.18.0.\r\n */\r\n private baseDir(): string {\r\n const env = process.env.KIMI_CODE_HOME;\r\n if (env && env.trim() !== \"\") {\r\n if (env.startsWith(\"~\")) {\r\n return join(homedir(), env.replace(/^~[/\\\\]?/, \"\"));\r\n }\r\n return resolve(env);\r\n }\r\n return join(homedir(), \".kimi-code\");\r\n }\r\n\r\n // ── MCP server install / uninstall (mcp.json → mcpServers.<id>) ──────────\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 kimi\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\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 changes: ChangeRecord[] = [];\r\n // Honesty: Kimi documents only stdio/http/sse. A connector declaring another\r\n // transport (e.g. the non-spec \"ws\") is still rendered best-effort as a bare\r\n // URL entry, but the mismatch is REPORTED rather than silently misregistered\r\n // — same \"degradation is never silent\" posture as the hook warn-skips.\r\n if (!this.capabilities.transports.includes(server.transport)) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `transport \"${server.transport}\" is not a Kimi MCP transport (stdio/http/sse); registered best-effort as a URL entry`,\r\n });\r\n }\r\n\r\n const serverPath = this.getServerConfigPath(ctx);\r\n const entry = this.renderServerEntry(ctx, server);\r\n changes.push(\r\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\r\n );\r\n return changes;\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 /**\r\n * Render a normalized ServerDef into Kimi's native mcpServers entry. Kimi's\r\n * mcp.json has no documented native interpolation, so `${env:VAR}` refs are\r\n * resolved to literals at install time (same posture as the TOML hosts).\r\n */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): KimiStdioServer | KimiHttpServer {\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 through\r\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\r\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n command = resolveEnvRefsDeep(command);\r\n args = resolveEnvRefsDeep(args);\r\n\r\n const entry: KimiStdioServer = { command };\r\n if (args.length > 0) entry.args = args;\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.env = env;\r\n return entry;\r\n }\r\n\r\n // Remote transports — Kimi registers a URL entry. A bare `url` is an HTTP\r\n // server; a legacy HTTP+SSE endpoint needs transport:\"sse\". (ws is not a\r\n // Kimi-documented transport — it falls through as a plain url, best-effort.)\r\n const entry: KimiHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\r\n if (transport === \"sse\") entry.transport = \"sse\";\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 /** Resolve env/header values to literals (no native interpolation on Kimi). */\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(resolveEnvRefsDeep(env))) {\r\n out[k] = String(v);\r\n }\r\n return out;\r\n }\r\n\r\n // ── Skills surface ────────────────────────────────────────────────────────\r\n // Kimi reads SKILL.md from <skills dir>/<name>/SKILL.md, scanning project then\r\n // user (docs/en/customization/skills.md, \"Project > User\"):\r\n // user scope: ~/.kimi-code/skills/<name>/SKILL.md\r\n // project scope: <projectDir>/.kimi-code/skills/<name>/SKILL.md\r\n // Derived from getConfigDir(ctx) so skills + mcp.json share ONE scope-resolved\r\n // root (config.toml/hooks deliberately do not — see getHookConfigPath).\r\n\r\n private skillsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"skills\");\r\n }\r\n\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\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 kimi\" }];\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\"), this.renderSkill(skill), ctx.dryRun),\r\n );\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 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;\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n private renderSkill(skill: SkillDef): string {\r\n return renderSkillMd(skill);\r\n }\r\n\r\n // ── Hook install / uninstall (config.toml → [[hooks]]) ───────────────────\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 (effectiveHookEvents /\r\n // warnSkipHookEvents already return [] for it). nativeHooks is a sibling,\r\n // kimi-scoped declaration on the same override and installs regardless.\r\n const events = this.effectiveHookEvents(ctx);\r\n const dropped = this.warnSkipHookEvents(ctx);\r\n const nativeHooks = override?.nativeHooks ?? {};\r\n const nativeEvents = Object.keys(nativeHooks);\r\n const path = this.getHookConfigPath(ctx);\r\n\r\n if (events.length === 0 && dropped.length === 0 && nativeEvents.length === 0) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: override?.hooks === false ? \"hooks disabled for kimi\" : \"no hooks declared\",\r\n },\r\n ];\r\n }\r\n\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return [symlink];\r\n\r\n const cfg = this.readToml(path);\r\n // Kimi's `hooks` is an ARRAY-of-tables ([[hooks]]); the BaseAdapter object-map\r\n // guard would mis-flag it. Inverse guard: a present-but-non-array `hooks`\r\n // (hand-edited to an object/primitive) cannot take `.push`/`.findIndex` — warn\r\n // and skip so the user's malformed value is preserved untouched.\r\n if (cfg.hooks !== undefined && !Array.isArray(cfg.hooks)) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"warn\",\r\n path,\r\n detail: `existing \"hooks\" in ${path} is not an array; left untouched (fix it, then re-run)`,\r\n },\r\n ];\r\n }\r\n const hooks = (cfg.hooks ??= []);\r\n const changes: ChangeRecord[] = [];\r\n let mutated = false;\r\n\r\n // Declared events Kimi cannot fire are reported, never silently dropped.\r\n for (const event of dropped) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n path,\r\n detail: `${event} has no Kimi CLI hook equivalent — skipped`,\r\n });\r\n }\r\n\r\n for (const event of events) {\r\n const desired = this.renderHook(ctx, event);\r\n // Match our entry FOR THIS EVENT — isOurHook alone would find whichever\r\n // of our entries comes first and clobber a sibling event's registration.\r\n const idx = hooks.findIndex((h) => this.isOurHook(ctx, h) && h?.event === event);\r\n if (idx < 0) {\r\n hooks.push(desired);\r\n changes.push({ platform: this.id, action: \"create\", path, detail: `hooks.${event}` });\r\n mutated = true;\r\n } else if (JSON.stringify(hooks[idx]) !== JSON.stringify(desired)) {\r\n hooks[idx] = desired;\r\n changes.push({ platform: this.id, action: \"update\", path, detail: `hooks.${event}` });\r\n mutated = true;\r\n } else {\r\n changes.push({ platform: this.id, action: \"skip\", path, detail: `hooks.${event}` });\r\n }\r\n }\r\n\r\n // NATIVE passthrough events: Kimi-native event names (e.g. StopFailure,\r\n // PermissionResult, Interrupt) written VERBATIM as [[hooks]] entries — no\r\n // canonical mapping, same command shape + idempotency. Matched by EXACT\r\n // command so a native name that coincides with a canonical event never\r\n // clobbers it.\r\n for (const event of nativeEvents) {\r\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\r\n const desired = { event, matcher: nativeHooks[event]?.matcher ?? \"\", command };\r\n const idx = hooks.findIndex((h) => h?.event === event && h?.command === command);\r\n if (idx < 0) {\r\n hooks.push(desired);\r\n changes.push({ platform: this.id, action: \"create\", path, detail: `hooks.${event} (native)` });\r\n mutated = true;\r\n } else if (JSON.stringify(hooks[idx]) !== JSON.stringify(desired)) {\r\n hooks[idx] = desired;\r\n changes.push({ platform: this.id, action: \"update\", path, detail: `hooks.${event} (native)` });\r\n mutated = true;\r\n } else {\r\n changes.push({ platform: this.id, action: \"skip\", path, detail: `hooks.${event} (native)` });\r\n }\r\n }\r\n\r\n if (mutated) this.writeToml(path, cfg, ctx.dryRun);\r\n return changes;\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n const path = this.getHookConfigPath(ctx);\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return [symlink];\r\n\r\n if (!existsSync(path)) {\r\n return [{ platform: this.id, action: \"skip\", path, detail: \"no config.toml\" }];\r\n }\r\n const cfg = this.readToml(path);\r\n const hooks = cfg.hooks;\r\n if (!Array.isArray(hooks) || hooks.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", path, detail: \"no hooks present\" }];\r\n }\r\n\r\n const kept = hooks.filter((h) => !this.isOurHook(ctx, h));\r\n const removed = hooks.length - kept.length;\r\n if (removed === 0) {\r\n return [{ platform: this.id, action: \"skip\", path, detail: \"no agent-connector hooks present\" }];\r\n }\r\n\r\n if (kept.length > 0) cfg.hooks = kept;\r\n else delete cfg.hooks;\r\n this.writeToml(path, cfg, ctx.dryRun);\r\n return [{ platform: this.id, action: \"remove\", path, detail: `hooks (${removed})` }];\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const serverPath = this.getServerConfigPath(ctx);\r\n const hookPath = this.getHookConfigPath(ctx);\r\n const connectorId = ctx.connector.id;\r\n const homeBin = ctx.homeBinPath;\r\n const hookEvents = this.effectiveHookEvents(ctx);\r\n const checks: HealthCheck[] = [\r\n {\r\n name: `${this.name}: mcp.json present`,\r\n check: () =>\r\n existsSync(serverPath)\r\n ? { status: \"OK\", detail: serverPath }\r\n : { status: \"FAIL\", detail: `not found: ${serverPath}` },\r\n },\r\n {\r\n name: `${this.name}: mcpServers.${connectorId} registered`,\r\n check: () => {\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<Record<string, Record<string, unknown>>>(serverPath);\r\n const bucket = cfg?.[MCP_ROOT_KEY];\r\n const present =\r\n typeof bucket === \"object\" && bucket !== null && connectorId in bucket;\r\n return present\r\n ? { status: \"OK\", detail: `mcpServers.${connectorId}` }\r\n : { status: \"FAIL\", detail: `mcpServers.${connectorId} not found in ${serverPath}` };\r\n },\r\n },\r\n {\r\n name: `${this.name}: hook command registered`,\r\n check: () => {\r\n if (hookEvents.length === 0) {\r\n return { status: \"OK\", detail: \"no hooks declared\" };\r\n }\r\n if (!existsSync(hookPath)) {\r\n return { status: \"FAIL\", detail: `not found: ${hookPath}` };\r\n }\r\n const cfg = this.readToml(hookPath);\r\n const registered = (cfg.hooks ?? []).some((h) =>\r\n isHomeBinHookCommand(h?.command, homeBin, connectorId),\r\n );\r\n return registered\r\n ? { status: \"OK\", detail: \"hook command present\" }\r\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${hookPath}` };\r\n },\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 return checks;\r\n }\r\n\r\n // ── Runtime: parse Kimi stdin JSON → normalized event ────────────────────\r\n\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as KimiHookInput;\r\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\r\n const sessionId = input.session_id ?? `pid-${process.ppid}`;\r\n const projectDir = input.cwd ?? process.env.KIMI_PROJECT_DIR ?? process.cwd();\r\n\r\n const base = {\r\n hostPlatform: HOST,\r\n connectorId,\r\n sessionId,\r\n projectDir,\r\n raw,\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 ev: PostToolUseEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n ...(typeof input.tool_output === \"string\"\r\n ? { toolOutput: input.tool_output }\r\n : {}),\r\n // kimi sends no `is_error` on the wire; success is encoded by the\r\n // event type (PostToolUseFailure fires on failure), so `?? false`\r\n // is always the correct value here.\r\n isError: input.is_error ?? false,\r\n };\r\n return ev;\r\n }\r\n case \"SessionStart\": {\r\n const ev: SessionStartEvent = {\r\n ...base,\r\n source: normalizeSessionSource(input.source),\r\n };\r\n return ev;\r\n }\r\n case \"SessionEnd\": {\r\n const ev: SessionEndEvent = {\r\n ...base,\r\n ...(typeof input.message === \"string\" ? { reason: input.message } : {}),\r\n };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: extractPromptText(input.prompt),\r\n };\r\n return ev;\r\n }\r\n case \"PreCompact\": {\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 \"PostCompact\": {\r\n // Kimi fires PostCompact after compaction completes (observation only),\r\n // payload `trigger`: manual|auto — mirrors PreCompact.\r\n const ev: PostCompactEvent = {\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 \"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 \"Notification\": {\r\n const ev: NotificationEvent = {\r\n ...base,\r\n message: typeof input.message === \"string\" ? input.message : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"PermissionRequest\": {\r\n // Kimi fires PermissionRequest just before waiting for user approval\r\n // (observation only); payload subject is the tool name.\r\n const ev: PermissionRequestEvent = {\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 \"PostToolUseFailure\": {\r\n // Kimi documents tool_name/tool_input/error only (no tool_use_id /\r\n // is_interrupt / duration_ms) — the optionals stay unset.\r\n const ev: PostToolUseFailureEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n error: extractErrorMessage(input.error),\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStart\": {\r\n // Kimi sends agent_name (the matcher subject) — normalize it as\r\n // agentType; there is no agent_id. The start prompt rides in `raw`.\r\n const ev: SubagentStartEvent = {\r\n ...base,\r\n ...(typeof input.agent_name === \"string\"\r\n ? { agentType: input.agent_name }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SubagentStop\": {\r\n const ev: SubagentStopEvent = {\r\n ...base,\r\n ...(typeof input.agent_name === \"string\"\r\n ? { agentType: input.agent_name }\r\n : {}),\r\n ...(typeof input.response === \"string\"\r\n ? { lastAssistantMessage: input.response }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n default: {\r\n const _never: never = event;\r\n throw new Error(`unsupported kimi hook event: ${String(_never)}`);\r\n }\r\n }\r\n }\r\n\r\n // ── Runtime: normalized response → Kimi native hook reply ────────────────\r\n\r\n formatReply(event: HookEventName, response: HookResponse): HookReply {\r\n const decision = response.decision ?? \"allow\";\r\n\r\n // deny → block the pending tool call. Kimi Code uses the Claude/Codex reply\r\n // shape: EXIT 0 + a `hookSpecificOutput` JSON object on stdout carrying\r\n // permissionDecision:\"deny\". PreToolUse is the only event using this\r\n // structured reply; the other blockable events (Stop, UserPromptSubmit,\r\n // SubagentStop) use the generic exit-2 protocol below.\r\n if (decision === \"deny\" && event === \"PreToolUse\") {\r\n return {\r\n exitCode: 0,\r\n stdout: JSON.stringify({\r\n hookSpecificOutput: {\r\n hookEventName: \"PreToolUse\",\r\n permissionDecision: \"deny\",\r\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\r\n },\r\n }),\r\n };\r\n }\r\n\r\n // PostToolUseFailure (feedback beside the error) and SubagentStart (context\r\n // for the subagent) are observe/context-only: Kimi's documented protocol\r\n // adds non-empty stdout on exit 0 to context, so \"context\" emits the text\r\n // PLAIN (no JSON envelope) and a \"deny\" DEGRADES to the same shape carrying\r\n // the reason (the tool already failed / the spawn is not blockable).\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 if (context) return { exitCode: 0, stdout: context };\r\n return { exitCode: 0 };\r\n }\r\n\r\n // BLOCKABLE events via Kimi's generic block protocol: deny → EXIT 2 with the\r\n // reason on stderr (fed back to the model). Per the kimi-code docs the\r\n // blockable events are PreToolUse (handled above with its structured reply),\r\n // Stop and UserPromptSubmit; SubagentStop reuses the same Stop semantics. For\r\n // Stop the stderr reason lets the model continue; for UserPromptSubmit EXIT 2\r\n // blocks the turn (the model is not called). \"context\" rides the exit-0\r\n // stdout channel (Kimi appends non-empty stdout to context).\r\n if (event === \"SubagentStop\" || event === \"Stop\" || event === \"UserPromptSubmit\") {\r\n if (decision === \"deny\") {\r\n return { exitCode: 2, stderr: response.reason ?? \"Blocked by hook\" };\r\n }\r\n if (decision === \"context\" && response.additionalContext) {\r\n return { exitCode: 0, stdout: response.additionalContext };\r\n }\r\n return { exitCode: 0 };\r\n }\r\n\r\n // allow / modify / context / ask / unsupported-event → passthrough (exit 0,\r\n // empty stdout). Kimi cannot rewrite args/output or inject context, so those\r\n // are dropped.\r\n return { exitCode: 0 };\r\n }\r\n\r\n // ── Internal helpers ───────────────────────────────────────────────────\r\n\r\n /** Which canonical hook events to register for Kimi, honoring overrides. */\r\n private effectiveHookEvents(ctx: InstallContext): KimiHookEventName[] {\r\n if (ctx.connector.platforms[HOST]?.hooks === false) return [];\r\n return KIMI_HOOK_EVENTS.filter((e) => ctx.connector.hookEvents.includes(e));\r\n }\r\n\r\n /** Declared events Kimi has no analog for — install reports a warn-skip. */\r\n private warnSkipHookEvents(ctx: InstallContext): HookEventName[] {\r\n if (ctx.connector.platforms[HOST]?.hooks === false) return [];\r\n return ctx.connector.hookEvents.filter((e) => WARN_SKIP_EVENTS.has(e));\r\n }\r\n\r\n /**\r\n * Render one `[[hooks]]` entry pointing at the stable home binary. Only the\r\n * PreToolUse deny gate carries the native tool matcher; the E1 events register\r\n * \"\" (match every tool failure / agent name) and the universal entrypoint\r\n * applies the connector's own matcher at runtime.\r\n */\r\n private renderHook(ctx: InstallContext, event: KimiHookEventName): KimiTomlHook {\r\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, ctx.connector.id);\r\n return {\r\n event,\r\n matcher: event === \"PreToolUse\" ? PRE_TOOL_USE_MATCHER : \"\",\r\n command,\r\n };\r\n }\r\n\r\n /**\r\n * Does this `[[hooks]]` entry belong to this connector? Anchored on the\r\n * home-bin + connector-id token (isHomeBinHookCommand) so uninstalling a\r\n * shared-prefix connector id never strips a sibling's hook.\r\n */\r\n private isOurHook(ctx: InstallContext, hook: KimiTomlHook | undefined): boolean {\r\n if (!hook || typeof hook !== \"object\") return false;\r\n return isHomeBinHookCommand(hook.command, ctx.homeBinPath, ctx.connector.id);\r\n }\r\n\r\n // ── TOML config IO (config.toml is TOML; MCP stays JSON via BaseAdapter) ──\r\n\r\n private readToml(path: string): KimiConfigToml {\r\n if (!existsSync(path)) return {};\r\n try {\r\n return TOML.parse(readFileSync(path, \"utf8\")) as unknown as KimiConfigToml;\r\n } catch {\r\n return {};\r\n }\r\n }\r\n\r\n private writeToml(path: string, data: KimiConfigToml, dryRun: boolean): void {\r\n if (dryRun) return;\r\n ensureDir(dirname(path));\r\n // NOTE: a @iarna/toml parse→stringify round-trip preserves config VALUES but\r\n // NOT user comments or the original key ordering/formatting in config.toml.\r\n // Values are safe; comments authored by the user are not preserved.\r\n writeFileSync(path, TOML.stringify(data as never), \"utf8\");\r\n }\r\n}\r\n\r\n/**\r\n * Extract the prompt text from Kimi's UserPromptSubmit payload. Kimi sends\r\n * `readonly ContentPart[]` (turn/index.ts:571); a text prompt is\r\n * [{type:'text', text}] (kosong message.ts:3-6). Concatenate the `text` of the\r\n * text parts. A plain string (e.g. SubagentStart) is returned as-is.\r\n */\r\nfunction extractPromptText(prompt: unknown): string {\r\n if (typeof prompt === \"string\") return prompt;\r\n if (Array.isArray(prompt)) {\r\n return prompt\r\n .map((part) =>\r\n part && typeof (part as { text?: unknown }).text === \"string\"\r\n ? (part as { text: string }).text\r\n : \"\",\r\n )\r\n .join(\"\");\r\n }\r\n return \"\";\r\n}\r\n\r\n/**\r\n * Extract the failure message from Kimi's PostToolUseFailure payload. Kimi\r\n * sends a KimiErrorPayload object {code, message, ...} (turn/index.ts:738);\r\n * use its `message`. A plain string is accepted defensively.\r\n */\r\nfunction extractErrorMessage(error: unknown): string {\r\n if (typeof error === \"string\") return error;\r\n if (error && typeof (error as { message?: unknown }).message === \"string\") {\r\n return (error as { message: string }).message;\r\n }\r\n return \"\";\r\n}\r\n\r\nexport const adapter = new KimiAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|