@ken-jo/agent-connector 0.4.94 → 0.4.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -202
- package/NOTICE +6 -6
- package/README.md +605 -485
- package/dist/{action-VW5SACXY.js → action-IPFDPOZU.js} +16 -16
- package/dist/action-IPFDPOZU.js.map +1 -0
- package/dist/{amazon-q-ETMAGY3D.js → amazon-q-IT44LEWV.js} +6 -6
- package/dist/amazon-q-IT44LEWV.js.map +1 -0
- package/dist/{amp-BQZOL5GR.js → amp-CEWOSWQO.js} +4 -4
- package/dist/amp-CEWOSWQO.js.map +1 -0
- package/dist/{amp-67BZONGF.js → amp-P35FRU2Z.js} +7 -7
- package/dist/amp-P35FRU2Z.js.map +1 -0
- package/dist/{antigravity-EA4L225L.js → antigravity-LHFEFNMC.js} +5 -5
- package/dist/antigravity-LHFEFNMC.js.map +1 -0
- package/dist/antigravity-TWIWXTQH.js +18 -0
- package/dist/{antigravity-cli-B2HXZFYQ.js → antigravity-cli-MOKFSWOU.js} +5 -5
- package/dist/antigravity-cli-MOKFSWOU.js.map +1 -0
- package/dist/{antigravity-cli-OM6SC3PE.js → antigravity-cli-MPE27LPI.js} +9 -9
- package/dist/antigravity-cli-MPE27LPI.js.map +1 -0
- package/dist/audit-3E5JAOP2.js +311 -0
- package/dist/audit-3E5JAOP2.js.map +1 -0
- package/dist/{chunk-KSPMSRVU.js → chunk-3EP5V2F4.js} +3 -3
- package/dist/chunk-3EP5V2F4.js.map +1 -0
- package/dist/{chunk-MGTDQLJJ.js → chunk-3FINQ2ZF.js} +4 -4
- package/dist/chunk-3FINQ2ZF.js.map +1 -0
- package/dist/{chunk-KHO5WNTP.js → chunk-4GH2KA7V.js} +1 -1
- package/dist/chunk-4GH2KA7V.js.map +1 -0
- package/dist/{chunk-2Y2MZRLP.js → chunk-7C2IPIIB.js} +3 -3
- package/dist/chunk-7C2IPIIB.js.map +1 -0
- package/dist/{chunk-NLE2J5P4.js → chunk-7HHW23AC.js} +29 -29
- package/dist/chunk-7HHW23AC.js.map +1 -0
- package/dist/{chunk-XD7MY6HB.js → chunk-7PSNXUFK.js} +1 -1
- package/dist/chunk-7PSNXUFK.js.map +1 -0
- package/dist/{chunk-KJLFGQQM.js → chunk-7ZFK2WEO.js} +8 -6
- package/dist/chunk-7ZFK2WEO.js.map +1 -0
- package/dist/{chunk-XC5SJ35F.js → chunk-C63AAXK7.js} +5 -5
- package/dist/chunk-C63AAXK7.js.map +1 -0
- package/dist/{chunk-UM5S7DKK.js → chunk-C747DYNT.js} +1 -1
- package/dist/chunk-C747DYNT.js.map +1 -0
- package/dist/{chunk-EHP7WISI.js → chunk-FHYR5Q5T.js} +19 -14
- package/dist/chunk-FHYR5Q5T.js.map +1 -0
- package/dist/{chunk-I5TO42QC.js → chunk-GCPEPUD7.js} +8 -8
- package/dist/chunk-GCPEPUD7.js.map +1 -0
- package/dist/{chunk-ZMAJ2XFD.js → chunk-GZZCHJDP.js} +2 -2
- package/dist/chunk-GZZCHJDP.js.map +1 -0
- package/dist/{chunk-UMQ6NBQR.js → chunk-ILWHLGIC.js} +2 -2
- package/dist/chunk-ILWHLGIC.js.map +1 -0
- package/dist/{chunk-IVAWP6HH.js → chunk-IOJDZJ72.js} +2 -2
- package/dist/chunk-IOJDZJ72.js.map +1 -0
- package/dist/{chunk-NBYKLUF6.js → chunk-KFPSJRHR.js} +2 -2
- package/dist/chunk-KFPSJRHR.js.map +1 -0
- package/dist/{chunk-O7SDRBVB.js → chunk-KM2YXO6V.js} +1 -1
- package/dist/chunk-KM2YXO6V.js.map +1 -0
- package/dist/{chunk-P23RVIUY.js → chunk-L2C5UMKW.js} +4 -4
- package/dist/chunk-L2C5UMKW.js.map +1 -0
- package/dist/{chunk-OP4KBXUO.js → chunk-LFWYYWLV.js} +1 -1
- package/dist/chunk-LFWYYWLV.js.map +1 -0
- package/dist/{chunk-B5W3RHTI.js → chunk-LQ55E7QI.js} +7 -7
- package/dist/chunk-LQ55E7QI.js.map +1 -0
- package/dist/{chunk-TTKSYJRY.js → chunk-MLU7NDAZ.js} +12 -12
- package/dist/chunk-MLU7NDAZ.js.map +1 -0
- package/dist/{chunk-TQRLMA2C.js → chunk-N4ENLZEU.js} +22 -19
- package/dist/chunk-N4ENLZEU.js.map +1 -0
- package/dist/{chunk-SILKSP2Y.js → chunk-NDMNMAKP.js} +43 -43
- package/dist/chunk-NDMNMAKP.js.map +1 -0
- package/dist/{chunk-H53QZQJI.js → chunk-PSGTHJQU.js} +1 -1
- package/dist/chunk-PSGTHJQU.js.map +1 -0
- package/dist/{chunk-FBJQGRET.js → chunk-Q4ISQHUQ.js} +1 -1
- package/dist/chunk-Q4ISQHUQ.js.map +1 -0
- package/dist/{chunk-6TF7MHG5.js → chunk-Q7PR2WGT.js} +2 -2
- package/dist/chunk-Q7PR2WGT.js.map +1 -0
- package/dist/{chunk-GZGLCCEE.js → chunk-QYOUQCC6.js} +1 -1
- package/dist/chunk-QYOUQCC6.js.map +1 -0
- package/dist/{chunk-Z2MRSS2I.js → chunk-SLJI5BOM.js} +2 -2
- package/dist/chunk-SLJI5BOM.js.map +1 -0
- package/dist/{chunk-JKKU2WKG.js → chunk-TGZFDXNH.js} +4 -4
- package/dist/chunk-TGZFDXNH.js.map +1 -0
- package/dist/{chunk-FJCUKXGX.js → chunk-THI4PI4H.js} +2 -2
- package/dist/chunk-THI4PI4H.js.map +1 -0
- package/dist/{chunk-MQPNU2CY.js → chunk-UZZTWWGG.js} +1 -1
- package/dist/chunk-UZZTWWGG.js.map +1 -0
- package/dist/{chunk-2RIFORQS.js → chunk-WPTNMYYM.js} +2 -2
- package/dist/chunk-WPTNMYYM.js.map +1 -0
- package/dist/{chunk-OPXAP3AC.js → chunk-XN7S44U4.js} +1 -1
- package/dist/chunk-XN7S44U4.js.map +1 -0
- package/dist/{chunk-6WZODR3Z.js → chunk-XVEJAFKW.js} +5 -5
- package/dist/chunk-XVEJAFKW.js.map +1 -0
- package/dist/{chunk-BEFVJ2OE.js → chunk-XXLCMSD3.js} +1 -1
- package/dist/chunk-XXLCMSD3.js.map +1 -0
- package/dist/{chunk-YT43MUSJ.js → chunk-XZWMJLIT.js} +1 -1
- package/dist/chunk-XZWMJLIT.js.map +1 -0
- package/dist/{chunk-4NHXLXSD.js → chunk-Y3K6KJMS.js} +2 -2
- package/dist/chunk-Y3K6KJMS.js.map +1 -0
- package/dist/{chunk-RK6VBLXP.js → chunk-ZSOS2KOR.js} +1 -1
- package/dist/chunk-ZSOS2KOR.js.map +1 -0
- package/dist/{claude-code-NMRKTAP7.js → claude-code-FS42PXZO.js} +4 -4
- package/dist/claude-code-FS42PXZO.js.map +1 -0
- package/dist/{claude-code-DUZNOAS2.js → claude-code-QBWDT5RT.js} +11 -11
- package/dist/claude-code-QBWDT5RT.js.map +1 -0
- package/dist/cli/sdk.js +9 -8
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{cline-25KW25IN.js → cline-JKEAYWVR.js} +6 -6
- package/dist/cline-JKEAYWVR.js.map +1 -0
- package/dist/{codebuddy-ZNYQACMF.js → codebuddy-EB6EYPC3.js} +7 -7
- package/dist/codebuddy-EB6EYPC3.js.map +1 -0
- package/dist/{codebuff-VR6JUDIY.js → codebuff-5RSXFU6G.js} +6 -6
- package/dist/codebuff-5RSXFU6G.js.map +1 -0
- package/dist/{codebuff-ETYT5UBL.js → codebuff-6KWBW6CT.js} +4 -4
- package/dist/codebuff-6KWBW6CT.js.map +1 -0
- package/dist/{codex-CPNKTXG3.js → codex-ART46CDD.js} +9 -9
- package/dist/codex-ART46CDD.js.map +1 -0
- package/dist/{codex-YAORPCOD.js → codex-DKBAAUCO.js} +4 -4
- package/dist/codex-DKBAAUCO.js.map +1 -0
- package/dist/{continue-WU2IB5KS.js → continue-JHZCMSPH.js} +8 -8
- package/dist/continue-JHZCMSPH.js.map +1 -0
- package/dist/{copilot-cli-MZTAWMPW.js → copilot-cli-CLBJACQ5.js} +4 -4
- package/dist/copilot-cli-CLBJACQ5.js.map +1 -0
- package/dist/{copilot-cli-PAP377OM.js → copilot-cli-QVAU5CFM.js} +7 -7
- package/dist/copilot-cli-QVAU5CFM.js.map +1 -0
- package/dist/{crush-3AVQA4YU.js → crush-7TORBYUL.js} +7 -7
- package/dist/crush-7TORBYUL.js.map +1 -0
- package/dist/{crush-QBXLNN7T.js → crush-A5C5USRL.js} +4 -4
- package/dist/crush-A5C5USRL.js.map +1 -0
- package/dist/{cursor-DIW43TRZ.js → cursor-D5SWDVSW.js} +3 -3
- package/dist/cursor-D5SWDVSW.js.map +1 -0
- package/dist/cursor-W7I4QUFO.js +22 -0
- package/dist/{define-connector-LQFJL_at.d.ts → define-connector-DTWb46UB.d.ts} +1 -1
- package/dist/{detect-P5OA5UYM.js → detect-JHSA3G3U.js} +4 -4
- package/dist/detect-JHSA3G3U.js.map +1 -0
- package/dist/{devin-QMEM3OFA.js → devin-SSR7S4WX.js} +7 -7
- package/dist/devin-SSR7S4WX.js.map +1 -0
- package/dist/{doctor-2O2Q6MIB.js → doctor-CQJ7TZPA.js} +26 -26
- package/dist/doctor-CQJ7TZPA.js.map +1 -0
- package/dist/{droid-MOKV53J4.js → droid-45PJ7JGF.js} +7 -7
- package/dist/droid-45PJ7JGF.js.map +1 -0
- package/dist/{droid-U3ZBLQFO.js → droid-PFQ2PZSF.js} +4 -4
- package/dist/droid-PFQ2PZSF.js.map +1 -0
- package/dist/{gemini-cli-47ZHCOZR.js → gemini-cli-24PFDK7D.js} +8 -8
- package/dist/gemini-cli-24PFDK7D.js.map +1 -0
- package/dist/{gemini-cli-NMVVBO3K.js → gemini-cli-Y6RJMU24.js} +4 -4
- package/dist/gemini-cli-Y6RJMU24.js.map +1 -0
- package/dist/{goose-64V46Y2W.js → goose-K2HKUTBK.js} +4 -4
- package/dist/goose-K2HKUTBK.js.map +1 -0
- package/dist/{goose-4EI5MYTI.js → goose-U5D3LCPC.js} +9 -9
- package/dist/goose-U5D3LCPC.js.map +1 -0
- package/dist/{grok-cli-QYQPDSVB.js → grok-cli-L2MHAPBY.js} +7 -7
- package/dist/grok-cli-L2MHAPBY.js.map +1 -0
- package/dist/{hermes-F75OSK3Y.js → hermes-2S5JUTTJ.js} +7 -7
- package/dist/hermes-2S5JUTTJ.js.map +1 -0
- package/dist/{hermes-F3EGTK6N.js → hermes-MF3NX4ZY.js} +4 -4
- package/dist/hermes-MF3NX4ZY.js.map +1 -0
- package/dist/{hook-4N3BMKIK.js → hook-VHICXHXL.js} +16 -16
- package/dist/hook-VHICXHXL.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/{install-NPN77N3S.js → install-WLENR4KF.js} +192 -28
- package/dist/install-WLENR4KF.js.map +1 -0
- package/dist/{introspect-D4fEGuhN.d.ts → introspect-dNekqPDY.d.ts} +1 -1
- package/dist/{jetbrains-copilot-ZGIWI6YV.js → jetbrains-copilot-Z4FC3RM3.js} +6 -6
- package/dist/jetbrains-copilot-Z4FC3RM3.js.map +1 -0
- package/dist/{junie-DIFN2P22.js → junie-ULGJJIHB.js} +6 -6
- package/dist/junie-ULGJJIHB.js.map +1 -0
- package/dist/{kilo-SW7BH6EG.js → kilo-SMHPOHJ5.js} +4 -4
- package/dist/kilo-SMHPOHJ5.js.map +1 -0
- package/dist/{kilo-EMZJBEBB.js → kilo-WWIJOVWD.js} +8 -8
- package/dist/kilo-WWIJOVWD.js.map +1 -0
- package/dist/{kilo-cli-S3GXBPAE.js → kilo-cli-QKE2EQLS.js} +8 -8
- package/dist/kilo-cli-QKE2EQLS.js.map +1 -0
- package/dist/{kilo-cli-ZF272ZHN.js → kilo-cli-T2SRRRJS.js} +5 -5
- package/dist/kilo-cli-T2SRRRJS.js.map +1 -0
- package/dist/{kimi-IQJOIY6B.js → kimi-JMUFTVSF.js} +7 -7
- package/dist/kimi-JMUFTVSF.js.map +1 -0
- package/dist/{kimi-5FHEXGZD.js → kimi-MSIDEMCI.js} +4 -4
- package/dist/kimi-MSIDEMCI.js.map +1 -0
- package/dist/{kiro-WGOI5CGT.js → kiro-NYRRBIKW.js} +4 -4
- package/dist/kiro-NYRRBIKW.js.map +1 -0
- package/dist/{kiro-BYX4HEAJ.js → kiro-UWUCRKR3.js} +7 -7
- package/dist/kiro-UWUCRKR3.js.map +1 -0
- package/dist/{leaderboard-QKB36OBR.js → leaderboard-NJWKGMXP.js} +7 -7
- package/dist/leaderboard-NJWKGMXP.js.map +1 -0
- package/dist/{mimo-code-7R53QDHB.js → mimo-code-BPNYYIVM.js} +7 -7
- package/dist/mimo-code-BPNYYIVM.js.map +1 -0
- package/dist/{mistral-vibe-LHJ55FSB.js → mistral-vibe-LT3DAJ3L.js} +6 -6
- package/dist/mistral-vibe-LT3DAJ3L.js.map +1 -0
- package/dist/{mux-XM6AP35L.js → mux-7PIJ7HUQ.js} +4 -4
- package/dist/mux-7PIJ7HUQ.js.map +1 -0
- package/dist/{mux-NYCNGL43.js → mux-AHNUAY5Z.js} +6 -6
- package/dist/mux-AHNUAY5Z.js.map +1 -0
- package/dist/{nemoclaw-WSIPSE7U.js → nemoclaw-RE5RZASZ.js} +7 -7
- package/dist/nemoclaw-RE5RZASZ.js.map +1 -0
- package/dist/{omp-562NK5BJ.js → omp-D2EXEPH7.js} +7 -7
- package/dist/omp-D2EXEPH7.js.map +1 -0
- package/dist/{open-interpreter-I2CNOEXY.js → open-interpreter-SSGBEUKX.js} +6 -6
- package/dist/open-interpreter-SSGBEUKX.js.map +1 -0
- package/dist/openclaw-IJ33K45M.js +17 -0
- package/dist/{openclaw-5EQFGOWL.js → openclaw-KAFTNLR2.js} +4 -4
- package/dist/openclaw-KAFTNLR2.js.map +1 -0
- package/dist/{opencode-YS4WX2E2.js → opencode-YKUKZY3J.js} +7 -7
- package/dist/opencode-YKUKZY3J.js.map +1 -0
- package/dist/{opencode-QGP4ALQY.js → opencode-Z65JYILL.js} +4 -4
- package/dist/opencode-Z65JYILL.js.map +1 -0
- package/dist/{openhands-QMYIKNOS.js → openhands-SEZMCUC3.js} +7 -7
- package/dist/openhands-SEZMCUC3.js.map +1 -0
- package/dist/{package-Q6DV5247.js → package-JECVQEFT.js} +15 -15
- package/dist/package-JECVQEFT.js.map +1 -0
- package/dist/{pi-GGDQREVG.js → pi-DLKCPOJE.js} +4 -4
- package/dist/pi-DLKCPOJE.js.map +1 -0
- package/dist/{pi-644FIN3A.js → pi-YPYV2ULH.js} +6 -6
- package/dist/pi-YPYV2ULH.js.map +1 -0
- package/dist/{qwen-code-GQILBJ5B.js → qwen-code-26CSFDX6.js} +4 -4
- package/dist/qwen-code-26CSFDX6.js.map +1 -0
- package/dist/{qwen-code-STDMX7EM.js → qwen-code-ZHCLCYMC.js} +9 -9
- package/dist/qwen-code-ZHCLCYMC.js.map +1 -0
- package/dist/{roo-code-DLPIHHQ6.js → roo-code-7F4HYB34.js} +6 -6
- package/dist/roo-code-7F4HYB34.js.map +1 -0
- package/dist/{roo-code-SUWI4BBN.js → roo-code-HSAE2CJU.js} +4 -4
- package/dist/roo-code-HSAE2CJU.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +14 -14
- package/dist/sdk/index.d.ts +4 -4
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +11 -11
- package/dist/{serve-MJTTXDX4.js → serve-LYSBH43G.js} +16 -16
- package/dist/serve-LYSBH43G.js.map +1 -0
- package/dist/{status-Q3UY4NZU.js → status-PHKKGEW5.js} +11 -11
- package/dist/status-PHKKGEW5.js.map +1 -0
- package/dist/{statusline-QF4G724E.js → statusline-ZDD4OZ4F.js} +15 -15
- package/dist/statusline-ZDD4OZ4F.js.map +1 -0
- package/dist/{synthetic-6FRA7P5Q.js → synthetic-LUT6V6SD.js} +4 -4
- package/dist/synthetic-LUT6V6SD.js.map +1 -0
- package/dist/{telemetry-JHVRDDNK.js → telemetry-HDGMI2BK.js} +10 -10
- package/dist/telemetry-HDGMI2BK.js.map +1 -0
- package/dist/{trae-CPPYASR2.js → trae-SIQI3C66.js} +4 -4
- package/dist/trae-SIQI3C66.js.map +1 -0
- package/dist/{trae-UOYD6JZZ.js → trae-Y67HSDOW.js} +6 -6
- package/dist/trae-Y67HSDOW.js.map +1 -0
- package/dist/{types-BhcUEIJJ.d.ts → types-JyhpJHJa.d.ts} +4 -2
- package/dist/{uninstall-H2SOV3AP.js → uninstall-RWO2GM2I.js} +21 -21
- package/dist/uninstall-RWO2GM2I.js.map +1 -0
- package/dist/{upgrade-UCSG7L5U.js → upgrade-YJCXNUEE.js} +21 -21
- package/dist/upgrade-YJCXNUEE.js.map +1 -0
- package/dist/{usage-4EGIJ4TM.js → usage-IWO4RQN6.js} +4 -4
- package/dist/usage-IWO4RQN6.js.map +1 -0
- package/dist/{usage-event-GRQE7XWT.js → usage-event-AFFKCLHE.js} +15 -15
- package/dist/usage-event-AFFKCLHE.js.map +1 -0
- package/dist/{vscode-copilot-NIMH2DGU.js → vscode-copilot-5CI5B3X6.js} +7 -7
- package/dist/vscode-copilot-5CI5B3X6.js.map +1 -0
- package/dist/{warp-NRBBJQR2.js → warp-5YBSP7FP.js} +4 -4
- package/dist/warp-5YBSP7FP.js.map +1 -0
- package/dist/{warp-QYJGKURM.js → warp-INAKVGBV.js} +6 -6
- package/dist/warp-INAKVGBV.js.map +1 -0
- package/dist/{windsurf-75LLZ37C.js → windsurf-4HM57QAY.js} +6 -6
- package/dist/windsurf-4HM57QAY.js.map +1 -0
- package/dist/{zed-XJFOOKCO.js → zed-XXCNYOIN.js} +4 -4
- package/dist/zed-XXCNYOIN.js.map +1 -0
- package/dist/{zed-HKAZXEJW.js → zed-YN5X37PQ.js} +7 -7
- package/dist/zed-YN5X37PQ.js.map +1 -0
- package/package.json +92 -88
- package/dist/action-VW5SACXY.js.map +0 -1
- package/dist/amazon-q-ETMAGY3D.js.map +0 -1
- package/dist/amp-67BZONGF.js.map +0 -1
- package/dist/amp-BQZOL5GR.js.map +0 -1
- package/dist/antigravity-EA4L225L.js.map +0 -1
- package/dist/antigravity-VXLDLTO7.js +0 -18
- package/dist/antigravity-cli-B2HXZFYQ.js.map +0 -1
- package/dist/antigravity-cli-OM6SC3PE.js.map +0 -1
- package/dist/chunk-2RIFORQS.js.map +0 -1
- package/dist/chunk-2Y2MZRLP.js.map +0 -1
- package/dist/chunk-4NHXLXSD.js.map +0 -1
- package/dist/chunk-6TF7MHG5.js.map +0 -1
- package/dist/chunk-6WZODR3Z.js.map +0 -1
- package/dist/chunk-B5W3RHTI.js.map +0 -1
- package/dist/chunk-BEFVJ2OE.js.map +0 -1
- package/dist/chunk-EHP7WISI.js.map +0 -1
- package/dist/chunk-FBJQGRET.js.map +0 -1
- package/dist/chunk-FJCUKXGX.js.map +0 -1
- package/dist/chunk-GZGLCCEE.js.map +0 -1
- package/dist/chunk-H53QZQJI.js.map +0 -1
- package/dist/chunk-I5TO42QC.js.map +0 -1
- package/dist/chunk-IVAWP6HH.js.map +0 -1
- package/dist/chunk-JKKU2WKG.js.map +0 -1
- package/dist/chunk-KHO5WNTP.js.map +0 -1
- package/dist/chunk-KJLFGQQM.js.map +0 -1
- package/dist/chunk-KSPMSRVU.js.map +0 -1
- package/dist/chunk-MGTDQLJJ.js.map +0 -1
- package/dist/chunk-MQPNU2CY.js.map +0 -1
- package/dist/chunk-NBYKLUF6.js.map +0 -1
- package/dist/chunk-NLE2J5P4.js.map +0 -1
- package/dist/chunk-O7SDRBVB.js.map +0 -1
- package/dist/chunk-OP4KBXUO.js.map +0 -1
- package/dist/chunk-OPXAP3AC.js.map +0 -1
- package/dist/chunk-P23RVIUY.js.map +0 -1
- package/dist/chunk-RK6VBLXP.js.map +0 -1
- package/dist/chunk-SILKSP2Y.js.map +0 -1
- package/dist/chunk-TQRLMA2C.js.map +0 -1
- package/dist/chunk-TTKSYJRY.js.map +0 -1
- package/dist/chunk-UM5S7DKK.js.map +0 -1
- package/dist/chunk-UMQ6NBQR.js.map +0 -1
- package/dist/chunk-XC5SJ35F.js.map +0 -1
- package/dist/chunk-XD7MY6HB.js.map +0 -1
- package/dist/chunk-YT43MUSJ.js.map +0 -1
- package/dist/chunk-Z2MRSS2I.js.map +0 -1
- package/dist/chunk-ZMAJ2XFD.js.map +0 -1
- package/dist/claude-code-DUZNOAS2.js.map +0 -1
- package/dist/claude-code-NMRKTAP7.js.map +0 -1
- package/dist/cline-25KW25IN.js.map +0 -1
- package/dist/codebuddy-ZNYQACMF.js.map +0 -1
- package/dist/codebuff-ETYT5UBL.js.map +0 -1
- package/dist/codebuff-VR6JUDIY.js.map +0 -1
- package/dist/codex-CPNKTXG3.js.map +0 -1
- package/dist/codex-YAORPCOD.js.map +0 -1
- package/dist/continue-WU2IB5KS.js.map +0 -1
- package/dist/copilot-cli-MZTAWMPW.js.map +0 -1
- package/dist/copilot-cli-PAP377OM.js.map +0 -1
- package/dist/crush-3AVQA4YU.js.map +0 -1
- package/dist/crush-QBXLNN7T.js.map +0 -1
- package/dist/cursor-DIW43TRZ.js.map +0 -1
- package/dist/cursor-GSLUET3V.js +0 -22
- package/dist/detect-P5OA5UYM.js.map +0 -1
- package/dist/devin-QMEM3OFA.js.map +0 -1
- package/dist/doctor-2O2Q6MIB.js.map +0 -1
- package/dist/droid-MOKV53J4.js.map +0 -1
- package/dist/droid-U3ZBLQFO.js.map +0 -1
- package/dist/gemini-cli-47ZHCOZR.js.map +0 -1
- package/dist/gemini-cli-NMVVBO3K.js.map +0 -1
- package/dist/goose-4EI5MYTI.js.map +0 -1
- package/dist/goose-64V46Y2W.js.map +0 -1
- package/dist/grok-cli-QYQPDSVB.js.map +0 -1
- package/dist/hermes-F3EGTK6N.js.map +0 -1
- package/dist/hermes-F75OSK3Y.js.map +0 -1
- package/dist/hook-4N3BMKIK.js.map +0 -1
- package/dist/install-NPN77N3S.js.map +0 -1
- package/dist/jetbrains-copilot-ZGIWI6YV.js.map +0 -1
- package/dist/junie-DIFN2P22.js.map +0 -1
- package/dist/kilo-EMZJBEBB.js.map +0 -1
- package/dist/kilo-SW7BH6EG.js.map +0 -1
- package/dist/kilo-cli-S3GXBPAE.js.map +0 -1
- package/dist/kilo-cli-ZF272ZHN.js.map +0 -1
- package/dist/kimi-5FHEXGZD.js.map +0 -1
- package/dist/kimi-IQJOIY6B.js.map +0 -1
- package/dist/kiro-BYX4HEAJ.js.map +0 -1
- package/dist/kiro-WGOI5CGT.js.map +0 -1
- package/dist/leaderboard-QKB36OBR.js.map +0 -1
- package/dist/mimo-code-7R53QDHB.js.map +0 -1
- package/dist/mistral-vibe-LHJ55FSB.js.map +0 -1
- package/dist/mux-NYCNGL43.js.map +0 -1
- package/dist/mux-XM6AP35L.js.map +0 -1
- package/dist/nemoclaw-WSIPSE7U.js.map +0 -1
- package/dist/omp-562NK5BJ.js.map +0 -1
- package/dist/open-interpreter-I2CNOEXY.js.map +0 -1
- package/dist/openclaw-5EQFGOWL.js.map +0 -1
- package/dist/openclaw-7EYBQS4R.js +0 -17
- package/dist/opencode-QGP4ALQY.js.map +0 -1
- package/dist/opencode-YS4WX2E2.js.map +0 -1
- package/dist/openhands-QMYIKNOS.js.map +0 -1
- package/dist/package-Q6DV5247.js.map +0 -1
- package/dist/pi-644FIN3A.js.map +0 -1
- package/dist/pi-GGDQREVG.js.map +0 -1
- package/dist/qwen-code-GQILBJ5B.js.map +0 -1
- package/dist/qwen-code-STDMX7EM.js.map +0 -1
- package/dist/roo-code-DLPIHHQ6.js.map +0 -1
- package/dist/roo-code-SUWI4BBN.js.map +0 -1
- package/dist/serve-MJTTXDX4.js.map +0 -1
- package/dist/status-Q3UY4NZU.js.map +0 -1
- package/dist/statusline-QF4G724E.js.map +0 -1
- package/dist/synthetic-6FRA7P5Q.js.map +0 -1
- package/dist/telemetry-JHVRDDNK.js.map +0 -1
- package/dist/trae-CPPYASR2.js.map +0 -1
- package/dist/trae-UOYD6JZZ.js.map +0 -1
- package/dist/uninstall-H2SOV3AP.js.map +0 -1
- package/dist/upgrade-UCSG7L5U.js.map +0 -1
- package/dist/usage-4EGIJ4TM.js.map +0 -1
- package/dist/usage-event-GRQE7XWT.js.map +0 -1
- package/dist/vscode-copilot-NIMH2DGU.js.map +0 -1
- package/dist/warp-NRBBJQR2.js.map +0 -1
- package/dist/warp-QYJGKURM.js.map +0 -1
- package/dist/windsurf-75LLZ37C.js.map +0 -1
- package/dist/zed-HKAZXEJW.js.map +0 -1
- package/dist/zed-XJFOOKCO.js.map +0 -1
- /package/dist/{antigravity-VXLDLTO7.js.map → antigravity-TWIWXTQH.js.map} +0 -0
- /package/dist/{cursor-GSLUET3V.js.map → cursor-W7I4QUFO.js.map} +0 -0
- /package/dist/{openclaw-7EYBQS4R.js.map → openclaw-IJ33K45M.js.map} +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
openSqlite
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XZWMJLIT.js";
|
|
5
5
|
import {
|
|
6
6
|
firstExistingRoot
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KM2YXO6V.js";
|
|
8
8
|
import {
|
|
9
9
|
emptyTokens,
|
|
10
10
|
normalizeOpencodeAgentName,
|
|
11
11
|
normalizeWorkspaceKey,
|
|
12
12
|
workspaceLabelFromKey
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7PSNXUFK.js";
|
|
14
14
|
|
|
15
15
|
// src/usage/readers/opencode.ts
|
|
16
16
|
var PLATFORM_ID = "opencode";
|
|
@@ -213,4 +213,4 @@ var opencode_default = opencodeReader;
|
|
|
213
213
|
export {
|
|
214
214
|
opencode_default as default
|
|
215
215
|
};
|
|
216
|
-
//# sourceMappingURL=opencode-
|
|
216
|
+
//# sourceMappingURL=opencode-Z65JYILL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/opencode.ts"],"sourcesContent":["/**\r\n * usage/readers/opencode — OpenCode SQLite session reader.\r\n *\r\n * Faithful port of tokscale sessions/opencode.rs (parse_opencode_sqlite, lines\r\n * 192-336). OpenCode 1.2+ stores every message as one row in a `message` table\r\n * whose `data` column is the raw message JSON; this reader reads that DB\r\n * read-only and reports the assistant rows' token usage. (The Rust crate also\r\n * walks a legacy `storage/message/*.json` tree and reconciles it with SQLite via\r\n * a migration cache — that legacy/JSON path and its cache are out of scope here:\r\n * SQLite is the system of record on every supported OpenCode version, and the\r\n * cross-source overlap it guards against is collapsed by the same dedupKey this\r\n * reader emits.)\r\n *\r\n * DB path: ~/.local/share/opencode/opencode.db (XDG_DATA_HOME / the\r\n * AGENT_CONNECTOR_OPENCODE_DIR override are honored via paths.ts hostRoots).\r\n *\r\n * SQL (modern, with the session table for workspace attribution):\r\n * SELECT m.id, m.session_id, m.data, NULLIF(s.directory, '') AS workspace_root\r\n * FROM message m\r\n * LEFT JOIN session s ON s.id = m.session_id\r\n * WHERE json_extract(m.data, '$.role') = 'assistant'\r\n * AND json_extract(m.data, '$.tokens') IS NOT NULL\r\n * ORDER BY m.id, m.session_id\r\n * When the `session` table is absent (legacy schema) the join cannot run, so we\r\n * fall back to the same query without it (workspace_root NULL), mirroring the\r\n * Rust `prepare(modern).or_else(prepare(legacy))`.\r\n *\r\n * Tokens (off the parsed `data` JSON, each clamped ≥ 0 — defense-in-depth):\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 (row skipped when absent) and data.$.providerID\r\n * (default \"unknown\"). agent prefers data.$.mode then data.$.agent, normalized via\r\n * normalizeOpencodeAgentName BEFORE the dedup fingerprint (matching opencode.rs:272)\r\n * so fork-copied history that differs only in a raw agent string collapses.\r\n *\r\n * session: the m.session_id column (the message→session linkage). Workspace\r\n * (project): session.directory (modern) else the embedded data.$.path.root\r\n * (legacy), normalized to a stable key + repo-name label.\r\n *\r\n * timestamp: data.$.time.created (Unix MILLISECONDS, float). Only assistant rows\r\n * with a tokens block are emitted.\r\n *\r\n * DEDUP — fingerprint, to drop SQLite-vs-legacy-JSON overlap and fork-copied\r\n * history that OpenCode duplicates across sessions. The fingerprint is the tuple\r\n * (created, completed, modelID, providerID, input, output, reasoning, cacheRead,\r\n * cacheWrite, cost, agent); the first row for a fingerprint wins. A later row that\r\n * carries an EMBEDDED data.$.id promotes the survivor's dedupKey to that id, so\r\n * the SQLite/JSON overlap (keyed on the same message id) keeps deduplicating\r\n * cross-source via the global dedupKey backstop. dedupKey itself prefers the\r\n * embedded data.$.id, falling back to the m.id row id. Duplicate rows that point\r\n * at a DIFFERENT workspace collapse the survivor's workspace to none (a forked\r\n * copy is genuinely ambiguous about which repo it belongs to).\r\n *\r\n * confidence: \"host-reported\" (OpenCode 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 {\r\n normalizeOpencodeAgentName,\r\n normalizeWorkspaceKey,\r\n workspaceLabelFromKey,\r\n} from \"../normalize.js\";\r\nimport { firstExistingRoot } from \"../paths.js\";\r\nimport { openSqlite } from \"../sqlite.js\";\r\n\r\nconst PLATFORM_ID = \"opencode\" as const;\r\nconst DEFAULT_PROVIDER = \"unknown\";\r\n\r\nconst MODERN_QUERY = `\r\n SELECT m.id, m.session_id, m.data, NULLIF(s.directory, '') AS workspace_root\r\n FROM message m\r\n LEFT JOIN session s ON s.id = m.session_id\r\n WHERE json_extract(m.data, '$.role') = 'assistant'\r\n AND json_extract(m.data, '$.tokens') IS NOT NULL\r\n ORDER BY m.id, m.session_id\r\n`;\r\n\r\nconst LEGACY_QUERY = `\r\n SELECT m.id, m.session_id, m.data, NULL AS workspace_root\r\n FROM message m\r\n WHERE json_extract(m.data, '$.role') = 'assistant'\r\n AND json_extract(m.data, '$.tokens') IS NOT NULL\r\n ORDER BY m.id, m.session_id\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 f64, or undefined (port of Option<f64> on time/cost). */\r\nfunction asF64(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// Workspace (port of workspace_from_root)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface Workspace {\r\n key?: string;\r\n label?: string;\r\n}\r\n\r\n/** Normalize a root dir into a stable workspace key + repo-name label. */\r\nfunction workspaceFromRoot(root: string | undefined): Workspace {\r\n if (root === undefined) return {};\r\n const key = normalizeWorkspaceKey(root);\r\n if (key === undefined) return {};\r\n const label = workspaceLabelFromKey(key);\r\n return label === undefined ? { key } : { key, label };\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// The parsed `data` column (the OpenCodeMessage subset we read)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface OpenCodeTokens {\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 modelId: string;\r\n providerId: string;\r\n agent: string | undefined;\r\n tokens: OpenCodeTokens;\r\n cost: number;\r\n created: number;\r\n completed: number | undefined;\r\n /** Embedded workspace root (data.$.path.root) — legacy fallback. */\r\n embeddedRoot: string | undefined;\r\n}\r\n\r\n/**\r\n * Parse the `data` JSON of a row. Returns undefined when the row is not an\r\n * assistant message, lacks a tokens block, or lacks a modelID (the Rust\r\n * `continue` cases). `path` is read only as an object with a `root` string (a\r\n * non-object `path`, e.g. a bare string, is ignored, not rejected).\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 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\r\n const modelId = asNonEmptyString(obj[\"modelID\"]);\r\n if (modelId === undefined) return undefined;\r\n\r\n const time = obj[\"time\"];\r\n const created = typeof time === \"object\" && time !== null\r\n ? asF64((time as Record<string, unknown>)[\"created\"])\r\n : undefined;\r\n if (created === undefined) return undefined;\r\n const completed = typeof time === \"object\" && time !== null\r\n ? asF64((time as Record<string, unknown>)[\"completed\"])\r\n : undefined;\r\n\r\n const cache = t[\"cache\"];\r\n const cacheObj = typeof cache === \"object\" && cache !== null ? (cache as Record<string, unknown>) : {};\r\n\r\n // agent prefers mode then agent (Rust: msg.mode.or(msg.agent)), then is run\r\n // through normalize_opencode_agent_name BEFORE the dedup fingerprint so fork\r\n // copies (which differ only in a raw agent string) collapse (opencode.rs:272).\r\n const rawAgent = asNonEmptyString(obj[\"mode\"]) ?? asNonEmptyString(obj[\"agent\"]);\r\n const agent = rawAgent === undefined ? undefined : normalizeOpencodeAgentName(rawAgent);\r\n\r\n const pathRaw = obj[\"path\"];\r\n const embeddedRoot = typeof pathRaw === \"object\" && pathRaw !== null\r\n ? asNonEmptyString((pathRaw as Record<string, unknown>)[\"root\"])\r\n : undefined;\r\n\r\n return {\r\n id: asNonEmptyString(obj[\"id\"]),\r\n modelId,\r\n providerId: asNonEmptyString(obj[\"providerID\"]) ?? DEFAULT_PROVIDER,\r\n agent,\r\n tokens: {\r\n input: tokenField(t[\"input\"]),\r\n output: tokenField(t[\"output\"]),\r\n reasoning: tokenField(t[\"reasoning\"]),\r\n cacheRead: tokenField(cacheObj[\"read\"]),\r\n cacheWrite: tokenField(cacheObj[\"write\"]),\r\n },\r\n cost: Math.max(0, asF64(obj[\"cost\"]) ?? 0),\r\n created,\r\n completed,\r\n embeddedRoot,\r\n };\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Fingerprint dedup (port of OpenCodeSqliteFingerprint + dedup state)\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * A stable fingerprint string for a parsed message. Uses the float values\r\n * verbatim (created/completed/cost) so distinct calls that merely share a\r\n * creation timestamp stay distinct, while byte-identical fork copies collapse —\r\n * the JS analog of the Rust f64::to_bits() tuple.\r\n */\r\nfunction fingerprint(m: ParsedMessage): string {\r\n return [\r\n m.created,\r\n m.completed ?? \"\",\r\n m.modelId,\r\n m.providerId,\r\n m.tokens.input,\r\n m.tokens.output,\r\n m.tokens.reasoning,\r\n m.tokens.cacheRead,\r\n m.tokens.cacheWrite,\r\n m.cost,\r\n m.agent ?? \"\",\r\n ].join(\"\\u0000\");\r\n}\r\n\r\n/** Per-survivor dedup bookkeeping (port of OpenCodeSqliteDedupState). */\r\ninterface DedupState {\r\n hasEmbeddedMessageId: boolean;\r\n hasWorkspaceConflict: boolean;\r\n}\r\n\r\n/** Apply a workspace to a record (clearing both fields together when undefined). */\r\nfunction setWorkspace(record: UsageRecord, ws: Workspace): void {\r\n if (ws.key !== undefined) record.projectKey = ws.key;\r\n else delete record.projectKey;\r\n if (ws.label !== undefined) record.projectLabel = ws.label;\r\n else delete record.projectLabel;\r\n}\r\n\r\n/**\r\n * Reconcile a duplicate row's workspace into the survivor (port of\r\n * merge_duplicate_workspace): fill a missing workspace from the candidate; on a\r\n * genuine conflict (two different repos) drop to none and latch the conflict.\r\n */\r\nfunction mergeDuplicateWorkspace(\r\n record: UsageRecord,\r\n state: DedupState,\r\n candidate: Workspace,\r\n): void {\r\n if (state.hasWorkspaceConflict) return;\r\n const existing = record.projectKey;\r\n if (existing === undefined) {\r\n if (candidate.key !== undefined) setWorkspace(record, candidate);\r\n return;\r\n }\r\n if (candidate.key !== undefined && existing !== candidate.key) {\r\n state.hasWorkspaceConflict = true;\r\n setWorkspace(record, {});\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// DB read\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The four selected columns of one row. */\r\ninterface Row {\r\n id: string;\r\n sessionId: string;\r\n data: string;\r\n workspaceRoot: string | undefined;\r\n}\r\n\r\n/**\r\n * Run the modern query; if it yields no rows fall back to the legacy query (no\r\n * session join). With sql.js a query against a missing `session` table returns\r\n * [] rather than throwing, so an empty modern result is the signal to retry\r\n * without the join — faithfully covering the legacy schema either way.\r\n */\r\nfunction selectRows(db: SqliteDb): Row[] {\r\n let raw = db.all(MODERN_QUERY);\r\n if (raw.length === 0) raw = db.all(LEGACY_QUERY);\r\n\r\n const rows: Row[] = [];\r\n for (const r of raw) {\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, workspaceRoot: asString(r[\"workspace_root\"]) });\r\n }\r\n return rows;\r\n}\r\n\r\n/** Parse the OpenCode SQLite DB into deduplicated usage records. */\r\nfunction parseDb(db: SqliteDb): UsageRecord[] {\r\n const records: UsageRecord[] = [];\r\n const indexByFingerprint = new Map<string, number>();\r\n const states: DedupState[] = [];\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 // Workspace: session.directory (modern) else embedded data.$.path.root (legacy).\r\n const ws = workspaceFromRoot(row.workspaceRoot ?? msg.embeddedRoot);\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 const fp = fingerprint(msg);\r\n\r\n const existingIndex = indexByFingerprint.get(fp);\r\n if (existingIndex !== undefined) {\r\n const state = states[existingIndex] as DedupState;\r\n const survivor = records[existingIndex] as UsageRecord;\r\n // Promote to the embedded id so SQLite/JSON cross-source overlap dedups.\r\n if (msg.id !== undefined && !state.hasEmbeddedMessageId) {\r\n state.hasEmbeddedMessageId = true;\r\n survivor.dedupKey = dedupKey;\r\n }\r\n mergeDuplicateWorkspace(survivor, state, ws);\r\n continue;\r\n }\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: row.sessionId,\r\n tokens,\r\n ts: Math.trunc(msg.created),\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 setWorkspace(record, ws);\r\n\r\n states.push({ hasEmbeddedMessageId: msg.id !== undefined, hasWorkspaceConflict: false });\r\n indexByFingerprint.set(fp, records.length);\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 OpenCode usage reader singleton. */\r\nconst opencodeReader: 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 opencode.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 rows = parseDb(db);\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 opencodeReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
normalizeSessionSource
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PSGTHJQU.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveEnvRefsDeep
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XXLCMSD3.js";
|
|
8
8
|
import {
|
|
9
9
|
BaseAdapter
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3FINQ2ZF.js";
|
|
11
11
|
import {
|
|
12
12
|
buildWrappedStdio,
|
|
13
13
|
isHomeBinHookCommand
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-Y3K6KJMS.js";
|
|
15
|
+
import "./chunk-ILWHLGIC.js";
|
|
16
|
+
import "./chunk-QYOUQCC6.js";
|
|
17
17
|
|
|
18
18
|
// src/adapters/openhands/index.ts
|
|
19
19
|
import { existsSync } from "fs";
|
|
@@ -381,4 +381,4 @@ export {
|
|
|
381
381
|
adapter,
|
|
382
382
|
openhands_default as default
|
|
383
383
|
};
|
|
384
|
-
//# sourceMappingURL=openhands-
|
|
384
|
+
//# sourceMappingURL=openhands-SEZMCUC3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/openhands/index.ts"],"sourcesContent":["/**\r\n * adapters/openhands — OpenHands (All-Hands-AI, ex-OpenDevin) platform adapter.\r\n *\r\n * OpenHands is a **json-stdio** host (the `openhands` CLI, installed via\r\n * `uv tool install openhands`). It exposes TWO native config surfaces that live\r\n * in DIFFERENT files, so getServerConfigPath ≠ getHookConfigPath:\r\n *\r\n * 1. MCP servers — `mcp.json` (root key `mcpServers`), in the CLI persistence\r\n * dir, which is USER-scoped only:\r\n * - persistence dir → ~/.openhands (override: $OPENHANDS_PERSISTENCE_DIR)\r\n * - file → <persistence>/mcp.json\r\n * Byte-confirmed from openhands_cli/locations.py (MCP_CONFIG_FILE=\"mcp.json\",\r\n * get_persistence_dir() → ~/.openhands, env $OPENHANDS_PERSISTENCE_DIR) and\r\n * openhands_cli/mcp/mcp_utils.py (MCPConfig.from_dict({\"mcpServers\": {}}),\r\n * config.mcpServers[name]; the error path literally suggests \"create\r\n * ~/.openhands/mcp.json manually\"). Native server entry shape is FastMCP's\r\n * StdioMCPServer { command, args, env, transport:\"stdio\", cwd? } and\r\n * RemoteMCPServer { url, transport, headers } (fastmcp.mcp_config).\r\n * There is NO project-scoped mcp.json for the CLI — it reads the single\r\n * persistence-dir file — so installServer ALWAYS targets the user file.\r\n *\r\n * 2. Hooks — a SEPARATE `.openhands/hooks.json` (root key `hooks`, the\r\n * Claude-Code-plugin-compatible wrapper). OpenHands ships a hook system\r\n * that the SDK explicitly documents as honoring \"Claude Code plugin hook\r\n * files\" (openhands-sdk/openhands/sdk/hooks/config.py — the\r\n * `_normalize_hooks_input` validator unwraps {\"hooks\": {...}} and accepts\r\n * PascalCase keys). HookConfig.load() searches, in order:\r\n * - <working_dir>/.openhands/hooks.json (project scope)\r\n * - ~/.openhands/hooks.json (user scope)\r\n * first-found wins, so BOTH scopes are valid; project takes precedence.\r\n * Registrations use the Claude NESTED-rule shape:\r\n * { hooks: { <Event>: [ { matcher?, hooks:[{ type:\"command\", command }] } ] } }\r\n * which is exactly what the shared hook-merge engine writes.\r\n *\r\n * Supported events (Claude-compatible, byte-confirmed from\r\n * openhands-sdk/openhands/sdk/hooks/types.py HookEventType): PreToolUse,\r\n * PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. OpenHands has\r\n * NO Notification / PreCompact / SubagentStop / PermissionRequest /\r\n * PostToolUseFailure / SubagentStart, so those degrade to a warn/skip at install.\r\n *\r\n * Runtime wire DIVERGES from Claude (do NOT assume Claude field names — verified\r\n * against HookEvent.model_dump_json() with use_enum_values=True in types.py):\r\n * - `event_type` (PascalCase string) — NOT `hook_event_name`\r\n * - `tool_name`, `tool_input` — Claude-identical\r\n * - `tool_response` is a DICT — Claude-identical key, object value\r\n * - `message` (the prompt text) — NOT `prompt`\r\n * - `session_id` — Claude-identical\r\n * - `working_dir` (the cwd) — NOT `cwd`\r\n * - `metadata` (free dict) — no normalized field\r\n *\r\n * Reply protocol (byte-confirmed from hooks/executor.py + the 33_hooks example):\r\n * exit 0 → success; stdout is parsed as a FLAT JSON object with keys\r\n * `decision` (\"allow\"|\"deny\"), `reason`, `additionalContext`. There is NO\r\n * `hookSpecificOutput` envelope and NO \"ask\" decision (HookDecision is\r\n * allow|deny; ASK is commented-out/future). exit 2 also blocks. So:\r\n * - deny → {\"decision\":\"deny\",\"reason\":...} (exit 0)\r\n * - context → {\"additionalContext\":...} (exit 0)\r\n * - ask → unsupported; degrades to a deny-style block with the reason\r\n * (OpenHands has no native confirm dialog on the hook wire)\r\n * canModifyOutput is false (it cannot rewrite already-emitted tool output);\r\n * canInjectSessionContext is true (additionalContext is honored).\r\n *\r\n * Env handling: env/header/url refs are resolved to literals at install time via\r\n * resolveEnvRefsDeep — the safe default matching the Droid/Kiro/Qwen adapters.\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\n\r\nimport { BaseAdapter, type HookMergeDescriptor } from \"../base.js\";\r\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookEventName,\r\n HookParadigm,\r\n HookResponse,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionEndEvent,\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 {\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 = \"openhands\";\r\nconst MCP_ROOT_KEY = \"mcpServers\";\r\n\r\n/**\r\n * Resolve the OpenHands CLI persistence dir. Byte-confirmed from\r\n * openhands_cli/locations.py: `os.environ.get(\"OPENHANDS_PERSISTENCE_DIR\",\r\n * os.path.expanduser(\"~/.openhands\"))`. The MCP `mcp.json` lives here regardless\r\n * of install scope (the CLI has no project-scoped mcp.json).\r\n */\r\nfunction persistenceDir(): string {\r\n return process.env.OPENHANDS_PERSISTENCE_DIR ?? join(homedir(), \".openhands\");\r\n}\r\n\r\n/**\r\n * Canonical events OpenHands actually fires (HookEventType in types.py). Event\r\n * names are Claude-identical PascalCase, so each canonical name registers 1:1.\r\n * OpenHands has no Notification / PreCompact / SubagentStop / PermissionRequest /\r\n * PostToolUseFailure / SubagentStart — those warn/skip at install time.\r\n */\r\nconst SUPPORTED_EVENTS: ReadonlySet<HookEventName> = new Set<HookEventName>([\r\n \"PreToolUse\",\r\n \"PostToolUse\",\r\n \"UserPromptSubmit\",\r\n \"SessionStart\",\r\n \"SessionEnd\",\r\n \"Stop\",\r\n]);\r\n\r\n/**\r\n * Native MCP server entry shapes OpenHands accepts under `mcpServers` (FastMCP\r\n * StdioMCPServer / RemoteMCPServer). A stdio entry carries an explicit\r\n * `transport:\"stdio\"` discriminator; remote transports register a URL.\r\n */\r\ninterface OpenHandsStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n transport: \"stdio\";\r\n}\r\ninterface OpenHandsRemoteServer {\r\n url: string;\r\n transport: \"http\" | \"sse\";\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/** A single OpenHands native hook registration entry (Claude-shaped, nested). */\r\ninterface OpenHandsHookEntry {\r\n matcher: string;\r\n hooks: Array<{ type: \"command\"; command: string }>;\r\n}\r\n\r\n/** The shape of OpenHands' hooks.json (only the parts we touch). */\r\ninterface OpenHandsHooksFile {\r\n hooks?: Record<string, OpenHandsHookEntry[]>;\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Raw OpenHands CLI hook stdin payload. These are the EXACT serialized field\r\n * names of the SDK's HookEvent (use_enum_values=True), NOT Claude's wire —\r\n * see the header note on the divergences (`event_type`, `working_dir`,\r\n * `message`, `tool_response` dict).\r\n */\r\ninterface OpenHandsWireInput {\r\n /** PascalCase event string (\"PreToolUse\", …). */\r\n event_type?: string;\r\n tool_name?: string;\r\n tool_input?: Record<string, unknown>;\r\n /** Tool result is a dict on the OpenHands wire (Claude sends it too). */\r\n tool_response?: Record<string, unknown> | null;\r\n /** UserPromptSubmit text rides on `message` (NOT `prompt`). */\r\n message?: string;\r\n session_id?: string;\r\n /** The cwd rides on `working_dir` (NOT `cwd`). */\r\n working_dir?: string;\r\n /** Free-form dict; no normalized field. */\r\n metadata?: Record<string, unknown>;\r\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\r\n connector?: unknown;\r\n}\r\n\r\nexport class OpenHandsAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"OpenHands\";\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 supportsMemory: true,\r\n preToolUse: true,\r\n postToolUse: true,\r\n userPromptSubmit: true,\r\n sessionStart: true,\r\n sessionEnd: true,\r\n stop: true,\r\n // OpenHands fires NONE of these on its hook wire (HookEventType has only the\r\n // six above) — install reports the standard skip-warn for any of them.\r\n // The two REQUIRED PlatformCapabilities flags below are explicitly false;\r\n // subagentStop / permissionRequest / postToolUseFailure / subagentStart are\r\n // optional and stay unset (read as ?? false) — no OpenHands analog.\r\n preCompact: false,\r\n notification: false,\r\n\r\n // PreToolUse/UserPromptSubmit/Stop can block (exit 2 or {\"decision\":\"deny\"}),\r\n // but the hook wire cannot rewrite tool ARGS or already-emitted tool OUTPUT.\r\n canModifyArgs: false,\r\n canModifyOutput: false,\r\n // additionalContext on the stdout reply is honored (executor.py parses it).\r\n canInjectSessionContext: true,\r\n // OpenHands registers stdio + remote (Streamable HTTP / SSE) MCP servers.\r\n transports: [\"stdio\", \"http\"],\r\n // Content surfaces (commands/skills/subagents/statusline/actions) are NOT\r\n // wired: OpenHands' CLI uses microagents + an interactive TUI rather than a\r\n // Claude-style file-per-command/skill/subagent tree, and no first-party\r\n // file layout for those was byte-confirmed. Left unset (honest CEILING).\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = persistenceDir();\r\n const userMcp = join(userDir, \"mcp.json\");\r\n const projDir = join(projectDir, \".openhands\");\r\n const projHooks = join(projDir, \"hooks.json\");\r\n\r\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\r\n const projInstalled = existsSync(projDir) || existsSync(projHooks);\r\n const installed = userInstalled || projInstalled;\r\n // MCP only lives at the user persistence dir; project scope only carries\r\n // hooks. Default the reported scope to user (where the MCP config lives).\r\n const scope = userInstalled || !projInstalled ? \"user\" : \"project\";\r\n const configPath = scope === \"user\" ? userMcp : projHooks;\r\n\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? `found OpenHands config (${scope}) at ${configPath}`\r\n : `no OpenHands config at ${userDir} or ${projDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".openhands\")\r\n : persistenceDir();\r\n }\r\n\r\n /**\r\n * MCP `mcp.json` lives in the CLI persistence dir, which is USER-scoped only —\r\n * the CLI reads exactly one `<persistence>/mcp.json` and has no project\r\n * variant. So this ALWAYS resolves to the user persistence dir regardless of\r\n * ctx.scope (writing a project `.openhands/mcp.json` the CLI never reads would\r\n * be a silent no-op).\r\n */\r\n getServerConfigPath(_ctx: InstallContext): string {\r\n return join(persistenceDir(), \"mcp.json\");\r\n }\r\n\r\n /**\r\n * Hooks live in a SEPARATE `.openhands/hooks.json`. HookConfig.load searches\r\n * <working_dir>/.openhands/hooks.json then ~/.openhands/hooks.json, so both\r\n * scopes are honored — project scope → <projectDir>/.openhands, user scope →\r\n * the persistence dir.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"hooks.json\");\r\n }\r\n\r\n // ── MCP server install / uninstall ───────────────────────────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n const override = connector.platforms[HOST]?.server;\r\n if (!connector.server || override === false) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: connector.server\r\n ? \"server registration disabled for openhands\"\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 OpenHands' native mcpServers entry. */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): OpenHandsStdioServer | OpenHandsRemoteServer {\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 every ${env:VAR} to a literal at install time (safe path).\r\n const entry: OpenHandsStdioServer = {\r\n command: resolveEnvRefsDeep(command),\r\n transport: \"stdio\",\r\n };\r\n if (args.length > 0) entry.args = resolveEnvRefsDeep(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 // http / sse — OpenHands registers a URL (FastMCP RemoteMCPServer). Default\r\n // a non-stdio transport to \"http\" (the recommended Streamable HTTP form);\r\n // honor an explicit \"sse\".\r\n const entry: OpenHandsRemoteServer = {\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n transport: transport === \"sse\" ? \"sse\" : \"http\",\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 (the safe path matching Droid).\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 (separate hooks.json, nested-rule shape) ─────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.hooks === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for openhands\" }];\r\n }\r\n if (connector.hookEvents.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\r\n }\r\n\r\n const pending = connector.hookEvents.map((event) => ({\r\n event,\r\n matcher: connector.hooks[event]?.matcher ?? \"\",\r\n }));\r\n return this.upsertHookEntries(\r\n ctx,\r\n this.getHookConfigPath(ctx),\r\n pending,\r\n this.hookDescriptor(ctx),\r\n );\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));\r\n }\r\n\r\n /**\r\n * OpenHands' hook-merge descriptor (NESTED shape `{ matcher, hooks: [...] }`).\r\n * Ownership is CONNECTOR-GENERIC (ANY of our commands in the entry's inner\r\n * `hooks`, not a specific-command match), identical to Droid:\r\n * - mapEvent = drop events outside SUPPORTED_EVENTS; supported event names are\r\n * Claude-identical, so they map 1:1.\r\n * - entryOwnsCommand reuses isOurCommand over the inner commands.\r\n * - uninstall = inner-strip ONLY (ownsEntryForRemove never-true).\r\n */\r\n private hookDescriptor(ctx: InstallContext): HookMergeDescriptor<OpenHandsHookEntry> {\r\n return {\r\n mapEvent: (e) => (SUPPORTED_EVENTS.has(e as HookEventName) ? e : undefined),\r\n unmappedWarnDetail: (e) => `${e} has no OpenHands hook equivalent — skipped`,\r\n renderEntry: (_event, matcher, command) => ({\r\n matcher,\r\n hooks: [{ type: \"command\", command }],\r\n }),\r\n entryOwnsCommand: (entry, _command) =>\r\n (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx)),\r\n ownsEntryForRemove: () => () => false,\r\n stripInner: (c) => (entry) => {\r\n const innerBefore = entry.hooks?.length ?? 0;\r\n const inner = (entry.hooks ?? []).filter((h) => !this.isOurCommand(h.command, c));\r\n return {\r\n next: inner.length > 0 ? { matcher: entry.matcher ?? \"\", hooks: inner } : null,\r\n removed: innerBefore - inner.length,\r\n };\r\n },\r\n skipDetail: (event) => `hooks.${event} already registered`,\r\n removeDetail: (event, removed) => `hooks.${event} (${removed})`,\r\n absentDetail: \"no hooks section present\",\r\n noMatchDetail: \"no matching hook entries\",\r\n };\r\n }\r\n\r\n /** True when a hook command references our home binary AND this connector id\r\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\r\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\r\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const mcpPath = 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 = ctx.connector.hookEvents;\r\n return [\r\n {\r\n name: `${this.name}: mcp.json present`,\r\n check: () =>\r\n existsSync(mcpPath)\r\n ? { status: \"OK\", detail: mcpPath }\r\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\r\n },\r\n {\r\n name: `${this.name}: 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}: 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 const file = this.readJson<OpenHandsHooksFile>(hookPath);\r\n if (!file) return { status: \"FAIL\", detail: `cannot read ${hookPath}` };\r\n const hooks = file.hooks ?? {};\r\n const registered = Object.values(hooks).some((entries) =>\r\n (entries ?? []).some((e) =>\r\n (e.hooks ?? []).some((h) =>\r\n isHomeBinHookCommand(h.command, homeBin, connectorId),\r\n ),\r\n ),\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 }\r\n\r\n // ── Runtime: parse OpenHands stdin JSON → normalized event ─────────────────\r\n // The wire field names DIVERGE from Claude (event_type / working_dir / message\r\n // / tool_response-dict) — see the header. Reading Claude's names here would be\r\n // a silent false-friend (the kimi-code bug class).\r\n\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as OpenHandsWireInput;\r\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\r\n const sessionId = typeof input.session_id === \"string\" ? input.session_id : \"\";\r\n const projectDir =\r\n typeof input.working_dir === \"string\" ? input.working_dir : undefined;\r\n\r\n const base = {\r\n hostPlatform: HOST,\r\n connectorId,\r\n sessionId,\r\n raw,\r\n ...(projectDir !== undefined ? { projectDir } : {}),\r\n } as const;\r\n\r\n switch (event) {\r\n case \"PreToolUse\": {\r\n const ev: PreToolUseEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"PostToolUse\": {\r\n const ev: PostToolUseEvent = {\r\n ...base,\r\n toolName: input.tool_name ?? \"\",\r\n toolInput: input.tool_input ?? {},\r\n ...(toolResponseToString(input.tool_response) !== undefined\r\n ? { toolOutput: toolResponseToString(input.tool_response) }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n // The prompt text rides on `message` (NOT `prompt`).\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: typeof input.message === \"string\" ? input.message : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"SessionStart\": {\r\n // OpenHands SessionStart carries no documented `source` discriminator on\r\n // the HookEvent wire; normalizeSessionSource(undefined) → the safe\r\n // \"startup\" default.\r\n const ev: SessionStartEvent = {\r\n ...base,\r\n source: normalizeSessionSource(undefined),\r\n };\r\n return ev;\r\n }\r\n case \"SessionEnd\": {\r\n // No documented `reason` enum on the HookEvent wire — omit the field.\r\n const ev: SessionEndEvent = { ...base };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n // No stop_hook_active loop-guard field on the OpenHands wire.\r\n const ev: StopEvent = { ...base };\r\n return ev;\r\n }\r\n default: {\r\n // OpenHands never delivers Notification / PreCompact / SubagentStop /\r\n // PermissionRequest / PostToolUseFailure / SubagentStart (no native\r\n // equivalent — see SUPPORTED_EVENTS). Surface it loudly rather than\r\n // silently mis-parse.\r\n throw new Error(`unsupported openhands hook event: ${String(event)}`);\r\n }\r\n }\r\n }\r\n\r\n // ── Runtime: normalized response → OpenHands native (FLAT JSON) hook reply ──\r\n // Reply is a FLAT top-level object (NO hookSpecificOutput envelope) parsed by\r\n // hooks/executor.py: keys `decision` (allow|deny), `reason`, `additionalContext`.\r\n // There is NO \"ask\" decision (HookDecision is allow|deny only).\r\n\r\n formatReply(event: HookEventName, response: HookResponse): HookReply {\r\n const decision = response.decision ?? \"allow\";\r\n\r\n // SessionStart / SessionEnd are observe-only (cannot block); they carry no\r\n // block surface. SessionStart still honors additionalContext, so it falls\r\n // through to the `context` branch; SessionEnd is an unconditional no-op.\r\n if (event === \"SessionEnd\") {\r\n return { exitCode: 0 };\r\n }\r\n\r\n // deny → block with a reason. OpenHands has no \"ask\" on the hook wire, so an\r\n // \"ask\" decision degrades to a deny-style block carrying the reason (the\r\n // closest honest mapping — a hook that wants confirmation blocks and tells\r\n // the agent why, rather than silently passing through).\r\n if (decision === \"deny\" || decision === \"ask\") {\r\n return this.stdout({\r\n decision: \"deny\",\r\n reason:\r\n response.reason ??\r\n (decision === \"ask\" ? \"Confirmation required by hook\" : \"Blocked by hook\"),\r\n });\r\n }\r\n\r\n // context → inject soft guidance (OpenHands honors additionalContext).\r\n if (decision === \"context\" && response.additionalContext) {\r\n return this.stdout({ additionalContext: response.additionalContext });\r\n }\r\n\r\n // allow / modify (unsupported — exit-code/decision protocol only) / void →\r\n // pass through with exit 0.\r\n return { exitCode: 0 };\r\n }\r\n\r\n private stdout(payload: unknown): HookReply {\r\n return { exitCode: 0, stdout: JSON.stringify(payload) };\r\n }\r\n}\r\n\r\n/** Coerce an OpenHands PostToolUse `tool_response` (a dict) into a string. */\r\nfunction toolResponseToString(value: unknown): string | undefined {\r\n if (value == null) return undefined;\r\n if (typeof value === \"string\") return value;\r\n try {\r\n return JSON.stringify(value);\r\n } catch {\r\n return String(value);\r\n }\r\n}\r\n\r\nexport const adapter = new OpenHandsAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -6,26 +6,26 @@ import {
|
|
|
6
6
|
isPackageFormat,
|
|
7
7
|
packageConnector,
|
|
8
8
|
packageConnectorAll
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-LQ55E7QI.js";
|
|
10
|
+
import "./chunk-XVEJAFKW.js";
|
|
11
|
+
import "./chunk-XN7S44U4.js";
|
|
12
12
|
import {
|
|
13
13
|
fail,
|
|
14
14
|
print
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-N4ENLZEU.js";
|
|
16
16
|
import {
|
|
17
17
|
findConnectorConfig,
|
|
18
18
|
loadConnectorFromPath
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
-
import "./chunk-
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-3EP5V2F4.js";
|
|
20
|
+
import "./chunk-7ZFK2WEO.js";
|
|
21
|
+
import "./chunk-NDMNMAKP.js";
|
|
22
|
+
import "./chunk-KFPSJRHR.js";
|
|
23
|
+
import "./chunk-PSGTHJQU.js";
|
|
24
|
+
import "./chunk-XXLCMSD3.js";
|
|
25
|
+
import "./chunk-3FINQ2ZF.js";
|
|
26
|
+
import "./chunk-Y3K6KJMS.js";
|
|
27
|
+
import "./chunk-ILWHLGIC.js";
|
|
28
|
+
import "./chunk-QYOUQCC6.js";
|
|
29
29
|
|
|
30
30
|
// src/cli/commands/package.ts
|
|
31
31
|
import { parseArgs } from "util";
|
|
@@ -132,4 +132,4 @@ async function run(argv) {
|
|
|
132
132
|
export {
|
|
133
133
|
run
|
|
134
134
|
};
|
|
135
|
-
//# sourceMappingURL=package-
|
|
135
|
+
//# sourceMappingURL=package-JECVQEFT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/package.ts"],"sourcesContent":["/**\r\n * cli/commands/package — emit a marketplace/extension-installable connector bundle.\r\n *\r\n * Resolves the connector config (--connector <path>, else findConnectorConfig\r\n * walking up from the project dir, exactly like install.ts), packages it for the\r\n * requested --format into --out (default <cwd>/dist-plugin), then prints the\r\n * emitted file tree plus per-format install instructions.\r\n *\r\n * `--format <x>` accepts the full union; `--format all` emits EVERY feasible\r\n * format, each into <out>/<format>/..., printing install instructions per format.\r\n * Default --format claude-plugin.\r\n */\r\n\r\nimport { parseArgs } from \"node:util\";\r\nimport { join, relative } from \"node:path\";\r\n\r\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\r\nimport {\r\n ALL_FORMATS,\r\n FEASIBLE_FORMATS,\r\n installInstructions,\r\n isPackageFormat,\r\n packageConnector,\r\n packageConnectorAll,\r\n type PackageFormat,\r\n type PackageResult,\r\n} from \"../../core/package.js\";\r\nimport { fail, print } from \"../app.js\";\r\n\r\nconst HELP = `agent-connector package — emit a plugin/extension/marketplace bundle.\r\n\r\nusage: agent-connector package [flags]\r\n\r\nflags:\r\n --connector <path> Connector config to package (else auto-discovered).\r\n --format <fmt> Output format (default: claude-plugin). One of:\r\n ${ALL_FORMATS.join(\", \")}\r\n or \"all\" to emit every feasible format into <out>/<fmt>/.\r\n --out <dir> Output directory. Default: <cwd>/dist-plugin.\r\n --project <dir> Project root for connector discovery (default: cwd).\r\n --dry-run Compute the file tree without writing anything.\r\n --help Show this help.`;\r\n\r\n/** Print the file tree + the per-format install instructions for one bundle. */\r\nfunction printFormatResult(\r\n format: PackageFormat,\r\n connectorId: string,\r\n outDir: string,\r\n result: PackageResult,\r\n): void {\r\n print(` pluginDir: ${result.pluginDir}`);\r\n if (result.marketplacePath) {\r\n print(` marketplace: ${relative(outDir, result.marketplacePath)}`);\r\n }\r\n print(\" emitted files:\");\r\n for (const f of result.files) {\r\n print(` + ${relative(outDir, f)}`);\r\n }\r\n if (result.notes && result.notes.length > 0) {\r\n print(\" notes:\");\r\n for (const n of result.notes) print(` ! ${n}`);\r\n }\r\n print(\" install:\");\r\n for (const line of installInstructions(format, connectorId, outDir)) {\r\n print(` ${line}`);\r\n }\r\n // `package` stays a pure emitter (no host CLIs spawned) — but for hosts whose\r\n // marketplace flow agent-connector can DRIVE, point at the lifecycle verb.\r\n if (format === \"claude-plugin\") {\r\n print(\r\n \" (or let agent-connector drive it: agent-connector install --method marketplace --targets claude-code)\",\r\n );\r\n }\r\n print(\"\");\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n connector: { type: \"string\" },\r\n format: { type: \"string\", default: \"claude-plugin\" },\r\n out: { type: \"string\" },\r\n project: { type: \"string\" },\r\n \"dry-run\": { type: \"boolean\", default: false },\r\n help: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n if (values.help) {\r\n print(HELP);\r\n return 0;\r\n }\r\n\r\n const formatArg = values.format ?? \"claude-plugin\";\r\n const isAll = formatArg === \"all\";\r\n if (!isAll && !isPackageFormat(formatArg)) {\r\n return fail(\r\n `invalid --format \"${formatArg}\" (expected one of: ${ALL_FORMATS.join(\", \")}, or \"all\")`,\r\n );\r\n }\r\n\r\n const projectDir = values.project ?? process.cwd();\r\n const configPath = values.connector ?? findConnectorConfig(projectDir);\r\n if (!configPath) {\r\n return fail(\r\n \"no connector config found. Pass --connector <path> or add an \" +\r\n \"agent-connector.config.{mjs,js,json} to your project.\",\r\n );\r\n }\r\n\r\n const outDir = values.out ?? `${process.cwd()}/dist-plugin`;\r\n const dryRun = values[\"dry-run\"];\r\n const mode = dryRun ? \" (dry-run — nothing written)\" : \"\";\r\n\r\n const { connector } = await loadConnectorFromPath(configPath);\r\n\r\n if (isAll) {\r\n print(`package \"${connector.id}\" → all formats${mode}`);\r\n print(` outDir: ${outDir}`);\r\n print(\"\");\r\n const results = packageConnectorAll(connector, { outDir, dryRun });\r\n for (const { format, result } of results) {\r\n const formatOut = join(outDir, format);\r\n print(`── ${format} ──`);\r\n printFormatResult(format, connector.id, formatOut, result);\r\n }\r\n print(`emitted ${results.length} formats: ${FEASIBLE_FORMATS.join(\", \")}`);\r\n return 0;\r\n }\r\n\r\n const format: PackageFormat = formatArg;\r\n let result: PackageResult;\r\n try {\r\n result = packageConnector(connector, { outDir, format, dryRun });\r\n } catch (err) {\r\n // Emitter validation errors (e.g. mcp-server-json without\r\n // publish.registryNamespace) are actionable one-liners — print them as a\r\n // normal CLI error, never a stack trace.\r\n const message = err instanceof Error ? err.message : String(err);\r\n return fail(message);\r\n }\r\n\r\n print(`package \"${connector.id}\" → ${format}${mode}`);\r\n print(` outDir: ${outDir}`);\r\n print(\"\");\r\n printFormatResult(format, connector.id, outDir, result);\r\n return 0;\r\n}\r\n"],"mappings":"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","names":["format","result"]}
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
fileMtimeMs,
|
|
4
4
|
readJsonlLines
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZSOS2KOR.js";
|
|
6
6
|
import {
|
|
7
7
|
isDir,
|
|
8
8
|
walkFiles
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KM2YXO6V.js";
|
|
10
10
|
import {
|
|
11
11
|
emptyTokens,
|
|
12
12
|
normalizeWorkspaceKey,
|
|
13
13
|
workspaceLabelFromKey
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7PSNXUFK.js";
|
|
15
15
|
|
|
16
16
|
// src/usage/readers/pi.ts
|
|
17
17
|
import { homedir } from "os";
|
|
@@ -136,4 +136,4 @@ var pi_default = piReader;
|
|
|
136
136
|
export {
|
|
137
137
|
pi_default as default
|
|
138
138
|
};
|
|
139
|
-
//# sourceMappingURL=pi-
|
|
139
|
+
//# sourceMappingURL=pi-DLKCPOJE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/pi.ts"],"sourcesContent":["/**\r\n * usage/readers/pi — Pi (badlogic/pi-mono) + OMP (oh-my-pi fork) session reader.\r\n *\r\n * Faithful port of tokscale sessions/pi.rs. Pi-format JSONL lives under TWO\r\n * roots that share the identical schema (tokscale scans both under ClientId::Pi):\r\n * - ~/.pi/agent/sessions/<encoded-cwd>/*.jsonl → emitted as platformId \"pi\"\r\n * - ~/.omp/agent/sessions/<encoded-cwd>/*.jsonl → emitted as platformId \"omp\"\r\n * (Oh My Pi fork, https://github.com/can1357/oh-my-pi — same format, new root)\r\n * The pi root honors the PI_CODING_AGENT_DIR override (verbatim when non-empty);\r\n * the omp root is the fixed ~/.omp default.\r\n *\r\n * File shape (port of parse_pi_file):\r\n * - Line 0 MUST be the session header `{type:\"session\", id, cwd?, timestamp?}`.\r\n * If the first non-empty line is not a parseable `session` header, the WHOLE\r\n * file yields nothing (mirrors the Rust early-return on header failure).\r\n * - Subsequent lines are entries; only `type:\"message\"` with\r\n * `message.role==\"assistant\"` AND a present `message.usage`, `message.model`,\r\n * and `message.provider` produce a record. Any of those missing → skip line.\r\n *\r\n * Tokens (message.usage): input, output, cacheRead→cacheRead, cacheWrite→cacheWrite;\r\n * reasoning is always 0 (Pi does not report it). Each token clamped ≥ 0.\r\n * Provider is the explicit `message.provider` field (NOT inferred). Timestamp is\r\n * the entry's RFC3339 `timestamp` (→ epoch ms), falling back to the file mtime.\r\n * Session id is the header `id`; workspace is the header `cwd` normalized once.\r\n *\r\n * Dedup: pi.rs performs NO dedup (one row per assistant line; file path + line\r\n * index are implicitly unique within a session). We still emit a stable\r\n * dedupKey `<platformId>:<sessionId>:<lineIndex>` so the global insertion-order\r\n * de-dup backstop has a per-record key to key on.\r\n *\r\n * Confidence: \"host-reported\" (Pi logs real token counts).\r\n *\r\n * Fail-open: no root → []; unreadable/malformed file or line → skipped; a file\r\n * whose header is missing/invalid contributes nothing (never throws).\r\n */\r\n\r\nimport { homedir } from \"node:os\";\r\nimport { isAbsolute, join, resolve } from \"node:path\";\r\n\r\nimport type { PlatformId } from \"../../core/types.js\";\r\nimport type { UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { fileMtimeMs, readJsonlLines } from \"../jsonl.js\";\r\nimport { normalizeWorkspaceKey, workspaceLabelFromKey } from \"../normalize.js\";\r\nimport { isDir, walkFiles } from \"../paths.js\";\r\n\r\nconst PI_PLATFORM_ID: PlatformId = \"pi\";\r\nconst OMP_PLATFORM_ID: PlatformId = \"omp\";\r\n\r\n/** The two Pi-format roots, each tagged with the platformId it emits. */\r\ninterface PiRoot {\r\n readonly dir: string;\r\n readonly platformId: PlatformId;\r\n}\r\n\r\n/** Session header (first JSONL line). */\r\ninterface PiSessionHeader {\r\n type?: unknown;\r\n id?: unknown;\r\n timestamp?: unknown;\r\n cwd?: unknown;\r\n}\r\n\r\n/** Subsequent JSONL entry. */\r\ninterface PiSessionEntry {\r\n type?: unknown;\r\n timestamp?: unknown;\r\n message?: {\r\n role?: unknown;\r\n model?: unknown;\r\n provider?: unknown;\r\n usage?: {\r\n input?: unknown;\r\n output?: unknown;\r\n cacheRead?: unknown;\r\n cacheWrite?: unknown;\r\n };\r\n };\r\n}\r\n\r\n/** Coerce an unknown to a non-negative integer (0 on absence/garbage). */\r\nfunction toNonNegInt(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/** Parse an RFC3339 / numeric timestamp to epoch ms, or null when unusable. */\r\nfunction parseTs(v: unknown): number | null {\r\n if (typeof v === \"string\") {\r\n const ms = Date.parse(v);\r\n if (!Number.isNaN(ms)) return ms;\r\n const num = Number(v);\r\n if (Number.isFinite(num) && num > 0) return num >= 1e12 ? num : num * 1000;\r\n return null;\r\n }\r\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) {\r\n return v >= 1e12 ? v : v * 1000;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Read an env override, treating empty/blank as unset (tokscale's\r\n * is_config_dir_overridden contract: an empty override must NOT resolve to \"\").\r\n * Relative paths resolve against the process CWD; \"~\" is expanded.\r\n */\r\nfunction envOverrideDir(name: string): string | undefined {\r\n const raw = process.env[name];\r\n if (raw == null || raw.trim() === \"\") return undefined;\r\n let p = raw.trim();\r\n if (p === \"~\") p = homedir();\r\n else if (p.startsWith(\"~/\") || p.startsWith(\"~\\\\\")) p = join(homedir(), p.slice(2));\r\n return isAbsolute(p) ? p : resolve(p);\r\n}\r\n\r\n/**\r\n * Resolve the two Pi-format roots, most-specific first. The pi root honors the\r\n * PI_CODING_AGENT_DIR override; the omp root is the fixed ~/.omp default. Roots\r\n * that are not existing directories are dropped (fail-open).\r\n */\r\nfunction piRoots(): PiRoot[] {\r\n const piDir = envOverrideDir(\"PI_CODING_AGENT_DIR\") ?? join(homedir(), \".pi\", \"agent\", \"sessions\");\r\n const ompDir = join(homedir(), \".omp\", \"agent\", \"sessions\");\r\n const candidates: PiRoot[] = [\r\n { dir: piDir, platformId: PI_PLATFORM_ID },\r\n { dir: ompDir, platformId: OMP_PLATFORM_ID },\r\n ];\r\n return candidates.filter((c) => isDir(c.dir));\r\n}\r\n\r\n/**\r\n * Parse one Pi JSONL session file into usage records (port of parse_pi_file).\r\n * Returns [] when the header is missing/invalid (whole-file early return) or no\r\n * assistant line qualifies. `platformId` tags which root the file came from.\r\n */\r\nfunction parsePiFile(path: string, platformId: PlatformId): UsageRecord[] {\r\n const lines = readJsonlLines(path);\r\n if (lines.length === 0) return [];\r\n\r\n const fallbackTs = fileMtimeMs(path);\r\n\r\n // ── Header (first non-empty parseable line) ────────────────────────────\r\n // readJsonlLines already drops blank/malformed lines; index 0 is the first\r\n // successfully-parsed line. It MUST be a `session` header or the file is void.\r\n const headerRaw = lines[0];\r\n if (typeof headerRaw !== \"object\" || headerRaw === null) return [];\r\n const header = headerRaw as PiSessionHeader;\r\n if (header.type !== \"session\") return [];\r\n if (typeof header.id !== \"string\" || header.id === \"\") return [];\r\n const sessionId = header.id;\r\n\r\n let projectKey: string | undefined;\r\n let projectLabel: string | undefined;\r\n if (typeof header.cwd === \"string\" && header.cwd !== \"\") {\r\n const key = normalizeWorkspaceKey(header.cwd);\r\n if (key !== undefined) {\r\n projectKey = key;\r\n projectLabel = workspaceLabelFromKey(key);\r\n }\r\n }\r\n\r\n const out: UsageRecord[] = [];\r\n\r\n // ── Entries (every line after the header) ──────────────────────────────\r\n for (let i = 1; i < lines.length; i++) {\r\n const raw = lines[i];\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const entry = raw as PiSessionEntry;\r\n\r\n if (entry.type !== \"message\") continue;\r\n const message = entry.message;\r\n if (message === undefined || message === null) continue;\r\n if (message.role !== \"assistant\") continue;\r\n\r\n const usage = message.usage;\r\n if (usage === undefined || usage === null) continue;\r\n if (typeof message.model !== \"string\" || message.model === \"\") continue;\r\n if (typeof message.provider !== \"string\" || message.provider === \"\") continue;\r\n\r\n const modelId = message.model;\r\n const providerId = message.provider;\r\n\r\n const ts = parseTs(entry.timestamp) ?? fallbackTs;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = toNonNegInt(usage.input);\r\n tokens.output = toNonNegInt(usage.output);\r\n tokens.cacheRead = toNonNegInt(usage.cacheRead);\r\n tokens.cacheWrite = toNonNegInt(usage.cacheWrite);\r\n // reasoning stays 0 (Pi does not report it).\r\n\r\n const record: UsageRecord = {\r\n platformId,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n // No host dedup key in Pi; synthesize a per-record key (path-implicit\r\n // uniqueness within a session, mirrored by session id + line index).\r\n dedupKey: `${platformId}:${sessionId}:${i}`,\r\n confidence: \"host-reported\",\r\n };\r\n if (projectKey !== undefined) record.projectKey = projectKey;\r\n if (projectLabel !== undefined) record.projectLabel = projectLabel;\r\n out.push(record);\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/** The Pi / OMP usage reader singleton (registry lists it under \"pi\"). */\r\nconst piReader: UsageReader = {\r\n platformId: PI_PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const roots = piRoots();\r\n if (roots.length === 0) return []; // no ~/.pi or ~/.omp → fail-open\r\n\r\n const records: UsageRecord[] = [];\r\n for (const root of roots) {\r\n // <root>/<encoded-cwd>/*.jsonl\r\n const files = walkFiles(root.dir, (name) => name.endsWith(\".jsonl\"));\r\n for (const file of files) {\r\n const rows = parsePiFile(file, root.platformId);\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 piReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
renderBridgePrelude
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Q4ISQHUQ.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-3FINQ2ZF.js";
|
|
8
|
+
import "./chunk-Y3K6KJMS.js";
|
|
9
|
+
import "./chunk-ILWHLGIC.js";
|
|
10
|
+
import "./chunk-QYOUQCC6.js";
|
|
11
11
|
|
|
12
12
|
// src/adapters/pi/index.ts
|
|
13
13
|
import { existsSync } from "fs";
|
|
@@ -425,4 +425,4 @@ export {
|
|
|
425
425
|
adapter,
|
|
426
426
|
pi_default as default
|
|
427
427
|
};
|
|
428
|
-
//# sourceMappingURL=pi-
|
|
428
|
+
//# sourceMappingURL=pi-YPYV2ULH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/pi/index.ts"],"sourcesContent":["/**\r\n * adapters/pi — Pi platform adapter for agent-connector.\r\n *\r\n * Pi is a file-based-skills host with NO writable MCP config and a native\r\n * prompt-template (slash command) surface. It has no lifecycle hook system in\r\n * the json-stdio or ts-plugin sense. Its extensibility surfaces are:\r\n *\r\n * - server → single \"skip\" (Pi has no writable MCP config).\r\n * - hooks → single \"skip\" (no json-stdio / ts-plugin hook layer).\r\n * - commands → write prompt templates under <piPromptsDir>/<name>.md.\r\n * project scope → <projectDir>/.pi/prompts/<name>.md\r\n * user scope → ~/.pi/agent/prompts/<name>.md\r\n * - skills → write <piSkillsDir>/<name>/SKILL.md (+ declared resources).\r\n * project scope → <projectDir>/.pi/skills/<name>/SKILL.md\r\n * user scope → ~/.pi/agent/skills/<name>/SKILL.md\r\n * - actions → write a self-contained TS extension module that calls\r\n * pi.registerCommand(<action.id>, { handler }) once per action.\r\n * project scope → <projectDir>/.pi/extensions/<id>/index.js\r\n * user scope → ~/.pi/agent/extensions/<id>/index.js\r\n * Each handler shells out to the home-bin `action pi <id>` verb\r\n * (the SAME mechanism the OMP fork — which wraps Pi — uses for its\r\n * action surface). Unlike OMP this module wires NO hook handlers:\r\n * Pi has no lifecycle hook layer here, so it is actions-only.\r\n * - subagents → unsupported (BaseAdapter skip/warn).\r\n *\r\n * Ground-truth refs (docs/research/kilo-pi-ground-truth.md):\r\n * - prompt templates: docs/prompt-templates.md → ~/.pi/agent/prompts/*.md\r\n * and .pi/prompts/*.md, invoked as /name.\r\n * - global skills: ~/.pi/agent/skills/<n>/SKILL.md (NOT ~/.pi/skills/).\r\n * - project skills: .pi/skills/<n>/SKILL.md (unchanged).\r\n * - allowed-tools: space-delimited (NOT comma-delimited).\r\n * - extensions: Pi loads TS extension modules that call pi.registerCommand(...);\r\n * the OMP adapter (Oh My Pi, a Pi fork) proved this exact mechanism — its\r\n * supportsActions emission was inferred FROM Pi. We mirror omp's emitter.\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 type { Adapter, GeneratedPluginFile, InstallContext } from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n CommandDef,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookParadigm,\r\n PlatformCapabilities,\r\n PlatformId,\r\n SkillDef,\r\n} from \"../../core/types.js\";\r\nimport { renderBridgePrelude } from \"../../core/ts-plugin-bridge.js\";\r\n\r\nconst HOST: PlatformId = \"pi\";\r\n\r\nexport class PiAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Pi\";\r\n /**\r\n * Pi has no MCP surface at all — the paradigm label \"mcp-only\" is backwards\r\n * for a host with NO writable MCP config. Pi is purely a content-surface host\r\n * (skills + prompt templates). Use \"mcp-only\" only because the HookParadigm\r\n * union has no \"no-mcp\" variant; MCP is explicitly unsupported below.\r\n */\r\n readonly paradigm: HookParadigm = \"mcp-only\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\r\n // (user scope: ~/.pi/agent/AGENTS.md per base.ts AGENTS_MD_USER_PATHS).\r\n supportsMemory: true,\r\n // Pi has no json-stdio / ts-plugin lifecycle hook system.\r\n preToolUse: false,\r\n postToolUse: false,\r\n preCompact: false,\r\n sessionStart: false,\r\n sessionEnd: false,\r\n userPromptSubmit: false,\r\n stop: false,\r\n notification: false,\r\n canModifyArgs: false,\r\n canModifyOutput: false,\r\n canInjectSessionContext: false,\r\n // No writable MCP config.\r\n transports: [],\r\n // Content surfaces: prompt-template commands + skills.\r\n supportsCommands: true,\r\n supportsSkills: true,\r\n supportsSubagents: false,\r\n // Action surface: each declared action becomes a user-invokable command\r\n // registered INSIDE a generated TS extension module (pi.registerCommand),\r\n // shelling out to the home-bin `action` verb — the SAME mechanism the omp\r\n // fork uses (omp's action support was inferred FROM pi). supportsActions →\r\n // the installActions/uninstallActions overrides below.\r\n supportsActions: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = join(homedir(), \".pi\");\r\n const projDir = join(projectDir, \".pi\");\r\n\r\n const userInstalled = existsSync(userDir);\r\n const projInstalled = existsSync(projDir);\r\n const installed = userInstalled || projInstalled;\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projDir : userDir;\r\n\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? `found Pi config (${scope}) at ${configPath}`\r\n : `no .pi config at ${userDir} or ${projDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Base config dir (used for server/hook doctor paths only; content surfaces\r\n * use dedicated helpers below so the scope split is explicit).\r\n */\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".pi\")\r\n : join(homedir(), \".pi\");\r\n }\r\n\r\n /**\r\n * Pi has no writable MCP config. Returning the config dir keeps the generic\r\n * doctor/backup sensible while installServer always skips.\r\n */\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return this.getConfigDir(ctx);\r\n }\r\n\r\n /** Pi has no hook file — point at the config dir for generic doctor/backup. */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return this.getConfigDir(ctx);\r\n }\r\n\r\n /**\r\n * Prompt-templates dir (slash commands):\r\n * project scope → <projectDir>/.pi/prompts/\r\n * user scope → ~/.pi/agent/prompts/\r\n * (ground truth: docs/prompt-templates.md)\r\n */\r\n private promptsDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".pi\", \"prompts\")\r\n : join(homedir(), \".pi\", \"agent\", \"prompts\");\r\n }\r\n\r\n /**\r\n * Skills dir:\r\n * project scope → <projectDir>/.pi/skills/\r\n * user scope → ~/.pi/agent/skills/\r\n * (ground truth: ~/.pi/agent/skills/ is what Pi actually reads for global skills)\r\n */\r\n private skillsDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".pi\", \"skills\")\r\n : join(homedir(), \".pi\", \"agent\", \"skills\");\r\n }\r\n\r\n /** Native skill dir: <skillsDir>/<name>. */\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\r\n\r\n /**\r\n * Extension package dir Pi loads the action module from, per scope:\r\n * project scope → <projectDir>/.pi/extensions/<id>/\r\n * user scope → ~/.pi/agent/extensions/<id>/\r\n * (mirrors the prompts/skills scope split; the OMP fork uses the analogous\r\n * <agentDir>/extensions/<id>/ path.)\r\n */\r\n private extensionDir(ctx: InstallContext): string {\r\n const base =\r\n ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".pi\")\r\n : join(homedir(), \".pi\", \"agent\");\r\n return join(base, \"extensions\", ctx.connector.id);\r\n }\r\n\r\n /** The generated action extension entry module: <extensionDir>/index.js. */\r\n private actionEntryPath(ctx: InstallContext): string {\r\n return join(this.extensionDir(ctx), \"index.js\");\r\n }\r\n\r\n // ── MCP server (unavailable — Pi has no writable MCP config) ─────────────\r\n\r\n installServer(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"Pi has no writable MCP config\",\r\n },\r\n ];\r\n }\r\n\r\n uninstallServer(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"Pi has no writable MCP config\",\r\n },\r\n ];\r\n }\r\n\r\n // ── Hooks (unavailable — Pi has no json-stdio/ts-plugin hook layer) ───────\r\n\r\n installHooks(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"hooks unavailable (Pi has no hook layer)\",\r\n },\r\n ];\r\n }\r\n\r\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"hooks unavailable (Pi has no hook layer)\",\r\n },\r\n ];\r\n }\r\n\r\n // ── Content surface: commands (prompt templates) ─────────────────────────\r\n // Pi slash commands are prompt template files: <promptsDir>/<name>.md.\r\n // Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\r\n // reversible via removeContentFile. Honors platforms[\"pi\"].commands === false.\r\n\r\n /** Native prompt-template file path: <promptsDir>/<name>.md. */\r\n private commandPath(ctx: InstallContext, name: string): string {\r\n return join(this.promptsDir(ctx), `${name}.md`);\r\n }\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 pi\" }];\r\n }\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.writeContentFile(\r\n this.commandPath(ctx, cmd.name),\r\n this.renderCommand(cmd),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\r\n );\r\n }\r\n\r\n /**\r\n * Render a command as a Pi prompt template (md+frontmatter).\r\n * Pi's format mirrors the generic command render: description, optional model,\r\n * optional argument-hint. The body is the prompt template text.\r\n */\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.model !== undefined) frontmatter.model = cmd.model;\r\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\r\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\r\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\r\n }\r\n\r\n // ── Content surface: skills ──────────────────────────────────────────────\r\n // CONTENT-ONLY: pure native-file writer under <skillsDir>/<name>.\r\n // Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\r\n // reversible via removeContentFile. Honors platforms[\"pi\"].skills === false.\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 pi\" }];\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 // Bundle any resource files beside SKILL.md (relative path → contents).\r\n // Defense-in-depth: skip+warn on any key that escapes the skill dir.\r\n 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 // Only remove the skill dir when WE own its full contents.\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n /**\r\n * Render a skill's SKILL.md.\r\n *\r\n * Pi's allowed-tools field is SPACE-delimited (not comma-delimited).\r\n * Every other field follows the uniform SKILL.md convention.\r\n */\r\n private renderSkill(skill: SkillDef): string {\r\n const frontmatter: Record<string, unknown> = {\r\n name: skill.name,\r\n description: skill.description,\r\n };\r\n if (skill.model !== undefined) frontmatter.model = skill.model;\r\n const allow = skill.tools?.allow;\r\n // Pi reads allowed-tools as space-separated — NOT the \", \" used by other hosts.\r\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\" \");\r\n if (skill.disableModelInvocation !== undefined) {\r\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\r\n }\r\n if (skill.extra) Object.assign(frontmatter, skill.extra);\r\n return this.renderFrontmatterMd(frontmatter, skill.body);\r\n }\r\n\r\n // ── Action surface (slash commands in a generated extension module) ───────\r\n // Each declared action becomes a pi.registerCommand(...) inside a generated,\r\n // self-contained TS extension module (<extensionDir>/index.js). This mirrors\r\n // the OMP adapter's emitter near-verbatim (omp wraps Pi; its action support was\r\n // inferred FROM Pi). UNLIKE omp the module is NOT shared with a hook surface —\r\n // Pi has no lifecycle hook layer here — so it is actions-only AND\r\n // uninstallActions owns the teardown directly (no uninstallHooks to delegate to).\r\n // Idempotent (byte-identical → skip) via writeManagedFile; honors\r\n // platforms[\"pi\"].actions === false and the empty-actions skip.\r\n\r\n override installActions(ctx: InstallContext): ChangeRecord[] {\r\n const entryPath = this.actionEntryPath(ctx);\r\n if (ctx.connector.platforms[HOST]?.actions === false) {\r\n return [{ platform: this.id, action: \"skip\", path: entryPath, detail: \"actions disabled for pi\" }];\r\n }\r\n if (this.actionTriggers(ctx).length === 0) {\r\n return [{ platform: this.id, action: \"skip\", path: entryPath, detail: \"connector declares no actions\" }];\r\n }\r\n return this.synthesizeExtension(ctx).map((file) =>\r\n this.writeManagedFile(\r\n file.path,\r\n file.contents,\r\n ctx.dryRun,\r\n \"pi extension module (action commands)\",\r\n file.executable,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallActions(ctx: InstallContext): ChangeRecord[] {\r\n const entryPath = this.actionEntryPath(ctx);\r\n if (!existsSync(entryPath)) {\r\n return [{ platform: this.id, action: \"skip\", path: entryPath, detail: \"no pi extension present\" }];\r\n }\r\n const changes: ChangeRecord[] = [\r\n this.removeManagedFile(entryPath, ctx.dryRun, \"pi extension module\", \"no pi extension module present\"),\r\n ];\r\n // Only remove the extension dir when we own its full contents (we write a\r\n // single index.js into a per-connector dir, so this is normally now empty).\r\n changes.push(this.removeDirIfEmpty(this.extensionDir(ctx), ctx.dryRun));\r\n return changes;\r\n }\r\n\r\n /**\r\n * Build the Pi action extension: a single self-contained ESM module\r\n * (<extensionDir>/index.js) whose default export is the Pi plugin factory\r\n * `(pi) => void`. It imports nothing from agent-connector. For each declared\r\n * action it calls `pi.registerCommand(action.id, { handler })`; the handler\r\n * shells out to the stable home binary's `action pi <id>` verb over\r\n * child_process (fail-open). Mirrors the OMP adapter's registerCommand emission\r\n * (the shared renderBridgePrelude head + the per-action block), minus the hook\r\n * handlers Pi has no surface for.\r\n */\r\n private synthesizeExtension(ctx: InstallContext): GeneratedPluginFile[] {\r\n return [\r\n {\r\n path: this.actionEntryPath(ctx),\r\n contents: this.buildExtensionSource(ctx),\r\n executable: false,\r\n },\r\n ];\r\n }\r\n\r\n /** Compose the generated extension source with plain string concatenation. */\r\n private buildExtensionSource(ctx: InstallContext): string {\r\n const header = `/**\r\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\r\n *\r\n * Self-contained Pi extension for connector ${ctx.connector.id}. It imports\r\n * nothing from agent-connector: each registered command shells out to the stable\r\n * home binary's universal action entrypoint. Fail-open: any launcher error\r\n * degrades to a no-op (never wedges Pi).\r\n *\r\n * Pi loads this module and calls its DEFAULT export, the plugin factory\r\n * (pi) => void, once at load time; each pi.registerCommand(...) wires one\r\n * user-invokable command.\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: \"pi\",\r\n payloadNoun: \"Pi\",\r\n failOpenComment: \"Fail-open — never break a Pi command invocation.\",\r\n})}\r\n`;\r\n\r\n // Action surface: one pi.registerCommand per declared action. The command\r\n // shells out to the home-bin `action` verb (host token literal \"pi\"). Both id\r\n // AND description are JSON.stringify'd — descriptions are free-form connector\r\n // text, so a raw \" / backtick would break the module.\r\n const actionHandlers: string[] = [];\r\n for (const action of this.actionTriggers(ctx)) {\r\n const id = JSON.stringify(action.id);\r\n const description = JSON.stringify(action.description);\r\n actionHandlers.push(` // Action /${action.id} → run the home-bin action verb directly.\r\n pi.registerCommand(${id}, {\r\n description: ${description},\r\n handler: async (_args, _ctx) => {\r\n try {\r\n const args = [\"action\", \"pi\", ${id}, \"--connector\", CONNECTOR_ID];\r\n process.platform === \"win32\"\r\n ? execSync([HOME_BIN, ...args].map((a) => '\"' + a + '\"').join(\" \"), { stdio: \"inherit\" })\r\n : execFileSync(HOME_BIN, args, { stdio: \"inherit\" });\r\n } catch { /* fail-open */ }\r\n return undefined;\r\n },\r\n });`);\r\n }\r\n\r\n const factory = `\r\nexport default function plugin(pi) {\r\n${actionHandlers.join(\"\\n\\n\")}\r\n}\r\n`;\r\n\r\n return header + factory;\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const checks: HealthCheck[] = [];\r\n\r\n // Command (prompt-template) 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)\r\n ? { status: \"OK\", detail: p }\r\n : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n\r\n // Skill-surface checks.\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)\r\n ? { status: \"OK\", detail: p }\r\n : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n\r\n // Action-surface check: the generated extension module carries every action,\r\n // so a connector declaring actions must have written it (unless opted out).\r\n if (\r\n this.actionTriggers(ctx).length > 0 &&\r\n ctx.connector.platforms[HOST]?.actions !== false\r\n ) {\r\n const p = this.actionEntryPath(ctx);\r\n checks.push({\r\n name: `${this.name}: action extension present`,\r\n check: () =>\r\n existsSync(p)\r\n ? { status: \"OK\", detail: p }\r\n : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n return checks;\r\n }\r\n}\r\n\r\nexport const adapter = new PiAdapter();\r\nexport default adapter;\r\n"],"mappings":";;;;;;;;;;;;AAoCA,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY;AAgBrB,IAAM,OAAmB;AAElB,IAAM,YAAN,cAAwB,YAA+B;AAAA,EACnD,KAAiB;AAAA,EACjB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOP,WAAyB;AAAA,EAEzB,eAAqC;AAAA;AAAA;AAAA,IAG5C,gBAAgB;AAAA;AAAA,IAEhB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,MAAM;AAAA,IACN,cAAc;AAAA,IACd,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,yBAAyB;AAAA;AAAA,IAEzB,YAAY,CAAC;AAAA;AAAA,IAEb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMnB,iBAAiB;AAAA,EACnB;AAAA;AAAA,EAIA,gBAAgB,YAAsC;AACpD,UAAM,UAAU,KAAK,QAAQ,GAAG,KAAK;AACrC,UAAM,UAAU,KAAK,YAAY,KAAK;AAEtC,UAAM,gBAAgB,WAAW,OAAO;AACxC,UAAM,gBAAgB,WAAW,OAAO;AACxC,UAAM,YAAY,iBAAiB;AACnC,UAAM,QAAQ,iBAAiB,CAAC,gBAAgB,YAAY;AAC5D,UAAM,aAAa,UAAU,YAAY,UAAU;AAEnD,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX;AAAA,MACA,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA,MACnB;AAAA,MACA;AAAA,MACA,QAAQ,YACJ,oBAAoB,KAAK,QAAQ,UAAU,KAC3C,oBAAoB,OAAO,OAAO,OAAO;AAAA,MAC7C,YAAY,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,KAA6B;AACxC,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,KAAK,IAC1B,KAAK,QAAQ,GAAG,KAAK;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoB,KAA6B;AAC/C,WAAO,KAAK,aAAa,GAAG;AAAA,EAC9B;AAAA;AAAA,EAGA,kBAAkB,KAA6B;AAC7C,WAAO,KAAK,aAAa,GAAG;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,WAAW,KAA6B;AAC9C,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,OAAO,SAAS,IACrC,KAAK,QAAQ,GAAG,OAAO,SAAS,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,UAAU,KAA6B;AAC7C,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,OAAO,QAAQ,IACpC,KAAK,QAAQ,GAAG,OAAO,SAAS,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAGQ,SAAS,KAAqB,MAAsB;AAC1D,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,IAAI;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,aAAa,KAA6B;AAChD,UAAM,OACJ,IAAI,UAAU,YACV,KAAK,IAAI,YAAY,KAAK,IAC1B,KAAK,QAAQ,GAAG,OAAO,OAAO;AACpC,WAAO,KAAK,MAAM,cAAc,IAAI,UAAU,EAAE;AAAA,EAClD;AAAA;AAAA,EAGQ,gBAAgB,KAA6B;AACnD,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,UAAU;AAAA,EAChD;AAAA;AAAA,EAIA,cAAc,MAAsC;AAClD,WAAO;AAAA,MACL;AAAA,QACE,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEA,gBAAgB,MAAsC;AACpD,WAAO;AAAA,MACL;AAAA,QACE,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,MAAsC;AACjD,WAAO;AAAA,MACL;AAAA,QACE,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eAAe,MAAsC;AACnD,WAAO;AAAA,MACL;AAAA,QACE,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAY,KAAqB,MAAsB;AAC7D,WAAO,KAAK,KAAK,WAAW,GAAG,GAAG,GAAG,IAAI,KAAK;AAAA,EAChD;AAAA,EAES,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,aAAa,OAAO;AACjD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,2BAA2B,CAAC;AAAA,IACnF;AACA,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK;AAAA,QACH,KAAK,YAAY,KAAK,IAAI,IAAI;AAAA,QAC9B,KAAK,cAAc,GAAG;AAAA,QACtB,IAAI;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EAES,kBAAkB,KAAqC;AAC9D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK,kBAAkB,KAAK,YAAY,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAAc,KAAyB;AAC7C,UAAM,cAAuC,CAAC;AAC9C,QAAI,IAAI,gBAAgB,OAAW,aAAY,cAAc,IAAI;AACjE,QAAI,IAAI,UAAU,OAAW,aAAY,QAAQ,IAAI;AACrD,QAAI,IAAI,iBAAiB,OAAW,aAAY,eAAe,IAAI,IAAI;AACvE,QAAI,IAAI,MAAO,QAAO,OAAO,aAAa,IAAI,KAAK;AACnD,WAAO,KAAK,oBAAoB,aAAa,IAAI,MAAM;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,cAAc,KAAqC;AAC1D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,WAAW,OAAO;AAC/C,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,yBAAyB,CAAC;AAAA,IACjF;AACA,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AACzC,cAAQ;AAAA,QACN,KAAK,iBAAiB,KAAK,KAAK,UAAU,GAAG,KAAK,YAAY,KAAK,GAAG,IAAI,MAAM;AAAA,MAClF;AAGA,iBAAW,CAAC,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,aAAa,CAAC,CAAC,GAAG;AACnE,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,MAAM;AACnB,kBAAQ,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,QAAQ,mBAAmB,GAAG;AAAA,UAChC,CAAC;AACD;AAAA,QACF;AACA,gBAAQ,KAAK,KAAK,iBAAiB,QAAQ,UAAU,IAAI,MAAM,CAAC;AAAA,MAClE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAES,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AACzC,cAAQ,KAAK,KAAK,kBAAkB,KAAK,KAAK,UAAU,GAAG,IAAI,MAAM,CAAC;AACtE,iBAAW,OAAO,OAAO,KAAK,MAAM,aAAa,CAAC,CAAC,GAAG;AACpD,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,KAAM;AACrB,gBAAQ,KAAK,KAAK,kBAAkB,QAAQ,IAAI,MAAM,CAAC;AAAA,MACzD;AAEA,cAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI,MAAM,CAAC;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAY,OAAyB;AAC3C,UAAM,cAAuC;AAAA,MAC3C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,IACrB;AACA,QAAI,MAAM,UAAU,OAAW,aAAY,QAAQ,MAAM;AACzD,UAAM,QAAQ,MAAM,OAAO;AAE3B,QAAI,SAAS,MAAM,SAAS,EAAG,aAAY,eAAe,IAAI,MAAM,KAAK,GAAG;AAC5E,QAAI,MAAM,2BAA2B,QAAW;AAC9C,kBAAY,0BAA0B,IAAI,MAAM;AAAA,IAClD;AACA,QAAI,MAAM,MAAO,QAAO,OAAO,aAAa,MAAM,KAAK;AACvD,WAAO,KAAK,oBAAoB,aAAa,MAAM,IAAI;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYS,eAAe,KAAqC;AAC3D,UAAM,YAAY,KAAK,gBAAgB,GAAG;AAC1C,QAAI,IAAI,UAAU,UAAU,IAAI,GAAG,YAAY,OAAO;AACpD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,MAAM,WAAW,QAAQ,0BAA0B,CAAC;AAAA,IACnG;AACA,QAAI,KAAK,eAAe,GAAG,EAAE,WAAW,GAAG;AACzC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,MAAM,WAAW,QAAQ,gCAAgC,CAAC;AAAA,IACzG;AACA,WAAO,KAAK,oBAAoB,GAAG,EAAE;AAAA,MAAI,CAAC,SACxC,KAAK;AAAA,QACH,KAAK;AAAA,QACL,KAAK;AAAA,QACL,IAAI;AAAA,QACJ;AAAA,QACA,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAES,iBAAiB,KAAqC;AAC7D,UAAM,YAAY,KAAK,gBAAgB,GAAG;AAC1C,QAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,MAAM,WAAW,QAAQ,0BAA0B,CAAC;AAAA,IACnG;AACA,UAAM,UAA0B;AAAA,MAC9B,KAAK,kBAAkB,WAAW,IAAI,QAAQ,uBAAuB,gCAAgC;AAAA,IACvG;AAGA,YAAQ,KAAK,KAAK,iBAAiB,KAAK,aAAa,GAAG,GAAG,IAAI,MAAM,CAAC;AACtE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,oBAAoB,KAA4C;AACtE,WAAO;AAAA,MACL;AAAA,QACE,MAAM,KAAK,gBAAgB,GAAG;AAAA,QAC9B,UAAU,KAAK,qBAAqB,GAAG;AAAA,QACvC,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,qBAAqB,KAA6B;AACxD,UAAM,SAAS;AAAA;AAAA;AAAA,+CAG4B,IAAI,UAAU,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW7D,oBAAoB;AAAA,MACpB,SAAS,IAAI;AAAA,MACb,aAAa,IAAI,UAAU;AAAA,MAC3B,UAAU;AAAA,MACV,aAAa;AAAA,MACb,iBAAiB;AAAA,IACnB,CAAC,CAAC;AAAA;AAOE,UAAM,iBAA2B,CAAC;AAClC,eAAW,UAAU,KAAK,eAAe,GAAG,GAAG;AAC7C,YAAM,KAAK,KAAK,UAAU,OAAO,EAAE;AACnC,YAAM,cAAc,KAAK,UAAU,OAAO,WAAW;AACrD,qBAAe,KAAK,gBAAgB,OAAO,EAAE;AAAA,uBAC5B,EAAE;AAAA,mBACN,WAAW;AAAA;AAAA;AAAA,wCAGU,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOpC;AAAA,IACF;AAEA,UAAM,UAAU;AAAA;AAAA,EAElB,eAAe,KAAK,MAAM,CAAC;AAAA;AAAA;AAIzB,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAIS,gBAAgB,KAA6C;AACpE,UAAM,SAAwB,CAAC;AAG/B,eAAW,OAAO,IAAI,UAAU,UAAU;AACxC,YAAM,IAAI,KAAK,YAAY,KAAK,IAAI,IAAI;AACxC,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,aAAa,IAAI,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IACR,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAC1B,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MACpD,CAAC;AAAA,IACH;AAGA,eAAW,SAAS,IAAI,UAAU,QAAQ;AACxC,YAAM,IAAI,KAAK,KAAK,SAAS,KAAK,MAAM,IAAI,GAAG,UAAU;AACzD,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,WAAW,MAAM,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IACR,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAC1B,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MACpD,CAAC;AAAA,IACH;AAIA,QACE,KAAK,eAAe,GAAG,EAAE,SAAS,KAClC,IAAI,UAAU,UAAU,IAAI,GAAG,YAAY,OAC3C;AACA,YAAM,IAAI,KAAK,gBAAgB,GAAG;AAClC,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MACL,WAAW,CAAC,IACR,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAC1B,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MACpD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;AAEO,IAAM,UAAU,IAAI,UAAU;AACrC,IAAO,aAAQ;","names":[]}
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
fileMtimeMs,
|
|
4
4
|
readJsonlLines
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZSOS2KOR.js";
|
|
6
6
|
import {
|
|
7
7
|
firstExistingRoot,
|
|
8
8
|
walkFiles
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KM2YXO6V.js";
|
|
10
10
|
import {
|
|
11
11
|
emptyTokens,
|
|
12
12
|
inferProvider,
|
|
13
13
|
normalizeWorkspaceKey,
|
|
14
14
|
workspaceLabelFromKey
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-7PSNXUFK.js";
|
|
16
16
|
|
|
17
17
|
// src/usage/readers/qwen-code.ts
|
|
18
18
|
import { basename, dirname } from "path";
|
|
@@ -131,4 +131,4 @@ var qwen_code_default = qwenReader;
|
|
|
131
131
|
export {
|
|
132
132
|
qwen_code_default as default
|
|
133
133
|
};
|
|
134
|
-
//# sourceMappingURL=qwen-code-
|
|
134
|
+
//# sourceMappingURL=qwen-code-26CSFDX6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/qwen-code.ts"],"sourcesContent":["/**\r\n * usage/readers/qwen-code — Qwen CLI native session-log reader.\r\n *\r\n * Faithful port of tokscale sessions/qwen.rs (the reference reader). Reads\r\n * ~/.qwen/projects/<project>/chats/*.jsonl. Each line is one entry; only\r\n * `type:\"assistant\"` lines carry a `usageMetadata` token block:\r\n * promptTokenCount → input (cumulative prompt incl. cached context)\r\n * candidatesTokenCount → output\r\n * thoughtsTokenCount → reasoning\r\n * cachedContentTokenCount → cacheRead\r\n * cacheWrite is always 0 (Qwen does not report it).\r\n *\r\n * Qwen reports the cumulative prompt as promptTokenCount and the cached portion\r\n * separately, so the net \"fresh\" input is promptTokenCount - cachedContentTokenCount\r\n * (clamped ≥ 0), keeping the dimensions disjoint for an honest total.\r\n *\r\n * No dedup, no deltas, no streaming merge — the simplest schema (one row per\r\n * assistant line). Session id prefers the line's sessionId, falling back to a\r\n * `<project>-<filename>` composite to stay unique across projects. Timestamp is\r\n * the line's RFC3339 ts (or the file mtime). Provider is inferred from the model\r\n * (qwen* → \"qwen\"), defaulting to \"qwen\". Confidence is \"host-reported\".\r\n *\r\n * Fail-open: no root → []; unreadable/malformed file or line → skipped.\r\n */\r\n\r\nimport { basename, dirname } from \"node:path\";\r\n\r\nimport type { UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { fileMtimeMs, readJsonlLines } from \"../jsonl.js\";\r\nimport { inferProvider, normalizeWorkspaceKey, workspaceLabelFromKey } from \"../normalize.js\";\r\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"qwen-code\" as const;\r\nconst DEFAULT_MODEL = \"unknown\";\r\nconst DEFAULT_PROVIDER = \"qwen\";\r\n\r\n/** The fields we read off a Qwen JSONL line (everything optional / unknown). */\r\ninterface QwenLine {\r\n type?: unknown;\r\n model?: unknown;\r\n timestamp?: unknown;\r\n sessionId?: unknown;\r\n usageMetadata?: {\r\n promptTokenCount?: unknown;\r\n candidatesTokenCount?: unknown;\r\n thoughtsTokenCount?: unknown;\r\n cachedContentTokenCount?: unknown;\r\n };\r\n}\r\n\r\n/** Coerce an unknown to a non-negative integer (0 on absence/garbage). */\r\nfunction toNonNegInt(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/** Parse an RFC3339 / numeric timestamp to epoch ms, or null when unusable. */\r\nfunction parseTs(v: unknown): number | null {\r\n if (typeof v === \"string\") {\r\n const ms = Date.parse(v);\r\n if (!Number.isNaN(ms)) return ms;\r\n const num = Number(v);\r\n if (Number.isFinite(num) && num > 0) return num >= 1e12 ? num : num * 1000;\r\n return null;\r\n }\r\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) {\r\n return v >= 1e12 ? v : v * 1000;\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Session id with fallback (port of extract_session_id_with_fallback):\r\n * 1. the line's sessionId, when a non-empty string;\r\n * 2. otherwise `<project>-<filename>` derived from the path\r\n * (.../projects/<project>/chats/<file>.jsonl), so identically-named files\r\n * in different projects never collide.\r\n */\r\nfunction sessionIdWithFallback(path: string, lineSessionId: unknown): string {\r\n if (typeof lineSessionId === \"string\" && lineSessionId !== \"\") return lineSessionId;\r\n const filename = stripExt(basename(path));\r\n const chatsDir = dirname(path); // .../chats\r\n const projectDir = dirname(chatsDir); // .../projects/<project>\r\n const project = basename(projectDir) || \"unknown\";\r\n return `${project}-${filename}`;\r\n}\r\n\r\nfunction stripExt(name: string): string {\r\n const dot = name.lastIndexOf(\".\");\r\n return dot > 0 ? name.slice(0, dot) : name;\r\n}\r\n\r\n/**\r\n * Workspace (project) from a path (port of qwen_workspace_from_path): scan the\r\n * path components for a `[projects, <key>, chats, …]` window (last match wins)\r\n * and normalize `<key>`. Anchoring on the chats segment ignores stray \"projects\"\r\n * directory names elsewhere in the path.\r\n */\r\nfunction workspaceFromPath(path: string): { projectKey?: string; projectLabel?: string } {\r\n const components = path.split(/[\\\\/]+/).filter((c) => c !== \"\");\r\n for (let i = components.length - 4; i >= 0; i--) {\r\n const a = components[i];\r\n const b = components[i + 1];\r\n const c = components[i + 2];\r\n if (a === \"projects\" && b !== undefined && b !== \"\" && c === \"chats\") {\r\n const key = normalizeWorkspaceKey(b);\r\n if (key === undefined) return {};\r\n const label = workspaceLabelFromKey(key);\r\n return label === undefined ? { projectKey: key } : { projectKey: key, projectLabel: label };\r\n }\r\n }\r\n return {};\r\n}\r\n\r\n/** Parse one Qwen JSONL file into usage records (port of parse_qwen_file). */\r\nfunction parseQwenFile(path: string): UsageRecord[] {\r\n const lines = readJsonlLines(path);\r\n if (lines.length === 0) return [];\r\n\r\n const mtime = fileMtimeMs(path);\r\n const { projectKey, projectLabel } = workspaceFromPath(path);\r\n const out: UsageRecord[] = [];\r\n\r\n for (const raw of lines) {\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const line = raw as QwenLine;\r\n\r\n // Only assistant lines with a usageMetadata block.\r\n if (line.type !== \"assistant\") continue;\r\n const usage = line.usageMetadata;\r\n if (usage === undefined || usage === null) continue;\r\n\r\n const promptTokens = toNonNegInt(usage.promptTokenCount);\r\n const output = toNonNegInt(usage.candidatesTokenCount);\r\n const reasoning = toNonNegInt(usage.thoughtsTokenCount);\r\n const cacheRead = toNonNegInt(usage.cachedContentTokenCount);\r\n // Net input: cumulative prompt minus the cached portion (clamped ≥ 0).\r\n const input = Math.max(0, promptTokens - cacheRead);\r\n\r\n // Skip zero-token entries (matches the Rust input+output+cacheRead+reasoning==0 check\r\n // — uses the raw prompt count so a fully-cached prompt is not dropped).\r\n if (promptTokens + output + cacheRead + reasoning === 0) continue;\r\n\r\n const ts = parseTs(line.timestamp) ?? mtime;\r\n\r\n const modelId = typeof line.model === \"string\" && line.model !== \"\" ? line.model : DEFAULT_MODEL;\r\n const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;\r\n const sessionId = sessionIdWithFallback(path, line.sessionId);\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.reasoning = reasoning;\r\n // cacheWrite stays 0 (Qwen does not report it).\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n confidence: \"host-reported\",\r\n };\r\n if (projectKey !== undefined) record.projectKey = projectKey;\r\n if (projectLabel !== undefined) record.projectLabel = projectLabel;\r\n out.push(record);\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/** The Qwen CLI usage reader singleton. */\r\nconst qwenReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const root = firstExistingRoot(PLATFORM_ID);\r\n if (root === undefined) return []; // no ~/.qwen/projects → fail-open\r\n\r\n // ~/.qwen/projects/<project>/chats/<file>.jsonl\r\n const files = walkFiles(root, (name, abs) => {\r\n return name.endsWith(\".jsonl\") && /[\\\\/]chats[\\\\/][^\\\\/]+\\.jsonl$/.test(abs);\r\n });\r\n\r\n const records: UsageRecord[] = [];\r\n for (const file of files) {\r\n const rows = parseQwenFile(file);\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 return records;\r\n },\r\n};\r\n\r\nexport default qwenReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
writeTomlString
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XN7S44U4.js";
|
|
5
5
|
import {
|
|
6
6
|
addLedgerOwner,
|
|
7
7
|
createLedgerEntry,
|
|
@@ -14,25 +14,25 @@ import {
|
|
|
14
14
|
loadConfigPatchLedger,
|
|
15
15
|
removeLedgerOwner,
|
|
16
16
|
saveConfigPatchLedger
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-KFPSJRHR.js";
|
|
18
18
|
import {
|
|
19
19
|
normalizeSessionSource
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-PSGTHJQU.js";
|
|
21
21
|
import {
|
|
22
22
|
resolveEnvRefsDeep
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XXLCMSD3.js";
|
|
24
24
|
import {
|
|
25
25
|
BaseAdapter,
|
|
26
26
|
renderSkillMd
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-3FINQ2ZF.js";
|
|
28
28
|
import {
|
|
29
29
|
buildHomeBinStatuslineCommand,
|
|
30
30
|
buildWrappedStdio,
|
|
31
31
|
isHomeBinHookCommand,
|
|
32
32
|
isHomeBinStatuslineCommand
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-Y3K6KJMS.js";
|
|
34
|
+
import "./chunk-ILWHLGIC.js";
|
|
35
|
+
import "./chunk-QYOUQCC6.js";
|
|
36
36
|
|
|
37
37
|
// src/adapters/qwen-code/index.ts
|
|
38
38
|
import { existsSync } from "fs";
|
|
@@ -1083,4 +1083,4 @@ export {
|
|
|
1083
1083
|
adapter,
|
|
1084
1084
|
qwen_code_default as default
|
|
1085
1085
|
};
|
|
1086
|
-
//# sourceMappingURL=qwen-code-
|
|
1086
|
+
//# sourceMappingURL=qwen-code-ZHCLCYMC.js.map
|