@ken-jo/agent-connector 0.4.97 → 0.4.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +6 -6
  3. package/README.md +604 -596
  4. package/dist/{action-IPFDPOZU.js → action-5OEM3QC4.js} +17 -16
  5. package/dist/action-5OEM3QC4.js.map +1 -0
  6. package/dist/{amazon-q-IT44LEWV.js → amazon-q-7DPVJXJN.js} +6 -6
  7. package/dist/amazon-q-7DPVJXJN.js.map +1 -0
  8. package/dist/{amp-CEWOSWQO.js → amp-BQZOL5GR.js} +4 -4
  9. package/dist/amp-BQZOL5GR.js.map +1 -0
  10. package/dist/{amp-P35FRU2Z.js → amp-VYXZWHXW.js} +7 -7
  11. package/dist/amp-VYXZWHXW.js.map +1 -0
  12. package/dist/{antigravity-LHFEFNMC.js → antigravity-EA4L225L.js} +5 -5
  13. package/dist/antigravity-EA4L225L.js.map +1 -0
  14. package/dist/antigravity-VXHL6ZPM.js +18 -0
  15. package/dist/{antigravity-cli-MOKFSWOU.js → antigravity-cli-B2HXZFYQ.js} +5 -5
  16. package/dist/antigravity-cli-B2HXZFYQ.js.map +1 -0
  17. package/dist/{antigravity-cli-MPE27LPI.js → antigravity-cli-JHQ7JGNX.js} +10 -9
  18. package/dist/antigravity-cli-JHQ7JGNX.js.map +1 -0
  19. package/dist/{audit-3E5JAOP2.js → audit-BO7JQYIH.js} +8 -8
  20. package/dist/{chunk-7C2IPIIB.js → chunk-2Y2MZRLP.js} +3 -3
  21. package/dist/chunk-2Y2MZRLP.js.map +1 -0
  22. package/dist/{chunk-GZZCHJDP.js → chunk-4KIXXJ7B.js} +2 -2
  23. package/dist/chunk-4KIXXJ7B.js.map +1 -0
  24. package/dist/chunk-4NFDNY3C.js +34 -0
  25. package/dist/chunk-4NFDNY3C.js.map +1 -0
  26. package/dist/{chunk-C63AAXK7.js → chunk-4QXCNZMD.js} +5 -5
  27. package/dist/chunk-4QXCNZMD.js.map +1 -0
  28. package/dist/{chunk-Q7PR2WGT.js → chunk-6TF7MHG5.js} +2 -2
  29. package/dist/chunk-6TF7MHG5.js.map +1 -0
  30. package/dist/{chunk-7ZFK2WEO.js → chunk-6WN37NVN.js} +113 -10
  31. package/dist/chunk-6WN37NVN.js.map +1 -0
  32. package/dist/{chunk-GCPEPUD7.js → chunk-6XMV2OOA.js} +6 -6
  33. package/dist/chunk-6XMV2OOA.js.map +1 -0
  34. package/dist/{chunk-XXLCMSD3.js → chunk-BEFVJ2OE.js} +1 -1
  35. package/dist/chunk-BEFVJ2OE.js.map +1 -0
  36. package/dist/{chunk-N4ENLZEU.js → chunk-BV5WK6VQ.js} +19 -19
  37. package/dist/chunk-BV5WK6VQ.js.map +1 -0
  38. package/dist/{chunk-WPTNMYYM.js → chunk-BXPSDNIB.js} +6 -6
  39. package/dist/chunk-BXPSDNIB.js.map +1 -0
  40. package/dist/{chunk-Q4ISQHUQ.js → chunk-FBJQGRET.js} +1 -1
  41. package/dist/chunk-FBJQGRET.js.map +1 -0
  42. package/dist/{chunk-THI4PI4H.js → chunk-FJCUKXGX.js} +2 -2
  43. package/dist/chunk-FJCUKXGX.js.map +1 -0
  44. package/dist/{chunk-L2C5UMKW.js → chunk-FKW5A6HE.js} +23 -7
  45. package/dist/chunk-FKW5A6HE.js.map +1 -0
  46. package/dist/{chunk-NDMNMAKP.js → chunk-G5HAIYRM.js} +43 -43
  47. package/dist/chunk-G5HAIYRM.js.map +1 -0
  48. package/dist/{chunk-SLJI5BOM.js → chunk-GDIAHWNY.js} +2 -2
  49. package/dist/chunk-GDIAHWNY.js.map +1 -0
  50. package/dist/{chunk-QYOUQCC6.js → chunk-GZGLCCEE.js} +1 -1
  51. package/dist/chunk-GZGLCCEE.js.map +1 -0
  52. package/dist/{chunk-PSGTHJQU.js → chunk-H53QZQJI.js} +1 -1
  53. package/dist/chunk-H53QZQJI.js.map +1 -0
  54. package/dist/{chunk-7HHW23AC.js → chunk-IRUYJD23.js} +29 -29
  55. package/dist/chunk-IRUYJD23.js.map +1 -0
  56. package/dist/{chunk-IOJDZJ72.js → chunk-IVAWP6HH.js} +2 -2
  57. package/dist/chunk-IVAWP6HH.js.map +1 -0
  58. package/dist/{chunk-3FINQ2ZF.js → chunk-JTN3AKZO.js} +30 -20
  59. package/dist/chunk-JTN3AKZO.js.map +1 -0
  60. package/dist/{chunk-4GH2KA7V.js → chunk-KHO5WNTP.js} +1 -1
  61. package/dist/chunk-KHO5WNTP.js.map +1 -0
  62. package/dist/{chunk-MLU7NDAZ.js → chunk-KLZBRNFP.js} +12 -12
  63. package/dist/chunk-KLZBRNFP.js.map +1 -0
  64. package/dist/{chunk-3EP5V2F4.js → chunk-M6OS4OLU.js} +3 -3
  65. package/dist/chunk-M6OS4OLU.js.map +1 -0
  66. package/dist/{chunk-UZZTWWGG.js → chunk-MQPNU2CY.js} +1 -1
  67. package/dist/chunk-MQPNU2CY.js.map +1 -0
  68. package/dist/{chunk-LQ55E7QI.js → chunk-N4STCQGP.js} +7 -7
  69. package/dist/chunk-N4STCQGP.js.map +1 -0
  70. package/dist/{chunk-KFPSJRHR.js → chunk-NBYKLUF6.js} +2 -2
  71. package/dist/chunk-NBYKLUF6.js.map +1 -0
  72. package/dist/{chunk-KM2YXO6V.js → chunk-O7SDRBVB.js} +1 -1
  73. package/dist/chunk-O7SDRBVB.js.map +1 -0
  74. package/dist/{chunk-LFWYYWLV.js → chunk-OP4KBXUO.js} +1 -1
  75. package/dist/chunk-OP4KBXUO.js.map +1 -0
  76. package/dist/{chunk-XN7S44U4.js → chunk-OPXAP3AC.js} +1 -1
  77. package/dist/chunk-OPXAP3AC.js.map +1 -0
  78. package/dist/{chunk-TGZFDXNH.js → chunk-PWCBWAM4.js} +6 -4
  79. package/dist/chunk-PWCBWAM4.js.map +1 -0
  80. package/dist/{chunk-Y3K6KJMS.js → chunk-QSY74NAP.js} +2 -2
  81. package/dist/chunk-QSY74NAP.js.map +1 -0
  82. package/dist/{chunk-ZSOS2KOR.js → chunk-RK6VBLXP.js} +1 -1
  83. package/dist/chunk-RK6VBLXP.js.map +1 -0
  84. package/dist/{chunk-FHYR5Q5T.js → chunk-SFY6YLVK.js} +19 -12
  85. package/dist/chunk-SFY6YLVK.js.map +1 -0
  86. package/dist/{chunk-C747DYNT.js → chunk-UM5S7DKK.js} +1 -1
  87. package/dist/chunk-UM5S7DKK.js.map +1 -0
  88. package/dist/{chunk-ILWHLGIC.js → chunk-UMQ6NBQR.js} +2 -2
  89. package/dist/chunk-UMQ6NBQR.js.map +1 -0
  90. package/dist/{chunk-7PSNXUFK.js → chunk-XD7MY6HB.js} +1 -1
  91. package/dist/chunk-XD7MY6HB.js.map +1 -0
  92. package/dist/{chunk-XVEJAFKW.js → chunk-XY3N2U6L.js} +5 -5
  93. package/dist/chunk-XY3N2U6L.js.map +1 -0
  94. package/dist/{chunk-XZWMJLIT.js → chunk-YT43MUSJ.js} +1 -1
  95. package/dist/chunk-YT43MUSJ.js.map +1 -0
  96. package/dist/{claude-code-QBWDT5RT.js → claude-code-LJ6DVXWQ.js} +24 -14
  97. package/dist/claude-code-LJ6DVXWQ.js.map +1 -0
  98. package/dist/{claude-code-FS42PXZO.js → claude-code-NMRKTAP7.js} +4 -4
  99. package/dist/claude-code-NMRKTAP7.js.map +1 -0
  100. package/dist/cli/sdk.js +7 -7
  101. package/dist/cli/sdk.js.map +1 -1
  102. package/dist/cli.js +1 -1
  103. package/dist/cli.js.map +1 -1
  104. package/dist/{cline-JKEAYWVR.js → cline-JAPJNOZQ.js} +6 -6
  105. package/dist/cline-JAPJNOZQ.js.map +1 -0
  106. package/dist/{codebuddy-EB6EYPC3.js → codebuddy-GC7VAE2Y.js} +7 -7
  107. package/dist/codebuddy-GC7VAE2Y.js.map +1 -0
  108. package/dist/{codebuff-5RSXFU6G.js → codebuff-3VODFPD4.js} +6 -6
  109. package/dist/codebuff-3VODFPD4.js.map +1 -0
  110. package/dist/{codebuff-6KWBW6CT.js → codebuff-ETYT5UBL.js} +4 -4
  111. package/dist/codebuff-ETYT5UBL.js.map +1 -0
  112. package/dist/{codex-ART46CDD.js → codex-RXIS5BHM.js} +9 -9
  113. package/dist/codex-RXIS5BHM.js.map +1 -0
  114. package/dist/{codex-DKBAAUCO.js → codex-YAORPCOD.js} +4 -4
  115. package/dist/codex-YAORPCOD.js.map +1 -0
  116. package/dist/{continue-JHZCMSPH.js → continue-MECVDV4Z.js} +8 -8
  117. package/dist/continue-MECVDV4Z.js.map +1 -0
  118. package/dist/{copilot-cli-CLBJACQ5.js → copilot-cli-MZTAWMPW.js} +4 -4
  119. package/dist/copilot-cli-MZTAWMPW.js.map +1 -0
  120. package/dist/{copilot-cli-QVAU5CFM.js → copilot-cli-WVWAWNSM.js} +7 -7
  121. package/dist/copilot-cli-WVWAWNSM.js.map +1 -0
  122. package/dist/{crush-A5C5USRL.js → crush-QBXLNN7T.js} +4 -4
  123. package/dist/crush-QBXLNN7T.js.map +1 -0
  124. package/dist/{crush-7TORBYUL.js → crush-YB3SK6NK.js} +7 -7
  125. package/dist/crush-YB3SK6NK.js.map +1 -0
  126. package/dist/{cursor-D5SWDVSW.js → cursor-DIW43TRZ.js} +3 -3
  127. package/dist/cursor-DIW43TRZ.js.map +1 -0
  128. package/dist/cursor-RSLHA2CY.js +22 -0
  129. package/dist/{define-connector-DTWb46UB.d.ts → define-connector-odRHEC4H.d.ts} +1 -1
  130. package/dist/{detect-JHSA3G3U.js → detect-ALP4G7WG.js} +4 -4
  131. package/dist/detect-ALP4G7WG.js.map +1 -0
  132. package/dist/{devin-SSR7S4WX.js → devin-WPDN3MXE.js} +7 -7
  133. package/dist/devin-WPDN3MXE.js.map +1 -0
  134. package/dist/{doctor-CQJ7TZPA.js → doctor-YEQWCWZJ.js} +27 -26
  135. package/dist/doctor-YEQWCWZJ.js.map +1 -0
  136. package/dist/{droid-45PJ7JGF.js → droid-HS6MX3IL.js} +10 -8
  137. package/dist/droid-HS6MX3IL.js.map +1 -0
  138. package/dist/{droid-PFQ2PZSF.js → droid-U3ZBLQFO.js} +4 -4
  139. package/dist/droid-U3ZBLQFO.js.map +1 -0
  140. package/dist/{gemini-cli-Y6RJMU24.js → gemini-cli-NMVVBO3K.js} +4 -4
  141. package/dist/gemini-cli-NMVVBO3K.js.map +1 -0
  142. package/dist/{gemini-cli-24PFDK7D.js → gemini-cli-VJ6X5DNF.js} +8 -8
  143. package/dist/gemini-cli-VJ6X5DNF.js.map +1 -0
  144. package/dist/{goose-U5D3LCPC.js → goose-3X7ID7YW.js} +9 -9
  145. package/dist/goose-3X7ID7YW.js.map +1 -0
  146. package/dist/{goose-K2HKUTBK.js → goose-64V46Y2W.js} +4 -4
  147. package/dist/goose-64V46Y2W.js.map +1 -0
  148. package/dist/{grok-cli-L2MHAPBY.js → grok-cli-4VFVF2CQ.js} +7 -7
  149. package/dist/grok-cli-4VFVF2CQ.js.map +1 -0
  150. package/dist/{hermes-2S5JUTTJ.js → hermes-AIVUE7LX.js} +10 -8
  151. package/dist/hermes-AIVUE7LX.js.map +1 -0
  152. package/dist/{hermes-MF3NX4ZY.js → hermes-F3EGTK6N.js} +4 -4
  153. package/dist/hermes-F3EGTK6N.js.map +1 -0
  154. package/dist/{hook-VHICXHXL.js → hook-F63I3SD5.js} +17 -16
  155. package/dist/hook-F63I3SD5.js.map +1 -0
  156. package/dist/index.d.ts +3 -3
  157. package/dist/index.js +5 -5
  158. package/dist/{install-WLENR4KF.js → install-23WRRFBY.js} +21 -21
  159. package/dist/install-23WRRFBY.js.map +1 -0
  160. package/dist/{introspect-dNekqPDY.d.ts → introspect-gTx6GzpW.d.ts} +1 -1
  161. package/dist/{jetbrains-copilot-Z4FC3RM3.js → jetbrains-copilot-XBO2JZRO.js} +6 -6
  162. package/dist/jetbrains-copilot-XBO2JZRO.js.map +1 -0
  163. package/dist/{junie-ULGJJIHB.js → junie-UCOS6Q37.js} +6 -6
  164. package/dist/junie-UCOS6Q37.js.map +1 -0
  165. package/dist/{kilo-SMHPOHJ5.js → kilo-SW7BH6EG.js} +4 -4
  166. package/dist/kilo-SW7BH6EG.js.map +1 -0
  167. package/dist/{kilo-WWIJOVWD.js → kilo-T4OXNUYY.js} +8 -8
  168. package/dist/kilo-T4OXNUYY.js.map +1 -0
  169. package/dist/{kilo-cli-QKE2EQLS.js → kilo-cli-I2S3W245.js} +8 -8
  170. package/dist/kilo-cli-I2S3W245.js.map +1 -0
  171. package/dist/{kilo-cli-T2SRRRJS.js → kilo-cli-ZF272ZHN.js} +5 -5
  172. package/dist/kilo-cli-ZF272ZHN.js.map +1 -0
  173. package/dist/{kimi-MSIDEMCI.js → kimi-5FHEXGZD.js} +4 -4
  174. package/dist/kimi-5FHEXGZD.js.map +1 -0
  175. package/dist/{kimi-JMUFTVSF.js → kimi-VLSUFLYV.js} +7 -7
  176. package/dist/kimi-VLSUFLYV.js.map +1 -0
  177. package/dist/{kiro-UWUCRKR3.js → kiro-AQFXGOJX.js} +10 -8
  178. package/dist/kiro-AQFXGOJX.js.map +1 -0
  179. package/dist/{kiro-NYRRBIKW.js → kiro-WGOI5CGT.js} +4 -4
  180. package/dist/kiro-WGOI5CGT.js.map +1 -0
  181. package/dist/{leaderboard-NJWKGMXP.js → leaderboard-YBD3IKC2.js} +7 -7
  182. package/dist/leaderboard-YBD3IKC2.js.map +1 -0
  183. package/dist/{mimo-code-BPNYYIVM.js → mimo-code-KETL7W7D.js} +7 -7
  184. package/dist/mimo-code-KETL7W7D.js.map +1 -0
  185. package/dist/{mistral-vibe-LT3DAJ3L.js → mistral-vibe-3AU7N2CA.js} +6 -6
  186. package/dist/mistral-vibe-3AU7N2CA.js.map +1 -0
  187. package/dist/{mux-AHNUAY5Z.js → mux-BO2L5CTW.js} +6 -6
  188. package/dist/mux-BO2L5CTW.js.map +1 -0
  189. package/dist/{mux-7PIJ7HUQ.js → mux-XM6AP35L.js} +4 -4
  190. package/dist/mux-XM6AP35L.js.map +1 -0
  191. package/dist/{nemoclaw-RE5RZASZ.js → nemoclaw-WA7RSKF2.js} +7 -7
  192. package/dist/nemoclaw-WA7RSKF2.js.map +1 -0
  193. package/dist/{omp-D2EXEPH7.js → omp-UDYJ2PYY.js} +9 -7
  194. package/dist/omp-UDYJ2PYY.js.map +1 -0
  195. package/dist/{open-interpreter-SSGBEUKX.js → open-interpreter-WMBNM4MQ.js} +6 -6
  196. package/dist/open-interpreter-WMBNM4MQ.js.map +1 -0
  197. package/dist/openclaw-3DHVHX5P.js +17 -0
  198. package/dist/{openclaw-KAFTNLR2.js → openclaw-5EQFGOWL.js} +4 -4
  199. package/dist/openclaw-5EQFGOWL.js.map +1 -0
  200. package/dist/{opencode-YKUKZY3J.js → opencode-IKMI3RI7.js} +7 -7
  201. package/dist/opencode-IKMI3RI7.js.map +1 -0
  202. package/dist/{opencode-Z65JYILL.js → opencode-QGP4ALQY.js} +4 -4
  203. package/dist/opencode-QGP4ALQY.js.map +1 -0
  204. package/dist/{openhands-SEZMCUC3.js → openhands-QGXMQR6I.js} +7 -7
  205. package/dist/openhands-QGXMQR6I.js.map +1 -0
  206. package/dist/{package-JECVQEFT.js → package-TAUTPP7Z.js} +15 -15
  207. package/dist/package-TAUTPP7Z.js.map +1 -0
  208. package/dist/{pi-YPYV2ULH.js → pi-A2HCGRJG.js} +9 -7
  209. package/dist/pi-A2HCGRJG.js.map +1 -0
  210. package/dist/{pi-DLKCPOJE.js → pi-GGDQREVG.js} +4 -4
  211. package/dist/pi-GGDQREVG.js.map +1 -0
  212. package/dist/{qwen-code-ZHCLCYMC.js → qwen-code-DNQTGJOF.js} +35 -17
  213. package/dist/qwen-code-DNQTGJOF.js.map +1 -0
  214. package/dist/{qwen-code-26CSFDX6.js → qwen-code-GQILBJ5B.js} +4 -4
  215. package/dist/qwen-code-GQILBJ5B.js.map +1 -0
  216. package/dist/{roo-code-HSAE2CJU.js → roo-code-SUWI4BBN.js} +4 -4
  217. package/dist/roo-code-SUWI4BBN.js.map +1 -0
  218. package/dist/{roo-code-7F4HYB34.js → roo-code-VI2ZKTZC.js} +6 -6
  219. package/dist/roo-code-VI2ZKTZC.js.map +1 -0
  220. package/dist/runtime/index.d.ts +9 -8
  221. package/dist/runtime/index.js +15 -14
  222. package/dist/sdk/index.d.ts +4 -4
  223. package/dist/sdk/index.js +6 -6
  224. package/dist/sdk/index.js.map +1 -1
  225. package/dist/sdk/test.d.ts +2 -2
  226. package/dist/sdk/test.js +12 -11
  227. package/dist/{serve-LYSBH43G.js → serve-6MDLRQS2.js} +17 -16
  228. package/dist/serve-6MDLRQS2.js.map +1 -0
  229. package/dist/{status-PHKKGEW5.js → status-IUP75XHP.js} +11 -11
  230. package/dist/status-IUP75XHP.js.map +1 -0
  231. package/dist/{statusline-ZDD4OZ4F.js → statusline-PRODZV2J.js} +16 -15
  232. package/dist/statusline-PRODZV2J.js.map +1 -0
  233. package/dist/{synthetic-LUT6V6SD.js → synthetic-6FRA7P5Q.js} +4 -4
  234. package/dist/synthetic-6FRA7P5Q.js.map +1 -0
  235. package/dist/{telemetry-HDGMI2BK.js → telemetry-X4PLZEDB.js} +10 -10
  236. package/dist/telemetry-X4PLZEDB.js.map +1 -0
  237. package/dist/{trae-SIQI3C66.js → trae-CPPYASR2.js} +4 -4
  238. package/dist/trae-CPPYASR2.js.map +1 -0
  239. package/dist/{trae-Y67HSDOW.js → trae-VOJXUYRN.js} +6 -6
  240. package/dist/trae-VOJXUYRN.js.map +1 -0
  241. package/dist/{types-JyhpJHJa.d.ts → types-DWXnnx-N.d.ts} +96 -22
  242. package/dist/{uninstall-RWO2GM2I.js → uninstall-BSIJ4QXN.js} +21 -21
  243. package/dist/uninstall-BSIJ4QXN.js.map +1 -0
  244. package/dist/{upgrade-YJCXNUEE.js → upgrade-ZSICU3NE.js} +21 -21
  245. package/dist/upgrade-ZSICU3NE.js.map +1 -0
  246. package/dist/{usage-IWO4RQN6.js → usage-EQUNVSCT.js} +4 -4
  247. package/dist/usage-EQUNVSCT.js.map +1 -0
  248. package/dist/{usage-event-AFFKCLHE.js → usage-event-J5CQ6LNT.js} +16 -15
  249. package/dist/usage-event-J5CQ6LNT.js.map +1 -0
  250. package/dist/{vscode-copilot-5CI5B3X6.js → vscode-copilot-ZBXRPKGG.js} +7 -7
  251. package/dist/vscode-copilot-ZBXRPKGG.js.map +1 -0
  252. package/dist/{warp-5YBSP7FP.js → warp-NRBBJQR2.js} +4 -4
  253. package/dist/warp-NRBBJQR2.js.map +1 -0
  254. package/dist/{warp-INAKVGBV.js → warp-S444B2S3.js} +9 -7
  255. package/dist/warp-S444B2S3.js.map +1 -0
  256. package/dist/{windsurf-4HM57QAY.js → windsurf-R6D2JUTN.js} +6 -6
  257. package/dist/windsurf-R6D2JUTN.js.map +1 -0
  258. package/dist/{zed-YN5X37PQ.js → zed-DQV3ZUCU.js} +10 -8
  259. package/dist/zed-DQV3ZUCU.js.map +1 -0
  260. package/dist/{zed-XXCNYOIN.js → zed-XJFOOKCO.js} +4 -4
  261. package/dist/zed-XJFOOKCO.js.map +1 -0
  262. package/package.json +88 -88
  263. package/dist/action-IPFDPOZU.js.map +0 -1
  264. package/dist/amazon-q-IT44LEWV.js.map +0 -1
  265. package/dist/amp-CEWOSWQO.js.map +0 -1
  266. package/dist/amp-P35FRU2Z.js.map +0 -1
  267. package/dist/antigravity-LHFEFNMC.js.map +0 -1
  268. package/dist/antigravity-TWIWXTQH.js +0 -18
  269. package/dist/antigravity-cli-MOKFSWOU.js.map +0 -1
  270. package/dist/antigravity-cli-MPE27LPI.js.map +0 -1
  271. package/dist/chunk-3EP5V2F4.js.map +0 -1
  272. package/dist/chunk-3FINQ2ZF.js.map +0 -1
  273. package/dist/chunk-4GH2KA7V.js.map +0 -1
  274. package/dist/chunk-7C2IPIIB.js.map +0 -1
  275. package/dist/chunk-7HHW23AC.js.map +0 -1
  276. package/dist/chunk-7PSNXUFK.js.map +0 -1
  277. package/dist/chunk-7ZFK2WEO.js.map +0 -1
  278. package/dist/chunk-C63AAXK7.js.map +0 -1
  279. package/dist/chunk-C747DYNT.js.map +0 -1
  280. package/dist/chunk-FHYR5Q5T.js.map +0 -1
  281. package/dist/chunk-GCPEPUD7.js.map +0 -1
  282. package/dist/chunk-GZZCHJDP.js.map +0 -1
  283. package/dist/chunk-ILWHLGIC.js.map +0 -1
  284. package/dist/chunk-IOJDZJ72.js.map +0 -1
  285. package/dist/chunk-KFPSJRHR.js.map +0 -1
  286. package/dist/chunk-KM2YXO6V.js.map +0 -1
  287. package/dist/chunk-L2C5UMKW.js.map +0 -1
  288. package/dist/chunk-LFWYYWLV.js.map +0 -1
  289. package/dist/chunk-LQ55E7QI.js.map +0 -1
  290. package/dist/chunk-MLU7NDAZ.js.map +0 -1
  291. package/dist/chunk-N4ENLZEU.js.map +0 -1
  292. package/dist/chunk-NDMNMAKP.js.map +0 -1
  293. package/dist/chunk-PSGTHJQU.js.map +0 -1
  294. package/dist/chunk-Q4ISQHUQ.js.map +0 -1
  295. package/dist/chunk-Q7PR2WGT.js.map +0 -1
  296. package/dist/chunk-QYOUQCC6.js.map +0 -1
  297. package/dist/chunk-SLJI5BOM.js.map +0 -1
  298. package/dist/chunk-TGZFDXNH.js.map +0 -1
  299. package/dist/chunk-THI4PI4H.js.map +0 -1
  300. package/dist/chunk-UZZTWWGG.js.map +0 -1
  301. package/dist/chunk-WPTNMYYM.js.map +0 -1
  302. package/dist/chunk-XN7S44U4.js.map +0 -1
  303. package/dist/chunk-XVEJAFKW.js.map +0 -1
  304. package/dist/chunk-XXLCMSD3.js.map +0 -1
  305. package/dist/chunk-XZWMJLIT.js.map +0 -1
  306. package/dist/chunk-Y3K6KJMS.js.map +0 -1
  307. package/dist/chunk-ZSOS2KOR.js.map +0 -1
  308. package/dist/claude-code-FS42PXZO.js.map +0 -1
  309. package/dist/claude-code-QBWDT5RT.js.map +0 -1
  310. package/dist/cline-JKEAYWVR.js.map +0 -1
  311. package/dist/codebuddy-EB6EYPC3.js.map +0 -1
  312. package/dist/codebuff-5RSXFU6G.js.map +0 -1
  313. package/dist/codebuff-6KWBW6CT.js.map +0 -1
  314. package/dist/codex-ART46CDD.js.map +0 -1
  315. package/dist/codex-DKBAAUCO.js.map +0 -1
  316. package/dist/continue-JHZCMSPH.js.map +0 -1
  317. package/dist/copilot-cli-CLBJACQ5.js.map +0 -1
  318. package/dist/copilot-cli-QVAU5CFM.js.map +0 -1
  319. package/dist/crush-7TORBYUL.js.map +0 -1
  320. package/dist/crush-A5C5USRL.js.map +0 -1
  321. package/dist/cursor-D5SWDVSW.js.map +0 -1
  322. package/dist/cursor-W7I4QUFO.js +0 -22
  323. package/dist/detect-JHSA3G3U.js.map +0 -1
  324. package/dist/devin-SSR7S4WX.js.map +0 -1
  325. package/dist/doctor-CQJ7TZPA.js.map +0 -1
  326. package/dist/droid-45PJ7JGF.js.map +0 -1
  327. package/dist/droid-PFQ2PZSF.js.map +0 -1
  328. package/dist/gemini-cli-24PFDK7D.js.map +0 -1
  329. package/dist/gemini-cli-Y6RJMU24.js.map +0 -1
  330. package/dist/goose-K2HKUTBK.js.map +0 -1
  331. package/dist/goose-U5D3LCPC.js.map +0 -1
  332. package/dist/grok-cli-L2MHAPBY.js.map +0 -1
  333. package/dist/hermes-2S5JUTTJ.js.map +0 -1
  334. package/dist/hermes-MF3NX4ZY.js.map +0 -1
  335. package/dist/hook-VHICXHXL.js.map +0 -1
  336. package/dist/install-WLENR4KF.js.map +0 -1
  337. package/dist/jetbrains-copilot-Z4FC3RM3.js.map +0 -1
  338. package/dist/junie-ULGJJIHB.js.map +0 -1
  339. package/dist/kilo-SMHPOHJ5.js.map +0 -1
  340. package/dist/kilo-WWIJOVWD.js.map +0 -1
  341. package/dist/kilo-cli-QKE2EQLS.js.map +0 -1
  342. package/dist/kilo-cli-T2SRRRJS.js.map +0 -1
  343. package/dist/kimi-JMUFTVSF.js.map +0 -1
  344. package/dist/kimi-MSIDEMCI.js.map +0 -1
  345. package/dist/kiro-NYRRBIKW.js.map +0 -1
  346. package/dist/kiro-UWUCRKR3.js.map +0 -1
  347. package/dist/leaderboard-NJWKGMXP.js.map +0 -1
  348. package/dist/mimo-code-BPNYYIVM.js.map +0 -1
  349. package/dist/mistral-vibe-LT3DAJ3L.js.map +0 -1
  350. package/dist/mux-7PIJ7HUQ.js.map +0 -1
  351. package/dist/mux-AHNUAY5Z.js.map +0 -1
  352. package/dist/nemoclaw-RE5RZASZ.js.map +0 -1
  353. package/dist/omp-D2EXEPH7.js.map +0 -1
  354. package/dist/open-interpreter-SSGBEUKX.js.map +0 -1
  355. package/dist/openclaw-IJ33K45M.js +0 -17
  356. package/dist/openclaw-KAFTNLR2.js.map +0 -1
  357. package/dist/opencode-YKUKZY3J.js.map +0 -1
  358. package/dist/opencode-Z65JYILL.js.map +0 -1
  359. package/dist/openhands-SEZMCUC3.js.map +0 -1
  360. package/dist/package-JECVQEFT.js.map +0 -1
  361. package/dist/pi-DLKCPOJE.js.map +0 -1
  362. package/dist/pi-YPYV2ULH.js.map +0 -1
  363. package/dist/qwen-code-26CSFDX6.js.map +0 -1
  364. package/dist/qwen-code-ZHCLCYMC.js.map +0 -1
  365. package/dist/roo-code-7F4HYB34.js.map +0 -1
  366. package/dist/roo-code-HSAE2CJU.js.map +0 -1
  367. package/dist/serve-LYSBH43G.js.map +0 -1
  368. package/dist/status-PHKKGEW5.js.map +0 -1
  369. package/dist/statusline-ZDD4OZ4F.js.map +0 -1
  370. package/dist/synthetic-LUT6V6SD.js.map +0 -1
  371. package/dist/telemetry-HDGMI2BK.js.map +0 -1
  372. package/dist/trae-SIQI3C66.js.map +0 -1
  373. package/dist/trae-Y67HSDOW.js.map +0 -1
  374. package/dist/uninstall-RWO2GM2I.js.map +0 -1
  375. package/dist/upgrade-YJCXNUEE.js.map +0 -1
  376. package/dist/usage-IWO4RQN6.js.map +0 -1
  377. package/dist/usage-event-AFFKCLHE.js.map +0 -1
  378. package/dist/vscode-copilot-5CI5B3X6.js.map +0 -1
  379. package/dist/warp-5YBSP7FP.js.map +0 -1
  380. package/dist/warp-INAKVGBV.js.map +0 -1
  381. package/dist/windsurf-4HM57QAY.js.map +0 -1
  382. package/dist/zed-XXCNYOIN.js.map +0 -1
  383. package/dist/zed-YN5X37PQ.js.map +0 -1
  384. /package/dist/{antigravity-TWIWXTQH.js.map → antigravity-VXHL6ZPM.js.map} +0 -0
  385. /package/dist/{audit-3E5JAOP2.js.map → audit-BO7JQYIH.js.map} +0 -0
  386. /package/dist/{cursor-W7I4QUFO.js.map → cursor-RSLHA2CY.js.map} +0 -0
  387. /package/dist/{openclaw-IJ33K45M.js.map → openclaw-3DHVHX5P.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/usage/readers/kimi.ts"],"sourcesContent":["/**\r\n * usage/readers/kimi — Moonshot native session-log reader (TWO products).\r\n *\r\n * Originally a faithful port of tokscale sessions/kimi.rs (origin of the Kimi\r\n * CLI wire parse), this reader now PARSES BOTH Moonshot products that share the\r\n * \"kimi\" platform id. They lay out their logs DIFFERENTLY *and* write a\r\n * different wire.jsonl record shape, so the parser auto-routes per line (a given\r\n * wire.jsonl is one product's format; no root-based branching is needed):\r\n *\r\n * - Kimi CLI (older, ~/.kimi):\r\n * ~/.kimi/sessions/<GROUP_ID>/<SESSION_UUID>/wire.jsonl\r\n * config.json sits at ~/.kimi/config.json. This is the tree tokscale's\r\n * sessions/kimi.rs reads and the one this port was first written against.\r\n * PARSE MODEL: progressive `message.type===\"StatusUpdate\"` snapshots,\r\n * deduped by `payload.message_id` keeping the MAX total (see parseKimiFile).\r\n *\r\n * - Kimi Code (newer, @moonshot-ai/kimi-code, ~/.kimi-code):\r\n * ~/.kimi-code/sessions/<SESSION>/agents/<AGENT>/wire.jsonl\r\n * config.json sits at ~/.kimi-code/config.json. This is a DEEPER tree (an\r\n * extra `agents/<AGENT>/` level) — the product our connector adapter\r\n * targets. The `~/.kimi-code` base + `$KIMI_CODE_HOME` override are\r\n * primary-doc-confirmed (moonshotai.github.io/kimi-code/en/configuration/\r\n * config-files.html), as is the `wire.jsonl` filename (\"the agent event\r\n * stream\", moonshotai.github.io/kimi-code docs).\r\n * PARSE MODEL: per-LLM-call usage DELTAS, SUMMED (see parseKimiCodeFile).\r\n *\r\n * Both default trees are scanned (Kimi Code preferred first); $KIMI_CODE_HOME\r\n * relocates the Kimi Code home and is honored ahead of the defaults; the\r\n * AGENT_CONNECTOR_KIMI_DIR override (via paths.ts hostRoots) is honored first.\r\n *\r\n * ─── Kimi CLI wire frame parse (port of tokscale sessions/kimi.rs) ───\r\n * Each line is a timestamped wire frame; only frames whose\r\n * `message.type === \"StatusUpdate\"` carry a `payload.token_usage` block:\r\n * input_other → input\r\n * output → output\r\n * input_cache_read → cacheRead\r\n * input_cache_creation → cacheWrite (cache CREATION cost, not a read)\r\n * reasoning is always 0 (the wire protocol folds reasoning into output).\r\n * The first line (`{\"type\":\"metadata\", …}`) and every non-StatusUpdate frame\r\n * (TurnBegin / ContentPart / ToolCall / StepBegin …) are skipped. Zero-token\r\n * StatusUpdates are dropped.\r\n * DEDUP (the double-counting hazard): Kimi CLI emits PROGRESSIVE StatusUpdates\r\n * for a single assistant message as generation streams (e.g. message_id \"msg-x\"\r\n * at 100→10 tokens, then 120→30). We dedup by `payload.message_id`, keeping the\r\n * row with the MAX total tokens (tie-break: the later timestamp). Records\r\n * WITHOUT a (non-empty) message_id are never merged — each passes through as its\r\n * own row, exactly as the Rust push_or_replace_status_update does. The kept\r\n * row's `dedupKey` is its message_id (absent for un-keyed rows).\r\n *\r\n * ─── Kimi Code wire record parse (SOURCE-VERIFIED from MoonshotAI/kimi-code) ───\r\n * The on-disk usage record is `{ type:\"usage.record\", time?, model, usage,\r\n * usageScope? }` — verified against the readable (non-minified) TypeScript\r\n * source:\r\n * - packages/agent-core/src/agent/records/types.ts → the wire.jsonl usage\r\n * record shape `{ type:\"usage.record\", time?:number, model:string,\r\n * usage:TokenUsage, usageScope?:\"session\"|\"turn\" }`.\r\n * - packages/kosong/src/usage.ts → `TokenUsage = { inputOther, output,\r\n * inputCacheRead, inputCacheCreation }` (camelCase; NO reasoning field).\r\n * - packages/agent-core/src/agent/usage/index.ts `record(model, usage, scope)`\r\n * logs exactly ONE `usage.record` per LLM call carrying that call's per-call\r\n * DELTA usage; the canonical session total is the SUM of all deltas\r\n * (`addUsage`), confirmed by packages/agent-core/test/agent/usage.test.ts\r\n * (record(inputOther:1)+record(inputOther:10) ⇒ total inputOther:11).\r\n * - `usageScope` ('session'|'turn') only drives an IN-MEMORY currentTurn\r\n * rollup; exactly one `usage.record` is written per record() call, so SUMMING\r\n * ALL usage.record deltas of ANY scope = the correct session total with NO\r\n * double-count. We deliberately do NOT filter or dedup by scope.\r\n * Field map (TokenUsage → TokenBreakdown):\r\n * inputOther → input\r\n * output → output\r\n * inputCacheRead → cacheRead\r\n * inputCacheCreation → cacheWrite\r\n * reasoning is always 0 (TokenUsage has no reasoning field).\r\n * Each usage.record is a DELTA, so each becomes its OWN row (no message_id\r\n * dedup; dedupKey is absent so aggregation never merges them) and the rows SUM\r\n * downstream. Zero-token records are dropped (consistent with the CLI path).\r\n * Per-record `model` is taken from the record itself (DEFAULT_MODEL fallback),\r\n * so the config.json walk is NOT consulted for the Kimi Code model. Timestamp is\r\n * `record.time` normalized via normalizeTimestampMs (>1e12 ⇒ ms, else\r\n * seconds×1000), falling back to the file mtime like the CLI path.\r\n *\r\n * Model (Kimi CLI only): `.model` from <home>/config.json (fallback\r\n * \"kimi-for-coding\"), where <home> is found by walking UP from wire.jsonl to the\r\n * nearest dir containing config.json — depth-robust, so it lands on ~/.kimi for\r\n * the CLI tree (and would land on ~/.kimi-code for the deeper tree, though Kimi\r\n * Code records carry their own model). Provider is hard-coded \"moonshot\".\r\n * Session id is the immediate parent dir of wire.jsonl: the SESSION_UUID for\r\n * Kimi CLI; for the deeper Kimi Code tree that is the <AGENT> dir (the best\r\n * available id at that depth — documented, acceptable). Kimi's wire log carries\r\n * no cwd, so there is no project attribution. Confidence is \"host-reported\"\r\n * (real host token counts).\r\n *\r\n * Fail-open: no root → []; an unreadable/malformed file or line → skipped.\r\n */\r\n\r\nimport { basename, dirname, join } from \"node:path\";\r\n\r\nimport type { TokenBreakdown, UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { fileMtimeMs, readJsonFile, readJsonlLines } from \"../jsonl.js\";\r\nimport { expandHome, hostRoots, isDir, isFile, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"kimi\" as const;\r\nconst DEFAULT_MODEL = \"kimi-for-coding\";\r\nconst DEFAULT_PROVIDER = \"moonshot\";\r\n\r\n/**\r\n * Bound on the upward config.json walk. Kimi CLI needs 4 hops (wire.jsonl →\r\n * UUID → GROUP → sessions → home); Kimi Code's deeper tree needs 5 (wire.jsonl →\r\n * AGENT → agents → SESSION → sessions → home). 6 leaves headroom without letting\r\n * a stray config.json far up the filesystem masquerade as the Kimi home.\r\n */\r\nconst MAX_HOME_WALK_LEVELS = 6;\r\n\r\n/** A Kimi CLI wire.jsonl line: metadata header OR a timestamped message frame. */\r\ninterface WireLine {\r\n type?: unknown;\r\n timestamp?: unknown;\r\n message?: {\r\n type?: unknown;\r\n payload?: {\r\n token_usage?: {\r\n input_other?: unknown;\r\n output?: unknown;\r\n input_cache_read?: unknown;\r\n input_cache_creation?: unknown;\r\n };\r\n message_id?: unknown;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * A Kimi Code wire.jsonl `usage.record` line (SOURCE-VERIFIED, see header). The\r\n * `usage` block is TokenUsage (camelCase, no reasoning); `time` is the record\r\n * timestamp; `model` is the per-call model; `usageScope` is informational only\r\n * and intentionally not read (every record is summed regardless of scope).\r\n */\r\ninterface KimiCodeUsageRecord {\r\n type?: unknown;\r\n time?: unknown;\r\n model?: unknown;\r\n usage?: {\r\n inputOther?: unknown;\r\n output?: unknown;\r\n inputCacheRead?: unknown;\r\n inputCacheCreation?: 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/**\r\n * Convert the Kimi CLI wire `timestamp` (Unix seconds, often fractional like\r\n * 1770983426.420942) to epoch ms. Returns null when unusable so the caller can\r\n * fall back to the file mtime (port of `timestamp * 1000.0 as i64`).\r\n */\r\nfunction parseWireTs(v: unknown): number | null {\r\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) {\r\n return Math.trunc(v * 1000);\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Normalize a Kimi Code `usage.record.time` to epoch ms, disambiguating\r\n * seconds-vs-ms by magnitude (the repo-wide convention): a value already in ms\r\n * (> 1e12) passes through truncated; a smaller value is treated as Unix seconds\r\n * (× 1000). Returns null when unusable so the caller falls back to the file mtime.\r\n */\r\nfunction normalizeTimestampMs(v: unknown): number | null {\r\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) {\r\n return v > 1e12 ? Math.trunc(v) : Math.trunc(v * 1000);\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Find the Kimi home for a wire.jsonl and read its `.model` (depth-robust\r\n * evolution of the Rust read_model_from_config). The two product trees differ in\r\n * DEPTH:\r\n * Kimi CLI : <home>/sessions/<GROUP_ID>/<SESSION_UUID>/wire.jsonl (4 hops)\r\n * Kimi Code: <home>/sessions/<SESSION>/agents/<AGENT>/wire.jsonl (5 hops)\r\n * A fixed dirname-hop count would land on `sessions/` for the deeper tree, so we\r\n * walk UP the ancestor chain (bounded by MAX_HOME_WALK_LEVELS) reading the first\r\n * `config.json` found — but the home is DEFINITIONALLY the parent of the\r\n * `sessions/` segment, so the moment we reach the `sessions` dir we read its\r\n * parent's config.json and STOP. That hard ceiling keeps the search inside the\r\n * Kimi home: it can never escape into an ancestor (e.g. a repo's or $HOME's stray\r\n * config.json) when the real home lacks one. For the Kimi CLI tree this resolves\r\n * the SAME <home> as the old 4-hop logic, so CLI behavior is byte-identical.\r\n * Fail-open to DEFAULT_MODEL on no config.json or any missing/garbage value.\r\n */\r\nfunction modelFromConfigAt(dir: string): string {\r\n const parsed = readJsonFile(join(dir, \"config.json\"));\r\n if (typeof parsed === \"object\" && parsed !== null) {\r\n const model = (parsed as { model?: unknown }).model;\r\n if (typeof model === \"string\" && model !== \"\") return model;\r\n }\r\n return DEFAULT_MODEL; // config.json absent/unreadable or no usable .model\r\n}\r\n\r\nfunction readModelFromConfig(wirePath: string): string {\r\n let dir = dirname(wirePath);\r\n for (let level = 0; level <= MAX_HOME_WALK_LEVELS; level += 1) {\r\n if (isFile(join(dir, \"config.json\"))) return modelFromConfigAt(dir);\r\n // The home is the parent of the `sessions/` segment — read it and STOP so the\r\n // walk never climbs above the Kimi home into a stray ancestor config.json.\r\n if (basename(dir) === \"sessions\") return modelFromConfigAt(dirname(dir));\r\n const parent = dirname(dir);\r\n if (parent === dir) break; // reached filesystem root\r\n dir = parent;\r\n }\r\n return DEFAULT_MODEL;\r\n}\r\n\r\n/**\r\n * Session id from the wire path: the immediate parent directory of wire.jsonl\r\n * (port of extract_session_id, UNCHANGED). For Kimi CLI that is the SESSION_UUID;\r\n * for the deeper Kimi Code tree (.../sessions/<SESSION>/agents/<AGENT>/wire.jsonl)\r\n * that is the <AGENT> dir — the best available id at that depth (documented,\r\n * acceptable). Keeping the immediate-parent rule keeps Kimi CLI byte-identical.\r\n */\r\nfunction extractSessionId(wirePath: string): string {\r\n const dir = basename(dirname(wirePath));\r\n return dir === \"\" ? \"unknown\" : dir;\r\n}\r\n\r\n/** Sum of the five token dimensions (port of TokenBreakdown::total). */\r\nfunction tokenTotal(t: TokenBreakdown): number {\r\n return t.input + t.output + t.cacheRead + t.cacheWrite + t.reasoning;\r\n}\r\n\r\n/**\r\n * Whether `candidate` should replace `existing` for the same message_id. Port of\r\n * should_replace_status_update: a strictly larger total wins; on an equal total\r\n * the later-or-equal timestamp wins (so the freshest progressive update is kept).\r\n */\r\nfunction shouldReplace(existing: UsageRecord, candidate: UsageRecord): boolean {\r\n const existingTotal = tokenTotal(existing.tokens);\r\n const candidateTotal = tokenTotal(candidate.tokens);\r\n return (\r\n candidateTotal > existingTotal ||\r\n (candidateTotal === existingTotal && candidate.ts >= existing.ts)\r\n );\r\n}\r\n\r\n/** Parse one Kimi wire.jsonl file into usage records (port of parse_kimi_file). */\r\nfunction parseKimiFile(path: string): UsageRecord[] {\r\n const lines = readJsonlLines(path);\r\n if (lines.length === 0) return [];\r\n\r\n const model = readModelFromConfig(path);\r\n const sessionId = extractSessionId(path);\r\n const mtime = fileMtimeMs(path);\r\n\r\n const out: UsageRecord[] = [];\r\n // message_id → index into `out`, for progressive-StatusUpdate dedup.\r\n const keyedIndices = new Map<string, number>();\r\n\r\n for (const raw of lines) {\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const wire = raw as WireLine;\r\n\r\n // Skip the metadata header line.\r\n if (wire.type === \"metadata\") continue;\r\n\r\n const message = wire.message;\r\n if (typeof message !== \"object\" || message === null) continue;\r\n\r\n // Only StatusUpdate frames carry token usage.\r\n if (message.type !== \"StatusUpdate\") continue;\r\n\r\n const payload = message.payload;\r\n if (typeof payload !== \"object\" || payload === null) continue;\r\n\r\n const usage = payload.token_usage;\r\n if (typeof usage !== \"object\" || usage === null) continue;\r\n\r\n const input = toNonNegInt(usage.input_other);\r\n const output = toNonNegInt(usage.output);\r\n const cacheRead = toNonNegInt(usage.input_cache_read);\r\n const cacheWrite = toNonNegInt(usage.input_cache_creation);\r\n\r\n // Skip zero-token entries.\r\n if (input + output + cacheRead + cacheWrite === 0) continue;\r\n\r\n const ts = parseWireTs(wire.timestamp) ?? mtime;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = cacheWrite;\r\n // reasoning stays 0 — the Kimi wire protocol folds reasoning into output.\r\n\r\n const messageId = payload.message_id;\r\n const dedupKey =\r\n typeof messageId === \"string\" && messageId !== \"\" ? messageId : undefined;\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId: model,\r\n providerId: DEFAULT_PROVIDER,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n confidence: \"host-reported\",\r\n };\r\n if (dedupKey !== undefined) record.dedupKey = dedupKey;\r\n\r\n if (dedupKey === undefined) {\r\n // Un-keyed StatusUpdates are never merged — each is its own row.\r\n out.push(record);\r\n continue;\r\n }\r\n\r\n const existingIndex = keyedIndices.get(dedupKey);\r\n if (existingIndex !== undefined) {\r\n const existing = out[existingIndex];\r\n if (existing !== undefined && shouldReplace(existing, record)) {\r\n out[existingIndex] = record;\r\n }\r\n continue;\r\n }\r\n\r\n keyedIndices.set(dedupKey, out.length);\r\n out.push(record);\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Parse one Kimi Code wire.jsonl file into usage records (SOURCE-VERIFIED, see\r\n * header). Each `type === \"usage.record\"` line is a per-LLM-call usage DELTA;\r\n * we emit each as its OWN row (NO message_id dedup — dedupKey is absent so\r\n * aggregation never merges them) and the rows SUM to the canonical session\r\n * total. usageScope is ignored on purpose: exactly one usage.record is written\r\n * per record() call, so summing all deltas of any scope never double-counts.\r\n * Non-usage.record lines (metadata, turn_begin, …) are skipped; zero-token\r\n * records are dropped, matching the CLI path.\r\n */\r\nfunction parseKimiCodeFile(path: string): UsageRecord[] {\r\n const lines = readJsonlLines(path);\r\n if (lines.length === 0) return [];\r\n\r\n const sessionId = extractSessionId(path);\r\n const mtime = fileMtimeMs(path);\r\n\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 rec = raw as KimiCodeUsageRecord;\r\n\r\n // Only usage.record lines carry token usage in the Kimi Code format.\r\n if (rec.type !== \"usage.record\") continue;\r\n\r\n const usage = rec.usage;\r\n if (typeof usage !== \"object\" || usage === null) continue;\r\n\r\n // TokenUsage → TokenBreakdown (camelCase source fields; no reasoning field).\r\n const input = toNonNegInt(usage.inputOther);\r\n const output = toNonNegInt(usage.output);\r\n const cacheRead = toNonNegInt(usage.inputCacheRead);\r\n const cacheWrite = toNonNegInt(usage.inputCacheCreation);\r\n\r\n // Skip zero-token deltas (consistent with the CLI path).\r\n if (input + output + cacheRead + cacheWrite === 0) continue;\r\n\r\n const ts = normalizeTimestampMs(rec.time) ?? mtime;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = cacheWrite;\r\n // reasoning stays 0 — Kimi Code's TokenUsage has no reasoning field.\r\n\r\n const model =\r\n typeof rec.model === \"string\" && rec.model !== \"\" ? rec.model : DEFAULT_MODEL;\r\n\r\n // Each delta is its own row (no dedupKey ⇒ never merged at aggregation).\r\n out.push({\r\n platformId: PLATFORM_ID,\r\n modelId: model,\r\n providerId: DEFAULT_PROVIDER,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n confidence: \"host-reported\",\r\n });\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/**\r\n * Detect which product wrote a wire.jsonl by its record shape (a given file is\r\n * ONE product's format). A file is Kimi Code iff it carries any\r\n * `type === \"usage.record\"` line; otherwise it is parsed as Kimi CLI. This keeps\r\n * the Kimi CLI path (parseKimiFile) provably untouched — a CLI StatusUpdate file\r\n * has no usage.record line and routes to parseKimiFile byte-identically.\r\n */\r\nfunction parseWireFile(path: string): UsageRecord[] {\r\n const lines = readJsonlLines(path);\r\n for (const raw of lines) {\r\n if (typeof raw === \"object\" && raw !== null && (raw as KimiCodeUsageRecord).type === \"usage.record\") {\r\n return parseKimiCodeFile(path);\r\n }\r\n }\r\n return parseKimiFile(path);\r\n}\r\n\r\n/**\r\n * Candidate Kimi session roots, most-preferred first. Covers BOTH Moonshot\r\n * products under the \"kimi\" id:\r\n * 1. $KIMI_CODE_HOME/sessions — Kimi Code's relocated home, when set (the env\r\n * var our adapter and the official kimi-code docs honor).\r\n * 2. paths.ts hostRoots(\"kimi\"), in order:\r\n * - AGENT_CONNECTOR_KIMI_DIR/sessions (explicit framework override)\r\n * - ~/.kimi-code/sessions (Kimi Code default — preferred)\r\n * - ~/.kimi/sessions (Kimi CLI default)\r\n * All existing roots are scanned (not just the first) so a box running BOTH\r\n * products is fully covered; the reader's `seen` set de-overlaps any duplicate\r\n * wire.jsonl reached via two roots (e.g. KIMI_CODE_HOME == ~/.kimi-code).\r\n */\r\nfunction kimiSessionRoots(): string[] {\r\n const roots: string[] = [];\r\n\r\n const codeHome = process.env.KIMI_CODE_HOME;\r\n if (codeHome != null && codeHome.trim() !== \"\") {\r\n roots.push(join(expandHome(codeHome.trim()), \"sessions\"));\r\n }\r\n\r\n // hostRoots already prepends the AGENT_CONNECTOR_KIMI_DIR override and lists\r\n // ~/.kimi-code/sessions then ~/.kimi/sessions as the two product defaults.\r\n for (const root of hostRoots(PLATFORM_ID)) roots.push(root);\r\n\r\n return roots;\r\n}\r\n\r\n/** The Kimi CLI usage reader singleton. */\r\nconst kimiReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const roots = kimiSessionRoots().filter((r) => isDir(r));\r\n if (roots.length === 0) return []; // no session root present → fail-open\r\n\r\n // Kimi CLI : <root>/<GROUP_ID>/<SESSION_UUID>/wire.jsonl\r\n // Kimi Code: <root>/<SESSION>/agents/<AGENT>/wire.jsonl (deeper — walkFiles\r\n // recurses, so the extra `agents/` level is found transparently).\r\n // parseWireFile routes each file to its product parser by record shape.\r\n const seen = new Set<string>();\r\n const records: UsageRecord[] = [];\r\n for (const root of roots) {\r\n const files = walkFiles(root, (name) => name === \"wire.jsonl\");\r\n for (const file of files) {\r\n if (seen.has(file)) continue; // de-overlap across overlapping roots\r\n seen.add(file);\r\n const rows = parseWireFile(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 }\r\n return records;\r\n },\r\n};\r\n\r\nexport default kimiReader;\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/usage/readers/kiro.ts"],"sourcesContent":["/**\r\n * usage/readers/kiro — Kiro CLI (Amazon Bedrock) native session reader.\r\n *\r\n * Faithful port of tokscale sessions/kiro.rs (parse_kiro_file). Each session is a\r\n * pair of adjacent files under ~/.kiro/sessions/cli/:\r\n * <stem>.json — header: session_id, cwd, and session_state with the model\r\n * info (model_id, context_window_tokens) and the per-turn\r\n * metadata list (user_turn_metadatas[*]).\r\n * <stem>.jsonl — a transcript of Prompt / AssistantMessage entries keyed by\r\n * message_id, used ONLY to estimate per-turn char counts when\r\n * the header carries no explicit token counts.\r\n *\r\n * Token logic (per turn), ported exactly from the Rust:\r\n * input = input_token_count when > 0 (host-reported)\r\n * else context_window × context_usage_percentage/100 when both > 0\r\n * else ceil(promptChars / 4) (host-estimated)\r\n * output = output_token_count when > 0 (host-reported)\r\n * else ceil(assistantChars / 4) (host-estimated)\r\n * cacheRead / cacheWrite / reasoning are always 0 (Kiro reports none).\r\n * A turn whose input+output == 0 is dropped (matches the Rust filter_map).\r\n *\r\n * Confidence is per-record: \"host-reported\" only when BOTH dimensions came from\r\n * explicit host counts; any estimation (context% × window, or chars/4) makes the\r\n * row \"host-estimated\" (design §6: Kiro token counts are often estimated).\r\n *\r\n * Provider is hardcoded \"amazon-bedrock\". Session id is the header's session_id\r\n * (else the JSON file stem). Project is header.cwd normalized to a workspace key.\r\n * Timestamp prefers the matched Prompt entry's meta.timestamp (float seconds →\r\n * ms), then end_timestamp (int/float seconds-or-ms / RFC3339 string), then file\r\n * mtime. Dedup key is `<sessionId>:<turnIndex>` (turn-level uniqueness across\r\n * file rewrites), exactly the Rust format!(\"{}:{}\", session_id, index).\r\n *\r\n * NOTE: kiro.rs also reads a macOS SQLite source\r\n * (~/Library/Application Support/kiro-cli/data.sqlite3, table conversations_v2).\r\n * That source is intentionally NOT read in v1 — only the json/jsonl file pairs\r\n * are parsed here.\r\n *\r\n * Fail-open: no root → []; unreadable/malformed json or jsonl → that file is\r\n * skipped (the jsonl is optional — its absence just leaves char estimation at 0).\r\n */\r\n\r\nimport { basename } from \"node:path\";\r\n\r\nimport type { UsageReader, UsageRecord, UsageConfidence } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { fileMtimeMs, readJsonFile, readJsonlLines } from \"../jsonl.js\";\r\nimport { normalizeWorkspaceKey, workspaceLabelFromKey } from \"../normalize.js\";\r\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"kiro\" as const;\r\nconst PROVIDER_ID = \"amazon-bedrock\";\r\nconst UNKNOWN_MODEL = \"unknown\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Header (.json) shapes — every field optional / unknown (host may omit any).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\ninterface KiroHeader {\r\n session_id?: unknown;\r\n cwd?: unknown;\r\n session_state?: {\r\n rts_model_state?: {\r\n model_info?: {\r\n model_id?: unknown;\r\n context_window_tokens?: unknown;\r\n };\r\n };\r\n conversation_metadata?: {\r\n user_turn_metadatas?: unknown;\r\n };\r\n };\r\n}\r\n\r\ninterface KiroTurn {\r\n input_token_count?: unknown;\r\n output_token_count?: unknown;\r\n end_timestamp?: unknown;\r\n total_request_count?: unknown;\r\n message_ids?: unknown;\r\n context_usage_percentage?: unknown;\r\n}\r\n\r\n/** Accumulated char counts (and first prompt ts) for one message_id. */\r\ninterface KiroMessageContent {\r\n promptChars: number;\r\n assistantChars: number;\r\n promptTimestampMs: number | null;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Coercion helpers (tolerant — garbage degrades to a safe default).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Coerce to a finite number, or null when not numeric. */\r\nfunction toNum(v: unknown): number | null {\r\n if (typeof v === \"number\" && Number.isFinite(v)) return v;\r\n if (typeof v === \"string\") {\r\n const n = Number(v);\r\n if (Number.isFinite(n)) return n;\r\n }\r\n return null;\r\n}\r\n\r\n/** Coerce to an integer clamped ≥ 0 (Rust `.unwrap_or(0).max(0)`). */\r\nfunction toNonNegInt(v: unknown): number {\r\n const n = toNum(v);\r\n if (n === null) return 0;\r\n return Math.max(0, Math.trunc(n));\r\n}\r\n\r\n/** ceil(chars / 4) — Rust div_ceil estimation (4 chars per token). */\r\nfunction estimateTokens(chars: number): number {\r\n return Math.ceil(Math.max(0, chars) / 4);\r\n}\r\n\r\n/** float seconds → epoch ms (Rust seconds_to_millis: truncating). */\r\nfunction secondsToMillis(seconds: number): number {\r\n return Math.trunc(seconds * 1000);\r\n}\r\n\r\n/** Strip a single file extension from a basename. */\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 * Parse end_timestamp (port of parse_timestamp_value): a number < 1e12 is\r\n * seconds (→ ms), ≥ 1e12 is already ms; a string is RFC3339, else numeric\r\n * seconds. Returns null when unusable.\r\n */\r\nfunction parseTimestampValue(v: unknown): number | null {\r\n if (typeof v === \"number\" && Number.isFinite(v)) {\r\n return Math.abs(v) < 1_000_000_000_000 ? secondsToMillis(v) : Math.trunc(v);\r\n }\r\n if (typeof v === \"string\") {\r\n const ms = Date.parse(v);\r\n if (!Number.isNaN(ms)) return ms;\r\n const n = Number(v);\r\n if (Number.isFinite(n)) return secondsToMillis(n);\r\n }\r\n return null;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// JSONL transcript → per-message char counts (port of the BufReader loop).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Sum chars of the \"text\" parts of a content array (kind absent ⇒ text). */\r\nfunction textCharCount(content: unknown): number {\r\n if (!Array.isArray(content)) return 0;\r\n let total = 0;\r\n for (const part of content) {\r\n if (typeof part !== \"object\" || part === null) continue;\r\n const kind = (part as { kind?: unknown }).kind;\r\n const isText = kind === undefined || kind === null || kind === \"text\";\r\n if (!isText) continue;\r\n const data = (part as { data?: unknown }).data;\r\n if (typeof data === \"string\") total += [...data].length; // chars, not UTF-16 units\r\n }\r\n return total;\r\n}\r\n\r\n/**\r\n * Build message_id → char-count map from the adjacent .jsonl, exactly as the\r\n * Rust: a \"Prompt\" entry stages a pending (chars, ts); the next\r\n * \"AssistantMessage\" attaches the staged prompt to that assistant's message_id\r\n * and adds the assistant's own chars. A missing/empty jsonl yields an empty map.\r\n */\r\nfunction readJsonlContent(jsonlPath: string): Map<string, KiroMessageContent> {\r\n const byId = new Map<string, KiroMessageContent>();\r\n const lines = readJsonlLines(jsonlPath);\r\n if (lines.length === 0) return byId;\r\n\r\n let pendingPromptChars: number | null = null;\r\n let pendingPromptTs: number | null = null;\r\n\r\n for (const raw of lines) {\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const entry = raw as { kind?: unknown; data?: unknown };\r\n const kind = entry.kind;\r\n const data = entry.data;\r\n if (typeof data !== \"object\" || data === null) continue;\r\n\r\n const messageId = (data as { message_id?: unknown }).message_id;\r\n if (typeof messageId !== \"string\") continue;\r\n\r\n const textChars = textCharCount((data as { content?: unknown }).content);\r\n\r\n if (kind === \"Prompt\") {\r\n const metaTs = (data as { meta?: { timestamp?: unknown } }).meta?.timestamp;\r\n const tsNum = toNum(metaTs);\r\n pendingPromptChars = textChars;\r\n pendingPromptTs = tsNum === null ? null : secondsToMillis(tsNum);\r\n } else if (kind === \"AssistantMessage\") {\r\n let msg = byId.get(messageId);\r\n if (msg === undefined) {\r\n msg = { promptChars: 0, assistantChars: 0, promptTimestampMs: null };\r\n byId.set(messageId, msg);\r\n }\r\n if (pendingPromptChars !== null) {\r\n msg.promptChars += pendingPromptChars;\r\n if (msg.promptTimestampMs === null) msg.promptTimestampMs = pendingPromptTs;\r\n pendingPromptChars = null;\r\n pendingPromptTs = null;\r\n }\r\n msg.assistantChars += textChars;\r\n }\r\n // other kinds are ignored\r\n }\r\n return byId;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// One session (.json + adjacent .jsonl) → usage records.\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\nfunction parseKiroFile(jsonPath: string): UsageRecord[] {\r\n const header = readJsonFile(jsonPath);\r\n if (typeof header !== \"object\" || header === null) return []; // malformed → skip\r\n const h = header as KiroHeader;\r\n\r\n const fallbackTs = fileMtimeMs(jsonPath);\r\n\r\n const sessionId =\r\n typeof h.session_id === \"string\" && h.session_id !== \"\"\r\n ? h.session_id\r\n : stripExt(basename(jsonPath)) || \"unknown\";\r\n\r\n const modelInfo = h.session_state?.rts_model_state?.model_info;\r\n const rawModel = modelInfo?.model_id;\r\n const modelId =\r\n typeof rawModel === \"string\" && rawModel.trim() !== \"\" ? rawModel : UNKNOWN_MODEL;\r\n const contextWindow = toNonNegInt(modelInfo?.context_window_tokens);\r\n\r\n let projectKey: string | undefined;\r\n let projectLabel: string | undefined;\r\n if (typeof h.cwd === \"string\") {\r\n projectKey = normalizeWorkspaceKey(h.cwd);\r\n if (projectKey !== undefined) projectLabel = workspaceLabelFromKey(projectKey);\r\n }\r\n\r\n const turnsRaw = h.session_state?.conversation_metadata?.user_turn_metadatas;\r\n const turns: KiroTurn[] = Array.isArray(turnsRaw) ? (turnsRaw as KiroTurn[]) : [];\r\n if (turns.length === 0) return [];\r\n\r\n // Adjacent .jsonl (same stem) drives char-based estimation.\r\n const jsonlPath = jsonPath.replace(/\\.json$/, \".jsonl\");\r\n const contentById = readJsonlContent(jsonlPath);\r\n\r\n const out: UsageRecord[] = [];\r\n\r\n turns.forEach((turn, index) => {\r\n if (typeof turn !== \"object\" || turn === null) return;\r\n\r\n // Aggregate char counts / first prompt ts over this turn's message_ids.\r\n let promptChars = 0;\r\n let assistantChars = 0;\r\n let promptTimestampMs: number | null = null;\r\n const messageIds = turn.message_ids;\r\n if (Array.isArray(messageIds)) {\r\n for (const mid of messageIds) {\r\n if (typeof mid !== \"string\") continue;\r\n const content = contentById.get(mid);\r\n if (content === undefined) continue;\r\n promptChars += content.promptChars;\r\n assistantChars += content.assistantChars;\r\n if (promptTimestampMs === null) promptTimestampMs = content.promptTimestampMs;\r\n }\r\n }\r\n\r\n const explicitInput = toNonNegInt(turn.input_token_count);\r\n const explicitOutput = toNonNegInt(turn.output_token_count);\r\n\r\n let input: number;\r\n let inputEstimated: boolean;\r\n if (explicitInput > 0) {\r\n input = explicitInput;\r\n inputEstimated = false;\r\n } else {\r\n inputEstimated = true;\r\n const ctxPct = toNum(turn.context_usage_percentage) ?? 0;\r\n if (contextWindow > 0 && ctxPct > 0) {\r\n input = Math.trunc((contextWindow * ctxPct) / 100);\r\n } else {\r\n input = estimateTokens(promptChars);\r\n }\r\n }\r\n\r\n let output: number;\r\n let outputEstimated: boolean;\r\n if (explicitOutput > 0) {\r\n output = explicitOutput;\r\n outputEstimated = false;\r\n } else {\r\n output = estimateTokens(assistantChars);\r\n outputEstimated = true;\r\n }\r\n\r\n if (input + output === 0) return; // matches Rust filter_map drop\r\n\r\n const endTs = parseTimestampValue(turn.end_timestamp);\r\n const ts = promptTimestampMs ?? endTs ?? fallbackTs;\r\n\r\n const messageCount = Math.max(1, toNonNegInt(turn.total_request_count) || 1);\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n // cacheRead / cacheWrite / reasoning stay 0 (Kiro reports none).\r\n\r\n // host-reported only when BOTH dimensions are explicit host counts.\r\n const confidence: UsageConfidence =\r\n inputEstimated || outputEstimated ? \"host-estimated\" : \"host-reported\";\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId,\r\n providerId: PROVIDER_ID,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount,\r\n dedupKey: `${sessionId}:${index}`,\r\n confidence,\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// ─────────────────────────────────────────────────────────────────────────\r\n// Reader singleton.\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\nconst kiroReader: 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 ~/.kiro/sessions/cli → fail-open\r\n\r\n // Drive off the .json headers; each pulls its adjacent .jsonl when present.\r\n const files = walkFiles(root, (name) => name.endsWith(\".json\"));\r\n\r\n const records: UsageRecord[] = [];\r\n for (const file of files) {\r\n const rows = parseKiroFile(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 kiroReader;\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/kiro/index.ts"],"sourcesContent":["/**\r\n * adapters/kiro — Kiro (AWS) platform adapter for agent-connector.\r\n *\r\n * Kiro is a json-stdio host with TWO native config surfaces that live in\r\n * DIFFERENT files (so getServerConfigPath ≠ getHookConfigPath):\r\n *\r\n * 1. MCP servers — `mcp.json` under `~/.kiro/settings/` (user) or\r\n * `<projectDir>/.kiro/settings/` (project). The file is JSONC; we WRITE\r\n * plain JSON (valid JSONC), mirroring the other JSON-config adapters. Root\r\n * key `mcpServers`; a stdio server is `{ command, args, env }`.\r\n * Ref: https://kiro.dev/docs/mcp/configuration/\r\n *\r\n * 2. Hooks — NOT a settings file but an AGENT file:\r\n * `~/.kiro/agents/kiro_default.json`. Kiro auto-loads the built-in default\r\n * agent `kiro_default` for a new chat session, so hooks must register on\r\n * THAT agent (a file literally named `default.json` would define an inactive\r\n * custom agent the user must `/agent`-swap to). We merge a `hooks` key into\r\n * the existing agent JSON, creating a minimal agent object if absent.\r\n * Ref: kiro.dev/docs/cli/custom-agents/configuration-reference#hooks-field\r\n *\r\n * Hook protocol is EXIT-CODE based (unlike Claude's JSON-decision wrapper):\r\n * - exit 0 → allow the action.\r\n * - exit 2 → block the action; the reason is written to stderr (PreToolUse).\r\n * - context injection → exit 0 with the guidance text written as PLAIN STDOUT\r\n * (NOT a JSON envelope). Kiro adds a hook's STDOUT to the agent's context\r\n * ONLY for agentSpawn and userPromptSubmit; for preToolUse / postToolUse /\r\n * stop the docs say STDOUT is \"captured but not shown\" — there is no\r\n * context channel, so a `context` decision on those degrades to exit 0.\r\n * Ref: https://kiro.dev/docs/cli/hooks (Hook output / Hook types).\r\n * Kiro CANNOT rewrite tool arguments or output (exit codes only), so\r\n * canModifyArgs / canModifyOutput are false; `modify` degrades to allow.\r\n *\r\n * Native hook event vocabulary differs from the canonical names and is mapped:\r\n * PreToolUse → preToolUse\r\n * PostToolUse → postToolUse\r\n * SessionStart → agentSpawn (Kiro's session-start equivalent)\r\n * UserPromptSubmit → userPromptSubmit\r\n * Stop → stop (documented Kiro hook)\r\n * Kiro has no equivalent for PreCompact / SessionEnd / Notification; those are\r\n * reported as a warn/skip at install time.\r\n *\r\n * Env handling: Kiro documents no `${env:VAR}` token of the framework's syntax,\r\n * so env/header/url refs are resolved to literals at install time via\r\n * resolveEnvRefsDeep — the safe default matching the Gemini/Codex adapters.\r\n *\r\n * Actions surface: Kiro reads `.kiro/hooks/<id>.kiro.hook` files (JSON) where a\r\n * `{ when:{ type:\"manual\" } }` Manual-Trigger paired with a\r\n * `{ then:{ type:\"runCommand\", command } }` Shell-Command action runs a local\r\n * shell command (NO LLM) and is user-invokable from the Agent Hooks panel /\r\n * Command Palette (kiro.dev/docs/hooks — \"Run Command\" action; verified against\r\n * real `.kiro.hook` files in the wild). For each AC action we write ONE fully\r\n * owned `.kiro/hooks/<id>.kiro.hook` that execs `<homeBin> action kiro <id>\r\n * --connector <id>`. CONSTRAINT (verified): Kiro discovers hooks ONLY from the\r\n * WORKSPACE `.kiro/hooks/` dir — `~/.kiro/hooks/` is NOT scanned — so actions\r\n * install at PROJECT scope only and warn-skip at user scope (mirrors warp's\r\n * project-only skills/actions precedent).\r\n *\r\n * Grounded in context-mode's proven Kiro adapter (src/adapters/kiro/*).\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, HookReply, InstallContext, MemoryTarget, 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 SessionStartEvent,\r\n SkillDef,\r\n StopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport {\r\n buildHomeBinHookCommand,\r\n buildWrappedStdio,\r\n isHomeBinHookCommand,\r\n} from \"../../core/spawn.js\";\r\nimport { normalizeSessionSource } from \"../claude-code/wire.js\";\r\n\r\nconst HOST: PlatformId = \"kiro\";\r\nconst MCP_ROOT_KEY = \"mcpServers\";\r\n\r\n/** The built-in agent Kiro auto-loads for a new chat session. */\r\nconst DEFAULT_AGENT_FILE = \"kiro_default.json\";\r\n\r\n/**\r\n * Kiro-native hook event names (the keys under an agent file's `hooks` object).\r\n * Only the events Kiro actually fires for the json-stdio command paradigm.\r\n */\r\nconst KIRO_EVENT = {\r\n preToolUse: \"preToolUse\",\r\n postToolUse: \"postToolUse\",\r\n agentSpawn: \"agentSpawn\",\r\n userPromptSubmit: \"userPromptSubmit\",\r\n stop: \"stop\",\r\n} as const;\r\n\r\n/**\r\n * Map canonical event names → Kiro's native hook event names. Only the events\r\n * Kiro supports are present; PreCompact / SessionEnd / Notification have no Kiro\r\n * equivalent and are reported as a warn/skip at install time.\r\n */\r\nconst EVENT_MAP: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: KIRO_EVENT.preToolUse,\r\n PostToolUse: KIRO_EVENT.postToolUse,\r\n SessionStart: KIRO_EVENT.agentSpawn,\r\n UserPromptSubmit: KIRO_EVENT.userPromptSubmit,\r\n Stop: KIRO_EVENT.stop,\r\n};\r\n\r\n/**\r\n * Kiro events whose hook STDOUT is added to the agent's context: agentSpawn\r\n * (≈ SessionStart) and userPromptSubmit. For preToolUse / postToolUse / stop the\r\n * docs say STDOUT is \"captured but not shown to user\" — no context channel — so a\r\n * `context` decision on those degrades to a plain exit-0 pass-through.\r\n * Ref: https://kiro.dev/docs/cli/hooks\r\n */\r\nconst CONTEXT_EVENTS: ReadonlySet<string> = new Set([\r\n KIRO_EVENT.agentSpawn,\r\n KIRO_EVENT.userPromptSubmit,\r\n]);\r\n\r\n/** A single Kiro native hook registration entry (Claude-shaped, nested). */\r\ninterface KiroHookEntry {\r\n matcher: string;\r\n hooks: Array<{ type: \"command\"; command: string }>;\r\n}\r\n\r\n/** The shape of a Kiro agent file (only the parts we touch). */\r\ninterface KiroAgentFile {\r\n hooks?: Record<string, KiroHookEntry[]>;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** The shape of Kiro's mcp.json (only the parts we touch). */\r\ninterface KiroMcpFile {\r\n mcpServers?: Record<string, unknown>;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Native MCP server entry shapes Kiro accepts under `mcpServers`. */\r\ninterface KiroStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n cwd?: string;\r\n}\r\ninterface KiroHttpServer {\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Raw Kiro CLI hook stdin payload (snake_case wire fields).\r\n *\r\n * Fields are the ones Kiro ACTUALLY serializes onto a hook's stdin per\r\n * kiro.dev/docs/cli/hooks. NOTE the stop hook: its stdin is exactly\r\n * `{ hook_event_name, cwd, session_id, assistant_response }` — there is NO\r\n * `stop_hook_active` field (Kiro does not model a re-entrant stop-hook flag),\r\n * so we read `assistant_response` (the agent's last response text) rather than a\r\n * never-emitted boolean. Ref: kiro.dev/docs/cli/hooks (Stop Hook → Hook Event).\r\n */\r\ninterface KiroWireInput {\r\n connector?: unknown;\r\n hook_event_name?: string;\r\n cwd?: string;\r\n session_id?: string;\r\n tool_name?: string;\r\n tool_input?: Record<string, unknown>;\r\n tool_response?: unknown;\r\n source?: string;\r\n prompt?: string;\r\n /** Stop hook only: the text of the assistant's last response. */\r\n assistant_response?: string;\r\n}\r\n\r\nexport class KiroAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Kiro\";\r\n readonly paradigm: HookParadigm = \"json-stdio\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md\r\n // via the base default — always included, no inclusion modes; user scope →\r\n // ~/.kiro/steering/agent-connector.md below).\r\n supportsMemory: true,\r\n preToolUse: true,\r\n postToolUse: true,\r\n preCompact: false,\r\n sessionStart: true,\r\n sessionEnd: false,\r\n // Kiro fires userPromptSubmit and stop, but it has no PreCompact /\r\n // SessionEnd / Notification equivalent.\r\n userPromptSubmit: true,\r\n stop: true,\r\n notification: false,\r\n // Newer events: Kiro's native set (agentSpawn / userPromptSubmit /\r\n // preToolUse / postToolUse / stop) has no permission-dialog, tool-failure,\r\n // or subagent lifecycle events, so permissionRequest / postToolUseFailure /\r\n // subagentStart / subagentStop stay unset — install reports the standard\r\n // skip-warn for them.\r\n // Kiro's hook protocol is exit-code only — a hook can allow (0), block (2),\r\n // or inject agentSpawn context, but it CANNOT rewrite tool args or output.\r\n canModifyArgs: false,\r\n canModifyOutput: false,\r\n // agentSpawn (and userPromptSubmit) add the hook's plain STDOUT to context.\r\n canInjectSessionContext: true,\r\n transports: [\"stdio\", \"http\"],\r\n // Skills: Kiro reads SKILL.md from .kiro/skills/<name>/SKILL.md (project)\r\n // and ~/.kiro/skills/<name>/SKILL.md (user).\r\n supportsSkills: true,\r\n // Actions: Kiro reads `.kiro/hooks/<id>.kiro.hook` Manual-Trigger +\r\n // Shell-Command hooks (when.type \"manual\" + then.type \"runCommand\"),\r\n // user-invokable from the Agent Hooks panel / Command Palette. WORKSPACE\r\n // (project) scope ONLY — Kiro does not scan ~/.kiro/hooks/ — so user scope\r\n // warn-skips (see installActions).\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(), \".kiro\");\r\n const userMcp = this.userMcpPath();\r\n const projectDirKiro = join(projectDir, \".kiro\");\r\n const projectMcp = this.projectMcpPath(projectDir);\r\n\r\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\r\n const projInstalled = existsSync(projectDirKiro) || existsSync(projectMcp);\r\n const installed = userInstalled || projInstalled;\r\n // Report the scope/path that actually matched, so a project-only install\r\n // isn't misreported as a (non-existent) user install.\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projectMcp : userMcp;\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? scope === \"project\"\r\n ? `found project Kiro config at ${projectMcp}`\r\n : `found Kiro config under ${userDir}`\r\n : `no Kiro config at ${userDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Memory surface: global steering dir at user scope ───────────────────\r\n // Project scope stays on the AGENTS.md base default (workspace-root\r\n // AGENTS.md is always included, with no inclusion modes). User scope targets\r\n // a dedicated agent-connector.md in Kiro's documented ~/.kiro/steering/ dir\r\n // (default-always inclusion; AC-created → cleanly deletable on uninstall).\r\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"user\") {\r\n return super.memoryTargets(ctx);\r\n }\r\n return [\r\n {\r\n path: join(homedir(), \".kiro\", \"steering\", \"agent-connector.md\"),\r\n reason: \"kiro global steering dir (~/.kiro/steering; agent-connector-owned file)\",\r\n },\r\n ];\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kiro\")\r\n : join(homedir(), \".kiro\");\r\n }\r\n\r\n /** MCP servers live in mcp.json under the scope's `.kiro/settings/`. */\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? this.projectMcpPath(ctx.projectDir)\r\n : this.userMcpPath();\r\n }\r\n\r\n /**\r\n * Hooks live in an AGENT file, NOT a settings file. Kiro auto-loads the\r\n * built-in default agent (`kiro_default`) for a new chat session, so we always\r\n * register hooks on the user-scope default agent — that is the agent Kiro\r\n * actually loads regardless of install scope.\r\n */\r\n getHookConfigPath(_ctx: InstallContext): string {\r\n return join(homedir(), \".kiro\", \"agents\", DEFAULT_AGENT_FILE);\r\n }\r\n\r\n private userMcpPath(): string {\r\n return join(homedir(), \".kiro\", \"settings\", \"mcp.json\");\r\n }\r\n\r\n private projectMcpPath(projectDir: string): string {\r\n return join(projectDir, \".kiro\", \"settings\", \"mcp.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 kiro\"\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 Kiro's native mcpServers entry. */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): KiroStdioServer | KiroHttpServer {\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 // Kiro documents no native interpolation token, so resolve every\r\n // ${env:VAR} to a literal at install time.\r\n const entry: KiroStdioServer = { command: resolveEnvRefsDeep(command) };\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 if (server.cwd) entry.cwd = resolveEnvRefsDeep(server.cwd);\r\n return entry;\r\n }\r\n\r\n // http (and any other remote transport) — Kiro registers a URL.\r\n const entry: KiroHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\r\n const headers = this.renderEnv(server.headers);\r\n if (headers) entry.headers = headers;\r\n return entry;\r\n }\r\n\r\n /**\r\n * Render env/header values. Kiro documents no native interpolation token, so\r\n * resolve `${env:VAR}` references to literals at install time.\r\n */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n // ── Skills surface ───────────────────────────────────────────────────────\r\n // Kiro reads SKILL.md from:\r\n // project scope → <projectDir>/.kiro/skills/<name>/SKILL.md\r\n // user scope → ~/.kiro/skills/<name>/SKILL.md\r\n\r\n private skillsDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".kiro\", \"skills\")\r\n : join(homedir(), \".kiro\", \"skills\");\r\n }\r\n\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\r\n\r\n override installSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.skills === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for kiro\" }];\r\n }\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\r\n );\r\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\r\n }\r\n }\r\n return changes;\r\n }\r\n\r\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue;\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n private renderSkill(skill: SkillDef): string {\r\n return renderSkillMd(skill);\r\n }\r\n\r\n // ── Action surface (one owned .kiro.hook per action; PROJECT scope only) ──\r\n // Kiro reads `<projectDir>/.kiro/hooks/<id>.kiro.hook` (JSON): a Manual-Trigger\r\n // (`when.type \"manual\"`) + Shell-Command (`then.type \"runCommand\"`, `command`)\r\n // hook, user-invokable from the Agent Hooks panel / Command Palette\r\n // (kiro.dev/docs/hooks). The command execs `<homeBin> action kiro <id>\r\n // --connector <id>`. Each file is FULLY OWNED → uninstall removes it.\r\n // SCOPE: Kiro discovers hooks ONLY from the workspace `.kiro/hooks/` dir\r\n // (~/.kiro/hooks/ is NOT scanned), so user scope warn-skips (mirrors warp's\r\n // project-only precedent) rather than writing a file Kiro would never load.\r\n\r\n private actionHookPath(ctx: InstallContext, id: string): string {\r\n return join(ctx.projectDir, \".kiro\", \"hooks\", `${id}.kiro.hook`);\r\n }\r\n\r\n override installActions(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.actions === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"actions disabled for kiro\" }];\r\n }\r\n const triggers = this.actionTriggers(ctx);\r\n if (triggers.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no actions\" }];\r\n }\r\n if (ctx.scope !== \"project\") {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `kiro actions are project-scoped only (Kiro does not scan ~/.kiro/hooks/); ${triggers.length} skipped`,\r\n },\r\n ];\r\n }\r\n return triggers.map((trigger) =>\r\n this.writeContentFile(\r\n this.actionHookPath(ctx, trigger.id),\r\n this.renderActionHook(trigger.label, trigger.description, trigger.command),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallActions(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.actions.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no actions\" }];\r\n }\r\n if (ctx.scope !== \"project\") {\r\n return [{ platform: this.id, action: \"skip\", detail: \"kiro actions are project-scoped only\" }];\r\n }\r\n return connector.actions.map((action) =>\r\n this.removeContentFile(this.actionHookPath(ctx, action.id), ctx.dryRun),\r\n );\r\n }\r\n\r\n /**\r\n * Render a Kiro `.kiro.hook` JSON: a Manual-Trigger (`when.type \"manual\"`) +\r\n * Shell-Command (`then.type \"runCommand\"`) hook. The key order matches the\r\n * files Kiro itself emits (enabled, name, description, version, when, then).\r\n */\r\n private renderActionHook(name: string, description: string, command: string): string {\r\n return (\r\n JSON.stringify(\r\n {\r\n enabled: true,\r\n name,\r\n description,\r\n version: \"1\",\r\n when: { type: \"manual\" },\r\n then: { type: \"runCommand\", command },\r\n },\r\n null,\r\n 2,\r\n ) + \"\\n\"\r\n );\r\n }\r\n\r\n // ── Hook install / uninstall (merge into the agent file) ─────────────────\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 kiro\" }];\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 agentPath = this.getHookConfigPath(ctx);\r\n // Merge into the existing agent JSON; create a minimal agent object if absent.\r\n const agent = this.readJson<KiroAgentFile>(agentPath) ?? {};\r\n const __skip = this.malformedHookRootSkip(agentPath, (agent as Record<string, unknown>).hooks);\r\n if (__skip) return [__skip];\r\n const hooks = (agent.hooks ??= {});\r\n\r\n const changes: ChangeRecord[] = [];\r\n let mutated = false;\r\n\r\n for (const event of connector.hookEvents) {\r\n const kiroEvent = EVENT_MAP[event];\r\n if (!kiroEvent) {\r\n // No Kiro equivalent for this canonical event — report and continue.\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n path: agentPath,\r\n detail: `${event} has no Kiro hook equivalent — skipped`,\r\n });\r\n continue;\r\n }\r\n\r\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\r\n const matcher = connector.hooks[event]?.matcher ?? \"\";\r\n const entry: KiroHookEntry = {\r\n matcher,\r\n hooks: [{ type: \"command\", command }],\r\n };\r\n\r\n const bucket = (hooks[kiroEvent] ??= []);\r\n const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));\r\n\r\n if (existingIdx >= 0) {\r\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"skip\",\r\n path: agentPath,\r\n detail: `hooks.${kiroEvent} already registered`,\r\n });\r\n continue;\r\n }\r\n bucket[existingIdx] = entry;\r\n changes.push({\r\n platform: this.id,\r\n action: \"update\",\r\n path: agentPath,\r\n detail: `hooks.${kiroEvent}`,\r\n });\r\n } else {\r\n bucket.push(entry);\r\n changes.push({\r\n platform: this.id,\r\n action: \"create\",\r\n path: agentPath,\r\n detail: `hooks.${kiroEvent}`,\r\n });\r\n }\r\n mutated = true;\r\n }\r\n\r\n if (mutated) this.writeJson(agentPath, agent, ctx.dryRun);\r\n return changes;\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n const agentPath = this.getHookConfigPath(ctx);\r\n const agent = this.readJson<KiroAgentFile>(agentPath);\r\n const hooks = agent?.hooks;\r\n if (!agent || !hooks) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: agentPath,\r\n detail: \"no hooks section present\",\r\n },\r\n ];\r\n }\r\n\r\n const changes: ChangeRecord[] = [];\r\n let mutated = false;\r\n\r\n for (const kiroEvent of Object.keys(hooks)) {\r\n const bucket = hooks[kiroEvent];\r\n if (!Array.isArray(bucket)) continue;\r\n\r\n // Strip our hook command from each entry; drop entries left empty so we\r\n // never remove another connector's (or the user's own) hook commands.\r\n const next: KiroHookEntry[] = [];\r\n let removed = 0;\r\n for (const e of bucket) {\r\n const innerBefore = e.hooks?.length ?? 0;\r\n const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\r\n removed += innerBefore - inner.length;\r\n if (inner.length > 0) next.push({ matcher: e.matcher ?? \"\", hooks: inner });\r\n }\r\n\r\n if (removed > 0) {\r\n if (next.length > 0) hooks[kiroEvent] = next;\r\n else delete hooks[kiroEvent];\r\n changes.push({\r\n platform: this.id,\r\n action: \"remove\",\r\n path: agentPath,\r\n detail: `hooks.${kiroEvent} (${removed})`,\r\n });\r\n mutated = true;\r\n }\r\n }\r\n\r\n if (mutated) this.writeJson(agentPath, agent, ctx.dryRun);\r\n if (changes.length === 0) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"skip\",\r\n path: agentPath,\r\n detail: \"no matching hook entries\",\r\n });\r\n }\r\n return changes;\r\n }\r\n\r\n private entryHasOurCommand(entry: KiroHookEntry, ctx: InstallContext): boolean {\r\n return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\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 agentPath = 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 // Only assert what the connector declares (same rule as the hook\r\n // check below): a server-less connector never writes an mcpServers\r\n // entry, so its absence is healthy.\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<KiroMcpFile>(mcpPath);\r\n const bucket = cfg?.mcpServers;\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 : { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}` };\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 agent = this.readJson<KiroAgentFile>(agentPath);\r\n if (!agent) return { status: \"FAIL\", detail: `cannot read ${agentPath}` };\r\n const hooks = agent.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 ${agentPath}` };\r\n },\r\n },\r\n ];\r\n }\r\n\r\n // ── Runtime: parse Kiro stdin JSON → normalized event ────────────────────\r\n\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as KiroWireInput;\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 = typeof input.cwd === \"string\" ? input.cwd : 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 \"SessionStart\": {\r\n const ev: SessionStartEvent = {\r\n ...base,\r\n source: normalizeSessionSource(input.source),\r\n };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n // Kiro's stop stdin is EXACTLY { hook_event_name, cwd, session_id,\r\n // assistant_response } — there is no `stop_hook_active` flag (reading it\r\n // always yielded undefined), so we read the real `assistant_response`\r\n // (the agent's last response text) instead and surface it as\r\n // lastAssistantMessage. Ref: kiro.dev/docs/cli/hooks (Stop Hook Event).\r\n const ev: StopEvent & { lastAssistantMessage?: string } = {\r\n ...base,\r\n ...(typeof input.assistant_response === \"string\"\r\n ? { lastAssistantMessage: input.assistant_response }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n default: {\r\n // Kiro never delivers PreCompact / SessionEnd / Notification nor the\r\n // newer PermissionRequest / PostToolUseFailure / SubagentStart /\r\n // SubagentStop (no native equivalents). If the runtime dispatches one\r\n // anyway, surface it loudly rather than silently mis-parse.\r\n throw new Error(`unsupported kiro hook event: ${String(event)}`);\r\n }\r\n }\r\n }\r\n\r\n // ── Runtime: normalized response → Kiro native (exit-code) hook reply ─────\r\n\r\n formatReply(event: HookEventName, response: HookResponse): HookReply {\r\n const decision = response.decision ?? \"allow\";\r\n\r\n // deny → block the action: exit 2 with the reason on stderr.\r\n if (decision === \"deny\") {\r\n return { exitCode: 2, stderr: response.reason ?? \"Blocked by hook\" };\r\n }\r\n\r\n // ask → Kiro has no native \"ask\"; degrade to deny (exit 2) to stay fail-safe.\r\n if (decision === \"ask\") {\r\n return {\r\n exitCode: 2,\r\n stderr: response.reason ?? \"Action requires user confirmation (security policy)\",\r\n };\r\n }\r\n\r\n // Stop → exit-code only (deny already handled above as exit 2). There is no\r\n // context/additionalContext channel on a Stop hook, so anything non-deny\r\n // passes through with exit 0 (do not fall into the context branch).\r\n if (event === \"Stop\") {\r\n return { exitCode: 0 };\r\n }\r\n\r\n // context → inject soft guidance. Kiro adds a hook's PLAIN STDOUT to the\r\n // agent's context (no JSON envelope), but ONLY for the agentSpawn and\r\n // userPromptSubmit events; preToolUse / postToolUse have no context channel\r\n // (their STDOUT is \"captured but not shown\"). So emit the raw text on stdout\r\n // only when the FIRING event maps to a context-supporting Kiro event;\r\n // otherwise the context decision degrades to a plain exit-0 pass-through\r\n // rather than a mislabeled/ineffective payload. exit 0 = allow.\r\n // Ref: https://kiro.dev/docs/cli/hooks\r\n const kiroEvent = EVENT_MAP[event];\r\n if (\r\n decision === \"context\" &&\r\n response.additionalContext &&\r\n kiroEvent !== undefined &&\r\n CONTEXT_EVENTS.has(kiroEvent)\r\n ) {\r\n return { exitCode: 0, stdout: response.additionalContext };\r\n }\r\n\r\n // modify is unsupported on Kiro (exit-code protocol — cannot rewrite\r\n // args/output); allow / void → pass through with exit 0.\r\n return { exitCode: 0 };\r\n }\r\n}\r\n\r\n/** Coerce a Kiro PostToolUse `tool_response` into a string for the normalized event. */\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 KiroAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/commands/leaderboard.ts"],"sourcesContent":["/**\r\n * cli/commands/leaderboard — the unified top-level `agent-connector leaderboard`.\r\n *\r\n * Prints THREE leaderboards, each clearly origin-labeled and NEVER summed:\r\n * 🔌 MCP / Plugin leaderboard ← origin `mcp-self`: the serve-proxy\r\n * telemetry store (which MCP server WE wrap costs the most — per-MCP `call`\r\n * + `tool_defs` rows; the `model_turn` rows are EXCLUDED here).\r\n * 🖥️ Host / User leaderboard ← origin `host-scan-logs`: the host usage\r\n * readers scanning agent CLI logs (which CLI / host spent the most).\r\n * 🛰️ Host-native turns (live, exact) ← origin `host-native-live`: the opt-in\r\n * AfterModel / PostInvocation usage hook (scope `model_turn`, confidence\r\n * host-native) — whole-conversation usage the host reported in real time.\r\n *\r\n * All three measure DIFFERENT things (per-MCP server bytes vs whole-conversation\r\n * usage from logs vs whole-conversation usage from a live hook). They are reported\r\n * side by side but their totals are NEVER added together.\r\n *\r\n * Flags:\r\n * --since 7d|24h|… lower-bound window applied to both sources.\r\n * --scope <value> MCP-section scope slice (user|project|npx|binary|http|…);\r\n * ignored by the host section (host logs carry no scope).\r\n * --connector <id> restrict the 🔌 MCP/plugin + 🛰️ host-native-turns\r\n * sections to ONE connector id. The 🖥️ host-scan section\r\n * is connector-agnostic (host CLI logs carry no connector\r\n * attribution) and is intentionally NOT filtered.\r\n * --json emit { mcp:[...], host:[...] } instead of the tables.\r\n */\r\n\r\nimport { parseArgs } from \"node:util\";\r\n\r\nimport {\r\n formatHostNativeTurns,\r\n formatMcpLeaderboard,\r\n hostNativeTurns,\r\n isScopeFilter,\r\n mcpLeaderboard,\r\n SCOPE_FILTER_VALUES,\r\n type ScopeFilter,\r\n} from \"../../telemetry/leaderboard.js\";\r\nimport { formatHostLeaderboard, hostLeaderboard } from \"../../usage/leaderboard.js\";\r\nimport { fail, print } from \"../app.js\";\r\n\r\n/**\r\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\r\n * Returns undefined for empty input and null for a malformed one. (Kept local so\r\n * the leaderboard command stays decoupled from the report commands.)\r\n */\r\nexport function parseSince(since: string | undefined): number | null | undefined {\r\n if (since == null || since.trim() === \"\") return undefined;\r\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\r\n if (!m || !m[1] || !m[2]) return null;\r\n const n = Number(m[1]);\r\n const unitMs: Record<string, number> = {\r\n s: 1000,\r\n m: 60_000,\r\n h: 3_600_000,\r\n d: 86_400_000,\r\n };\r\n const factor = unitMs[m[2].toLowerCase()];\r\n if (factor == null) return null;\r\n return Date.now() - n * factor;\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n const first = argv[0];\r\n if (first === \"--help\" || first === \"-h\") {\r\n print(\"usage: agent-connector leaderboard [flags]\");\r\n print(\" --since 7d|24h|… window applied to BOTH sources\");\r\n print(` --scope <value> MCP-section slice (${SCOPE_FILTER_VALUES.join(\"|\")})`);\r\n print(\" --connector <id> restrict the 🔌 MCP + 🛰️ host-native sections to one connector\");\r\n print(\" --json emit { mcp:[...], host:[...] } (never summed)\");\r\n return 0;\r\n }\r\n\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n since: { type: \"string\" },\r\n scope: { type: \"string\" },\r\n connector: { type: \"string\" },\r\n json: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n const sinceMs = parseSince(values.since);\r\n if (sinceMs === null) {\r\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\r\n }\r\n\r\n let scope: ScopeFilter | undefined;\r\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\r\n const s = values.scope.trim();\r\n if (!isScopeFilter(s)) {\r\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\r\n }\r\n scope = s;\r\n }\r\n\r\n // The optional --connector <id> FILTER restricts the two connector-attributed\r\n // sections (🔌 MCP/plugin + 🛰️ host-native turns) to one connector. The\r\n // 🖥️ host-scan section below is intentionally NOT filtered: host CLI logs carry\r\n // no connector attribution, so it stays connector-agnostic (whole-conversation).\r\n const connectorId =\r\n values.connector !== undefined && values.connector.trim() !== \"\"\r\n ? values.connector.trim()\r\n : undefined;\r\n\r\n // 🔌 MCP / Plugin leaderboard — serve-proxy telemetry (origin: mcp-self).\r\n const mcpOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\r\n if (sinceMs !== undefined) mcpOpts.sinceMs = sinceMs;\r\n if (scope !== undefined) mcpOpts.scope = scope;\r\n if (connectorId !== undefined) mcpOpts.connectorId = connectorId;\r\n const mcp = mcpLeaderboard(mcpOpts);\r\n\r\n // 🖥️ Host / User leaderboard — host usage readers (origin: host-scan-logs).\r\n // Connector-agnostic by construction: NOT filtered by --connector.\r\n const hostOpts: { sinceMs?: number } = {};\r\n if (sinceMs !== undefined) hostOpts.sinceMs = sinceMs;\r\n const host = await hostLeaderboard(hostOpts);\r\n\r\n // 🛰️ Host-native turns — opt-in AfterModel usage hook (origin: host-native-live).\r\n // Scope `model_turn` rows ONLY; the MCP section above already excludes them.\r\n const turnsOpts: { sinceMs?: number; scope?: ScopeFilter; connectorId?: string } = {};\r\n if (sinceMs !== undefined) turnsOpts.sinceMs = sinceMs;\r\n if (scope !== undefined) turnsOpts.scope = scope;\r\n if (connectorId !== undefined) turnsOpts.connectorId = connectorId;\r\n const turns = hostNativeTurns(turnsOpts);\r\n\r\n if (values.json) {\r\n // Three separate arrays — by construction the consumer cannot sum origins.\r\n print(\r\n JSON.stringify(\r\n {\r\n mcp, // origin: mcp-self\r\n host: host.rows, // origin: host-scan-logs\r\n hostSkipped: host.skipped,\r\n hostNativeTurns: turns, // origin: host-native-live (scope model_turn)\r\n },\r\n null,\r\n 2,\r\n ),\r\n );\r\n return 0;\r\n }\r\n\r\n const lines: string[] = [];\r\n lines.push(\r\n \"🔌 MCP / Plugin leaderboard (origin: mcp-self — per-MCP server bytes we wrap; \" +\r\n \"excludes host-native model_turn rows)\",\r\n );\r\n if (scope !== undefined) lines.push(` scope: ${scope}`);\r\n if (connectorId !== undefined) lines.push(` connector: ${connectorId}`);\r\n lines.push(\"\");\r\n lines.push(formatMcpLeaderboard(mcp));\r\n lines.push(\"\");\r\n lines.push(\r\n \"🖥️ Host / User leaderboard (origin: host-scan-logs — whole-conversation usage from CLI logs)\",\r\n );\r\n if (connectorId !== undefined) {\r\n lines.push(\" (connector-agnostic — host CLI logs carry no connector attribution; --connector not applied here)\");\r\n }\r\n lines.push(\"\");\r\n lines.push(formatHostLeaderboard(host));\r\n lines.push(\"\");\r\n lines.push(\r\n \"🛰️ Host-native turns (live, exact) (origin: host-native-live — opt-in AfterModel usage hook)\",\r\n );\r\n lines.push(\"\");\r\n lines.push(formatHostNativeTurns(turns));\r\n lines.push(\"\");\r\n lines.push(\r\n \"note: the THREE leaderboards measure DIFFERENT things (per-MCP server bytes vs \" +\r\n \"whole-conversation usage from logs vs live host-native turns) and are never \" +\r\n \"summed together (their totals are NEVER added across origins).\",\r\n );\r\n print(lines.join(\"\\n\"));\r\n return 0;\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/mimo-code/index.ts"],"sourcesContent":["/**\r\n * adapters/mimo-code — Xiaomi MiMoCode platform adapter for agent-connector.\r\n *\r\n * MiMoCode (github.com/XiaomiMiMo/MiMo-Code, MIT) is Xiaomi's open-source\r\n * terminal AI coding agent — a FORK OF OpenCode (anomalyco/opencode) that adds\r\n * cross-session memory, checkpoints, subagents, etc. Official npm `@mimo-ai/cli`\r\n * (bin: `mimo`). NOTE: `@xiaomi-mimo/cli` is an UNOFFICIAL squatter (GPL) — not\r\n * referenced here; the bin is `mimo`, NOT `mimo-code`.\r\n *\r\n * DESIGN — STANDALONE (mirrors OpenCode's render logic with mimocode paths),\r\n * NOT `extends OpenCodeAdapter`. The OpenCode adapter binds the host string in\r\n * several places that a subclass cannot cleanly override:\r\n * - a module-level `const HOST = \"opencode\"` used for the per-platform server/\r\n * hooks override lookup (`ctx.connector.platforms[HOST]`) and stamped as\r\n * `hostPlatform` on every parsed event — extending would read\r\n * `platforms[\"opencode\"]` overrides and mis-stamp events as opencode;\r\n * - the PRIVATE `buildPluginSource` hardcodes `[\"hook\", \"opencode\", event, …]`\r\n * in the GENERATED bridge, so an inherited plugin would dispatch the runtime\r\n * hook to the opencode adapter (`hook opencode`) instead of mimo-code;\r\n * - the config/plugin/content directory builders hardcode \"opencode\" /\r\n * \".opencode\" / \"opencode.json\".\r\n * Overriding all of that means re-implementing the private render core anyway,\r\n * so this adapter mirrors OpenCode's logic with a `HOST = \"mimo-code\"` constant\r\n * and the mimocode paths — a clean standalone that routes detection, the runtime\r\n * bridge, and per-platform overrides to its own id.\r\n *\r\n * MiMoCode IS OpenCode's config dialect, so the render shapes are IDENTICAL:\r\n * - config file `mimocode.json`\r\n * user scope → ~/.config/mimocode/mimocode.json\r\n * project scope → <projectDir>/mimocode.json\r\n * (the dir is `.mimocode` / `~/.config/mimocode` — NO hyphen; the committed\r\n * example is `.mimocode/mimocode.jsonc`).\r\n * - MCP root key \"mcp\" (the OpenCode shape, NOT \"mcpServers\"); each server\r\n * keyed by name; stdio → { type:\"local\", command:[exe,…args], environment },\r\n * remote → { type:\"remote\", url }.\r\n * - ts-plugin hooks: a self-contained ESM bridge module auto-loaded from the\r\n * user scope → ~/.config/mimocode/plugin/<id>.js\r\n * project scope → <projectDir>/.mimocode/plugin/<id>.js\r\n * plugin dir (writing the file IS the registration; no config array edit).\r\n * - content surfaces under <mcDir>/{commands,skills,agent} (singular `agent/`,\r\n * matching OpenCode).\r\n *\r\n * Event mapping (OpenCode's, unchanged):\r\n * PreToolUse → \"tool.execute.before\" (mutate output.args; throw to deny)\r\n * PostToolUse → \"tool.execute.after\" (mutate output.output)\r\n * SessionStart → \"experimental.chat.system.transform\" (inject into output.system)\r\n *\r\n * SOURCES: github.com/XiaomiMiMo/MiMo-Code (README, .mimocode/mimocode.jsonc,\r\n * packages/opencode/src/config/{config.ts,mcp.ts,plugin.ts}). npm @mimo-ai/cli.\r\n * mimo.xiaomi.com/en/mimocode.\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 {\r\n Adapter,\r\n GeneratedPluginFile,\r\n HookReply,\r\n InstallContext,\r\n MemoryTarget,\r\n NormalizedEvent,\r\n} from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n CommandDef,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookEventName,\r\n HookParadigm,\r\n HookResponse,\r\n PlatformCapabilities,\r\n PlatformId,\r\n PostToolUseEvent,\r\n PreToolUseEvent,\r\n ServerDef,\r\n SessionStartEvent,\r\n StopEvent,\r\n Transport,\r\n UserPromptSubmitEvent,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport { renderBridgePrelude } from \"../../core/ts-plugin-bridge.js\";\r\nimport {\r\n buildWrappedStdio,\r\n} from \"../../core/spawn.js\";\r\nimport { renderOpenCodeSubagentMd, renderSkillMd } from \"../claude-code/render.js\";\r\n\r\nconst HOST: PlatformId = \"mimo-code\";\r\nconst MCP_ROOT_KEY = \"mcp\";\r\n\r\n/** The config dir name (NO hyphen): `.mimocode` / `~/.config/mimocode`. */\r\nconst CONFIG_DIR_NAME = \"mimocode\";\r\n/** The config file name: `mimocode.json`. */\r\nconst CONFIG_FILE_NAME = \"mimocode.json\";\r\n\r\n/**\r\n * Canonical → MiMoCode (OpenCode-shaped) event name map. A connector hook event\r\n * is only emitted by the generated plugin when it appears here AND is declared\r\n * by the connector.\r\n */\r\nconst EVENT_TO_MIMOCODE: Partial<Record<HookEventName, string>> = {\r\n PreToolUse: \"tool.execute.before\",\r\n PostToolUse: \"tool.execute.after\",\r\n // No real SessionStart hook (inherited from OpenCode #14808 / #5409). The\r\n // verified surrogate is experimental.chat.system.transform.\r\n SessionStart: \"experimental.chat.system.transform\",\r\n // chat.message fires on the user's prompt submission; the handler mutates\r\n // output (pushes a text part) to inject context. No documented block/abort.\r\n UserPromptSubmit: \"chat.message\",\r\n // session.idle (\"session finished responding\") → canonical Stop. NOT a direct\r\n // hook key — dispatched through the generic `event` hook (event.type switch).\r\n // session.idle is the OpenCode-family session-completion event (mirrors kilo /\r\n // kilo-cli); if it never fires on a given MiMoCode build, Stop is a silent\r\n // no-op (an acceptable degrade — it never mis-fires), so coverage may be\r\n // optimistic.\r\n Stop: \"session.idle\",\r\n};\r\n\r\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\r\ninterface MiMoCodeBridgePayload {\r\n toolName?: string;\r\n toolInput?: Record<string, unknown>;\r\n toolOutput?: string;\r\n isError?: boolean;\r\n prompt?: string;\r\n sessionId?: string;\r\n projectDir?: string;\r\n}\r\n\r\n/** Native MCP server entry shapes MiMoCode accepts under the \"mcp\" key. */\r\ninterface MiMoCodeLocalServer {\r\n type: \"local\";\r\n command: string[];\r\n environment?: Record<string, string>;\r\n enabled?: boolean;\r\n}\r\ninterface MiMoCodeRemoteServer {\r\n type: \"remote\";\r\n url: string;\r\n enabled?: boolean;\r\n}\r\n\r\nexport class MiMoCodeAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"MiMoCode\";\r\n readonly paradigm: HookParadigm = \"ts-plugin\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block (CLAUDE.md fallback, like\r\n // OpenCode — MiMoCode keeps OpenCode's CLAUDE.md import + AGENTS.md reading).\r\n supportsMemory: true,\r\n preToolUse: true,\r\n postToolUse: true,\r\n preCompact: false,\r\n sessionStart: true,\r\n sessionEnd: false,\r\n userPromptSubmit: true,\r\n // session.idle (via the generic `event` hook) backs Stop (mirrors kilo /\r\n // kilo-cli — same OpenCode-family ts-plugin layer).\r\n stop: true,\r\n notification: false,\r\n // tool.execute.before mutates output.args → input rewrite supported.\r\n canModifyArgs: true,\r\n // tool.execute.after mutates output.output → output rewrite supported.\r\n canModifyOutput: true,\r\n // injected via experimental.chat.system.transform at session start.\r\n canInjectSessionContext: true,\r\n transports: [\"stdio\", \"sse\", \"http\"],\r\n // Content surfaces: MiMoCode authors all three natively under <mcDir>\r\n // (inherited from OpenCode's commands/skills/agent layout).\r\n supportsCommands: true,\r\n supportsSkills: true,\r\n supportsSubagents: true,\r\n };\r\n\r\n // ── Detection ──────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userConfigDir = join(homedir(), \".config\", CONFIG_DIR_NAME);\r\n const userConfig = join(userConfigDir, CONFIG_FILE_NAME);\r\n const projectConfig = join(projectDir, CONFIG_FILE_NAME);\r\n\r\n const userInstalled = existsSync(userConfigDir) || existsSync(userConfig);\r\n const projInstalled = existsSync(projectConfig);\r\n const installed = userInstalled || projInstalled;\r\n\r\n // Report the marker that actually matched so a project-only install isn't\r\n // misreported as a (non-existent) user install.\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projectConfig : userConfig;\r\n\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? scope === \"project\"\r\n ? `found project MiMoCode config at ${projectConfig}`\r\n : `found MiMoCode config under ${userConfigDir}`\r\n : `no MiMoCode config at ${userConfigDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Memory surface: AGENTS.md / CLAUDE.md-fallback probe (project) ──────\r\n // Mirrors OpenCode: project AGENTS.md, falling back to CLAUDE.md ONLY when no\r\n // AGENTS.md exists (creating AGENTS.md beside a relied-on CLAUDE.md would\r\n // shadow the user's rules). User scope stays on the BaseAdapter default.\r\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\r\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"project\") {\r\n return super.memoryTargets(ctx);\r\n }\r\n const agentsMd = join(ctx.projectDir, \"AGENTS.md\");\r\n if (existsSync(agentsMd)) {\r\n return [{ path: agentsMd, reason: \"AGENTS.md (mimocode's primary project rules file)\" }];\r\n }\r\n const claudeMd = join(ctx.projectDir, \"CLAUDE.md\");\r\n if (existsSync(claudeMd)) {\r\n return [\r\n {\r\n path: claudeMd,\r\n reason:\r\n \"CLAUDE.md (mimocode's fallback rules file — creating AGENTS.md would shadow it)\",\r\n },\r\n ];\r\n }\r\n return [{ path: agentsMd, reason: \"AGENTS.md standard (created; no mimocode rules file yet)\" }];\r\n }\r\n\r\n // ── Native paths ───────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? ctx.projectDir\r\n : join(homedir(), \".config\", CONFIG_DIR_NAME);\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), CONFIG_FILE_NAME);\r\n }\r\n\r\n /**\r\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\r\n * MiMoCode (like OpenCode) auto-loads every file in the plugin dir; writing\r\n * this file IS the registration.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return join(this.pluginDir(ctx), this.pluginFileName(ctx));\r\n }\r\n\r\n /** Plugin directory MiMoCode auto-loads modules from, per scope. */\r\n private pluginDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, `.${CONFIG_DIR_NAME}`, \"plugin\")\r\n : join(homedir(), \".config\", CONFIG_DIR_NAME, \"plugin\");\r\n }\r\n\r\n /** Plugin module file name (one per connector, kebab-case id). */\r\n private pluginFileName(ctx: InstallContext): string {\r\n return `${ctx.connector.id}.js`;\r\n }\r\n\r\n // ── MCP server install / uninstall ─────────────────────────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const server = this.effectiveServer(ctx);\r\n const serverPath = this.getServerConfigPath(ctx);\r\n\r\n if (!server) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: serverPath,\r\n detail: ctx.connector.server\r\n ? \"server registration disabled for mimo-code\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\r\n const entry = this.renderServerEntry(ctx, server);\r\n return [\r\n this.upsertServerInJson(\r\n serverPath,\r\n MCP_ROOT_KEY,\r\n ctx.connector.id,\r\n entry,\r\n ctx.dryRun,\r\n ),\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(\r\n serverPath,\r\n MCP_ROOT_KEY,\r\n ctx.connector.id,\r\n ctx.dryRun,\r\n ),\r\n ];\r\n }\r\n\r\n /** Resolve the per-platform server override into an effective ServerDef. */\r\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\r\n const override = ctx.connector.platforms[HOST]?.server;\r\n if (override === false) return undefined;\r\n const base = ctx.connector.server;\r\n if (!base) return undefined;\r\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\r\n }\r\n\r\n /**\r\n * Render a normalized ServerDef into MiMoCode's native \"mcp\" entry (OpenCode\r\n * dialect).\r\n *\r\n * stdio → { type: \"local\", command: [exe, ...args], environment }\r\n * remote → { type: \"remote\", url }\r\n *\r\n * MiMoCode flattens command+args into a single ARRAY. When telemetry wrapping\r\n * applies, the wrapper's command+args (which already include the real command\r\n * tail after `--`) become the head of that array. No native interpolation\r\n * token → resolve every ${env:VAR} reference to a literal at install time.\r\n */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): MiMoCodeLocalServer | MiMoCodeRemoteServer {\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 ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n const commandArray = resolveEnvRefsDeep([command, ...args]).filter(\r\n (s) => s !== \"\",\r\n );\r\n const entry: MiMoCodeLocalServer = {\r\n type: \"local\",\r\n command: commandArray,\r\n };\r\n const environment = this.renderEnv(server.env);\r\n if (environment) entry.environment = environment;\r\n if (server.enabled === false) entry.enabled = false;\r\n return entry;\r\n }\r\n\r\n // sse / http / ws (any remote transport) — MiMoCode registers a URL.\r\n const entry: MiMoCodeRemoteServer = {\r\n type: \"remote\",\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n };\r\n if (server.enabled === false) entry.enabled = false;\r\n return entry;\r\n }\r\n\r\n /** Render env values, resolving every ${env:VAR} reference to a literal. */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n // ── Hook install / uninstall (ts-plugin) ───────────────────────────────\r\n\r\n installHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n\r\n if (ctx.connector.platforms[HOST]?.hooks === false) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: pluginPath,\r\n detail: \"hooks disabled for mimo-code\",\r\n },\r\n ];\r\n }\r\n if (ctx.connector.hookEvents.length === 0) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path: pluginPath,\r\n detail: \"connector declares no hooks\",\r\n },\r\n ];\r\n }\r\n\r\n const files = this.synthesizePlugin(ctx);\r\n const changes: ChangeRecord[] = [];\r\n\r\n for (const file of files) {\r\n changes.push(\r\n this.writeManagedFile(\r\n file.path,\r\n file.contents,\r\n ctx.dryRun,\r\n `mimo-code plugin module (${this.hookDetail(ctx)})`,\r\n file.executable,\r\n ),\r\n );\r\n }\r\n\r\n return changes;\r\n }\r\n\r\n /**\r\n * Human-facing summary of which declared events the synthesized module\r\n * ACTUALLY wires. Only events present in EVENT_TO_MIMOCODE are mapped/wired;\r\n * any declared event with no mapping is reported separately as \"unsupported\r\n * here\" so the detail never overstates coverage.\r\n */\r\n private hookDetail(ctx: InstallContext): string {\r\n const declared = ctx.connector.hookEvents;\r\n const mapped = declared.filter((e) => EVENT_TO_MIMOCODE[e] !== undefined);\r\n const unsupported = declared.filter((e) => EVENT_TO_MIMOCODE[e] === undefined);\r\n const base = mapped.join(\",\");\r\n return unsupported.length > 0\r\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\r\n : base;\r\n }\r\n\r\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n return [\r\n this.removeManagedFile(\r\n pluginPath,\r\n ctx.dryRun,\r\n \"mimo-code plugin module\",\r\n \"no mimo-code plugin module present\",\r\n ),\r\n ];\r\n }\r\n\r\n // ── Content surfaces: commands / skills / subagents ──────────────────────\r\n // CONTENT-ONLY: pure native-file writers under <mcDir>/{commands,skills,\r\n // agent}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\r\n // method is idempotent (byte-identical → skip) and reversible. Mirrors\r\n // OpenCode's layout: commands/<name>.md, skills/<name>/SKILL.md, and the\r\n // SINGULAR agent/<name>.md dir for subagents. For project scope the content\r\n // root is <projectDir>/.mimocode (NOT the project root where mimocode.json\r\n // lives).\r\n\r\n private contentRootDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, `.${CONFIG_DIR_NAME}`)\r\n : this.getConfigDir(ctx);\r\n }\r\n private commandsDir(ctx: InstallContext): string {\r\n return join(this.contentRootDir(ctx), \"commands\");\r\n }\r\n private skillsDir(ctx: InstallContext): string {\r\n return join(this.contentRootDir(ctx), \"skills\");\r\n }\r\n private agentDir(ctx: InstallContext): string {\r\n return join(this.contentRootDir(ctx), \"agent\");\r\n }\r\n\r\n /** Native command file path: <mcDir>/commands/<name>.md. */\r\n private commandPath(ctx: InstallContext, name: string): string {\r\n return join(this.commandsDir(ctx), `${name}.md`);\r\n }\r\n /** Native skill dir: <mcDir>/skills/<name>. */\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.skillsDir(ctx), name);\r\n }\r\n /** Native subagent file path: <mcDir>/agent/<name>.md (SINGULAR dir). */\r\n private subagentPath(ctx: InstallContext, name: string): string {\r\n return join(this.agentDir(ctx), `${name}.md`);\r\n }\r\n\r\n // ── Commands ──────────────────────────────────────────────────────────────\r\n\r\n override installCommands(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.commands === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for mimo-code\" }];\r\n }\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.writeContentFile(\r\n this.commandPath(ctx, cmd.name),\r\n this.renderCommand(cmd),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.commands.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\r\n }\r\n return connector.commands.map((cmd) =>\r\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\r\n );\r\n }\r\n\r\n /** Render a command to md+frontmatter (description, model, subtask). */\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.subtask !== undefined) frontmatter.subtask = cmd.subtask;\r\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\r\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\r\n }\r\n\r\n // ── Skills ────────────────────────────────────────────────────────────────\r\n\r\n override installSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.skills === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for mimo-code\" }];\r\n }\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\r\n );\r\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\r\n }\r\n }\r\n return changes;\r\n }\r\n\r\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue;\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n // ── Subagents ───────────────────────────────────────────────────────────────\r\n\r\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.subagents === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for mimo-code\" }];\r\n }\r\n if (connector.subagents.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\r\n }\r\n return connector.subagents.map((agent) =>\r\n this.writeContentFile(\r\n this.subagentPath(ctx, agent.name),\r\n renderOpenCodeSubagentMd(agent),\r\n ctx.dryRun,\r\n ),\r\n );\r\n }\r\n\r\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.subagents.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\r\n }\r\n return connector.subagents.map((agent) =>\r\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\r\n );\r\n }\r\n\r\n // ── ts-plugin synthesis ────────────────────────────────────────────────\r\n\r\n /**\r\n * Build ONE self-contained ESM bridge module for MiMoCode. The module imports\r\n * nothing from agent-connector; it embeds the home-bin path + connector id and\r\n * a `bridge()` helper that shells out to the universal hook entrypoint\r\n * (`<homeBin> hook mimo-code <event> --connector <id>`), feeding the payload on\r\n * stdin and JSON.parsing the normalized HookResponse from stdout (fail-open).\r\n */\r\n synthesizePlugin(ctx: InstallContext): GeneratedPluginFile[] {\r\n const path = this.getHookConfigPath(ctx);\r\n const contents = this.buildPluginSource(ctx);\r\n return [{ path, contents, executable: false }];\r\n }\r\n\r\n /** Compose the generated plugin source with plain string concatenation. */\r\n private buildPluginSource(ctx: InstallContext): string {\r\n const events = ctx.connector.hookEvents.filter(\r\n (e): e is HookEventName => EVENT_TO_MIMOCODE[e] !== undefined,\r\n );\r\n const has = (e: HookEventName) => events.includes(e);\r\n\r\n const header = `/**\r\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\r\n *\r\n * Self-contained MiMoCode plugin bridge for connector ${ctx.connector.id}.\r\n * It imports nothing from agent-connector: every hook invocation shells out to\r\n * the stable home binary's universal entrypoint and JSON-parses the normalized\r\n * response. Fail-open: any bridge error degrades to \"allow\".\r\n */\r\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: \"mimo-code\",\r\n payloadNoun: \"MiMoCode\",\r\n eventDoc: \" (PreToolUse|PostToolUse|SessionStart)\",\r\n failOpenComment: \"Fail-open — never wedge a tool call on a bridge error.\",\r\n})}\r\n`;\r\n\r\n const handlers: string[] = [];\r\n\r\n if (has(\"PreToolUse\")) {\r\n handlers.push(` // PreToolUse → block (throw) / rewrite args (mutate output.args).\r\n \"tool.execute.before\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: (output && output.args) ?? {},\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PreToolUse\", payload);\r\n if (!res) return;\r\n // MiMoCode has no \"ask\" gate — degrade \"ask\" to a block (safe direction).\r\n if (res.decision === \"deny\" || res.decision === \"ask\") {\r\n throw new Error(res.reason || \"Blocked by ${ctx.connector.id}\");\r\n }\r\n if (res.updatedInput && output && output.args) {\r\n Object.assign(output.args, res.updatedInput);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"PostToolUse\")) {\r\n handlers.push(` // PostToolUse → observe / rewrite tool output (mutate output.output).\r\n \"tool.execute.after\": async (input, output) => {\r\n const payload = {\r\n toolName: input.tool ?? \"\",\r\n toolInput: input.args ?? {},\r\n toolOutput: output ? output.output : undefined,\r\n sessionId: input.sessionID ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"PostToolUse\", payload);\r\n if (!res) return;\r\n if (typeof res.updatedOutput === \"string\" && output) {\r\n output.output = res.updatedOutput;\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"SessionStart\")) {\r\n handlers.push(` // SessionStart surrogate → inject context into the system prompt.\r\n // MiMoCode has no real SessionStart hook (inherited from OpenCode\r\n // #14808 / #5409); experimental.chat.system.transform is the injection point.\r\n \"experimental.chat.system.transform\": async (input, output) => {\r\n const payload = {\r\n sessionId: (input && input.sessionID) ?? \"\",\r\n projectDir: PROJECT_DIR,\r\n };\r\n const res = bridge(\"SessionStart\", payload);\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.system)) {\r\n // Insert at index 1 (after the header) to preserve the prompt-cache\r\n // fold (header must remain system[0]).\r\n output.system.splice(1, 0, res.additionalContext);\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"UserPromptSubmit\")) {\r\n handlers.push(` // UserPromptSubmit → context injection on prompt submission.\r\n // chat.message fires on the USER's prompt; output.message is a UserMessage\r\n // and output.parts holds the prompt parts. Inject context by PUSHING a text\r\n // part onto output.parts. chat.message has NO documented block/abort\r\n // mechanism, so a \"deny\" decision degrades to a NO-OP (best-effort) — same\r\n // way the tool/system handlers degrade decisions this host cannot honor.\r\n \"chat.message\": async (input, output) => {\r\n const promptText =\r\n output && Array.isArray(output.parts)\r\n ? output.parts\r\n .filter((p) => p && p.type === \"text\" && typeof p.text === \"string\")\r\n .map((p) => p.text)\r\n .join(\"\\\\n\")\r\n : \"\";\r\n const res = bridge(\"UserPromptSubmit\", {\r\n prompt: promptText,\r\n sessionId: (input && input.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (!res) return;\r\n if (res.additionalContext && output && Array.isArray(output.parts)) {\r\n output.parts.push({ type: \"text\", text: res.additionalContext });\r\n }\r\n },`);\r\n }\r\n\r\n if (has(\"Stop\")) {\r\n handlers.push(` // Stop → session.idle (\"session finished responding\"). session.idle is NOT a\r\n // direct hook key — it is dispatched through the generic \\`event\\` hook\r\n // switching on event.type (the OpenCode plugin shape, per opencode.ai/docs/\r\n // plugins). A block decision throws to halt (MiMoCode has no Stop-gate return\r\n // value). If session.idle never fires on a given build, Stop is a silent\r\n // no-op (an acceptable degrade — it never mis-fires).\r\n event: async ({ event }) => {\r\n if (!event || event.type !== \"session.idle\") return;\r\n const res = bridge(\"Stop\", {\r\n sessionId: (event.properties && event.properties.sessionID) || \"\",\r\n projectDir: PROJECT_DIR,\r\n });\r\n if (res && res.decision === \"deny\") {\r\n throw new Error(res.reason || \"Stop blocked by ${ctx.connector.id}\");\r\n }\r\n },`);\r\n }\r\n\r\n const factory = `\r\nexport default async function (ctx) {\r\n // ctx.directory is the MiMoCode project root; fall back to cwd.\r\n const PROJECT_DIR =\r\n (ctx && (ctx.directory || (ctx.worktree && ctx.worktree.path))) ||\r\n process.cwd();\r\n\r\n return {\r\n${handlers.join(\"\\n\")}\r\n };\r\n}\r\n`;\r\n\r\n return header + factory;\r\n }\r\n\r\n // ── Runtime: parse OUR bridge payload → normalized event ───────────────\r\n\r\n /**\r\n * `raw` is the payload OUR generated plugin posts (NOT a host-native shape):\r\n * { toolName, toolInput, toolOutput?, isError?, sessionId, projectDir }\r\n * so this maps straight through.\r\n */\r\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\r\n const input = (raw ?? {}) as MiMoCodeBridgePayload;\r\n const base = {\r\n hostPlatform: HOST,\r\n connectorId: \"\",\r\n sessionId: typeof input.sessionId === \"string\" ? input.sessionId : \"\",\r\n raw,\r\n ...(typeof input.projectDir === \"string\"\r\n ? { projectDir: input.projectDir }\r\n : {}),\r\n } as const;\r\n\r\n switch (event) {\r\n case \"PreToolUse\": {\r\n const ev: PreToolUseEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n };\r\n return ev;\r\n }\r\n case \"PostToolUse\": {\r\n const ev: PostToolUseEvent = {\r\n ...base,\r\n toolName: input.toolName ?? \"\",\r\n toolInput: input.toolInput ?? {},\r\n ...(typeof input.toolOutput === \"string\"\r\n ? { toolOutput: input.toolOutput }\r\n : {}),\r\n ...(typeof input.isError === \"boolean\"\r\n ? { isError: input.isError }\r\n : {}),\r\n };\r\n return ev;\r\n }\r\n case \"SessionStart\": {\r\n const ev: SessionStartEvent = { ...base, source: \"startup\" };\r\n return ev;\r\n }\r\n case \"UserPromptSubmit\": {\r\n const ev: UserPromptSubmitEvent = {\r\n ...base,\r\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\r\n };\r\n return ev;\r\n }\r\n case \"Stop\": {\r\n const ev: StopEvent = { ...base };\r\n return ev;\r\n }\r\n default:\r\n // Other canonical events are not surfaced by MiMoCode; treat as a\r\n // session-start-shaped no-op so the dispatcher fails open gracefully.\r\n return { ...base, source: \"startup\" } satisfies SessionStartEvent;\r\n }\r\n }\r\n\r\n // ── Runtime: normalized response → reply the generated bridge parses ───\r\n\r\n /**\r\n * Our generated bridge consumes this stdout directly, so the reply body is the\r\n * NORMALIZED HookResponse itself — the bridge JSON.parses it and reads\r\n * decision / updatedInput / updatedOutput / additionalContext.\r\n */\r\n formatReply(_event: HookEventName, response: HookResponse): HookReply {\r\n return {\r\n exitCode: 0,\r\n stdout: JSON.stringify(response ?? { decision: \"allow\" }),\r\n };\r\n }\r\n\r\n // ── Diagnostics ────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const serverPath = this.getServerConfigPath(ctx);\r\n const pluginPath = this.getHookConfigPath(ctx);\r\n const connectorId = ctx.connector.id;\r\n const hasHooks = ctx.connector.hookEvents.length > 0;\r\n\r\n const checks: HealthCheck[] = [\r\n {\r\n name: `${this.name}: mimocode.json present`,\r\n check: () =>\r\n existsSync(serverPath)\r\n ? { status: \"OK\", detail: serverPath }\r\n : { status: \"FAIL\", detail: `not found: ${serverPath}` },\r\n },\r\n {\r\n name: `${this.name}: mcp.${connectorId} registered`,\r\n check: () => {\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(\r\n serverPath,\r\n );\r\n const bucket = cfg?.[MCP_ROOT_KEY];\r\n if (!cfg || !bucket) {\r\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${serverPath}` };\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 ${serverPath}`,\r\n };\r\n },\r\n },\r\n {\r\n name: `${this.name}: plugin module present`,\r\n check: () => {\r\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\r\n return existsSync(pluginPath)\r\n ? { status: \"OK\", detail: pluginPath }\r\n : { status: \"FAIL\", detail: `not found: ${pluginPath}` };\r\n },\r\n },\r\n ];\r\n\r\n for (const cmd of ctx.connector.commands) {\r\n const p = this.commandPath(ctx, cmd.name);\r\n checks.push({\r\n name: `${this.name}: command ${cmd.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n for (const skill of ctx.connector.skills) {\r\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\r\n checks.push({\r\n name: `${this.name}: skill ${skill.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n for (const agent of ctx.connector.subagents) {\r\n const p = this.subagentPath(ctx, agent.name);\r\n checks.push({\r\n name: `${this.name}: subagent ${agent.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n return checks;\r\n }\r\n\r\n /** Read a file, returning undefined on any error (idempotency compare). */\r\n}\r\n\r\nexport const adapter = new MiMoCodeAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/mistral-vibe/index.ts"],"sourcesContent":["/**\r\n * adapters/mistral-vibe — Mistral Vibe (Mistral's coding-agent CLI) adapter.\r\n *\r\n * Mistral Vibe is an **mcp-only** host: it registers MCP servers but exposes no\r\n * user-installable lifecycle-hook surface AC can wire today. Its native config\r\n * is TOML, with a two-level lookup order (project precedes user):\r\n * 1. <projectDir>/.vibe/config.toml (PROJECT — takes precedence)\r\n * 2. ~/.vibe/config.toml (USER)\r\n *\r\n * MCP shape — byte-confirmed from the OFFICIAL repo README\r\n * (github.com/mistralai/mistral-vibe) + docs (docs.mistral.ai/vibe/code/cli/\r\n * configuration + /mcp-servers): the root key `mcp_servers` is a TOML\r\n * ARRAY-OF-TABLES (`[[mcp_servers]]`), NOT codex's table-keyed\r\n * `[mcp_servers.<name>]`. Each entry carries a REQUIRED short-alias `name` field\r\n * — AC writes the CONNECTOR ID there and keys ownership on it (the array-by-name\r\n * merge the `continue` adapter uses for YAML, applied over TOML):\r\n *\r\n * [[mcp_servers]]\r\n * name = \"fetch_server\"\r\n * transport = \"stdio\"\r\n * command = \"uvx\"\r\n * args = [\"mcp-server-fetch\"]\r\n * env = { \"DEBUG\" = \"1\", \"LOG_LEVEL\" = \"info\" }\r\n *\r\n * [[mcp_servers]]\r\n * name = \"my_http_server\"\r\n * transport = \"http\"\r\n * url = \"http://localhost:8000\"\r\n * headers = { \"Authorization\" = \"Bearer my_token\" }\r\n * api_key_env = \"MY_API_KEY_ENV_VAR\"\r\n *\r\n * Per-entry fields:\r\n * - name (required short alias — the connector id)\r\n * - transport (\"stdio\" | \"http\" | \"streamable-http\")\r\n * - stdio → command / args / env\r\n * - http/sse → url / headers / api_key_env / api_key_header / api_key_format\r\n * - optional startup_timeout_sec / tool_timeout_sec\r\n *\r\n * TOML has NO native interpolation token, so every `${env:VAR}` is resolved to a\r\n * literal at install time (the safe path matching codex/droid). The stdio entry\r\n * is routed through the telemetry serve-wrapper (`<homeBin> serve --connector\r\n * <id> -- <command> <args...>`); remote transports are registered but never\r\n * wrapped (they cannot be intercepted).\r\n *\r\n * HOOKS: HONEST CEILING — Mistral Vibe ships only an experimental, unstable hook\r\n * surface (no byte-confirmed format/event-name contract), so AC wires NO hooks\r\n * here. The capability flags stay unset and the host is reported mcp-only (the\r\n * generic installHooks reports \"hooks unavailable\"). When a first-party hook\r\n * contract is byte-confirmed this becomes a normal capability addition.\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { dirname, join } from \"node:path\";\r\n\r\nimport TOML from \"@iarna/toml\";\r\n\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookParadigm,\r\n PlatformCapabilities,\r\n PlatformId,\r\n ServerDef,\r\n Transport,\r\n} from \"../../core/types.js\";\r\nimport { ensureDir } from \"../../core/paths.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport { buildWrappedStdio } from \"../../core/spawn.js\";\r\nimport { BaseAdapter } from \"../base.js\";\r\nimport type { Adapter, InstallContext } from \"../spi.js\";\r\n\r\nconst HOST: PlatformId = \"mistral-vibe\";\r\n/** Root key under which Mistral Vibe stores MCP servers — a TOML ARRAY-OF-TABLES. */\r\nconst MCP_ROOT_KEY = \"mcp_servers\";\r\n\r\n/**\r\n * Native Mistral Vibe MCP server entry shapes. `name` is the required short\r\n * alias (we key ownership on it). A stdio entry carries an explicit\r\n * `transport: \"stdio\"` + command/args/env; a remote entry carries the chosen\r\n * transport + url/headers. NO api_key_* / *_timeout_sec unless declared.\r\n */\r\ninterface VibeStdioServer {\r\n name: string;\r\n transport: \"stdio\";\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n}\r\ninterface VibeRemoteServer {\r\n name: string;\r\n transport: \"http\" | \"streamable-http\";\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\ntype VibeServer = VibeStdioServer | VibeRemoteServer;\r\n\r\nexport class MistralVibeAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Mistral Vibe\";\r\n readonly paradigm: HookParadigm = \"mcp-only\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // mcp-only: no hook layer wired (experimental host hooks are not\r\n // byte-confirmed — see header HONEST CEILING). No memory/content surfaces\r\n // wired either; only the MCP server is installed. Every hook capability is\r\n // false.\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 // Mistral Vibe registers stdio + remote (http / streamable-http) MCP\r\n // servers. The framework's `http` transport maps to Vibe's \"http\"; `sse`\r\n // maps to Vibe's \"streamable-http\" (its closest remote form).\r\n transports: [\"stdio\", \"http\", \"sse\"],\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = this.userConfigDir();\r\n const userCfg = join(userDir, \"config.toml\");\r\n const projDir = join(projectDir, \".vibe\");\r\n const projCfg = join(projDir, \"config.toml\");\r\n\r\n const userInstalled = existsSync(userDir) || existsSync(userCfg);\r\n const projInstalled = existsSync(projDir) || existsSync(projCfg);\r\n const installed = userInstalled || projInstalled;\r\n // Project config.toml takes precedence in Vibe's lookup order, so a\r\n // project-only install reports project scope.\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projCfg : userCfg;\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 Mistral Vibe config (${scope}) at ${configPath}`\r\n : `no .vibe 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 /** ~/.vibe (user) or <projectDir>/.vibe (project). */\r\n override getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".vibe\")\r\n : this.userConfigDir();\r\n }\r\n\r\n /** MCP config: config.toml under the per-scope .vibe dir. */\r\n override getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"config.toml\");\r\n }\r\n\r\n /**\r\n * Mistral Vibe has no AC-wired hook file (mcp-only — see header). The hook\r\n * \"config path\" is the same config.toml so the generic doctor/backup behave\r\n * sensibly (mirrors warp/zed).\r\n */\r\n override getHookConfigPath(ctx: InstallContext): string {\r\n return this.getServerConfigPath(ctx);\r\n }\r\n\r\n /** ~/.vibe — homedir() covers %USERPROFILE% on Windows. */\r\n private userConfigDir(): string {\r\n return join(homedir(), \".vibe\");\r\n }\r\n\r\n // ── TOML config IO ─────────────────────────────────────────────────────────\r\n\r\n private readToml(path: string): Record<string, unknown> {\r\n if (!existsSync(path)) return {};\r\n try {\r\n return TOML.parse(readFileSync(path, \"utf8\")) as Record<string, unknown>;\r\n } catch {\r\n return {};\r\n }\r\n }\r\n\r\n private writeToml(path: string, data: Record<string, unknown>, dryRun: boolean): void {\r\n if (dryRun) return;\r\n ensureDir(dirname(path));\r\n // @iarna/toml's stringify type wants its JsonMap; our object is structurally compatible.\r\n writeFileSync(path, TOML.stringify(data as never), \"utf8\");\r\n }\r\n\r\n // ── MCP server install / uninstall (TOML — ARRAY-OF-TABLES, by `name`) ──────\r\n\r\n override installServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector, dryRun } = ctx;\r\n const path = this.getServerConfigPath(ctx);\r\n const server = this.effectiveServer(ctx);\r\n\r\n if (!server) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: connector.server\r\n ? \"server registration disabled for mistral-vibe\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return [symlink];\r\n\r\n const entry = this.renderServerEntry(ctx, server);\r\n\r\n // Merge into existing TOML, preserving every other config key + sibling\r\n // mcp_servers entry. mcp_servers is a TOML ARRAY-OF-TABLES; we key on `name`.\r\n const cfg = this.readToml(path);\r\n // NEVER clobber a malformed `mcp_servers`: if it exists and is not an array,\r\n // skip-and-warn (symmetric with uninstallServer) rather than silently\r\n // replacing the user's hand-written value.\r\n const existingRoot = cfg[MCP_ROOT_KEY];\r\n if (existingRoot !== undefined && !Array.isArray(existingRoot)) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `${MCP_ROOT_KEY} is not a TOML array — left untouched (manual fix needed)`,\r\n },\r\n ];\r\n }\r\n\r\n const list = Array.isArray(existingRoot) ? (existingRoot as VibeServer[]) : [];\r\n const idx = list.findIndex((e) => this.entryName(e) === connector.id);\r\n\r\n let action: ChangeRecord[\"action\"];\r\n if (idx < 0) {\r\n list.push(entry);\r\n action = \"create\";\r\n } else if (JSON.stringify(list[idx]) === JSON.stringify(entry)) {\r\n action = \"skip\";\r\n } else {\r\n list[idx] = entry;\r\n action = \"update\";\r\n }\r\n\r\n if (action !== \"skip\") {\r\n cfg[MCP_ROOT_KEY] = list;\r\n this.writeToml(path, cfg, dryRun);\r\n }\r\n return [{ platform: this.id, action, path, detail: `${MCP_ROOT_KEY}[name=${connector.id}]` }];\r\n }\r\n\r\n override uninstallServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector, dryRun } = ctx;\r\n const path = this.getServerConfigPath(ctx);\r\n const symlink = this.symlinkPathWarning(path);\r\n if (symlink) return [symlink];\r\n\r\n const cfg = this.readToml(path);\r\n const rawList = cfg[MCP_ROOT_KEY];\r\n if (!Array.isArray(rawList)) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `${MCP_ROOT_KEY}[name=${connector.id}] absent`,\r\n },\r\n ];\r\n }\r\n\r\n const list = rawList as VibeServer[];\r\n const kept = list.filter((e) => this.entryName(e) !== connector.id);\r\n if (kept.length === list.length) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `${MCP_ROOT_KEY}[name=${connector.id}] absent`,\r\n },\r\n ];\r\n }\r\n\r\n cfg[MCP_ROOT_KEY] = kept;\r\n this.writeToml(path, cfg, dryRun);\r\n return [\r\n { platform: this.id, action: \"remove\", path, detail: `${MCP_ROOT_KEY}[name=${connector.id}]` },\r\n ];\r\n }\r\n\r\n /**\r\n * Render a normalized ServerDef into Mistral Vibe's native mcp_servers entry.\r\n * TOML has no native ${env:VAR} token — resolve every reference to a literal at\r\n * install time (the safe path, matching codex/droid). Honors the telemetry\r\n * serve-wrapper for stdio.\r\n */\r\n private renderServerEntry(ctx: InstallContext, server: ServerDef): VibeServer {\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 ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n command = resolveEnvRefsDeep(command);\r\n args = resolveEnvRefsDeep(args);\r\n\r\n const entry: VibeStdioServer = {\r\n name: ctx.connector.id,\r\n transport: \"stdio\",\r\n command,\r\n };\r\n if (args.length > 0) entry.args = args;\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.env = env;\r\n return entry;\r\n }\r\n\r\n // Remote (sse / http / ws) — Vibe registers an explicit transport + url. The\r\n // framework's `http` transport maps to Vibe's \"http\"; `sse` maps to\r\n // \"streamable-http\" (ws has no Vibe analog → also \"streamable-http\", the\r\n // closest documented remote form).\r\n const vibeTransport: VibeRemoteServer[\"transport\"] =\r\n transport === \"http\" ? \"http\" : \"streamable-http\";\r\n const entry: VibeRemoteServer = {\r\n name: ctx.connector.id,\r\n transport: vibeTransport,\r\n url: resolveEnvRefsDeep(server.url ?? \"\"),\r\n };\r\n const headers = this.renderEnv(server.headers);\r\n if (headers) entry.headers = headers;\r\n return entry;\r\n }\r\n\r\n /**\r\n * Render env/header values. Resolve `${env:VAR}` references to literals at\r\n * install time (TOML cannot interpolate).\r\n */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n const out: Record<string, string> = {};\r\n for (const [k, v] of Object.entries(resolveEnvRefsDeep({ ...env }))) {\r\n out[k] = String(v);\r\n }\r\n return out;\r\n }\r\n\r\n // ── Hooks (unavailable — Mistral Vibe is mcp-only) ───────────────────────\r\n // HONEST CEILING: Vibe ships only an experimental hook surface with no\r\n // byte-confirmed format/event-name contract, so AC wires no hooks here.\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 (Mistral Vibe is mcp-only)\",\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 (Mistral Vibe is mcp-only)\",\r\n },\r\n ];\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const path = this.getServerConfigPath(ctx);\r\n const id = ctx.connector.id;\r\n return [\r\n {\r\n name: `${this.name}: config.toml present`,\r\n check: () =>\r\n existsSync(path)\r\n ? { status: \"OK\", detail: path }\r\n : { status: \"FAIL\", detail: `not found: ${path}` },\r\n },\r\n {\r\n name: `${this.name}: ${MCP_ROOT_KEY}[name=${id}] registered`,\r\n check: () => {\r\n if (!ctx.connector.server) return { status: \"OK\", detail: \"no MCP server declared\" };\r\n const cfg = this.readToml(path);\r\n const list = cfg[MCP_ROOT_KEY];\r\n const present =\r\n Array.isArray(list) &&\r\n (list as VibeServer[]).some((e) => this.entryName(e) === id);\r\n return present\r\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}[name=${id}]` }\r\n : { status: \"FAIL\", detail: `${MCP_ROOT_KEY}[name=${id}] not found in ${path}` };\r\n },\r\n },\r\n ];\r\n }\r\n\r\n // ── Internal helpers ──────────────────────────────────────────────────────\r\n\r\n /** The `name` of an array entry, or undefined when it is not a named object. */\r\n private entryName(entry: unknown): string | undefined {\r\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\r\n const name = (entry as { name?: unknown }).name;\r\n return typeof name === \"string\" ? name : undefined;\r\n }\r\n\r\n /** Resolve the per-platform server override into an effective ServerDef. */\r\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\r\n const override = ctx.connector.platforms[this.id]?.server;\r\n if (override === false) return undefined;\r\n const base = ctx.connector.server;\r\n if (!base) return undefined;\r\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\r\n }\r\n}\r\n\r\nexport const adapter = new MistralVibeAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/usage/readers/mux.ts"],"sourcesContent":["/**\r\n * usage/readers/mux — Mux (Coder) native session-usage reader.\r\n *\r\n * Faithful port of tokscale sessions/mux.rs. Reads the aggregate\r\n * ~/.mux/sessions/<workspaceId>/session-usage.json file (one per workspace).\r\n * This is NOT a JSONL log: each file is a single JSON object carrying a\r\n * `byModel` map keyed by `<provider>:<model>`, with one cumulative token bucket\r\n * group per model used in the session:\r\n * byModel.<key>.input.tokens → input\r\n * byModel.<key>.cached.tokens → cacheRead\r\n * byModel.<key>.cacheCreate.tokens → cacheWrite\r\n * byModel.<key>.output.tokens → output\r\n * byModel.<key>.reasoning.tokens → reasoning\r\n * Each bucket also carries an optional `.cost_usd`; the Rust sums those across\r\n * the five buckets into a source cost, but cost is out of scope for v1 readers\r\n * (matching the droid/amp JSON siblings) so we do not emit it. Negative token\r\n * counts are clamped to 0 and an entry whose five dimensions sum to 0 is dropped.\r\n *\r\n * One UsageRecord is produced per `byModel` entry (model used in the session).\r\n * The model key is split on the FIRST ':' only: the prefix is the provider id,\r\n * the remainder is the model id (so \"provider:sub:model\" → provider=\"provider\",\r\n * model=\"sub:model\"). A key with no ':' yields an empty provider and the full\r\n * key as the model id (matching the Rust empty-string provider).\r\n *\r\n * Session id is the parent directory name (the workspaceId), e.g.\r\n * \".../sessions/abc123/session-usage.json\" → \"abc123\". The session-usage.json\r\n * structure carries no cwd/dir, so there is no project attribution. Timestamp\r\n * prefers `lastRequest.timestamp` (i64 epoch milliseconds), falling back to the\r\n * file mtime. No dedup is needed — the file is an aggregate, not an incremental\r\n * log, and each model key appears once. Confidence is \"host-reported\".\r\n *\r\n * Fail-open: no root → []; unreadable/malformed file → skipped (never throws).\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, readJsonFile } from \"../jsonl.js\";\r\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"mux\" as const;\r\n\r\n/** A single token bucket within a model entry (every field optional / unknown). */\r\ninterface MuxTokenBucket {\r\n tokens?: unknown;\r\n}\r\n\r\n/** One model entry under `byModel` (every bucket optional / unknown). */\r\ninterface MuxModelUsage {\r\n input?: MuxTokenBucket;\r\n cached?: MuxTokenBucket;\r\n cacheCreate?: MuxTokenBucket;\r\n output?: MuxTokenBucket;\r\n reasoning?: MuxTokenBucket;\r\n}\r\n\r\n/** The session-usage.json shape we read (everything optional / unknown). */\r\ninterface MuxSessionUsage {\r\n byModel?: unknown;\r\n lastRequest?: {\r\n timestamp?: unknown;\r\n };\r\n}\r\n\r\n/**\r\n * Coerce a bucket's token count to a non-negative integer, mirroring the Rust\r\n * closure `b.as_ref().and_then(|b| b.tokens).unwrap_or(0).max(0)`: absent or\r\n * non-numeric → 0, negatives clamped to 0.\r\n */\r\nfunction bucketTokens(bucket: MuxTokenBucket | undefined): number {\r\n const v = bucket?.tokens;\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/**\r\n * Parse a `lastRequest.timestamp` to epoch ms, or null when unusable. Mux logs\r\n * an i64 of epoch milliseconds, so a positive finite number is taken verbatim\r\n * (no seconds heuristic — the Rust treats it as raw millis).\r\n */\r\nfunction parseTimestampMs(v: unknown): number | null {\r\n if (typeof v === \"number\" && Number.isFinite(v) && v > 0) return Math.trunc(v);\r\n if (typeof v === \"string\") {\r\n const n = Number(v);\r\n if (Number.isFinite(n) && n > 0) return Math.trunc(n);\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Split a model key on the FIRST ':' into provider + model (port of the Rust\r\n * splitn(2, ':')): \"anthropic:claude-opus-4-6\" → { provider: \"anthropic\",\r\n * model: \"claude-opus-4-6\" }; \"provider:sub:model\" → { provider: \"provider\",\r\n * model: \"sub:model\" }; a key with no ':' → empty provider, full key as model.\r\n */\r\nfunction splitModelKey(key: string): { provider: string; model: string } {\r\n const colon = key.indexOf(\":\");\r\n if (colon < 0) return { provider: \"\", model: key };\r\n return { provider: key.slice(0, colon), model: key.slice(colon + 1) };\r\n}\r\n\r\n/** Parse one mux session-usage.json file into usage records (port of parse_mux_file). */\r\nfunction parseMuxFile(path: string): UsageRecord[] {\r\n const raw = readJsonFile(path);\r\n if (typeof raw !== \"object\" || raw === null) return [];\r\n const usage = raw as MuxSessionUsage;\r\n\r\n const byModel = usage.byModel;\r\n if (typeof byModel !== \"object\" || byModel === null) return [];\r\n\r\n // Timestamp: lastRequest.timestamp (epoch ms) else the file mtime.\r\n const ts = parseTimestampMs(usage.lastRequest?.timestamp) ?? fileMtimeMs(path);\r\n\r\n // Session id = the parent directory name (the workspaceId).\r\n const sessionId = basename(dirname(path));\r\n\r\n const out: UsageRecord[] = [];\r\n for (const [modelKey, value] of Object.entries(byModel as Record<string, unknown>)) {\r\n if (typeof value !== \"object\" || value === null) continue;\r\n const modelUsage = value as MuxModelUsage;\r\n\r\n const input = bucketTokens(modelUsage.input);\r\n const cacheRead = bucketTokens(modelUsage.cached);\r\n const cacheWrite = bucketTokens(modelUsage.cacheCreate);\r\n const output = bucketTokens(modelUsage.output);\r\n const reasoning = bucketTokens(modelUsage.reasoning);\r\n\r\n // Skip entries with no tokens in any dimension.\r\n if (input + cacheRead + cacheWrite + output + reasoning === 0) continue;\r\n\r\n const { provider, model } = splitModelKey(modelKey);\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = cacheWrite;\r\n tokens.reasoning = reasoning;\r\n\r\n out.push({\r\n platformId: PLATFORM_ID,\r\n modelId: model,\r\n providerId: provider,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n confidence: \"host-reported\",\r\n });\r\n }\r\n\r\n return out;\r\n}\r\n\r\n/** The Mux (Coder) usage reader singleton. */\r\nconst muxReader: 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 ~/.mux/sessions → fail-open\r\n\r\n // ~/.mux/sessions/<workspaceId>/session-usage.json\r\n const files = walkFiles(root, (name) => name === \"session-usage.json\");\r\n\r\n const records: UsageRecord[] = [];\r\n for (const file of files) {\r\n const rows = parseMuxFile(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 muxReader;\r\n"],"mappings":";;;;;;;;;;;;;;AAkCA,SAAS,UAAU,eAAe;AAOlC,IAAM,cAAc;AA6BpB,SAAS,aAAa,QAA4C;AAChE,QAAM,IAAI,QAAQ;AAClB,QAAM,IAAI,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,WAAW,OAAO,CAAC,IAAI;AAC1E,MAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,SAAO,KAAK,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC;AAClC;AAOA,SAAS,iBAAiB,GAA2B;AACnD,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,IAAI,EAAG,QAAO,KAAK,MAAM,CAAC;AAC7E,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,IAAI,OAAO,CAAC;AAClB,QAAI,OAAO,SAAS,CAAC,KAAK,IAAI,EAAG,QAAO,KAAK,MAAM,CAAC;AAAA,EACtD;AACA,SAAO;AACT;AAQA,SAAS,cAAc,KAAkD;AACvE,QAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,MAAI,QAAQ,EAAG,QAAO,EAAE,UAAU,IAAI,OAAO,IAAI;AACjD,SAAO,EAAE,UAAU,IAAI,MAAM,GAAG,KAAK,GAAG,OAAO,IAAI,MAAM,QAAQ,CAAC,EAAE;AACtE;AAGA,SAAS,aAAa,MAA6B;AACjD,QAAM,MAAM,aAAa,IAAI;AAC7B,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,CAAC;AACrD,QAAM,QAAQ;AAEd,QAAM,UAAU,MAAM;AACtB,MAAI,OAAO,YAAY,YAAY,YAAY,KAAM,QAAO,CAAC;AAG7D,QAAM,KAAK,iBAAiB,MAAM,aAAa,SAAS,KAAK,YAAY,IAAI;AAG7E,QAAM,YAAY,SAAS,QAAQ,IAAI,CAAC;AAExC,QAAM,MAAqB,CAAC;AAC5B,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,OAAkC,GAAG;AAClF,QAAI,OAAO,UAAU,YAAY,UAAU,KAAM;AACjD,UAAM,aAAa;AAEnB,UAAM,QAAQ,aAAa,WAAW,KAAK;AAC3C,UAAM,YAAY,aAAa,WAAW,MAAM;AAChD,UAAM,aAAa,aAAa,WAAW,WAAW;AACtD,UAAM,SAAS,aAAa,WAAW,MAAM;AAC7C,UAAM,YAAY,aAAa,WAAW,SAAS;AAGnD,QAAI,QAAQ,YAAY,aAAa,SAAS,cAAc,EAAG;AAE/D,UAAM,EAAE,UAAU,MAAM,IAAI,cAAc,QAAQ;AAElD,UAAM,SAAS,YAAY;AAC3B,WAAO,QAAQ;AACf,WAAO,SAAS;AAChB,WAAO,YAAY;AACnB,WAAO,aAAa;AACpB,WAAO,YAAY;AAEnB,QAAI,KAAK;AAAA,MACP,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAGA,IAAM,YAAyB;AAAA,EAC7B,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,MAAM,KAAK,EAAE,QAAQ,GAAiD;AACpE,UAAM,OAAO,kBAAkB,WAAW;AAC1C,QAAI,SAAS,OAAW,QAAO,CAAC;AAGhC,UAAM,QAAQ,UAAU,MAAM,CAAC,SAAS,SAAS,oBAAoB;AAErE,UAAM,UAAyB,CAAC;AAChC,eAAW,QAAQ,OAAO;AACxB,YAAM,OAAO,aAAa,IAAI;AAC9B,iBAAW,OAAO,MAAM;AACtB,YAAI,YAAY,UAAa,IAAI,KAAK,QAAS;AAC/C,gBAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAO,cAAQ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/mux/index.ts"],"sourcesContent":["/**\r\n * adapters/mux — Mux (Coder) platform adapter for agent-connector.\r\n *\r\n * Mux is an **mcp-only** host: it exposes no lifecycle hook system, and MCP is\r\n * its extensibility mechanism. This adapter therefore installs only the MCP\r\n * server and reports hooks as unavailable — the same shape as the Warp\r\n * reference adapter.\r\n *\r\n * MCP config:\r\n * - user scope → ~/.mux/mcp.jsonc\r\n * - project scope → <projectDir>/.mux/mcp.jsonc\r\n * Both are JSONC (comments allowed) but we write strict JSON. The root key is\r\n * \"servers\", and this file doubles as the (non-existent) hook config — there\r\n * is no separate hook file here.\r\n *\r\n * QUIRK: Mux models each server entry as a single shell-command STRING, not an\r\n * object. So `servers[id]` is `\"<exe> <arg1> <arg2> ...\"` — space-joined, with\r\n * any token containing whitespace double-quoted. We therefore build that string\r\n * ourselves and upsert it idempotently (the generic object upsert helper would\r\n * write the wrong shape). When telemetry-wrapping, the string is the home-bin\r\n * `serve` wrapper command followed by its args.\r\n *\r\n * Mux documents no native `${env:VAR}` interpolation token, so env-refs in the\r\n * command/args are resolved to literals at install time. The string form has no\r\n * place for an env map, so server.env is dropped with no native equivalent.\r\n */\r\n\r\nimport { existsSync, statSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { dirname, join } from \"node:path\";\r\n\r\nimport { BaseAdapter } from \"../base.js\";\r\nimport type { Adapter, InstallContext } from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookParadigm,\r\n PlatformCapabilities,\r\n PlatformId,\r\n ServerDef,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefs, resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport {\r\n buildWrappedStdio,\r\n} from \"../../core/spawn.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\n\r\nconst HOST: PlatformId = \"mux\";\r\nconst MCP_ROOT_KEY = \"servers\";\r\n\r\n/**\r\n * Mux enforces this exact pattern (1–64 chars) on a SKILL directory name, and\r\n * the SKILL.md `name` field MUST equal the directory name\r\n * (mux.coder.com/agents/agent-skills). A skill name that does not match is\r\n * skip-warned rather than written to a dir Mux would reject.\r\n */\r\nconst MUX_SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\r\nconst MUX_SKILL_NAME_MAX = 64;\r\n\r\n/** Quote a token only when it contains whitespace (Mux command-string form). */\r\nfunction quoteToken(token: string): string {\r\n return /\\s/.test(token) ? `\"${token}\"` : token;\r\n}\r\n\r\n/** Join an executable + args into Mux's single shell-command string. */\r\nfunction buildCommandString(command: string, args: readonly string[]): string {\r\n return [command, ...args].map(quoteToken).join(\" \");\r\n}\r\n\r\nexport class MuxAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Mux\";\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 // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\r\n supportsMemory: true,\r\n // Mux has no lifecycle hook system — every hook capability is false.\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 // Mux's command-string server entry is stdio-only.\r\n transports: [\"stdio\"],\r\n // Content surface: Mux auto-discovers dir-per-skill SKILL.md from its\r\n // workspace-local and global roots (mux.coder.com/agents/agent-skills,\r\n // fetched 2026-06-16):\r\n // project → <projectDir>/.mux/skills/<name>/SKILL.md (workspace-local)\r\n // user → ~/.mux/skills/<name>/SKILL.md (global, Mux-specific)\r\n // The skill directory name MUST match ^[a-z0-9]+(?:-[a-z0-9]+)*$ (1–64\r\n // chars) and the SKILL.md `name` field must equal it — a name that cannot\r\n // be represented is skip-warned (see installSkills).\r\n supportsSkills: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = join(homedir(), \".mux\");\r\n const userMcp = join(userDir, \"mcp.jsonc\");\r\n const projDir = join(projectDir, \".mux\");\r\n const projMcp = join(projDir, \"mcp.jsonc\");\r\n\r\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\r\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\r\n const installed = userInstalled || projInstalled;\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projMcp : userMcp;\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 Mux config (${scope})`\r\n : `no Mux 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, \".mux\")\r\n : join(homedir(), \".mux\");\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"mcp.jsonc\");\r\n }\r\n\r\n /**\r\n * Mux has no hook file — hooks are not a thing here. The hook \"config path\"\r\n * is the same mcp.jsonc so the generic doctor/backup behave sensibly.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return this.getServerConfigPath(ctx);\r\n }\r\n\r\n // ── MCP server install / uninstall ───────────────────────────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector, dryRun } = 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 mux\"\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 path = this.getServerConfigPath(ctx);\r\n\r\n if (server.transport !== \"stdio\" || !server.command) {\r\n // Mux's command-string entry is stdio-only; remote transports skip.\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n path,\r\n detail: `transport \"${server.transport}\" not registrable (mux expects a stdio command string)`,\r\n },\r\n ];\r\n }\r\n\r\n const entry = this.renderCommandString(ctx, server);\r\n // Mux's server VALUE is a command string, but the object-map upsert is\r\n // value-agnostic — route through the shared helper (byte-identical output).\r\n return [this.upsertServerInJson(path, MCP_ROOT_KEY, connector.id, entry, dryRun)];\r\n }\r\n\r\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\r\n const path = this.getServerConfigPath(ctx);\r\n return [\r\n this.removeServerFromJson(path, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\r\n ];\r\n }\r\n\r\n /**\r\n * Render a stdio ServerDef into Mux's single shell-command string. Honors the\r\n * telemetry serve-wrapper and resolves every `${env:VAR}` to a literal (Mux\r\n * documents no native interpolation token).\r\n */\r\n private renderCommandString(ctx: InstallContext, server: ServerDef): string {\r\n let command = server.command ?? \"\";\r\n let args = [...(server.args ?? [])];\r\n\r\n // Transparent telemetry wrapping: route the real command through\r\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\r\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n // Resolve env-refs to literals (Mux has no native interpolation token).\r\n command = resolveEnvRefs(command);\r\n args = resolveEnvRefsDeep(args);\r\n\r\n return buildCommandString(command, args);\r\n }\r\n\r\n // ── Hooks (unavailable — Mux is mcp-only) ─────────────────────────────────\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 (Mux is mcp-only)\",\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 (Mux is mcp-only)\",\r\n },\r\n ];\r\n }\r\n\r\n // ── Content surface: skills (dir-per-skill SKILL.md) ─────────────────────\r\n // CONTENT-ONLY: pure native-file writers, mirroring goose/openclaw. No\r\n // runtime dispatch, no home-bin pointer, no telemetry wrap. Idempotent\r\n // (byte-identical → skip) via writeContentFile and reversible via\r\n // removeContentFile + removeDirIfEmpty. Honors platforms[\"mux\"].skills ===\r\n // false. No mcp.jsonc entry — Mux auto-discovers the skills dirs.\r\n //\r\n // Native locations (mux.coder.com/agents/agent-skills):\r\n // project → <projectDir>/.mux/skills/<name>/SKILL.md (workspace-local)\r\n // user → ~/.mux/skills/<name>/SKILL.md (global, Mux-specific)\r\n // The dir name MUST match MUX_SKILL_NAME_RE (1–64 chars) and the SKILL.md\r\n // `name` field must equal it — a name that can't be represented is skip-warned.\r\n\r\n /** The skills ROOT dir for ctx.scope (parent of every per-skill dir). */\r\n private skillsDir(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"skills\");\r\n }\r\n\r\n /** Per-skill directory: <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 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 mux\" }];\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 // Mux REQUIRES the dir name (and SKILL.md `name`) to match its pattern;\r\n // a name we cannot represent is skip-warned rather than written to a dir\r\n // Mux would reject (the honesty bar — never write an unreadable path).\r\n if (!this.isValidSkillName(skill.name)) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail:\r\n `skill \"${skill.name}\" cannot be represented on mux ` +\r\n `(name must match ${MUX_SKILL_NAME_RE.source}, 1–${MUX_SKILL_NAME_MAX} chars); skipped`,\r\n });\r\n continue;\r\n }\r\n const dir = this.skillDir(ctx, skill.name);\r\n // Guard a skills path occupied by a regular FILE (mkdir would throw\r\n // ENOTDIR): skip-warn rather than crash (cline `.clinerules`-is-a-file\r\n // precedent).\r\n const blockingFile = this.firstFileOnSkillPath(ctx, dir);\r\n if (blockingFile !== null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n path: blockingFile,\r\n detail: `${blockingFile} is a file, not a directory; skill \"${skill.name}\" skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\r\n );\r\n // Bundle any resource files beside SKILL.md (relative path → contents).\r\n // Defense-in-depth: skip+warn on any key that escapes the skill dir.\r\n 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 // Skip names install never wrote (invalid → never on disk under our dir).\r\n if (!this.isValidSkillName(skill.name)) continue;\r\n const dir = this.skillDir(ctx, skill.name);\r\n // Remove only the files we wrote (SKILL.md + declared resources), then the\r\n // skill dir itself when we own its full contents.\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue; // never delete outside the skill dir\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n // Only remove the skill dir when WE own its full contents — never rm -rf a\r\n // dir that still holds user-added / sibling-tool / shared files.\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n if (changes.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"no installable skills to remove\" }];\r\n }\r\n return changes;\r\n }\r\n\r\n /** True when a skill name is representable as a Mux skill directory name. */\r\n private isValidSkillName(name: string): boolean {\r\n return name.length >= 1 && name.length <= MUX_SKILL_NAME_MAX && MUX_SKILL_NAME_RE.test(name);\r\n }\r\n\r\n /**\r\n * Walk from the skills root down to `leaf` and return the FIRST segment that\r\n * exists as a regular file (a mkdir there throws ENOTDIR), else null — so\r\n * installSkills can skip-warn instead of crashing.\r\n */\r\n private firstFileOnSkillPath(ctx: InstallContext, leaf: string): string | null {\r\n const root = this.skillsDir(ctx);\r\n const segments: string[] = [];\r\n let cur = leaf;\r\n while (cur.length >= root.length) {\r\n segments.unshift(cur);\r\n if (cur === root) break;\r\n const parent = dirname(cur);\r\n if (parent === cur) break;\r\n cur = parent;\r\n }\r\n for (const p of segments) {\r\n if (!existsSync(p)) return null;\r\n try {\r\n if (statSync(p).isFile()) return p;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n return null;\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 connectorId = ctx.connector.id;\r\n return [\r\n {\r\n name: `${this.name}: mcp.jsonc 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 // Only assert what the connector declares: a server-less connector\r\n // never writes an mcpServers entry, so its absence is healthy.\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> }>(\r\n mcpPath,\r\n );\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 }\r\n}\r\n\r\nexport const adapter = new MuxAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/nemoclaw/index.ts"],"sourcesContent":["/**\r\n * adapters/nemoclaw — NVIDIA NemoClaw platform adapter for agent-connector.\r\n *\r\n * NemoClaw (github.com/NVIDIA/NemoClaw, Apache-2.0, v0.1.0) is an\r\n * orchestrator/wrapper that deploys and lifecycle-manages an OpenClaw agent\r\n * (the default) inside an NVIDIA OpenShell sandbox. It is ALSO an OpenClaw\r\n * plugin. It is NOT a Claude/Codex/Gemini fork: the agent it wraps is OpenClaw,\r\n * and the config the wrapped agent actually loads is the SAME\r\n * `~/.openclaw/openclaw.json` the OpenClaw adapter already targets (top-level\r\n * `mcp.servers.<id>` for MCP sidecars; plugins.entries + plugins.load.paths for\r\n * the ts-plugin bridge — OpenClaw's verified DUAL REGISTRATION shape).\r\n *\r\n * DESIGN — a thin fork of {@link OpenClawAdapter} (precedent:\r\n * AntigravityCliAdapter extends AntigravityAdapter). It REUSES every render /\r\n * hook / parse / surface path from the parent unchanged — MCP still lands in\r\n * the wrapped `~/.openclaw/openclaw.json`, the paradigm stays ts-plugin, and the\r\n * content surfaces (skills) are inherited. The ONLY differences are identity and\r\n * detection:\r\n *\r\n * - id = \"nemoclaw\", name = \"NVIDIA NemoClaw\". Identity flows into the\r\n * ChangeRecord `platform` stamp and the host-detection result.\r\n * - detectInstalled probes the NemoClaw-specific marker `~/.nemoclaw/`\r\n * (config.json + rebuild-backups/ + blueprints/). A NemoClaw box has BOTH\r\n * markers on disk: it DRIVES the wrapped `~/.openclaw/openclaw.json`, so\r\n * `~/.openclaw/` is present too. Exclusivity is therefore guaranteed at the\r\n * SOURCE, not by registry order alone — {@link OpenClawAdapter.detectInstalled}\r\n * BOWS OUT (reports its user scope not-installed) whenever `~/.nemoclaw/`\r\n * exists, so the shared config is never double-targeted as two platforms\r\n * (an `uninstall openclaw` would otherwise strip nemoclaw's entries). nemoclaw\r\n * is ALSO registered BEFORE openclaw (PlatformId union AND ADAPTER_REGISTRY)\r\n * as the deterministic tie-break — a NemoClaw box classifies as nemoclaw; an\r\n * OpenClaw-only box (no `~/.nemoclaw/`) classifies as openclaw.\r\n *\r\n * HOOKS: NemoClaw ships NO Claude-style lifecycle hooks of its own\r\n * (managedChannels are messaging; plugin activation.onStartup and runtime-slash\r\n * aliases are not hook events). It nonetheless INHERITS OpenClaw's ts-plugin\r\n * hook machinery — when a connector declares hooks, the inherited installHooks\r\n * writes the same self-contained OpenClaw plugin bridge into the wrapped\r\n * `~/.openclaw/openclaw.json` (the agent NemoClaw runs), so the paradigm stays\r\n * ts-plugin honestly.\r\n *\r\n * SOURCES: github.com/NVIDIA/NemoClaw (README, nemoclaw/openclaw.plugin.json,\r\n * src/onboard/config.ts, test/openclaw-config-snapshot.test.ts,\r\n * src/lib/state/sandbox.ts), docs.nvidia.com/nemoclaw.\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 { OpenClawAdapter } from \"../openclaw/index.js\";\r\nimport type { Adapter } from \"../spi.js\";\r\nimport type { DetectedPlatform, PlatformId } from \"../../core/types.js\";\r\n\r\nconst HOST: PlatformId = \"nemoclaw\";\r\n\r\nexport class NemoClawAdapter extends OpenClawAdapter implements Adapter {\r\n override readonly id: PlatformId = HOST;\r\n override readonly name = \"NVIDIA NemoClaw\";\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Probe the NemoClaw-specific marker `~/.nemoclaw/` (its onboarding writes\r\n * config.json + rebuild-backups/ + blueprints/ there). This is DISTINCT from\r\n * OpenClaw's `~/.openclaw/` marker even though NemoClaw drives the wrapped\r\n * OpenClaw config: a box with `~/.nemoclaw/` is a NemoClaw install. Reported\r\n * before the OpenClaw adapter in the registry so the more-specific NemoClaw\r\n * marker wins host detection (a plain OpenClaw box — `~/.openclaw/` only,\r\n * no `~/.nemoclaw/` — falls through to the openclaw adapter).\r\n *\r\n * The config path returned is the WRAPPED OpenClaw config (where MCP/hooks are\r\n * actually written) so install/doctor point at the file the agent loads.\r\n */\r\n override detectInstalled(projectDir: string): DetectedPlatform {\r\n const nemoclawDir = join(homedir(), \".nemoclaw\");\r\n const installed = existsSync(nemoclawDir);\r\n\r\n // Inherit OpenClaw's path resolution for the wrapped config (the file the\r\n // agent NemoClaw runs actually loads) and the capabilities/paradigm.\r\n const base = super.detectInstalled(projectDir);\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 // Where MCP/hooks land for NemoClaw: the wrapped OpenClaw config.\r\n configPath: base.configPath,\r\n scope: base.scope,\r\n reason: installed\r\n ? `found NVIDIA NemoClaw config at ${nemoclawDir} (wraps OpenClaw at ${base.configPath})`\r\n : `no NVIDIA NemoClaw config at ${nemoclawDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n}\r\n\r\nexport const adapter = new NemoClawAdapter();\r\nexport default adapter;\r\n"],"mappings":";;;;;;;;;;;AA8CA,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY;AAMrB,IAAM,OAAmB;AAElB,IAAM,kBAAN,cAA8B,gBAAmC;AAAA,EACpD,KAAiB;AAAA,EACjB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBhB,gBAAgB,YAAsC;AAC7D,UAAM,cAAc,KAAK,QAAQ,GAAG,WAAW;AAC/C,UAAM,YAAY,WAAW,WAAW;AAIxC,UAAM,OAAO,MAAM,gBAAgB,UAAU;AAE7C,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX;AAAA,MACA,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA;AAAA,MAEnB,YAAY,KAAK;AAAA,MACjB,OAAO,KAAK;AAAA,MACZ,QAAQ,YACJ,mCAAmC,WAAW,uBAAuB,KAAK,UAAU,MACpF,gCAAgC,WAAW;AAAA,MAC/C,YAAY,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AACF;AAEO,IAAM,UAAU,IAAI,gBAAgB;AAC3C,IAAO,mBAAQ;","names":[]}