@shareai-lab/kode 2.0.2 → 2.0.3

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 (343) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +649 -25
  3. package/README.zh-CN.md +579 -0
  4. package/cli-acp.js +3 -17
  5. package/cli.js +5 -7
  6. package/dist/chunks/Doctor-M3J7GRTJ.js +12 -0
  7. package/dist/chunks/LogList-ISWZ6DDD.js +121 -0
  8. package/dist/chunks/LogList-ISWZ6DDD.js.map +7 -0
  9. package/dist/chunks/REPL-RQ6LO6S7.js +56 -0
  10. package/dist/chunks/ResumeConversation-6DMVBEGH.js +56 -0
  11. package/dist/chunks/agentLoader-FCRG3TFJ.js +31 -0
  12. package/dist/{agentsValidate-XP3CFN6F.js → chunks/agentsValidate-PEWMYN4Q.js} +97 -69
  13. package/dist/chunks/agentsValidate-PEWMYN4Q.js.map +7 -0
  14. package/dist/{ask-3G5H5KD5.js → chunks/ask-D7SOHJ6Z.js} +36 -44
  15. package/dist/chunks/ask-D7SOHJ6Z.js.map +7 -0
  16. package/dist/chunks/autoUpdater-CNESBOKO.js +19 -0
  17. package/dist/{chunk-EH34V7CY.js → chunks/chunk-2JN5MY67.js} +12 -14
  18. package/dist/chunks/chunk-2JN5MY67.js.map +7 -0
  19. package/dist/chunks/chunk-2QONJ5MG.js +14 -0
  20. package/dist/chunks/chunk-2QONJ5MG.js.map +7 -0
  21. package/dist/chunks/chunk-2WEXPKHH.js +903 -0
  22. package/dist/chunks/chunk-2WEXPKHH.js.map +7 -0
  23. package/dist/{chunk-K2MI4TPB.js → chunks/chunk-3BYE3ME6.js} +717 -792
  24. package/dist/chunks/chunk-3BYE3ME6.js.map +7 -0
  25. package/dist/chunks/chunk-3JDNWX7W.js +1264 -0
  26. package/dist/chunks/chunk-3JDNWX7W.js.map +7 -0
  27. package/dist/chunks/chunk-3OEJVB5A.js +906 -0
  28. package/dist/chunks/chunk-3OEJVB5A.js.map +7 -0
  29. package/dist/chunks/chunk-3TNIOEBO.js +369 -0
  30. package/dist/chunks/chunk-3TNIOEBO.js.map +7 -0
  31. package/dist/chunks/chunk-4A46ZXMJ.js +67 -0
  32. package/dist/chunks/chunk-4A46ZXMJ.js.map +7 -0
  33. package/dist/{chunk-4GAIJGRH.js → chunks/chunk-4ATBQOFO.js} +107 -55
  34. package/dist/chunks/chunk-4ATBQOFO.js.map +7 -0
  35. package/dist/chunks/chunk-4CRUCZR4.js +0 -0
  36. package/dist/{chunk-54DNHKOD.js → chunks/chunk-4EO6SIQY.js} +32 -75
  37. package/dist/chunks/chunk-4EO6SIQY.js.map +7 -0
  38. package/dist/chunks/chunk-53M46S5I.js +64 -0
  39. package/dist/chunks/chunk-53M46S5I.js.map +7 -0
  40. package/dist/{chunk-JC6NCUG5.js → chunks/chunk-54KOYG5C.js} +0 -2
  41. package/dist/{chunk-EZXMVTDU.js → chunks/chunk-6BAS4WY6.js} +29 -45
  42. package/dist/chunks/chunk-6BAS4WY6.js.map +7 -0
  43. package/dist/{chunk-BHGTA6JQ.js → chunks/chunk-6KRRFSDN.js} +4 -6
  44. package/dist/chunks/chunk-6KRRFSDN.js.map +7 -0
  45. package/dist/chunks/chunk-6LJNZK4K.js +39 -0
  46. package/dist/chunks/chunk-6LJNZK4K.js.map +7 -0
  47. package/dist/chunks/chunk-6ZWEOSEI.js +666 -0
  48. package/dist/chunks/chunk-6ZWEOSEI.js.map +7 -0
  49. package/dist/chunks/chunk-77XDJMBP.js +3326 -0
  50. package/dist/chunks/chunk-77XDJMBP.js.map +7 -0
  51. package/dist/chunks/chunk-7RRW4NTB.js +6454 -0
  52. package/dist/chunks/chunk-7RRW4NTB.js.map +7 -0
  53. package/dist/chunks/chunk-7X3TW4JB.js +4520 -0
  54. package/dist/chunks/chunk-7X3TW4JB.js.map +7 -0
  55. package/dist/chunks/chunk-B3MW3YGY.js +1409 -0
  56. package/dist/chunks/chunk-B3MW3YGY.js.map +7 -0
  57. package/dist/chunks/chunk-BBJFHTBC.js +28 -0
  58. package/dist/chunks/chunk-BBJFHTBC.js.map +7 -0
  59. package/dist/chunks/chunk-BHDHXOXB.js +24 -0
  60. package/dist/chunks/chunk-BHDHXOXB.js.map +7 -0
  61. package/dist/{chunk-OZNRLY3E.js → chunks/chunk-BTA7SZ26.js} +152 -223
  62. package/dist/chunks/chunk-BTA7SZ26.js.map +7 -0
  63. package/dist/chunks/chunk-CDGRYGPZ.js +103 -0
  64. package/dist/chunks/chunk-CDGRYGPZ.js.map +7 -0
  65. package/dist/{chunk-S6HRABTA.js → chunks/chunk-CP6E5UG6.js} +1 -4
  66. package/dist/chunks/chunk-CP6E5UG6.js.map +7 -0
  67. package/dist/{chunk-2PMO2FS2.js → chunks/chunk-DQ4JHXMT.js} +462 -424
  68. package/dist/chunks/chunk-DQ4JHXMT.js.map +7 -0
  69. package/dist/chunks/chunk-DXD76CMV.js +208 -0
  70. package/dist/chunks/chunk-DXD76CMV.js.map +7 -0
  71. package/dist/chunks/chunk-GCQCAXJZ.js +0 -0
  72. package/dist/chunks/chunk-GELCZWMB.js +42 -0
  73. package/dist/chunks/chunk-GELCZWMB.js.map +7 -0
  74. package/dist/{chunk-NQLEUHMS.js → chunks/chunk-HJYOH4HC.js} +23 -18
  75. package/dist/chunks/chunk-HJYOH4HC.js.map +7 -0
  76. package/dist/chunks/chunk-HPYNW6TT.js +744 -0
  77. package/dist/chunks/chunk-HPYNW6TT.js.map +7 -0
  78. package/dist/{chunk-2KWKUXLT.js → chunks/chunk-HRJ3ICQK.js} +59 -55
  79. package/dist/chunks/chunk-HRJ3ICQK.js.map +7 -0
  80. package/dist/{chunk-ZQU3TXLC.js → chunks/chunk-IFCIADS3.js} +571 -573
  81. package/dist/chunks/chunk-IFCIADS3.js.map +7 -0
  82. package/dist/chunks/chunk-IN7XZ7BC.js +27 -0
  83. package/dist/chunks/chunk-IN7XZ7BC.js.map +7 -0
  84. package/dist/chunks/chunk-L7P4M4KW.js +193 -0
  85. package/dist/chunks/chunk-L7P4M4KW.js.map +7 -0
  86. package/dist/chunks/chunk-LB6TCPDI.js +0 -0
  87. package/dist/{chunk-3RUXVV4S.js → chunks/chunk-LOCXPQNJ.js} +1 -4
  88. package/dist/{chunk-3RUXVV4S.js.map → chunks/chunk-LOCXPQNJ.js.map} +2 -2
  89. package/dist/{chunk-IE2CG2TV.js → chunks/chunk-LOD5ZHCI.js} +213 -208
  90. package/dist/chunks/chunk-LOD5ZHCI.js.map +7 -0
  91. package/dist/{chunk-S3J2TLV6.js → chunks/chunk-M7P3QNRU.js} +1 -4
  92. package/dist/{chunk-S3J2TLV6.js.map → chunks/chunk-M7P3QNRU.js.map} +2 -2
  93. package/dist/chunks/chunk-PPHLQVL7.js +4234 -0
  94. package/dist/chunks/chunk-PPHLQVL7.js.map +7 -0
  95. package/dist/{chunk-ABLVTESJ.js → chunks/chunk-QAXE37B5.js} +1 -4
  96. package/dist/chunks/chunk-QAXE37B5.js.map +7 -0
  97. package/dist/chunks/chunk-QHQOBUF6.js +60 -0
  98. package/dist/chunks/chunk-QHQOBUF6.js.map +7 -0
  99. package/dist/{chunk-SRZZFAS7.js → chunks/chunk-RPJXO7GG.js} +241 -214
  100. package/dist/chunks/chunk-RPJXO7GG.js.map +7 -0
  101. package/dist/{chunk-NPFOMITO.js → chunks/chunk-SWQV4KSY.js} +1 -4
  102. package/dist/{chunk-NPFOMITO.js.map → chunks/chunk-SWQV4KSY.js.map} +2 -2
  103. package/dist/chunks/chunk-SZLAPULP.js +28 -0
  104. package/dist/chunks/chunk-SZLAPULP.js.map +7 -0
  105. package/dist/{chunk-SDGKPKDK.js → chunks/chunk-T7RB5V5J.js} +23 -25
  106. package/dist/chunks/chunk-T7RB5V5J.js.map +7 -0
  107. package/dist/{chunk-HN4E4UUQ.js → chunks/chunk-TI2CTTMA.js} +25 -17
  108. package/dist/chunks/chunk-TI2CTTMA.js.map +7 -0
  109. package/dist/{chunk-G6I7XROM.js → chunks/chunk-TNGVRTO5.js} +45 -20
  110. package/dist/chunks/chunk-TNGVRTO5.js.map +7 -0
  111. package/dist/chunks/chunk-TNWB3U5Y.js +2077 -0
  112. package/dist/chunks/chunk-TNWB3U5Y.js.map +7 -0
  113. package/dist/chunks/chunk-U2IHWPCU.js +12 -0
  114. package/dist/chunks/chunk-U2IHWPCU.js.map +7 -0
  115. package/dist/{chunk-KAA5BGMQ.js → chunks/chunk-UNOY3VJ2.js} +1 -4
  116. package/dist/{chunk-KAA5BGMQ.js.map → chunks/chunk-UNOY3VJ2.js.map} +2 -2
  117. package/dist/{chunk-3TXNP6HH.js → chunks/chunk-UVDJL6ZZ.js} +97 -58
  118. package/dist/chunks/chunk-UVDJL6ZZ.js.map +7 -0
  119. package/dist/chunks/chunk-VNCW4C2Z.js +13452 -0
  120. package/dist/chunks/chunk-VNCW4C2Z.js.map +7 -0
  121. package/dist/chunks/chunk-W5EGGA44.js +15 -0
  122. package/dist/chunks/chunk-W5EGGA44.js.map +7 -0
  123. package/dist/chunks/chunk-XR2W3MAM.js +1533 -0
  124. package/dist/chunks/chunk-XR2W3MAM.js.map +7 -0
  125. package/dist/{chunk-QYFKRZQC.js → chunks/chunk-YIO5EBMQ.js} +423 -377
  126. package/dist/chunks/chunk-YIO5EBMQ.js.map +7 -0
  127. package/dist/chunks/chunk-ZBVLKZ5V.js +1062 -0
  128. package/dist/chunks/chunk-ZBVLKZ5V.js.map +7 -0
  129. package/dist/{chunk-E6YNABER.js → chunks/chunk-ZCLTZIVP.js} +1 -4
  130. package/dist/chunks/chunk-ZCLTZIVP.js.map +7 -0
  131. package/dist/chunks/client-SILZNM5N.js +42 -0
  132. package/dist/{config-6ZMBCL23.js → chunks/config-25HRTPSP.js} +48 -10
  133. package/dist/chunks/cost-tracker-Z2UZT2J5.js +28 -0
  134. package/dist/{customCommands-DNEJS3ZU.js → chunks/customCommands-TYMYZRG5.js} +11 -8
  135. package/dist/chunks/engine-MRVF6FK6.js +39 -0
  136. package/dist/{env-OFAXZ3XG.js → chunks/env-TJ5NOBEB.js} +7 -5
  137. package/dist/{kodeAgentSessionId-X6XWQW7B.js → chunks/kodeAgentSessionId-VTNISJ2L.js} +2 -4
  138. package/dist/chunks/kodeAgentSessionLoad-YB2RKBGJ.js +15 -0
  139. package/dist/chunks/kodeAgentSessionResume-DZSIVKVA.js +13 -0
  140. package/dist/chunks/kodeAgentStreamJson-X5PLS2S6.js +11 -0
  141. package/dist/{kodeAgentStreamJsonSession-GRWG3SPE.js → chunks/kodeAgentStreamJsonSession-RDXM4XYF.js} +38 -24
  142. package/dist/chunks/kodeAgentStreamJsonSession-RDXM4XYF.js.map +7 -0
  143. package/dist/{chunk-4RTX4AG4.js → chunks/kodeAgentStructuredStdio-SVGDSB4P.js} +14 -9
  144. package/dist/chunks/kodeAgentStructuredStdio-SVGDSB4P.js.map +7 -0
  145. package/dist/{kodeHooks-TDMXFWSO.js → chunks/kodeHooks-RVKYRJHG.js} +11 -9
  146. package/dist/{llm-XVXWYOHK.js → chunks/llm-62N6T5ZT.js} +1734 -1526
  147. package/dist/chunks/llm-62N6T5ZT.js.map +7 -0
  148. package/dist/chunks/llmLazy-ZUSSE3ZA.js +13 -0
  149. package/dist/{mentionProcessor-YD7YXYGF.js → chunks/mentionProcessor-RJW5UPJD.js} +46 -16
  150. package/dist/chunks/mentionProcessor-RJW5UPJD.js.map +7 -0
  151. package/dist/{messages-OFUJSPRV.js → chunks/messages-EEWWLPHN.js} +2 -6
  152. package/dist/chunks/model-5TIEKQPD.js +37 -0
  153. package/dist/{openai-5G5D5Q4B.js → chunks/openai-XXK3YZG4.js} +13 -10
  154. package/dist/{outputStyles-HLDXFQK3.js → chunks/outputStyles-FAJTXN2A.js} +6 -9
  155. package/dist/chunks/permissions-HO7INPWM.js +27 -0
  156. package/dist/{pluginRuntime-FPTKK6NY.js → chunks/pluginRuntime-C7K5ULK2.js} +31 -48
  157. package/dist/chunks/pluginRuntime-C7K5ULK2.js.map +7 -0
  158. package/dist/chunks/pluginValidation-DAM7WRTC.js +20 -0
  159. package/dist/chunks/registry-XYJXMOA5.js +60 -0
  160. package/dist/chunks/responsesStreaming-JNGE2P3D.js +8 -0
  161. package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js +577 -0
  162. package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js.map +7 -0
  163. package/dist/chunks/server-REXXF5IK.js +46 -0
  164. package/dist/{skillMarketplace-PSNKDINM.js → chunks/skillMarketplace-N4HVHNST.js} +8 -6
  165. package/dist/chunks/src-OROQIWP3.js +44 -0
  166. package/dist/chunks/src-QXLGGMUW.js +1647 -0
  167. package/dist/chunks/src-QXLGGMUW.js.map +7 -0
  168. package/dist/{cli-SRV2INSL.js → chunks/src-SSDT6MVP.js} +2659 -3384
  169. package/dist/chunks/src-SSDT6MVP.js.map +7 -0
  170. package/dist/chunks/theme-YBJUIMWK.js +10 -0
  171. package/dist/{toolPermissionContext-65L65VEZ.js → chunks/toolPermissionContext-MOCTRR7N.js} +2 -4
  172. package/dist/chunks/toolPermissionSettings-EV2EJAXL.js +18 -0
  173. package/dist/chunks/toolPermissionSettings-EV2EJAXL.js.map +7 -0
  174. package/dist/chunks/uuid-6577SO6X.js +7 -0
  175. package/dist/chunks/uuid-6577SO6X.js.map +7 -0
  176. package/dist/chunks/webOnlyMode-ALXX7UQY.js +66 -0
  177. package/dist/chunks/webOnlyMode-ALXX7UQY.js.map +7 -0
  178. package/dist/entrypoints/cli.js +10 -0
  179. package/dist/entrypoints/cli.js.map +7 -0
  180. package/dist/entrypoints/daemon.js +10 -0
  181. package/dist/entrypoints/daemon.js.map +7 -0
  182. package/dist/entrypoints/mcp.js +71 -0
  183. package/dist/entrypoints/mcp.js.map +7 -0
  184. package/dist/index.js +6 -7
  185. package/dist/index.js.map +3 -3
  186. package/dist/sdk/client.cjs +391 -0
  187. package/dist/sdk/client.cjs.map +7 -0
  188. package/dist/sdk/client.js +364 -0
  189. package/dist/sdk/client.js.map +7 -0
  190. package/dist/sdk/core.cjs +19932 -0
  191. package/dist/sdk/core.cjs.map +7 -0
  192. package/dist/sdk/core.js +19893 -0
  193. package/dist/sdk/core.js.map +7 -0
  194. package/dist/sdk/daemon-client.cjs +257 -0
  195. package/dist/sdk/daemon-client.cjs.map +7 -0
  196. package/dist/sdk/daemon-client.js +221 -0
  197. package/dist/sdk/daemon-client.js.map +7 -0
  198. package/dist/sdk/protocol.cjs +170 -0
  199. package/dist/sdk/protocol.cjs.map +7 -0
  200. package/dist/sdk/protocol.js +140 -0
  201. package/dist/sdk/protocol.js.map +7 -0
  202. package/dist/sdk/runtime-node.cjs +236 -0
  203. package/dist/sdk/runtime-node.cjs.map +7 -0
  204. package/dist/sdk/runtime-node.js +222 -0
  205. package/dist/sdk/runtime-node.js.map +7 -0
  206. package/dist/sdk/runtime.cjs +17 -0
  207. package/dist/sdk/runtime.cjs.map +7 -0
  208. package/dist/sdk/runtime.js +0 -0
  209. package/dist/sdk/runtime.js.map +7 -0
  210. package/dist/sdk/tools.cjs +30300 -0
  211. package/dist/sdk/tools.cjs.map +7 -0
  212. package/dist/sdk/tools.js +30282 -0
  213. package/dist/sdk/tools.js.map +7 -0
  214. package/dist/webui/assets/index-5hlfByVS.css +1 -0
  215. package/dist/webui/assets/index-BR9lm1lA.js +82 -0
  216. package/dist/webui/index.html +28 -0
  217. package/package.json +93 -22
  218. package/scripts/binary-utils.cjs +12 -4
  219. package/scripts/cli-acp-wrapper.cjs +3 -17
  220. package/scripts/cli-wrapper.cjs +5 -7
  221. package/scripts/postinstall.js +8 -4
  222. package/dist/REPL-GIU4ZIXM.js +0 -42
  223. package/dist/acp-H3VJ77YG.js +0 -1357
  224. package/dist/acp-H3VJ77YG.js.map +0 -7
  225. package/dist/agentsValidate-XP3CFN6F.js.map +0 -7
  226. package/dist/ask-3G5H5KD5.js.map +0 -7
  227. package/dist/autoUpdater-DNRMJWFQ.js +0 -17
  228. package/dist/chunk-2KWKUXLT.js.map +0 -7
  229. package/dist/chunk-2PMO2FS2.js.map +0 -7
  230. package/dist/chunk-3TXNP6HH.js.map +0 -7
  231. package/dist/chunk-4GAIJGRH.js.map +0 -7
  232. package/dist/chunk-4RTX4AG4.js.map +0 -7
  233. package/dist/chunk-54DNHKOD.js.map +0 -7
  234. package/dist/chunk-67PY5IX6.js +0 -34
  235. package/dist/chunk-67PY5IX6.js.map +0 -7
  236. package/dist/chunk-6DRDLOLP.js +0 -2613
  237. package/dist/chunk-6DRDLOLP.js.map +0 -7
  238. package/dist/chunk-7CQVZNQV.js +0 -1609
  239. package/dist/chunk-7CQVZNQV.js.map +0 -7
  240. package/dist/chunk-ABLVTESJ.js.map +0 -7
  241. package/dist/chunk-AIMIPK4B.js +0 -835
  242. package/dist/chunk-AIMIPK4B.js.map +0 -7
  243. package/dist/chunk-BHGTA6JQ.js.map +0 -7
  244. package/dist/chunk-CIG63V4E.js +0 -72
  245. package/dist/chunk-CIG63V4E.js.map +0 -7
  246. package/dist/chunk-E6YNABER.js.map +0 -7
  247. package/dist/chunk-EH34V7CY.js.map +0 -7
  248. package/dist/chunk-EZXMVTDU.js.map +0 -7
  249. package/dist/chunk-FH5CHM6L.js +0 -148
  250. package/dist/chunk-FH5CHM6L.js.map +0 -7
  251. package/dist/chunk-G6I7XROM.js.map +0 -7
  252. package/dist/chunk-HN4E4UUQ.js.map +0 -7
  253. package/dist/chunk-HSPVVDIW.js +0 -30198
  254. package/dist/chunk-HSPVVDIW.js.map +0 -7
  255. package/dist/chunk-IE2CG2TV.js.map +0 -7
  256. package/dist/chunk-K2MI4TPB.js.map +0 -7
  257. package/dist/chunk-MN77D2F7.js +0 -2931
  258. package/dist/chunk-MN77D2F7.js.map +0 -7
  259. package/dist/chunk-NQLEUHMS.js.map +0 -7
  260. package/dist/chunk-OIFQB3S4.js +0 -515
  261. package/dist/chunk-OIFQB3S4.js.map +0 -7
  262. package/dist/chunk-OWTG2W3A.js +0 -164
  263. package/dist/chunk-OWTG2W3A.js.map +0 -7
  264. package/dist/chunk-OZNRLY3E.js.map +0 -7
  265. package/dist/chunk-QYFKRZQC.js.map +0 -7
  266. package/dist/chunk-S6HRABTA.js.map +0 -7
  267. package/dist/chunk-SDGKPKDK.js.map +0 -7
  268. package/dist/chunk-SRZZFAS7.js.map +0 -7
  269. package/dist/chunk-UKHTVRJM.js +0 -47
  270. package/dist/chunk-UKHTVRJM.js.map +0 -7
  271. package/dist/chunk-UYXEDKOZ.js +0 -24
  272. package/dist/chunk-UYXEDKOZ.js.map +0 -7
  273. package/dist/chunk-VBXVYQYY.js +0 -145
  274. package/dist/chunk-VBXVYQYY.js.map +0 -7
  275. package/dist/chunk-WVHORZQ5.js +0 -17
  276. package/dist/chunk-WVHORZQ5.js.map +0 -7
  277. package/dist/chunk-WWUWDNWW.js +0 -49
  278. package/dist/chunk-WWUWDNWW.js.map +0 -7
  279. package/dist/chunk-Z33T5YN5.js +0 -654
  280. package/dist/chunk-Z33T5YN5.js.map +0 -7
  281. package/dist/chunk-ZQU3TXLC.js.map +0 -7
  282. package/dist/cli-SRV2INSL.js.map +0 -7
  283. package/dist/commands-TWH6PGVG.js +0 -46
  284. package/dist/context-JQIOOI4W.js +0 -30
  285. package/dist/costTracker-6SL26FDB.js +0 -19
  286. package/dist/kodeAgentSessionLoad-6N27AC5K.js +0 -18
  287. package/dist/kodeAgentSessionResume-HUSAEO24.js +0 -16
  288. package/dist/kodeAgentStreamJson-NXFN7TXH.js +0 -13
  289. package/dist/kodeAgentStreamJsonSession-GRWG3SPE.js.map +0 -7
  290. package/dist/kodeAgentStructuredStdio-HGWJT7CU.js +0 -10
  291. package/dist/llm-XVXWYOHK.js.map +0 -7
  292. package/dist/llmLazy-7TD5N7XP.js +0 -15
  293. package/dist/loader-AUXIJTY6.js +0 -28
  294. package/dist/mcp-BXJ3K7NZ.js +0 -49
  295. package/dist/mentionProcessor-YD7YXYGF.js.map +0 -7
  296. package/dist/model-KPYCXWBK.js +0 -30
  297. package/dist/pluginRuntime-FPTKK6NY.js.map +0 -7
  298. package/dist/pluginValidation-DSFXZ4GF.js +0 -17
  299. package/dist/prompts-LWLAJRS2.js +0 -48
  300. package/dist/query-HVPWL27C.js +0 -50
  301. package/dist/responsesStreaming-AW344PQO.js +0 -10
  302. package/dist/ripgrep-YOPCY2GO.js +0 -17
  303. package/dist/state-KNRWP3FO.js +0 -16
  304. package/dist/theme-7S2QN2FO.js +0 -14
  305. package/dist/toolPermissionSettings-GPOBH4IV.js +0 -18
  306. package/dist/tools-FZU2FZBD.js +0 -47
  307. package/dist/userInput-VHNBN2MW.js +0 -311
  308. package/dist/userInput-VHNBN2MW.js.map +0 -7
  309. package/dist/uuid-QN2CNKKN.js +0 -9
  310. /package/dist/{REPL-GIU4ZIXM.js.map → chunks/Doctor-M3J7GRTJ.js.map} +0 -0
  311. /package/dist/{autoUpdater-DNRMJWFQ.js.map → chunks/REPL-RQ6LO6S7.js.map} +0 -0
  312. /package/dist/{chunk-JC6NCUG5.js.map → chunks/ResumeConversation-6DMVBEGH.js.map} +0 -0
  313. /package/dist/{commands-TWH6PGVG.js.map → chunks/agentLoader-FCRG3TFJ.js.map} +0 -0
  314. /package/dist/{config-6ZMBCL23.js.map → chunks/autoUpdater-CNESBOKO.js.map} +0 -0
  315. /package/dist/{context-JQIOOI4W.js.map → chunks/chunk-4CRUCZR4.js.map} +0 -0
  316. /package/dist/{costTracker-6SL26FDB.js.map → chunks/chunk-54KOYG5C.js.map} +0 -0
  317. /package/dist/{customCommands-DNEJS3ZU.js.map → chunks/chunk-GCQCAXJZ.js.map} +0 -0
  318. /package/dist/{env-OFAXZ3XG.js.map → chunks/chunk-LB6TCPDI.js.map} +0 -0
  319. /package/dist/{kodeAgentSessionId-X6XWQW7B.js.map → chunks/client-SILZNM5N.js.map} +0 -0
  320. /package/dist/{kodeAgentSessionLoad-6N27AC5K.js.map → chunks/config-25HRTPSP.js.map} +0 -0
  321. /package/dist/{kodeAgentSessionResume-HUSAEO24.js.map → chunks/cost-tracker-Z2UZT2J5.js.map} +0 -0
  322. /package/dist/{kodeAgentStreamJson-NXFN7TXH.js.map → chunks/customCommands-TYMYZRG5.js.map} +0 -0
  323. /package/dist/{kodeAgentStructuredStdio-HGWJT7CU.js.map → chunks/engine-MRVF6FK6.js.map} +0 -0
  324. /package/dist/{kodeHooks-TDMXFWSO.js.map → chunks/env-TJ5NOBEB.js.map} +0 -0
  325. /package/dist/{llmLazy-7TD5N7XP.js.map → chunks/kodeAgentSessionId-VTNISJ2L.js.map} +0 -0
  326. /package/dist/{loader-AUXIJTY6.js.map → chunks/kodeAgentSessionLoad-YB2RKBGJ.js.map} +0 -0
  327. /package/dist/{mcp-BXJ3K7NZ.js.map → chunks/kodeAgentSessionResume-DZSIVKVA.js.map} +0 -0
  328. /package/dist/{messages-OFUJSPRV.js.map → chunks/kodeAgentStreamJson-X5PLS2S6.js.map} +0 -0
  329. /package/dist/{model-KPYCXWBK.js.map → chunks/kodeHooks-RVKYRJHG.js.map} +0 -0
  330. /package/dist/{openai-5G5D5Q4B.js.map → chunks/llmLazy-ZUSSE3ZA.js.map} +0 -0
  331. /package/dist/{outputStyles-HLDXFQK3.js.map → chunks/messages-EEWWLPHN.js.map} +0 -0
  332. /package/dist/{pluginValidation-DSFXZ4GF.js.map → chunks/model-5TIEKQPD.js.map} +0 -0
  333. /package/dist/{prompts-LWLAJRS2.js.map → chunks/openai-XXK3YZG4.js.map} +0 -0
  334. /package/dist/{query-HVPWL27C.js.map → chunks/outputStyles-FAJTXN2A.js.map} +0 -0
  335. /package/dist/{responsesStreaming-AW344PQO.js.map → chunks/permissions-HO7INPWM.js.map} +0 -0
  336. /package/dist/{ripgrep-YOPCY2GO.js.map → chunks/pluginValidation-DAM7WRTC.js.map} +0 -0
  337. /package/dist/{skillMarketplace-PSNKDINM.js.map → chunks/registry-XYJXMOA5.js.map} +0 -0
  338. /package/dist/{state-KNRWP3FO.js.map → chunks/responsesStreaming-JNGE2P3D.js.map} +0 -0
  339. /package/dist/{theme-7S2QN2FO.js.map → chunks/server-REXXF5IK.js.map} +0 -0
  340. /package/dist/{toolPermissionContext-65L65VEZ.js.map → chunks/skillMarketplace-N4HVHNST.js.map} +0 -0
  341. /package/dist/{toolPermissionSettings-GPOBH4IV.js.map → chunks/src-OROQIWP3.js.map} +0 -0
  342. /package/dist/{tools-FZU2FZBD.js.map → chunks/theme-YBJUIMWK.js.map} +0 -0
  343. /package/dist/{uuid-QN2CNKKN.js.map → chunks/toolPermissionContext-MOCTRR7N.js.map} +0 -0
@@ -1,238 +1,73 @@
1
- import { createRequire as __kodeCreateRequire } from "node:module";
2
- const require = __kodeCreateRequire(import.meta.url);
1
+ import {
2
+ getSessionPlugins
3
+ } from "./chunk-M7P3QNRU.js";
3
4
  import {
4
5
  getKodeAgentSessionId
5
- } from "./chunk-NPFOMITO.js";
6
+ } from "./chunk-SWQV4KSY.js";
6
7
  import {
7
- loadSettingsWithLegacyFallback
8
- } from "./chunk-VBXVYQYY.js";
8
+ logError
9
+ } from "./chunk-3OEJVB5A.js";
9
10
  import {
10
- getSessionPlugins
11
- } from "./chunk-S3J2TLV6.js";
11
+ getCwd
12
+ } from "./chunk-BBJFHTBC.js";
12
13
  import {
13
- getCwd,
14
- logError
15
- } from "./chunk-MN77D2F7.js";
14
+ loadSettingsWithLegacyFallback
15
+ } from "./chunk-XR2W3MAM.js";
16
16
 
17
- // src/utils/session/kodeHooks.ts
18
- import { spawn } from "child_process";
19
- import { readFileSync, statSync } from "fs";
20
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "fs";
17
+ // packages/core/src/hooks/tool.ts
18
+ import { mkdirSync, writeFileSync } from "fs";
21
19
  import { tmpdir } from "os";
22
20
  import { join } from "path";
23
- import { minimatch } from "minimatch";
24
- var cache = /* @__PURE__ */ new Map();
25
- var pluginHooksCache = /* @__PURE__ */ new Map();
26
- var sessionStartCache = /* @__PURE__ */ new Map();
27
- var HOOK_RUNTIME_STATE_KEY = "__kodeHookRuntimeState";
28
- function getHookRuntimeState(toolUseContext) {
29
- const existing = toolUseContext?.[HOOK_RUNTIME_STATE_KEY];
30
- if (existing && typeof existing === "object" && Array.isArray(existing.queuedSystemMessages) && Array.isArray(existing.queuedAdditionalContexts)) {
31
- return existing;
32
- }
33
- const created = {
34
- transcriptPath: void 0,
35
- queuedSystemMessages: [],
36
- queuedAdditionalContexts: []
37
- };
38
- if (toolUseContext && typeof toolUseContext === "object") {
39
- ;
40
- toolUseContext[HOOK_RUNTIME_STATE_KEY] = created;
41
- }
42
- return created;
43
- }
44
- function updateHookTranscriptForMessages(toolUseContext, messages) {
45
- const state = getHookRuntimeState(toolUseContext);
46
- const sessionId = getKodeAgentSessionId();
47
- const dir = join(tmpdir(), "kode-hooks-transcripts");
48
- try {
49
- mkdirSync(dir, { recursive: true });
50
- } catch {
51
- }
52
- if (!state.transcriptPath) {
53
- state.transcriptPath = join(dir, `${sessionId}.transcript.txt`);
54
- }
55
- const lines = [];
56
- for (const msg of Array.isArray(messages) ? messages : []) {
57
- if (!msg || typeof msg !== "object") continue;
58
- if (msg.type !== "user" && msg.type !== "assistant") continue;
59
- if (msg.type === "user") {
60
- const content2 = msg?.message?.content;
61
- if (typeof content2 === "string") {
62
- lines.push(`user: ${content2}`);
63
- continue;
64
- }
65
- if (Array.isArray(content2)) {
66
- const parts2 = [];
67
- for (const block of content2) {
68
- if (!block || typeof block !== "object") continue;
69
- if (block.type === "text") parts2.push(String(block.text ?? ""));
70
- if (block.type === "tool_result")
71
- parts2.push(`[tool_result] ${String(block.content ?? "")}`);
72
- }
73
- lines.push(`user: ${parts2.join("")}`);
74
- }
75
- continue;
76
- }
77
- const content = msg?.message?.content;
78
- if (typeof content === "string") {
79
- lines.push(`assistant: ${content}`);
80
- continue;
81
- }
82
- if (!Array.isArray(content)) continue;
83
- const parts = [];
84
- for (const block of content) {
85
- if (!block || typeof block !== "object") continue;
86
- if (block.type === "text") parts.push(String(block.text ?? ""));
87
- if (block.type === "tool_use" || block.type === "server_tool_use") {
88
- parts.push(
89
- `[tool_use:${String(block.name ?? "")}] ${hookValueForPrompt(block.input)}`
90
- );
91
- }
92
- if (block.type === "mcp_tool_use") {
93
- parts.push(
94
- `[mcp_tool_use:${String(block.name ?? "")}] ${hookValueForPrompt(block.input)}`
95
- );
96
- }
97
- }
98
- lines.push(`assistant: ${parts.join("")}`);
99
- }
100
- try {
101
- writeFileSync(state.transcriptPath, lines.join("\n") + "\n", "utf8");
102
- } catch {
103
- }
104
- }
105
- function drainHookSystemPromptAdditions(toolUseContext) {
106
- const state = getHookRuntimeState(toolUseContext);
107
- const systemMessages = state.queuedSystemMessages.splice(
108
- 0,
109
- state.queuedSystemMessages.length
110
- );
111
- const contexts = state.queuedAdditionalContexts.splice(
112
- 0,
113
- state.queuedAdditionalContexts.length
114
- );
115
- const additions = [];
116
- if (systemMessages.length > 0) {
117
- additions.push(
118
- ["\n# Hook system messages", ...systemMessages.map((m) => m.trim())].filter(Boolean).join("\n\n")
119
- );
120
- }
121
- if (contexts.length > 0) {
122
- additions.push(
123
- ["\n# Hook additional context", ...contexts.map((m) => m.trim())].filter(Boolean).join("\n\n")
124
- );
125
- }
126
- return additions;
127
- }
128
- function getHookTranscriptPath(toolUseContext) {
129
- return getHookRuntimeState(toolUseContext).transcriptPath;
130
- }
131
- function queueHookSystemMessages(toolUseContext, messages) {
132
- const state = getHookRuntimeState(toolUseContext);
133
- for (const msg of messages) {
134
- const trimmed = String(msg ?? "").trim();
135
- if (trimmed) state.queuedSystemMessages.push(trimmed);
136
- }
137
- }
138
- function queueHookAdditionalContexts(toolUseContext, contexts) {
139
- const state = getHookRuntimeState(toolUseContext);
140
- for (const ctx of contexts) {
141
- const trimmed = String(ctx ?? "").trim();
142
- if (trimmed) state.queuedAdditionalContexts.push(trimmed);
143
- }
21
+
22
+ // packages/core/src/hooks/types.ts
23
+ function asRecord(value) {
24
+ if (!value || typeof value !== "object") return null;
25
+ return value;
144
26
  }
145
- function isCommandHook(value) {
146
- return value !== null && typeof value === "object" && value.type === "command" && typeof value.command === "string" && Boolean(value.command.trim());
27
+ function normalizePermissionDecision(value) {
28
+ if (typeof value !== "string") return null;
29
+ const normalized = value.trim().toLowerCase();
30
+ if (normalized === "allow" || normalized === "approve") return "allow";
31
+ if (normalized === "deny" || normalized === "block") return "deny";
32
+ if (normalized === "ask") return "ask";
33
+ if (normalized === "passthrough" || normalized === "continue")
34
+ return "passthrough";
35
+ return null;
147
36
  }
148
- function isPromptHook(value) {
149
- return value !== null && typeof value === "object" && value.type === "prompt" && typeof value.prompt === "string" && Boolean(value.prompt.trim());
37
+ function normalizeStopDecision(value) {
38
+ if (typeof value !== "string") return null;
39
+ const normalized = value.trim().toLowerCase();
40
+ if (normalized === "approve" || normalized === "allow") return "approve";
41
+ if (normalized === "block" || normalized === "deny") return "block";
42
+ return null;
150
43
  }
151
- function isHook(value) {
152
- return isCommandHook(value) || isPromptHook(value);
44
+ function getHookSystemMessage(json) {
45
+ const systemMessage = json.systemMessage;
46
+ return typeof systemMessage === "string" && systemMessage.trim() ? systemMessage.trim() : null;
153
47
  }
154
- function parseHookMatchers(value) {
155
- if (!Array.isArray(value)) return [];
156
- const out = [];
157
- for (const item of value) {
158
- if (!item || typeof item !== "object") continue;
159
- const matcher = typeof item.matcher === "string" ? item.matcher.trim() : "";
160
- const effectiveMatcher = matcher || "*";
161
- const hooksRaw = item.hooks;
162
- const hooks = Array.isArray(hooksRaw) ? hooksRaw.filter(isHook) : [];
163
- if (hooks.length === 0) continue;
164
- out.push({ matcher: effectiveMatcher, hooks });
165
- }
166
- return out;
48
+ function getHookAdditionalContext(json) {
49
+ const hookSpecificOutput = asRecord(json.hookSpecificOutput);
50
+ const additionalContext = hookSpecificOutput?.additionalContext;
51
+ return typeof additionalContext === "string" && additionalContext.trim() ? additionalContext.trim() : null;
167
52
  }
168
- function parseHooksByEvent(rawHooks) {
169
- if (!rawHooks || typeof rawHooks !== "object") return {};
170
- const hooks = rawHooks;
171
- return {
172
- PreToolUse: parseHookMatchers(hooks.PreToolUse),
173
- PostToolUse: parseHookMatchers(hooks.PostToolUse),
174
- Stop: parseHookMatchers(hooks.Stop),
175
- SubagentStop: parseHookMatchers(hooks.SubagentStop),
176
- UserPromptSubmit: parseHookMatchers(hooks.UserPromptSubmit),
177
- SessionStart: parseHookMatchers(hooks.SessionStart),
178
- SessionEnd: parseHookMatchers(hooks.SessionEnd)
179
- };
53
+ function getHookUpdatedInput(json) {
54
+ const hookSpecificOutput = asRecord(json.hookSpecificOutput);
55
+ return asRecord(hookSpecificOutput?.updatedInput);
180
56
  }
181
- function loadInlinePluginHooksByEvent(plugin) {
182
- const manifestHooks = plugin.manifest?.hooks;
183
- if (!manifestHooks || typeof manifestHooks !== "object" || Array.isArray(manifestHooks))
184
- return null;
185
- const hookObj = manifestHooks.hooks && typeof manifestHooks.hooks === "object" && !Array.isArray(manifestHooks.hooks) ? manifestHooks.hooks : manifestHooks;
186
- const cacheKey = `${plugin.manifestPath}#inlineHooks`;
187
- try {
188
- const stat = statSync(plugin.manifestPath);
189
- const cached = pluginHooksCache.get(cacheKey);
190
- if (cached && cached.mtimeMs === stat.mtimeMs) return cached.byEvent;
191
- const byEvent = parseHooksByEvent(hookObj);
192
- pluginHooksCache.set(cacheKey, { mtimeMs: stat.mtimeMs, byEvent });
193
- return byEvent;
194
- } catch (err) {
195
- logError(err);
196
- pluginHooksCache.delete(cacheKey);
197
- return null;
198
- }
57
+ function getHookPermissionDecision(json) {
58
+ const hookSpecificOutput = asRecord(json.hookSpecificOutput);
59
+ return normalizePermissionDecision(hookSpecificOutput?.permissionDecision);
199
60
  }
200
- function loadSettingsMatchers(projectDir, event) {
201
- const loaded = loadSettingsWithLegacyFallback({
202
- destination: "projectSettings",
203
- projectDir,
204
- migrateToPrimary: true
205
- });
206
- const settingsPath = loaded.usedPath;
207
- if (!settingsPath) return [];
208
- try {
209
- const stat = statSync(settingsPath);
210
- const cached = cache.get(settingsPath);
211
- if (cached && cached.mtimeMs === stat.mtimeMs)
212
- return cached.byEvent[event] ?? [];
213
- const parsed = loaded.settings;
214
- const byEvent = parseHooksByEvent(parsed?.hooks);
215
- cache.set(settingsPath, { mtimeMs: stat.mtimeMs, byEvent });
216
- return byEvent[event] ?? [];
217
- } catch {
218
- cache.delete(settingsPath);
219
- return [];
220
- }
61
+ function getHookStopDecision(json) {
62
+ return normalizeStopDecision(json.decision);
221
63
  }
222
- function matcherMatchesTool(matcher, toolName) {
223
- if (!matcher) return false;
224
- if (matcher === "*" || matcher === "all") return true;
225
- if (matcher === toolName) return true;
226
- try {
227
- if (minimatch(toolName, matcher, { dot: true, nocase: false })) return true;
228
- } catch {
229
- }
230
- try {
231
- if (new RegExp(matcher).test(toolName)) return true;
232
- } catch {
233
- }
234
- return false;
64
+ function getHookReason(json) {
65
+ const reason = json.reason;
66
+ return typeof reason === "string" && reason.trim() ? reason.trim() : null;
235
67
  }
68
+
69
+ // packages/core/src/hooks/executor.ts
70
+ import { spawn } from "node:child_process";
236
71
  function buildShellCommand(command) {
237
72
  if (process.platform === "win32") {
238
73
  return ["cmd.exe", "/d", "/s", "/c", command];
@@ -240,16 +75,22 @@ function buildShellCommand(command) {
240
75
  return ["/bin/sh", "-c", command];
241
76
  }
242
77
  async function runCommandHook(args) {
243
- const cmd = buildShellCommand(args.command);
244
- const proc = spawn(cmd[0], cmd.slice(1), {
245
- cwd: args.cwd,
246
- env: { ...process.env, ...args.env ?? {} },
247
- stdio: ["pipe", "pipe", "pipe"],
248
- windowsHide: true
249
- });
250
- let wasAborted = false;
78
+ let proc;
79
+ try {
80
+ const cmd = buildShellCommand(args.command);
81
+ proc = spawn(cmd[0], cmd.slice(1), {
82
+ cwd: args.cwd,
83
+ env: { ...process.env, ...args.env ?? {} },
84
+ stdio: ["pipe", "pipe", "pipe"]
85
+ });
86
+ } catch (err) {
87
+ return {
88
+ exitCode: 1,
89
+ stdout: "",
90
+ stderr: err instanceof Error ? err.message : String(err)
91
+ };
92
+ }
251
93
  const onAbort = () => {
252
- wasAborted = true;
253
94
  try {
254
95
  proc.kill();
255
96
  } catch {
@@ -261,76 +102,30 @@ async function runCommandHook(args) {
261
102
  }
262
103
  try {
263
104
  const input = JSON.stringify(args.stdinJson);
264
- try {
265
- proc.stdin?.write(input);
266
- proc.stdin?.end();
267
- } catch {
268
- }
105
+ proc.stdin?.write(input);
106
+ proc.stdin?.end();
269
107
  let stdout = "";
270
108
  let stderr = "";
271
- const collect = (stream, append) => {
272
- if (!stream) {
273
- return { done: Promise.resolve(), cleanup: () => {
274
- } };
275
- }
276
- try {
277
- ;
278
- stream.setEncoding?.("utf8");
279
- } catch {
280
- }
281
- let resolveDone = null;
282
- const done = new Promise((resolve) => {
283
- resolveDone = resolve;
109
+ if (proc.stdout) {
110
+ proc.stdout.setEncoding("utf8");
111
+ proc.stdout.on("data", (chunk) => {
112
+ stdout += chunk;
284
113
  });
285
- const finish = () => {
286
- cleanup();
287
- if (!resolveDone) return;
288
- resolveDone();
289
- resolveDone = null;
290
- };
291
- const onData = (chunk) => {
292
- append(
293
- typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk)
294
- );
295
- };
296
- const onError = () => finish();
297
- const cleanup = () => {
298
- stream.off("data", onData);
299
- stream.off("end", finish);
300
- stream.off("close", finish);
301
- stream.off("error", onError);
302
- };
303
- stream.on("data", onData);
304
- stream.once("end", finish);
305
- stream.once("close", finish);
306
- stream.once("error", onError);
307
- return { done, cleanup };
308
- };
309
- const stdoutCollector = collect(proc.stdout, (chunk) => {
310
- stdout += chunk;
311
- });
312
- const stderrCollector = collect(proc.stderr, (chunk) => {
313
- stderr += chunk;
314
- });
114
+ }
115
+ if (proc.stderr) {
116
+ proc.stderr.setEncoding("utf8");
117
+ proc.stderr.on("data", (chunk) => {
118
+ stderr += chunk;
119
+ });
120
+ }
315
121
  const exitCode = await new Promise((resolve) => {
316
- proc.once("exit", (code, signal) => {
317
- if (typeof code === "number") return resolve(code);
318
- if (signal) return resolve(143);
319
- return resolve(0);
122
+ proc.once("exit", (code) => resolve(code ?? 0));
123
+ proc.once("error", (err) => {
124
+ stderr = [stderr, err instanceof Error ? err.message : String(err)].filter(Boolean).join("\n");
125
+ resolve(2);
320
126
  });
321
- proc.once("error", () => resolve(1));
322
127
  });
323
- await Promise.race([
324
- Promise.allSettled([stdoutCollector.done, stderrCollector.done]),
325
- new Promise((resolve) => setTimeout(resolve, 250))
326
- ]);
327
- stdoutCollector.cleanup();
328
- stderrCollector.cleanup();
329
- return {
330
- exitCode: wasAborted && exitCode === 0 ? 143 : exitCode,
331
- stdout,
332
- stderr
333
- };
128
+ return { exitCode, stdout, stderr };
334
129
  } finally {
335
130
  if (args.signal) {
336
131
  try {
@@ -365,7 +160,8 @@ function mergeAbortSignals(signals) {
365
160
  }
366
161
  function withHookTimeout(args) {
367
162
  const timeoutMs = typeof args.timeoutSeconds === "number" && Number.isFinite(args.timeoutSeconds) ? Math.max(0, Math.floor(args.timeoutSeconds * 1e3)) : args.fallbackTimeoutMs;
368
- const timeoutSignal = typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(timeoutMs) : (() => {
163
+ const timeoutFactory = AbortSignal;
164
+ const timeoutSignal = typeof timeoutFactory.timeout === "function" ? timeoutFactory.timeout(timeoutMs) : (() => {
369
165
  const controller = new AbortController();
370
166
  const timer = setTimeout(() => controller.abort(), timeoutMs);
371
167
  const signal = controller.signal;
@@ -437,46 +233,17 @@ function extractFirstJsonObject(text) {
437
233
  }
438
234
  return null;
439
235
  }
440
- function parseSessionStartAdditionalContext(stdout) {
441
- const trimmed = String(stdout ?? "").trim();
442
- if (!trimmed) return null;
443
- const jsonStr = extractFirstJsonObject(trimmed) ?? trimmed;
444
- try {
445
- const parsed = JSON.parse(jsonStr);
446
- const additional = parsed && typeof parsed === "object" && parsed.hookSpecificOutput && typeof parsed.hookSpecificOutput.additionalContext === "string" ? String(parsed.hookSpecificOutput.additionalContext) : null;
447
- return additional && additional.trim() ? additional : null;
448
- } catch {
449
- return null;
450
- }
451
- }
452
236
  function tryParseHookJson(stdout) {
453
237
  const trimmed = String(stdout ?? "").trim();
454
238
  if (!trimmed) return null;
455
239
  const jsonStr = extractFirstJsonObject(trimmed) ?? trimmed;
456
240
  try {
457
241
  const parsed = JSON.parse(jsonStr);
458
- return parsed && typeof parsed === "object" ? parsed : null;
242
+ return asRecord(parsed);
459
243
  } catch {
460
244
  return null;
461
245
  }
462
246
  }
463
- function normalizePermissionDecision(value) {
464
- if (typeof value !== "string") return null;
465
- const normalized = value.trim().toLowerCase();
466
- if (normalized === "allow" || normalized === "approve") return "allow";
467
- if (normalized === "deny" || normalized === "block") return "deny";
468
- if (normalized === "ask") return "ask";
469
- if (normalized === "passthrough" || normalized === "continue")
470
- return "passthrough";
471
- return null;
472
- }
473
- function normalizeStopDecision(value) {
474
- if (typeof value !== "string") return null;
475
- const normalized = value.trim().toLowerCase();
476
- if (normalized === "approve" || normalized === "allow") return "approve";
477
- if (normalized === "block" || normalized === "deny") return "block";
478
- return null;
479
- }
480
247
  function hookValueForPrompt(value) {
481
248
  if (value === null || value === void 0) return "";
482
249
  if (typeof value === "string") return value;
@@ -490,10 +257,18 @@ function interpolatePromptHookTemplate(template, hookInput) {
490
257
  return String(template ?? "").replaceAll("$TOOL_INPUT", hookValueForPrompt(hookInput.tool_input)).replaceAll("$TOOL_RESULT", hookValueForPrompt(hookInput.tool_result)).replaceAll("$TOOL_RESPONSE", hookValueForPrompt(hookInput.tool_response)).replaceAll("$USER_PROMPT", hookValueForPrompt(hookInput.user_prompt)).replaceAll("$PROMPT", hookValueForPrompt(hookInput.prompt)).replaceAll("$REASON", hookValueForPrompt(hookInput.reason));
491
258
  }
492
259
  function extractAssistantText(message) {
493
- const content = message?.message?.content;
260
+ const record = asRecord(message);
261
+ const messageRecord = asRecord(record?.message);
262
+ const content = messageRecord?.content;
494
263
  if (typeof content === "string") return content;
495
264
  if (!Array.isArray(content)) return "";
496
- return content.filter((b) => b && typeof b === "object" && b.type === "text").map((b) => String(b.text ?? "")).join("");
265
+ const parts = [];
266
+ for (const block of content) {
267
+ const blockRecord = asRecord(block);
268
+ if (!blockRecord) continue;
269
+ if (blockRecord.type === "text") parts.push(String(blockRecord.text ?? ""));
270
+ }
271
+ return parts.join("");
497
272
  }
498
273
  async function runPromptHook(args) {
499
274
  const { signal, cleanup } = withHookTimeout({
@@ -502,7 +277,7 @@ async function runPromptHook(args) {
502
277
  fallbackTimeoutMs: args.fallbackTimeoutMs
503
278
  });
504
279
  try {
505
- const { queryQuick } = await import("./llmLazy-7TD5N7XP.js");
280
+ const { queryQuick } = await import("./llmLazy-ZUSSE3ZA.js");
506
281
  const systemPrompt = [
507
282
  "You are executing a Kode prompt hook.",
508
283
  "Return a single JSON object only (no markdown, no prose).",
@@ -539,30 +314,157 @@ ${hookValueForPrompt(args.hookInput)}`;
539
314
  cleanup();
540
315
  }
541
316
  }
542
- function applyEnvFileToProcessEnv(envFilePath) {
543
- let raw;
544
- try {
545
- raw = readFileSync(envFilePath, "utf8");
546
- } catch {
547
- return;
548
- }
549
- const lines = raw.split(/\r?\n/);
550
- for (const line of lines) {
551
- const trimmed = line.trim();
552
- if (!trimmed || trimmed.startsWith("#")) continue;
553
- const withoutExport = trimmed.startsWith("export ") ? trimmed.slice("export ".length).trim() : trimmed;
554
- const eq = withoutExport.indexOf("=");
555
- if (eq <= 0) continue;
556
- const key = withoutExport.slice(0, eq).trim();
557
- let value = withoutExport.slice(eq + 1).trim();
558
- if (!key) continue;
559
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
560
- value = value.slice(1, -1);
317
+ async function executeHooksForMatchers(args) {
318
+ const executions = [];
319
+ for (const entry of args.matchers) {
320
+ for (const hook of entry.hooks) {
321
+ if (hook.type === "prompt") {
322
+ executions.push(
323
+ runPromptHook({
324
+ hook,
325
+ hookEvent: args.hookEvent,
326
+ hookInput: args.hookInput,
327
+ safeMode: args.safeMode,
328
+ parentSignal: args.parentSignal,
329
+ fallbackTimeoutMs: args.promptFallbackTimeoutMs
330
+ }).then((result) => ({ hook, result }))
331
+ );
332
+ continue;
333
+ }
334
+ const { signal, cleanup } = withHookTimeout({
335
+ timeoutSeconds: hook.timeout,
336
+ parentSignal: args.parentSignal,
337
+ fallbackTimeoutMs: args.commandFallbackTimeoutMs
338
+ });
339
+ const env = {
340
+ CLAUDE_PROJECT_DIR: args.cwd,
341
+ ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {},
342
+ ...args.baseEnv ?? {}
343
+ };
344
+ executions.push(
345
+ runCommandHook({
346
+ command: hook.command,
347
+ stdinJson: args.hookInput,
348
+ cwd: args.cwd,
349
+ env,
350
+ signal
351
+ }).then((result) => ({ hook, result })).finally(cleanup)
352
+ );
561
353
  }
562
- process.env[key] = value;
563
354
  }
355
+ return Promise.allSettled(executions);
356
+ }
357
+
358
+ // packages/core/src/hooks/registry.ts
359
+ import { readFileSync, statSync } from "fs";
360
+ import { minimatch } from "minimatch";
361
+ var settingsHooksCache = /* @__PURE__ */ new Map();
362
+ var pluginHooksCache = /* @__PURE__ */ new Map();
363
+ function isCommandHook(value) {
364
+ const record = asRecord(value);
365
+ if (!record) return false;
366
+ if (record.type !== "command") return false;
367
+ const command = record.command;
368
+ return typeof command === "string" && Boolean(command.trim());
369
+ }
370
+ function isPromptHook(value) {
371
+ const record = asRecord(value);
372
+ if (!record) return false;
373
+ if (record.type !== "prompt") return false;
374
+ const prompt = record.prompt;
375
+ return typeof prompt === "string" && Boolean(prompt.trim());
376
+ }
377
+ function isHook(value) {
378
+ return isCommandHook(value) || isPromptHook(value);
379
+ }
380
+ function parseHookMatchers(value) {
381
+ if (!Array.isArray(value)) return [];
382
+ const out = [];
383
+ for (const item of value) {
384
+ const record = asRecord(item);
385
+ if (!record) continue;
386
+ const matcher = typeof record.matcher === "string" ? record.matcher.trim() : "";
387
+ const effectiveMatcher = matcher || "*";
388
+ const hooksRaw = record.hooks;
389
+ const hooks = Array.isArray(hooksRaw) ? hooksRaw.filter(isHook) : [];
390
+ if (hooks.length === 0) continue;
391
+ out.push({ matcher: effectiveMatcher, hooks });
392
+ }
393
+ return out;
564
394
  }
565
- function loadPluginMatchers(projectDir, event) {
395
+ function parseHooksByEvent(rawHooks) {
396
+ const hooks = asRecord(rawHooks);
397
+ if (!hooks || Array.isArray(rawHooks)) return {};
398
+ return {
399
+ PreToolUse: parseHookMatchers(hooks.PreToolUse),
400
+ PostToolUse: parseHookMatchers(hooks.PostToolUse),
401
+ Stop: parseHookMatchers(hooks.Stop),
402
+ SubagentStop: parseHookMatchers(hooks.SubagentStop),
403
+ UserPromptSubmit: parseHookMatchers(hooks.UserPromptSubmit),
404
+ SessionStart: parseHookMatchers(hooks.SessionStart),
405
+ SessionEnd: parseHookMatchers(hooks.SessionEnd)
406
+ };
407
+ }
408
+ function loadInlinePluginHooksByEvent(plugin) {
409
+ const manifest = asRecord(plugin.manifest);
410
+ const manifestHooks = manifest?.hooks;
411
+ if (!manifestHooks || typeof manifestHooks !== "object" || Array.isArray(manifestHooks))
412
+ return null;
413
+ const manifestHooksRecord = asRecord(manifestHooks);
414
+ if (!manifestHooksRecord) return null;
415
+ const nestedHooks = manifestHooksRecord.hooks && typeof manifestHooksRecord.hooks === "object" && !Array.isArray(manifestHooksRecord.hooks) ? asRecord(manifestHooksRecord.hooks) : null;
416
+ const hookObj = nestedHooks ?? manifestHooksRecord;
417
+ const cacheKey = `${plugin.manifestPath}#inlineHooks`;
418
+ try {
419
+ const stat = statSync(plugin.manifestPath);
420
+ const cached = pluginHooksCache.get(cacheKey);
421
+ if (cached && cached.mtimeMs === stat.mtimeMs) return cached.byEvent;
422
+ const byEvent = parseHooksByEvent(hookObj);
423
+ pluginHooksCache.set(cacheKey, { mtimeMs: stat.mtimeMs, byEvent });
424
+ return byEvent;
425
+ } catch (err) {
426
+ logError(err);
427
+ pluginHooksCache.delete(cacheKey);
428
+ return null;
429
+ }
430
+ }
431
+ function loadSettingsMatchers(projectDir, event) {
432
+ const loaded = loadSettingsWithLegacyFallback({
433
+ destination: "projectSettings",
434
+ projectDir,
435
+ migrateToPrimary: true
436
+ });
437
+ const settingsPath = loaded.usedPath;
438
+ if (!settingsPath) return [];
439
+ try {
440
+ const stat = statSync(settingsPath);
441
+ const cached = settingsHooksCache.get(settingsPath);
442
+ if (cached && cached.mtimeMs === stat.mtimeMs)
443
+ return cached.byEvent[event] ?? [];
444
+ const parsed = loaded.settings;
445
+ const byEvent = parseHooksByEvent(parsed?.hooks);
446
+ settingsHooksCache.set(settingsPath, { mtimeMs: stat.mtimeMs, byEvent });
447
+ return byEvent[event] ?? [];
448
+ } catch {
449
+ settingsHooksCache.delete(settingsPath);
450
+ return [];
451
+ }
452
+ }
453
+ function matcherMatchesTool(matcher, toolName) {
454
+ if (!matcher) return false;
455
+ if (matcher === "*" || matcher === "all") return true;
456
+ if (matcher === toolName) return true;
457
+ try {
458
+ if (minimatch(toolName, matcher, { dot: true, nocase: false })) return true;
459
+ } catch {
460
+ }
461
+ try {
462
+ if (new RegExp(matcher).test(toolName)) return true;
463
+ } catch {
464
+ }
465
+ return false;
466
+ }
467
+ function loadPluginMatchers(_projectDir, event) {
566
468
  const plugins = getSessionPlugins();
567
469
  if (plugins.length === 0) return [];
568
470
  const out = [];
@@ -608,118 +510,140 @@ function loadPluginMatchers(projectDir, event) {
608
510
  }
609
511
  return out;
610
512
  }
611
- function parseSessionStartHooks(value) {
612
- if (!Array.isArray(value)) return [];
613
- const out = [];
614
- for (const item of value) {
615
- if (!item || typeof item !== "object") continue;
616
- const hooksRaw = item.hooks;
617
- const hooks = Array.isArray(hooksRaw) ? hooksRaw.filter(isCommandHook) : [];
618
- out.push(...hooks);
619
- }
620
- return out;
513
+ function __resetHookRegistryCacheForTests() {
514
+ settingsHooksCache.clear();
515
+ pluginHooksCache.clear();
621
516
  }
622
- async function getSessionStartAdditionalContext(args) {
517
+
518
+ // packages/core/src/hooks/tool.ts
519
+ var HOOK_RUNTIME_STATE_KEY = "__kodeHookRuntimeState";
520
+ function isHookRuntimeState(value) {
521
+ const record = asRecord(value);
522
+ if (!record) return false;
523
+ const systemMessages = record.queuedSystemMessages;
524
+ const additionalContexts = record.queuedAdditionalContexts;
525
+ return Array.isArray(systemMessages) && systemMessages.every((item) => typeof item === "string") && Array.isArray(additionalContexts) && additionalContexts.every((item) => typeof item === "string") && (record.transcriptPath === void 0 || typeof record.transcriptPath === "string");
526
+ }
527
+ function getHookRuntimeState(toolUseContext) {
528
+ const contextRecord = asRecord(toolUseContext);
529
+ const existing = contextRecord?.[HOOK_RUNTIME_STATE_KEY];
530
+ if (isHookRuntimeState(existing)) return existing;
531
+ const created = {
532
+ transcriptPath: void 0,
533
+ queuedSystemMessages: [],
534
+ queuedAdditionalContexts: []
535
+ };
536
+ if (contextRecord) contextRecord[HOOK_RUNTIME_STATE_KEY] = created;
537
+ return created;
538
+ }
539
+ function updateHookTranscriptForMessages(toolUseContext, messages) {
540
+ const state = getHookRuntimeState(toolUseContext);
623
541
  const sessionId = getKodeAgentSessionId();
624
- const cached = sessionStartCache.get(sessionId);
625
- if (cached) return cached.additionalContext;
626
- const projectDir = args?.cwd ?? getCwd();
627
- const plugins = getSessionPlugins();
628
- if (plugins.length === 0) {
629
- sessionStartCache.set(sessionId, { additionalContext: "" });
630
- return "";
631
- }
632
- const envFileDir = mkdtempSync(join(tmpdir(), "kode-env-"));
633
- const envFilePath = join(envFileDir, `${sessionId}.env`);
542
+ const dir = join(tmpdir(), "kode-hooks-transcripts");
634
543
  try {
635
- writeFileSync(envFilePath, "", "utf8");
544
+ mkdirSync(dir, { recursive: true });
636
545
  } catch {
637
546
  }
638
- const additionalContexts = [];
639
- try {
640
- for (const plugin of plugins) {
641
- for (const hookPath of plugin.hooksFiles ?? []) {
642
- let hookObj;
643
- try {
644
- const raw = readFileSync(hookPath, "utf8");
645
- const parsed = JSON.parse(raw);
646
- hookObj = parsed && typeof parsed === "object" && parsed.hooks ? parsed.hooks : parsed;
647
- } catch {
648
- continue;
649
- }
650
- const hooks = parseSessionStartHooks(hookObj?.SessionStart).map((h) => ({
651
- ...h,
652
- pluginRoot: plugin.rootDir
653
- }));
654
- if (hooks.length === 0) continue;
655
- for (const hook of hooks) {
656
- const payload = {
657
- session_id: sessionId,
658
- cwd: projectDir,
659
- hook_event_name: "SessionStart",
660
- permission_mode: coerceHookPermissionMode(args?.permissionMode)
661
- };
662
- const result = await runCommandHook({
663
- command: hook.command,
664
- stdinJson: payload,
665
- cwd: projectDir,
666
- env: {
667
- CLAUDE_PROJECT_DIR: projectDir,
668
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {},
669
- CLAUDE_ENV_FILE: envFilePath
670
- },
671
- signal: args?.signal
672
- });
673
- if (result.exitCode !== 0) continue;
674
- const injected = parseSessionStartAdditionalContext(result.stdout);
675
- if (injected) additionalContexts.push(injected);
676
- }
547
+ if (!state.transcriptPath) {
548
+ state.transcriptPath = join(dir, `${sessionId}.transcript.txt`);
549
+ }
550
+ const lines = [];
551
+ for (const msg of messages) {
552
+ const msgRecord = asRecord(msg);
553
+ if (!msgRecord) continue;
554
+ const msgType = msgRecord.type;
555
+ if (msgType !== "user" && msgType !== "assistant") continue;
556
+ const messageRecord = asRecord(msgRecord.message);
557
+ const content = messageRecord?.content;
558
+ if (msgType === "user") {
559
+ if (typeof content === "string") {
560
+ lines.push(`user: ${content}`);
561
+ continue;
677
562
  }
678
- const inlineHooks = plugin.manifest?.hooks;
679
- if (inlineHooks && typeof inlineHooks === "object" && !Array.isArray(inlineHooks)) {
680
- const hookObj = inlineHooks.hooks && typeof inlineHooks.hooks === "object" && !Array.isArray(inlineHooks.hooks) ? inlineHooks.hooks : inlineHooks;
681
- const hooks = parseSessionStartHooks(
682
- hookObj?.SessionStart
683
- ).map((h) => ({
684
- ...h,
685
- pluginRoot: plugin.rootDir
686
- }));
687
- if (hooks.length > 0) {
688
- for (const hook of hooks) {
689
- const payload = {
690
- session_id: sessionId,
691
- cwd: projectDir,
692
- hook_event_name: "SessionStart",
693
- permission_mode: coerceHookPermissionMode(args?.permissionMode)
694
- };
695
- const result = await runCommandHook({
696
- command: hook.command,
697
- stdinJson: payload,
698
- cwd: projectDir,
699
- env: {
700
- CLAUDE_PROJECT_DIR: projectDir,
701
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {},
702
- CLAUDE_ENV_FILE: envFilePath
703
- },
704
- signal: args?.signal
705
- });
706
- if (result.exitCode !== 0) continue;
707
- const injected = parseSessionStartAdditionalContext(result.stdout);
708
- if (injected) additionalContexts.push(injected);
563
+ if (Array.isArray(content)) {
564
+ const parts2 = [];
565
+ for (const block of content) {
566
+ const blockRecord = asRecord(block);
567
+ if (!blockRecord) continue;
568
+ if (blockRecord.type === "text") {
569
+ parts2.push(String(blockRecord.text ?? ""));
570
+ }
571
+ if (blockRecord.type === "tool_result") {
572
+ parts2.push(`[tool_result] ${String(blockRecord.content ?? "")}`);
709
573
  }
710
574
  }
575
+ lines.push(`user: ${parts2.join("")}`);
711
576
  }
577
+ continue;
712
578
  }
713
- } finally {
714
- applyEnvFileToProcessEnv(envFilePath);
715
- try {
716
- rmSync(envFileDir, { recursive: true, force: true });
717
- } catch {
579
+ if (typeof content === "string") {
580
+ lines.push(`assistant: ${content}`);
581
+ continue;
582
+ }
583
+ if (!Array.isArray(content)) continue;
584
+ const parts = [];
585
+ for (const block of content) {
586
+ const blockRecord = asRecord(block);
587
+ if (!blockRecord) continue;
588
+ if (blockRecord.type === "text")
589
+ parts.push(String(blockRecord.text ?? ""));
590
+ if (blockRecord.type === "tool_use" || blockRecord.type === "server_tool_use") {
591
+ parts.push(
592
+ `[tool_use:${String(blockRecord.name ?? "")}] ${hookValueForPrompt(blockRecord.input)}`
593
+ );
594
+ }
595
+ if (blockRecord.type === "mcp_tool_use") {
596
+ parts.push(
597
+ `[mcp_tool_use:${String(blockRecord.name ?? "")}] ${hookValueForPrompt(blockRecord.input)}`
598
+ );
599
+ }
718
600
  }
601
+ lines.push(`assistant: ${parts.join("")}`);
602
+ }
603
+ try {
604
+ writeFileSync(state.transcriptPath, lines.join("\n") + "\n", "utf8");
605
+ } catch {
606
+ }
607
+ }
608
+ function drainHookSystemPromptAdditions(toolUseContext) {
609
+ const state = getHookRuntimeState(toolUseContext);
610
+ const systemMessages = state.queuedSystemMessages.splice(
611
+ 0,
612
+ state.queuedSystemMessages.length
613
+ );
614
+ const contexts = state.queuedAdditionalContexts.splice(
615
+ 0,
616
+ state.queuedAdditionalContexts.length
617
+ );
618
+ const additions = [];
619
+ if (systemMessages.length > 0) {
620
+ additions.push(
621
+ ["\n# Hook system messages", ...systemMessages.map((m) => m.trim())].filter(Boolean).join("\n\n")
622
+ );
623
+ }
624
+ if (contexts.length > 0) {
625
+ additions.push(
626
+ ["\n# Hook additional context", ...contexts.map((m) => m.trim())].filter(Boolean).join("\n\n")
627
+ );
628
+ }
629
+ return additions;
630
+ }
631
+ function getHookTranscriptPath(toolUseContext) {
632
+ return getHookRuntimeState(toolUseContext).transcriptPath;
633
+ }
634
+ function queueHookSystemMessages(toolUseContext, messages) {
635
+ const state = getHookRuntimeState(toolUseContext);
636
+ for (const msg of messages) {
637
+ const trimmed = String(msg ?? "").trim();
638
+ if (trimmed) state.queuedSystemMessages.push(trimmed);
639
+ }
640
+ }
641
+ function queueHookAdditionalContexts(toolUseContext, contexts) {
642
+ const state = getHookRuntimeState(toolUseContext);
643
+ for (const ctx of contexts) {
644
+ const trimmed = String(ctx ?? "").trim();
645
+ if (trimmed) state.queuedAdditionalContexts.push(trimmed);
719
646
  }
720
- const additionalContext = additionalContexts.filter(Boolean).join("\n\n");
721
- sessionStartCache.set(sessionId, { additionalContext });
722
- return additionalContext;
723
647
  }
724
648
  async function runPreToolUseHooks(args) {
725
649
  const projectDir = args.cwd ?? getCwd();
@@ -747,49 +671,23 @@ async function runPreToolUseHooks(args) {
747
671
  const additionalContexts = [];
748
672
  let mergedUpdatedInput;
749
673
  let permissionDecision = null;
750
- const executions = [];
751
- for (const entry of applicable) {
752
- for (const hook of entry.hooks) {
753
- if (hook.type === "prompt") {
754
- executions.push(
755
- runPromptHook({
756
- hook,
757
- hookEvent: "PreToolUse",
758
- hookInput,
759
- safeMode: args.safeMode ?? false,
760
- parentSignal: args.signal,
761
- fallbackTimeoutMs: 3e4
762
- }).then((result) => ({ hook, result }))
763
- );
764
- continue;
765
- }
766
- const { signal, cleanup } = withHookTimeout({
767
- timeoutSeconds: hook.timeout,
768
- parentSignal: args.signal,
769
- fallbackTimeoutMs: 6e4
770
- });
771
- executions.push(
772
- runCommandHook({
773
- command: hook.command,
774
- stdinJson: hookInput,
775
- cwd: projectDir,
776
- env: {
777
- CLAUDE_PROJECT_DIR: projectDir,
778
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {}
779
- },
780
- signal
781
- }).then((result) => ({ hook, result })).finally(cleanup)
782
- );
783
- }
784
- }
785
- const settled = await Promise.allSettled(executions);
674
+ const settled = await executeHooksForMatchers({
675
+ matchers: applicable,
676
+ hookEvent: "PreToolUse",
677
+ hookInput,
678
+ cwd: projectDir,
679
+ safeMode: args.safeMode ?? false,
680
+ parentSignal: args.signal,
681
+ promptFallbackTimeoutMs: 3e4,
682
+ commandFallbackTimeoutMs: 6e4
683
+ });
786
684
  for (const item of settled) {
787
685
  if (item.status === "rejected") {
788
686
  logError(item.reason);
789
687
  warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
790
688
  continue;
791
689
  }
792
- const { hook, result } = item.value;
690
+ const { result } = item.value;
793
691
  if (result.exitCode === 2) {
794
692
  return {
795
693
  kind: "block",
@@ -802,31 +700,21 @@ async function runPreToolUseHooks(args) {
802
700
  }
803
701
  const json = tryParseHookJson(result.stdout);
804
702
  if (!json) continue;
805
- if (typeof json.systemMessage === "string" && json.systemMessage.trim()) {
806
- systemMessages.push(json.systemMessage.trim());
807
- }
808
- const additional = json.hookSpecificOutput && typeof json.hookSpecificOutput === "object" && typeof json.hookSpecificOutput.additionalContext === "string" ? String(json.hookSpecificOutput.additionalContext) : null;
809
- if (additional && additional.trim()) {
810
- additionalContexts.push(additional.trim());
811
- }
812
- const decision = normalizePermissionDecision(
813
- json.hookSpecificOutput?.permissionDecision
814
- );
703
+ const systemMessage = getHookSystemMessage(json);
704
+ if (systemMessage) systemMessages.push(systemMessage);
705
+ const additional = getHookAdditionalContext(json);
706
+ if (additional) additionalContexts.push(additional);
707
+ const decision = getHookPermissionDecision(json);
815
708
  if (decision === "deny") {
816
709
  const msg = systemMessages.length > 0 ? systemMessages.join("\n\n") : coerceHookMessage(result.stdout, result.stderr);
817
- return {
818
- kind: "block",
819
- message: msg,
820
- systemMessages,
821
- additionalContexts
822
- };
710
+ return { kind: "block", message: msg, systemMessages, additionalContexts };
823
711
  }
824
712
  if (decision === "ask") {
825
713
  permissionDecision = "ask";
826
714
  } else if (decision === "allow") {
827
715
  if (!permissionDecision) permissionDecision = "allow";
828
716
  }
829
- const updated = json.hookSpecificOutput && typeof json.hookSpecificOutput === "object" && json.hookSpecificOutput.updatedInput && typeof json.hookSpecificOutput.updatedInput === "object" ? json.hookSpecificOutput.updatedInput : null;
717
+ const updated = getHookUpdatedInput(json);
830
718
  if (updated) {
831
719
  mergedUpdatedInput = { ...mergedUpdatedInput ?? {}, ...updated };
832
720
  }
@@ -870,42 +758,230 @@ async function runPostToolUseHooks(args) {
870
758
  const warnings = [];
871
759
  const systemMessages = [];
872
760
  const additionalContexts = [];
873
- const executions = [];
874
- for (const entry of applicable) {
875
- for (const hook of entry.hooks) {
876
- if (hook.type === "prompt") {
877
- executions.push(
878
- runPromptHook({
879
- hook,
880
- hookEvent: "PostToolUse",
881
- hookInput,
882
- safeMode: args.safeMode ?? false,
883
- parentSignal: args.signal,
884
- fallbackTimeoutMs: 3e4
885
- }).then((result) => ({ hook, result }))
761
+ const settled = await executeHooksForMatchers({
762
+ matchers: applicable,
763
+ hookEvent: "PostToolUse",
764
+ hookInput,
765
+ cwd: projectDir,
766
+ safeMode: args.safeMode ?? false,
767
+ parentSignal: args.signal,
768
+ promptFallbackTimeoutMs: 3e4,
769
+ commandFallbackTimeoutMs: 6e4
770
+ });
771
+ for (const item of settled) {
772
+ if (item.status === "rejected") {
773
+ logError(item.reason);
774
+ warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
775
+ continue;
776
+ }
777
+ const { result } = item.value;
778
+ if (result.exitCode !== 0) {
779
+ warnings.push(coerceHookMessage(result.stdout, result.stderr));
780
+ continue;
781
+ }
782
+ const json = tryParseHookJson(result.stdout);
783
+ if (!json) continue;
784
+ const systemMessage = getHookSystemMessage(json);
785
+ if (systemMessage) systemMessages.push(systemMessage);
786
+ const additional = getHookAdditionalContext(json);
787
+ if (additional) additionalContexts.push(additional);
788
+ }
789
+ return { warnings, systemMessages, additionalContexts };
790
+ }
791
+
792
+ // packages/core/src/hooks/lifecycle/sessionStart.ts
793
+ import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
794
+ import { tmpdir as tmpdir2 } from "os";
795
+ import { join as join2 } from "path";
796
+ var sessionStartCache = /* @__PURE__ */ new Map();
797
+ function isCommandHook2(value) {
798
+ const record = asRecord(value);
799
+ if (!record) return false;
800
+ if (record.type !== "command") return false;
801
+ const command = record.command;
802
+ return typeof command === "string" && Boolean(command.trim());
803
+ }
804
+ function parseSessionStartHooks(value) {
805
+ if (!Array.isArray(value)) return [];
806
+ const out = [];
807
+ for (const item of value) {
808
+ const record = asRecord(item);
809
+ if (!record) continue;
810
+ const hooksRaw = record.hooks;
811
+ const hooks = Array.isArray(hooksRaw) ? hooksRaw.filter(isCommandHook2) : [];
812
+ out.push(...hooks);
813
+ }
814
+ return out;
815
+ }
816
+ function parseSessionStartAdditionalContext(stdout) {
817
+ const trimmed = String(stdout ?? "").trim();
818
+ if (!trimmed) return null;
819
+ const jsonStr = extractFirstJsonObject(trimmed) ?? trimmed;
820
+ try {
821
+ const parsed = JSON.parse(jsonStr);
822
+ const parsedRecord = asRecord(parsed);
823
+ const hookSpecificOutput = asRecord(parsedRecord?.hookSpecificOutput);
824
+ const additional = typeof hookSpecificOutput?.additionalContext === "string" ? hookSpecificOutput.additionalContext : null;
825
+ return additional && additional.trim() ? additional : null;
826
+ } catch {
827
+ return null;
828
+ }
829
+ }
830
+ function applyEnvFileToProcessEnv(envFilePath) {
831
+ let raw;
832
+ try {
833
+ raw = readFileSync2(envFilePath, "utf8");
834
+ } catch {
835
+ return;
836
+ }
837
+ const lines = raw.split(/\r?\n/);
838
+ for (const line of lines) {
839
+ const trimmed = line.trim();
840
+ if (!trimmed || trimmed.startsWith("#")) continue;
841
+ const withoutExport = trimmed.startsWith("export ") ? trimmed.slice("export ".length).trim() : trimmed;
842
+ const eq = withoutExport.indexOf("=");
843
+ if (eq <= 0) continue;
844
+ const key = withoutExport.slice(0, eq).trim();
845
+ let value = withoutExport.slice(eq + 1).trim();
846
+ if (!key) continue;
847
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
848
+ value = value.slice(1, -1);
849
+ }
850
+ process.env[key] = value;
851
+ }
852
+ }
853
+ async function getSessionStartAdditionalContext(args) {
854
+ const sessionId = getKodeAgentSessionId();
855
+ const cached = sessionStartCache.get(sessionId);
856
+ if (cached) return cached.additionalContext;
857
+ const projectDir = args?.cwd ?? getCwd();
858
+ const plugins = getSessionPlugins();
859
+ if (plugins.length === 0) {
860
+ sessionStartCache.set(sessionId, { additionalContext: "" });
861
+ return "";
862
+ }
863
+ const envFileDir = mkdtempSync(join2(tmpdir2(), "kode-env-"));
864
+ const envFilePath = join2(envFileDir, `${sessionId}.env`);
865
+ try {
866
+ writeFileSync2(envFilePath, "", "utf8");
867
+ } catch {
868
+ }
869
+ const additionalContexts = [];
870
+ try {
871
+ for (const plugin of plugins) {
872
+ for (const hookPath of plugin.hooksFiles ?? []) {
873
+ let hookObj;
874
+ try {
875
+ const raw = readFileSync2(hookPath, "utf8");
876
+ const parsed = JSON.parse(raw);
877
+ hookObj = parsed && typeof parsed === "object" && parsed.hooks ? parsed.hooks : parsed;
878
+ } catch {
879
+ continue;
880
+ }
881
+ const hookRecord = asRecord(hookObj);
882
+ const hooks = parseSessionStartHooks(hookRecord?.SessionStart).map(
883
+ (h) => ({
884
+ ...h,
885
+ pluginRoot: plugin.rootDir
886
+ })
886
887
  );
887
- continue;
888
+ if (hooks.length === 0) continue;
889
+ for (const hook of hooks) {
890
+ const payload = {
891
+ session_id: sessionId,
892
+ cwd: projectDir,
893
+ hook_event_name: "SessionStart",
894
+ permission_mode: coerceHookPermissionMode(args?.permissionMode)
895
+ };
896
+ const result = await runCommandHook({
897
+ command: hook.command,
898
+ stdinJson: payload,
899
+ cwd: projectDir,
900
+ env: {
901
+ CLAUDE_PROJECT_DIR: projectDir,
902
+ ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {},
903
+ CLAUDE_ENV_FILE: envFilePath
904
+ },
905
+ signal: args?.signal
906
+ });
907
+ if (result.exitCode !== 0) continue;
908
+ const injected = parseSessionStartAdditionalContext(result.stdout);
909
+ if (injected) additionalContexts.push(injected);
910
+ }
911
+ }
912
+ const manifest = asRecord(plugin.manifest);
913
+ const inlineHooks = manifest?.hooks;
914
+ if (inlineHooks && typeof inlineHooks === "object" && !Array.isArray(inlineHooks)) {
915
+ const inlineHooksRecord = asRecord(inlineHooks);
916
+ if (!inlineHooksRecord) continue;
917
+ const nestedHooks = inlineHooksRecord.hooks && typeof inlineHooksRecord.hooks === "object" && !Array.isArray(inlineHooksRecord.hooks) ? asRecord(inlineHooksRecord.hooks) : null;
918
+ const hookObj = nestedHooks ?? inlineHooksRecord;
919
+ const hooks = parseSessionStartHooks(hookObj.SessionStart).map((h) => ({
920
+ ...h,
921
+ pluginRoot: plugin.rootDir
922
+ }));
923
+ if (hooks.length === 0) continue;
924
+ for (const hook of hooks) {
925
+ const payload = {
926
+ session_id: sessionId,
927
+ cwd: projectDir,
928
+ hook_event_name: "SessionStart",
929
+ permission_mode: coerceHookPermissionMode(args?.permissionMode)
930
+ };
931
+ const result = await runCommandHook({
932
+ command: hook.command,
933
+ stdinJson: payload,
934
+ cwd: projectDir,
935
+ env: {
936
+ CLAUDE_PROJECT_DIR: projectDir,
937
+ ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {},
938
+ CLAUDE_ENV_FILE: envFilePath
939
+ },
940
+ signal: args?.signal
941
+ });
942
+ if (result.exitCode !== 0) continue;
943
+ const injected = parseSessionStartAdditionalContext(result.stdout);
944
+ if (injected) additionalContexts.push(injected);
945
+ }
888
946
  }
889
- const { signal, cleanup } = withHookTimeout({
890
- timeoutSeconds: hook.timeout,
891
- parentSignal: args.signal,
892
- fallbackTimeoutMs: 6e4
893
- });
894
- executions.push(
895
- runCommandHook({
896
- command: hook.command,
897
- stdinJson: hookInput,
898
- cwd: projectDir,
899
- env: {
900
- CLAUDE_PROJECT_DIR: projectDir,
901
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {}
902
- },
903
- signal
904
- }).then((result) => ({ hook, result })).finally(cleanup)
905
- );
947
+ }
948
+ } finally {
949
+ applyEnvFileToProcessEnv(envFilePath);
950
+ try {
951
+ rmSync(envFileDir, { recursive: true, force: true });
952
+ } catch {
906
953
  }
907
954
  }
908
- const settled = await Promise.allSettled(executions);
955
+ const additionalContext = additionalContexts.filter(Boolean).join("\n\n");
956
+ sessionStartCache.set(sessionId, { additionalContext });
957
+ return additionalContext;
958
+ }
959
+ function __resetSessionStartCacheForTests() {
960
+ sessionStartCache.clear();
961
+ }
962
+
963
+ // packages/core/src/hooks/lifecycle/events.ts
964
+ function getApplicableMatchers(projectDir, event) {
965
+ const matchers = [
966
+ ...loadSettingsMatchers(projectDir, event),
967
+ ...loadPluginMatchers(projectDir, event)
968
+ ];
969
+ return matchers.filter((m) => matcherMatchesTool(m.matcher, "*"));
970
+ }
971
+ async function runBlockableHooks(args) {
972
+ const warnings = [];
973
+ const systemMessages = [];
974
+ const additionalContexts = [];
975
+ const settled = await executeHooksForMatchers({
976
+ matchers: args.applicable,
977
+ hookEvent: args.hookEvent,
978
+ hookInput: args.hookInput,
979
+ cwd: args.cwd,
980
+ safeMode: args.safeMode ?? false,
981
+ parentSignal: args.signal,
982
+ promptFallbackTimeoutMs: 3e4,
983
+ commandFallbackTimeoutMs: 6e4
984
+ });
909
985
  for (const item of settled) {
910
986
  if (item.status === "rejected") {
911
987
  logError(item.reason);
@@ -913,37 +989,67 @@ async function runPostToolUseHooks(args) {
913
989
  continue;
914
990
  }
915
991
  const { result } = item.value;
992
+ if (result.exitCode === 2) {
993
+ return {
994
+ blocked: coerceHookMessage(result.stdout, result.stderr),
995
+ warnings,
996
+ systemMessages,
997
+ additionalContexts
998
+ };
999
+ }
916
1000
  if (result.exitCode !== 0) {
917
1001
  warnings.push(coerceHookMessage(result.stdout, result.stderr));
918
1002
  continue;
919
1003
  }
920
1004
  const json = tryParseHookJson(result.stdout);
921
1005
  if (!json) continue;
922
- if (typeof json.systemMessage === "string" && json.systemMessage.trim()) {
923
- systemMessages.push(json.systemMessage.trim());
1006
+ const systemMessage = getHookSystemMessage(json);
1007
+ if (systemMessage) systemMessages.push(systemMessage);
1008
+ const additional = getHookAdditionalContext(json);
1009
+ if (additional) additionalContexts.push(additional);
1010
+ const stopDecision = getHookStopDecision(json);
1011
+ if (stopDecision === "block") {
1012
+ const reason = getHookReason(json);
1013
+ const msg = reason || (systemMessages.length > 0 ? systemMessages.join("\n\n") : coerceHookMessage(result.stdout, result.stderr));
1014
+ return { blocked: msg, warnings, systemMessages, additionalContexts };
1015
+ }
1016
+ }
1017
+ return { blocked: null, warnings, systemMessages, additionalContexts };
1018
+ }
1019
+ async function runNonBlockingHooks(args) {
1020
+ const warnings = [];
1021
+ const systemMessages = [];
1022
+ const settled = await executeHooksForMatchers({
1023
+ matchers: args.applicable,
1024
+ hookEvent: args.hookEvent,
1025
+ hookInput: args.hookInput,
1026
+ cwd: args.cwd,
1027
+ safeMode: args.safeMode ?? false,
1028
+ parentSignal: args.signal,
1029
+ promptFallbackTimeoutMs: 3e4,
1030
+ commandFallbackTimeoutMs: 6e4
1031
+ });
1032
+ for (const item of settled) {
1033
+ if (item.status === "rejected") {
1034
+ logError(item.reason);
1035
+ warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
1036
+ continue;
924
1037
  }
925
- const additional = json.hookSpecificOutput && typeof json.hookSpecificOutput === "object" && typeof json.hookSpecificOutput.additionalContext === "string" ? String(json.hookSpecificOutput.additionalContext) : null;
926
- if (additional && additional.trim()) {
927
- additionalContexts.push(additional.trim());
1038
+ const { result } = item.value;
1039
+ if (result.exitCode !== 0) {
1040
+ warnings.push(coerceHookMessage(result.stdout, result.stderr));
1041
+ continue;
928
1042
  }
1043
+ const json = tryParseHookJson(result.stdout);
1044
+ if (!json) continue;
1045
+ const systemMessage = getHookSystemMessage(json);
1046
+ if (systemMessage) systemMessages.push(systemMessage);
929
1047
  }
930
- return { warnings, systemMessages, additionalContexts };
1048
+ return { warnings, systemMessages };
931
1049
  }
932
1050
  async function runStopHooks(args) {
933
1051
  const projectDir = args.cwd ?? getCwd();
934
- const matchers = [
935
- ...loadSettingsMatchers(projectDir, args.hookEvent),
936
- ...loadPluginMatchers(projectDir, args.hookEvent)
937
- ];
938
- if (matchers.length === 0) {
939
- return {
940
- decision: "approve",
941
- warnings: [],
942
- systemMessages: [],
943
- additionalContexts: []
944
- };
945
- }
946
- const applicable = matchers.filter((m) => matcherMatchesTool(m.matcher, "*"));
1052
+ const applicable = getApplicableMatchers(projectDir, args.hookEvent);
947
1053
  if (applicable.length === 0) {
948
1054
  return {
949
1055
  decision: "approve",
@@ -962,104 +1068,33 @@ async function runStopHooks(args) {
962
1068
  stop_hook_active: args.stopHookActive === true,
963
1069
  ...args.hookEvent === "SubagentStop" ? { agent_id: args.agentId, agent_transcript_path: args.transcriptPath } : {}
964
1070
  };
965
- const warnings = [];
966
- const systemMessages = [];
967
- const additionalContexts = [];
968
- const executions = [];
969
- for (const entry of applicable) {
970
- for (const hook of entry.hooks) {
971
- if (hook.type === "prompt") {
972
- executions.push(
973
- runPromptHook({
974
- hook,
975
- hookEvent: args.hookEvent,
976
- hookInput,
977
- safeMode: args.safeMode ?? false,
978
- parentSignal: args.signal,
979
- fallbackTimeoutMs: 3e4
980
- }).then((result) => ({ hook, result }))
981
- );
982
- continue;
983
- }
984
- const { signal, cleanup } = withHookTimeout({
985
- timeoutSeconds: hook.timeout,
986
- parentSignal: args.signal,
987
- fallbackTimeoutMs: 6e4
988
- });
989
- executions.push(
990
- runCommandHook({
991
- command: hook.command,
992
- stdinJson: hookInput,
993
- cwd: projectDir,
994
- env: {
995
- CLAUDE_PROJECT_DIR: projectDir,
996
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {}
997
- },
998
- signal
999
- }).then((result) => ({ hook, result })).finally(cleanup)
1000
- );
1001
- }
1002
- }
1003
- const settled = await Promise.allSettled(executions);
1004
- for (const item of settled) {
1005
- if (item.status === "rejected") {
1006
- logError(item.reason);
1007
- warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
1008
- continue;
1009
- }
1010
- const { result } = item.value;
1011
- if (result.exitCode === 2) {
1012
- return {
1013
- decision: "block",
1014
- message: coerceHookMessage(result.stdout, result.stderr),
1015
- warnings,
1016
- systemMessages,
1017
- additionalContexts
1018
- };
1019
- }
1020
- if (result.exitCode !== 0) {
1021
- warnings.push(coerceHookMessage(result.stdout, result.stderr));
1022
- continue;
1023
- }
1024
- const json = tryParseHookJson(result.stdout);
1025
- if (!json) continue;
1026
- if (typeof json.systemMessage === "string" && json.systemMessage.trim()) {
1027
- systemMessages.push(json.systemMessage.trim());
1028
- }
1029
- const additional = json.hookSpecificOutput && typeof json.hookSpecificOutput === "object" && typeof json.hookSpecificOutput.additionalContext === "string" ? String(json.hookSpecificOutput.additionalContext) : null;
1030
- if (additional && additional.trim()) {
1031
- additionalContexts.push(additional.trim());
1032
- }
1033
- const stopDecision = normalizeStopDecision(json.decision);
1034
- if (stopDecision === "block") {
1035
- const reason = typeof json.reason === "string" && json.reason.trim() ? json.reason.trim() : null;
1036
- const msg = reason || (systemMessages.length > 0 ? systemMessages.join("\n\n") : coerceHookMessage(result.stdout, result.stderr));
1037
- return {
1038
- decision: "block",
1039
- message: msg,
1040
- warnings,
1041
- systemMessages,
1042
- additionalContexts
1043
- };
1044
- }
1071
+ const outcome = await runBlockableHooks({
1072
+ applicable,
1073
+ hookEvent: args.hookEvent,
1074
+ hookInput,
1075
+ cwd: projectDir,
1076
+ safeMode: args.safeMode,
1077
+ signal: args.signal
1078
+ });
1079
+ if (outcome.blocked) {
1080
+ return {
1081
+ decision: "block",
1082
+ message: outcome.blocked,
1083
+ warnings: outcome.warnings,
1084
+ systemMessages: outcome.systemMessages,
1085
+ additionalContexts: outcome.additionalContexts
1086
+ };
1045
1087
  }
1046
- return { decision: "approve", warnings, systemMessages, additionalContexts };
1088
+ return {
1089
+ decision: "approve",
1090
+ warnings: outcome.warnings,
1091
+ systemMessages: outcome.systemMessages,
1092
+ additionalContexts: outcome.additionalContexts
1093
+ };
1047
1094
  }
1048
1095
  async function runUserPromptSubmitHooks(args) {
1049
1096
  const projectDir = args.cwd ?? getCwd();
1050
- const matchers = [
1051
- ...loadSettingsMatchers(projectDir, "UserPromptSubmit"),
1052
- ...loadPluginMatchers(projectDir, "UserPromptSubmit")
1053
- ];
1054
- if (matchers.length === 0) {
1055
- return {
1056
- decision: "allow",
1057
- warnings: [],
1058
- systemMessages: [],
1059
- additionalContexts: []
1060
- };
1061
- }
1062
- const applicable = matchers.filter((m) => matcherMatchesTool(m.matcher, "*"));
1097
+ const applicable = getApplicableMatchers(projectDir, "UserPromptSubmit");
1063
1098
  if (applicable.length === 0) {
1064
1099
  return {
1065
1100
  decision: "allow",
@@ -1077,97 +1112,33 @@ async function runUserPromptSubmitHooks(args) {
1077
1112
  user_prompt: args.prompt,
1078
1113
  prompt: args.prompt
1079
1114
  };
1080
- const warnings = [];
1081
- const systemMessages = [];
1082
- const additionalContexts = [];
1083
- const executions = [];
1084
- for (const entry of applicable) {
1085
- for (const hook of entry.hooks) {
1086
- if (hook.type === "prompt") {
1087
- executions.push(
1088
- runPromptHook({
1089
- hook,
1090
- hookEvent: "UserPromptSubmit",
1091
- hookInput,
1092
- safeMode: args.safeMode ?? false,
1093
- parentSignal: args.signal,
1094
- fallbackTimeoutMs: 3e4
1095
- }).then((result) => ({ hook, result }))
1096
- );
1097
- continue;
1098
- }
1099
- const { signal, cleanup } = withHookTimeout({
1100
- timeoutSeconds: hook.timeout,
1101
- parentSignal: args.signal,
1102
- fallbackTimeoutMs: 6e4
1103
- });
1104
- executions.push(
1105
- runCommandHook({
1106
- command: hook.command,
1107
- stdinJson: hookInput,
1108
- cwd: projectDir,
1109
- env: {
1110
- CLAUDE_PROJECT_DIR: projectDir,
1111
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {}
1112
- },
1113
- signal
1114
- }).then((result) => ({ hook, result })).finally(cleanup)
1115
- );
1116
- }
1117
- }
1118
- const settled = await Promise.allSettled(executions);
1119
- for (const item of settled) {
1120
- if (item.status === "rejected") {
1121
- logError(item.reason);
1122
- warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
1123
- continue;
1124
- }
1125
- const { result } = item.value;
1126
- if (result.exitCode === 2) {
1127
- return {
1128
- decision: "block",
1129
- message: coerceHookMessage(result.stdout, result.stderr),
1130
- warnings,
1131
- systemMessages,
1132
- additionalContexts
1133
- };
1134
- }
1135
- if (result.exitCode !== 0) {
1136
- warnings.push(coerceHookMessage(result.stdout, result.stderr));
1137
- continue;
1138
- }
1139
- const json = tryParseHookJson(result.stdout);
1140
- if (!json) continue;
1141
- if (typeof json.systemMessage === "string" && json.systemMessage.trim()) {
1142
- systemMessages.push(json.systemMessage.trim());
1143
- }
1144
- const additional = json.hookSpecificOutput && typeof json.hookSpecificOutput === "object" && typeof json.hookSpecificOutput.additionalContext === "string" ? String(json.hookSpecificOutput.additionalContext) : null;
1145
- if (additional && additional.trim()) {
1146
- additionalContexts.push(additional.trim());
1147
- }
1148
- const stopDecision = normalizeStopDecision(json.decision);
1149
- if (stopDecision === "block") {
1150
- const reason = typeof json.reason === "string" && json.reason.trim() ? json.reason.trim() : null;
1151
- const msg = reason || (systemMessages.length > 0 ? systemMessages.join("\n\n") : coerceHookMessage(result.stdout, result.stderr));
1152
- return {
1153
- decision: "block",
1154
- message: msg,
1155
- warnings,
1156
- systemMessages,
1157
- additionalContexts
1158
- };
1159
- }
1115
+ const outcome = await runBlockableHooks({
1116
+ applicable,
1117
+ hookEvent: "UserPromptSubmit",
1118
+ hookInput,
1119
+ cwd: projectDir,
1120
+ safeMode: args.safeMode,
1121
+ signal: args.signal
1122
+ });
1123
+ if (outcome.blocked) {
1124
+ return {
1125
+ decision: "block",
1126
+ message: outcome.blocked,
1127
+ warnings: outcome.warnings,
1128
+ systemMessages: outcome.systemMessages,
1129
+ additionalContexts: outcome.additionalContexts
1130
+ };
1160
1131
  }
1161
- return { decision: "allow", warnings, systemMessages, additionalContexts };
1132
+ return {
1133
+ decision: "allow",
1134
+ warnings: outcome.warnings,
1135
+ systemMessages: outcome.systemMessages,
1136
+ additionalContexts: outcome.additionalContexts
1137
+ };
1162
1138
  }
1163
1139
  async function runSessionEndHooks(args) {
1164
1140
  const projectDir = args.cwd ?? getCwd();
1165
- const matchers = [
1166
- ...loadSettingsMatchers(projectDir, "SessionEnd"),
1167
- ...loadPluginMatchers(projectDir, "SessionEnd")
1168
- ];
1169
- if (matchers.length === 0) return { warnings: [], systemMessages: [] };
1170
- const applicable = matchers.filter((m) => matcherMatchesTool(m.matcher, "*"));
1141
+ const applicable = getApplicableMatchers(projectDir, "SessionEnd");
1171
1142
  if (applicable.length === 0) return { warnings: [], systemMessages: [] };
1172
1143
  const hookInput = {
1173
1144
  session_id: getKodeAgentSessionId(),
@@ -1177,78 +1148,32 @@ async function runSessionEndHooks(args) {
1177
1148
  permission_mode: coerceHookPermissionMode(args.permissionMode),
1178
1149
  reason: args.reason
1179
1150
  };
1180
- const warnings = [];
1181
- const systemMessages = [];
1182
- const executions = [];
1183
- for (const entry of applicable) {
1184
- for (const hook of entry.hooks) {
1185
- if (hook.type === "prompt") {
1186
- executions.push(
1187
- runPromptHook({
1188
- hook,
1189
- hookEvent: "SessionEnd",
1190
- hookInput,
1191
- safeMode: args.safeMode ?? false,
1192
- parentSignal: args.signal,
1193
- fallbackTimeoutMs: 3e4
1194
- }).then((result) => ({ hook, result }))
1195
- );
1196
- continue;
1197
- }
1198
- const { signal, cleanup } = withHookTimeout({
1199
- timeoutSeconds: hook.timeout,
1200
- parentSignal: args.signal,
1201
- fallbackTimeoutMs: 6e4
1202
- });
1203
- executions.push(
1204
- runCommandHook({
1205
- command: hook.command,
1206
- stdinJson: hookInput,
1207
- cwd: projectDir,
1208
- env: {
1209
- CLAUDE_PROJECT_DIR: projectDir,
1210
- ...hook.pluginRoot ? { CLAUDE_PLUGIN_ROOT: hook.pluginRoot } : {}
1211
- },
1212
- signal
1213
- }).then((result) => ({ hook, result })).finally(cleanup)
1214
- );
1215
- }
1216
- }
1217
- const settled = await Promise.allSettled(executions);
1218
- for (const item of settled) {
1219
- if (item.status === "rejected") {
1220
- logError(item.reason);
1221
- warnings.push(`Hook failed to run: ${String(item.reason ?? "")}`);
1222
- continue;
1223
- }
1224
- const { result } = item.value;
1225
- if (result.exitCode !== 0) {
1226
- warnings.push(coerceHookMessage(result.stdout, result.stderr));
1227
- continue;
1228
- }
1229
- const json = tryParseHookJson(result.stdout);
1230
- if (!json) continue;
1231
- if (typeof json.systemMessage === "string" && json.systemMessage.trim()) {
1232
- systemMessages.push(json.systemMessage.trim());
1233
- }
1234
- }
1235
- return { warnings, systemMessages };
1151
+ return runNonBlockingHooks({
1152
+ applicable,
1153
+ hookEvent: "SessionEnd",
1154
+ hookInput,
1155
+ cwd: projectDir,
1156
+ safeMode: args.safeMode,
1157
+ signal: args.signal
1158
+ });
1236
1159
  }
1160
+
1161
+ // packages/core/src/hooks/index.ts
1237
1162
  function __resetKodeHooksCacheForTests() {
1238
- cache.clear();
1239
- pluginHooksCache.clear();
1240
- sessionStartCache.clear();
1163
+ __resetHookRegistryCacheForTests();
1164
+ __resetSessionStartCacheForTests();
1241
1165
  }
1242
1166
 
1243
1167
  export {
1168
+ asRecord,
1244
1169
  updateHookTranscriptForMessages,
1245
1170
  drainHookSystemPromptAdditions,
1246
1171
  getHookTranscriptPath,
1247
1172
  queueHookSystemMessages,
1248
1173
  queueHookAdditionalContexts,
1249
- getSessionStartAdditionalContext,
1250
1174
  runPreToolUseHooks,
1251
1175
  runPostToolUseHooks,
1176
+ getSessionStartAdditionalContext,
1252
1177
  runStopHooks,
1253
1178
  runUserPromptSubmitHooks,
1254
1179
  runSessionEndHooks,