@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.
- package/LICENSE +201 -0
- package/README.md +649 -25
- package/README.zh-CN.md +579 -0
- package/cli-acp.js +3 -17
- package/cli.js +5 -7
- package/dist/chunks/Doctor-M3J7GRTJ.js +12 -0
- package/dist/chunks/LogList-ISWZ6DDD.js +121 -0
- package/dist/chunks/LogList-ISWZ6DDD.js.map +7 -0
- package/dist/chunks/REPL-RQ6LO6S7.js +56 -0
- package/dist/chunks/ResumeConversation-6DMVBEGH.js +56 -0
- package/dist/chunks/agentLoader-FCRG3TFJ.js +31 -0
- package/dist/{agentsValidate-XP3CFN6F.js → chunks/agentsValidate-PEWMYN4Q.js} +97 -69
- package/dist/chunks/agentsValidate-PEWMYN4Q.js.map +7 -0
- package/dist/{ask-3G5H5KD5.js → chunks/ask-D7SOHJ6Z.js} +36 -44
- package/dist/chunks/ask-D7SOHJ6Z.js.map +7 -0
- package/dist/chunks/autoUpdater-CNESBOKO.js +19 -0
- package/dist/{chunk-EH34V7CY.js → chunks/chunk-2JN5MY67.js} +12 -14
- package/dist/chunks/chunk-2JN5MY67.js.map +7 -0
- package/dist/chunks/chunk-2QONJ5MG.js +14 -0
- package/dist/chunks/chunk-2QONJ5MG.js.map +7 -0
- package/dist/chunks/chunk-2WEXPKHH.js +903 -0
- package/dist/chunks/chunk-2WEXPKHH.js.map +7 -0
- package/dist/{chunk-K2MI4TPB.js → chunks/chunk-3BYE3ME6.js} +717 -792
- package/dist/chunks/chunk-3BYE3ME6.js.map +7 -0
- package/dist/chunks/chunk-3JDNWX7W.js +1264 -0
- package/dist/chunks/chunk-3JDNWX7W.js.map +7 -0
- package/dist/chunks/chunk-3OEJVB5A.js +906 -0
- package/dist/chunks/chunk-3OEJVB5A.js.map +7 -0
- package/dist/chunks/chunk-3TNIOEBO.js +369 -0
- package/dist/chunks/chunk-3TNIOEBO.js.map +7 -0
- package/dist/chunks/chunk-4A46ZXMJ.js +67 -0
- package/dist/chunks/chunk-4A46ZXMJ.js.map +7 -0
- package/dist/{chunk-4GAIJGRH.js → chunks/chunk-4ATBQOFO.js} +107 -55
- package/dist/chunks/chunk-4ATBQOFO.js.map +7 -0
- package/dist/chunks/chunk-4CRUCZR4.js +0 -0
- package/dist/{chunk-54DNHKOD.js → chunks/chunk-4EO6SIQY.js} +32 -75
- package/dist/chunks/chunk-4EO6SIQY.js.map +7 -0
- package/dist/chunks/chunk-53M46S5I.js +64 -0
- package/dist/chunks/chunk-53M46S5I.js.map +7 -0
- package/dist/{chunk-JC6NCUG5.js → chunks/chunk-54KOYG5C.js} +0 -2
- package/dist/{chunk-EZXMVTDU.js → chunks/chunk-6BAS4WY6.js} +29 -45
- package/dist/chunks/chunk-6BAS4WY6.js.map +7 -0
- package/dist/{chunk-BHGTA6JQ.js → chunks/chunk-6KRRFSDN.js} +4 -6
- package/dist/chunks/chunk-6KRRFSDN.js.map +7 -0
- package/dist/chunks/chunk-6LJNZK4K.js +39 -0
- package/dist/chunks/chunk-6LJNZK4K.js.map +7 -0
- package/dist/chunks/chunk-6ZWEOSEI.js +666 -0
- package/dist/chunks/chunk-6ZWEOSEI.js.map +7 -0
- package/dist/chunks/chunk-77XDJMBP.js +3326 -0
- package/dist/chunks/chunk-77XDJMBP.js.map +7 -0
- package/dist/chunks/chunk-7RRW4NTB.js +6454 -0
- package/dist/chunks/chunk-7RRW4NTB.js.map +7 -0
- package/dist/chunks/chunk-7X3TW4JB.js +4520 -0
- package/dist/chunks/chunk-7X3TW4JB.js.map +7 -0
- package/dist/chunks/chunk-B3MW3YGY.js +1409 -0
- package/dist/chunks/chunk-B3MW3YGY.js.map +7 -0
- package/dist/chunks/chunk-BBJFHTBC.js +28 -0
- package/dist/chunks/chunk-BBJFHTBC.js.map +7 -0
- package/dist/chunks/chunk-BHDHXOXB.js +24 -0
- package/dist/chunks/chunk-BHDHXOXB.js.map +7 -0
- package/dist/{chunk-OZNRLY3E.js → chunks/chunk-BTA7SZ26.js} +152 -223
- package/dist/chunks/chunk-BTA7SZ26.js.map +7 -0
- package/dist/chunks/chunk-CDGRYGPZ.js +103 -0
- package/dist/chunks/chunk-CDGRYGPZ.js.map +7 -0
- package/dist/{chunk-S6HRABTA.js → chunks/chunk-CP6E5UG6.js} +1 -4
- package/dist/chunks/chunk-CP6E5UG6.js.map +7 -0
- package/dist/{chunk-2PMO2FS2.js → chunks/chunk-DQ4JHXMT.js} +462 -424
- package/dist/chunks/chunk-DQ4JHXMT.js.map +7 -0
- package/dist/chunks/chunk-DXD76CMV.js +208 -0
- package/dist/chunks/chunk-DXD76CMV.js.map +7 -0
- package/dist/chunks/chunk-GCQCAXJZ.js +0 -0
- package/dist/chunks/chunk-GELCZWMB.js +42 -0
- package/dist/chunks/chunk-GELCZWMB.js.map +7 -0
- package/dist/{chunk-NQLEUHMS.js → chunks/chunk-HJYOH4HC.js} +23 -18
- package/dist/chunks/chunk-HJYOH4HC.js.map +7 -0
- package/dist/chunks/chunk-HPYNW6TT.js +744 -0
- package/dist/chunks/chunk-HPYNW6TT.js.map +7 -0
- package/dist/{chunk-2KWKUXLT.js → chunks/chunk-HRJ3ICQK.js} +59 -55
- package/dist/chunks/chunk-HRJ3ICQK.js.map +7 -0
- package/dist/{chunk-ZQU3TXLC.js → chunks/chunk-IFCIADS3.js} +571 -573
- package/dist/chunks/chunk-IFCIADS3.js.map +7 -0
- package/dist/chunks/chunk-IN7XZ7BC.js +27 -0
- package/dist/chunks/chunk-IN7XZ7BC.js.map +7 -0
- package/dist/chunks/chunk-L7P4M4KW.js +193 -0
- package/dist/chunks/chunk-L7P4M4KW.js.map +7 -0
- package/dist/chunks/chunk-LB6TCPDI.js +0 -0
- package/dist/{chunk-3RUXVV4S.js → chunks/chunk-LOCXPQNJ.js} +1 -4
- package/dist/{chunk-3RUXVV4S.js.map → chunks/chunk-LOCXPQNJ.js.map} +2 -2
- package/dist/{chunk-IE2CG2TV.js → chunks/chunk-LOD5ZHCI.js} +213 -208
- package/dist/chunks/chunk-LOD5ZHCI.js.map +7 -0
- package/dist/{chunk-S3J2TLV6.js → chunks/chunk-M7P3QNRU.js} +1 -4
- package/dist/{chunk-S3J2TLV6.js.map → chunks/chunk-M7P3QNRU.js.map} +2 -2
- package/dist/chunks/chunk-PPHLQVL7.js +4234 -0
- package/dist/chunks/chunk-PPHLQVL7.js.map +7 -0
- package/dist/{chunk-ABLVTESJ.js → chunks/chunk-QAXE37B5.js} +1 -4
- package/dist/chunks/chunk-QAXE37B5.js.map +7 -0
- package/dist/chunks/chunk-QHQOBUF6.js +60 -0
- package/dist/chunks/chunk-QHQOBUF6.js.map +7 -0
- package/dist/{chunk-SRZZFAS7.js → chunks/chunk-RPJXO7GG.js} +241 -214
- package/dist/chunks/chunk-RPJXO7GG.js.map +7 -0
- package/dist/{chunk-NPFOMITO.js → chunks/chunk-SWQV4KSY.js} +1 -4
- package/dist/{chunk-NPFOMITO.js.map → chunks/chunk-SWQV4KSY.js.map} +2 -2
- package/dist/chunks/chunk-SZLAPULP.js +28 -0
- package/dist/chunks/chunk-SZLAPULP.js.map +7 -0
- package/dist/{chunk-SDGKPKDK.js → chunks/chunk-T7RB5V5J.js} +23 -25
- package/dist/chunks/chunk-T7RB5V5J.js.map +7 -0
- package/dist/{chunk-HN4E4UUQ.js → chunks/chunk-TI2CTTMA.js} +25 -17
- package/dist/chunks/chunk-TI2CTTMA.js.map +7 -0
- package/dist/{chunk-G6I7XROM.js → chunks/chunk-TNGVRTO5.js} +45 -20
- package/dist/chunks/chunk-TNGVRTO5.js.map +7 -0
- package/dist/chunks/chunk-TNWB3U5Y.js +2077 -0
- package/dist/chunks/chunk-TNWB3U5Y.js.map +7 -0
- package/dist/chunks/chunk-U2IHWPCU.js +12 -0
- package/dist/chunks/chunk-U2IHWPCU.js.map +7 -0
- package/dist/{chunk-KAA5BGMQ.js → chunks/chunk-UNOY3VJ2.js} +1 -4
- package/dist/{chunk-KAA5BGMQ.js.map → chunks/chunk-UNOY3VJ2.js.map} +2 -2
- package/dist/{chunk-3TXNP6HH.js → chunks/chunk-UVDJL6ZZ.js} +97 -58
- package/dist/chunks/chunk-UVDJL6ZZ.js.map +7 -0
- package/dist/chunks/chunk-VNCW4C2Z.js +13452 -0
- package/dist/chunks/chunk-VNCW4C2Z.js.map +7 -0
- package/dist/chunks/chunk-W5EGGA44.js +15 -0
- package/dist/chunks/chunk-W5EGGA44.js.map +7 -0
- package/dist/chunks/chunk-XR2W3MAM.js +1533 -0
- package/dist/chunks/chunk-XR2W3MAM.js.map +7 -0
- package/dist/{chunk-QYFKRZQC.js → chunks/chunk-YIO5EBMQ.js} +423 -377
- package/dist/chunks/chunk-YIO5EBMQ.js.map +7 -0
- package/dist/chunks/chunk-ZBVLKZ5V.js +1062 -0
- package/dist/chunks/chunk-ZBVLKZ5V.js.map +7 -0
- package/dist/{chunk-E6YNABER.js → chunks/chunk-ZCLTZIVP.js} +1 -4
- package/dist/chunks/chunk-ZCLTZIVP.js.map +7 -0
- package/dist/chunks/client-SILZNM5N.js +42 -0
- package/dist/{config-6ZMBCL23.js → chunks/config-25HRTPSP.js} +48 -10
- package/dist/chunks/cost-tracker-Z2UZT2J5.js +28 -0
- package/dist/{customCommands-DNEJS3ZU.js → chunks/customCommands-TYMYZRG5.js} +11 -8
- package/dist/chunks/engine-MRVF6FK6.js +39 -0
- package/dist/{env-OFAXZ3XG.js → chunks/env-TJ5NOBEB.js} +7 -5
- package/dist/{kodeAgentSessionId-X6XWQW7B.js → chunks/kodeAgentSessionId-VTNISJ2L.js} +2 -4
- package/dist/chunks/kodeAgentSessionLoad-YB2RKBGJ.js +15 -0
- package/dist/chunks/kodeAgentSessionResume-DZSIVKVA.js +13 -0
- package/dist/chunks/kodeAgentStreamJson-X5PLS2S6.js +11 -0
- package/dist/{kodeAgentStreamJsonSession-GRWG3SPE.js → chunks/kodeAgentStreamJsonSession-RDXM4XYF.js} +38 -24
- package/dist/chunks/kodeAgentStreamJsonSession-RDXM4XYF.js.map +7 -0
- package/dist/{chunk-4RTX4AG4.js → chunks/kodeAgentStructuredStdio-SVGDSB4P.js} +14 -9
- package/dist/chunks/kodeAgentStructuredStdio-SVGDSB4P.js.map +7 -0
- package/dist/{kodeHooks-TDMXFWSO.js → chunks/kodeHooks-RVKYRJHG.js} +11 -9
- package/dist/{llm-XVXWYOHK.js → chunks/llm-62N6T5ZT.js} +1734 -1526
- package/dist/chunks/llm-62N6T5ZT.js.map +7 -0
- package/dist/chunks/llmLazy-ZUSSE3ZA.js +13 -0
- package/dist/{mentionProcessor-YD7YXYGF.js → chunks/mentionProcessor-RJW5UPJD.js} +46 -16
- package/dist/chunks/mentionProcessor-RJW5UPJD.js.map +7 -0
- package/dist/{messages-OFUJSPRV.js → chunks/messages-EEWWLPHN.js} +2 -6
- package/dist/chunks/model-5TIEKQPD.js +37 -0
- package/dist/{openai-5G5D5Q4B.js → chunks/openai-XXK3YZG4.js} +13 -10
- package/dist/{outputStyles-HLDXFQK3.js → chunks/outputStyles-FAJTXN2A.js} +6 -9
- package/dist/chunks/permissions-HO7INPWM.js +27 -0
- package/dist/{pluginRuntime-FPTKK6NY.js → chunks/pluginRuntime-C7K5ULK2.js} +31 -48
- package/dist/chunks/pluginRuntime-C7K5ULK2.js.map +7 -0
- package/dist/chunks/pluginValidation-DAM7WRTC.js +20 -0
- package/dist/chunks/registry-XYJXMOA5.js +60 -0
- package/dist/chunks/responsesStreaming-JNGE2P3D.js +8 -0
- package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js +577 -0
- package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js.map +7 -0
- package/dist/chunks/server-REXXF5IK.js +46 -0
- package/dist/{skillMarketplace-PSNKDINM.js → chunks/skillMarketplace-N4HVHNST.js} +8 -6
- package/dist/chunks/src-OROQIWP3.js +44 -0
- package/dist/chunks/src-QXLGGMUW.js +1647 -0
- package/dist/chunks/src-QXLGGMUW.js.map +7 -0
- package/dist/{cli-SRV2INSL.js → chunks/src-SSDT6MVP.js} +2659 -3384
- package/dist/chunks/src-SSDT6MVP.js.map +7 -0
- package/dist/chunks/theme-YBJUIMWK.js +10 -0
- package/dist/{toolPermissionContext-65L65VEZ.js → chunks/toolPermissionContext-MOCTRR7N.js} +2 -4
- package/dist/chunks/toolPermissionSettings-EV2EJAXL.js +18 -0
- package/dist/chunks/toolPermissionSettings-EV2EJAXL.js.map +7 -0
- package/dist/chunks/uuid-6577SO6X.js +7 -0
- package/dist/chunks/uuid-6577SO6X.js.map +7 -0
- package/dist/chunks/webOnlyMode-ALXX7UQY.js +66 -0
- package/dist/chunks/webOnlyMode-ALXX7UQY.js.map +7 -0
- package/dist/entrypoints/cli.js +10 -0
- package/dist/entrypoints/cli.js.map +7 -0
- package/dist/entrypoints/daemon.js +10 -0
- package/dist/entrypoints/daemon.js.map +7 -0
- package/dist/entrypoints/mcp.js +71 -0
- package/dist/entrypoints/mcp.js.map +7 -0
- package/dist/index.js +6 -7
- package/dist/index.js.map +3 -3
- package/dist/sdk/client.cjs +391 -0
- package/dist/sdk/client.cjs.map +7 -0
- package/dist/sdk/client.js +364 -0
- package/dist/sdk/client.js.map +7 -0
- package/dist/sdk/core.cjs +19932 -0
- package/dist/sdk/core.cjs.map +7 -0
- package/dist/sdk/core.js +19893 -0
- package/dist/sdk/core.js.map +7 -0
- package/dist/sdk/daemon-client.cjs +257 -0
- package/dist/sdk/daemon-client.cjs.map +7 -0
- package/dist/sdk/daemon-client.js +221 -0
- package/dist/sdk/daemon-client.js.map +7 -0
- package/dist/sdk/protocol.cjs +170 -0
- package/dist/sdk/protocol.cjs.map +7 -0
- package/dist/sdk/protocol.js +140 -0
- package/dist/sdk/protocol.js.map +7 -0
- package/dist/sdk/runtime-node.cjs +236 -0
- package/dist/sdk/runtime-node.cjs.map +7 -0
- package/dist/sdk/runtime-node.js +222 -0
- package/dist/sdk/runtime-node.js.map +7 -0
- package/dist/sdk/runtime.cjs +17 -0
- package/dist/sdk/runtime.cjs.map +7 -0
- package/dist/sdk/runtime.js +0 -0
- package/dist/sdk/runtime.js.map +7 -0
- package/dist/sdk/tools.cjs +30300 -0
- package/dist/sdk/tools.cjs.map +7 -0
- package/dist/sdk/tools.js +30282 -0
- package/dist/sdk/tools.js.map +7 -0
- package/dist/webui/assets/index-5hlfByVS.css +1 -0
- package/dist/webui/assets/index-BR9lm1lA.js +82 -0
- package/dist/webui/index.html +28 -0
- package/package.json +93 -22
- package/scripts/binary-utils.cjs +12 -4
- package/scripts/cli-acp-wrapper.cjs +3 -17
- package/scripts/cli-wrapper.cjs +5 -7
- package/scripts/postinstall.js +8 -4
- package/dist/REPL-GIU4ZIXM.js +0 -42
- package/dist/acp-H3VJ77YG.js +0 -1357
- package/dist/acp-H3VJ77YG.js.map +0 -7
- package/dist/agentsValidate-XP3CFN6F.js.map +0 -7
- package/dist/ask-3G5H5KD5.js.map +0 -7
- package/dist/autoUpdater-DNRMJWFQ.js +0 -17
- package/dist/chunk-2KWKUXLT.js.map +0 -7
- package/dist/chunk-2PMO2FS2.js.map +0 -7
- package/dist/chunk-3TXNP6HH.js.map +0 -7
- package/dist/chunk-4GAIJGRH.js.map +0 -7
- package/dist/chunk-4RTX4AG4.js.map +0 -7
- package/dist/chunk-54DNHKOD.js.map +0 -7
- package/dist/chunk-67PY5IX6.js +0 -34
- package/dist/chunk-67PY5IX6.js.map +0 -7
- package/dist/chunk-6DRDLOLP.js +0 -2613
- package/dist/chunk-6DRDLOLP.js.map +0 -7
- package/dist/chunk-7CQVZNQV.js +0 -1609
- package/dist/chunk-7CQVZNQV.js.map +0 -7
- package/dist/chunk-ABLVTESJ.js.map +0 -7
- package/dist/chunk-AIMIPK4B.js +0 -835
- package/dist/chunk-AIMIPK4B.js.map +0 -7
- package/dist/chunk-BHGTA6JQ.js.map +0 -7
- package/dist/chunk-CIG63V4E.js +0 -72
- package/dist/chunk-CIG63V4E.js.map +0 -7
- package/dist/chunk-E6YNABER.js.map +0 -7
- package/dist/chunk-EH34V7CY.js.map +0 -7
- package/dist/chunk-EZXMVTDU.js.map +0 -7
- package/dist/chunk-FH5CHM6L.js +0 -148
- package/dist/chunk-FH5CHM6L.js.map +0 -7
- package/dist/chunk-G6I7XROM.js.map +0 -7
- package/dist/chunk-HN4E4UUQ.js.map +0 -7
- package/dist/chunk-HSPVVDIW.js +0 -30198
- package/dist/chunk-HSPVVDIW.js.map +0 -7
- package/dist/chunk-IE2CG2TV.js.map +0 -7
- package/dist/chunk-K2MI4TPB.js.map +0 -7
- package/dist/chunk-MN77D2F7.js +0 -2931
- package/dist/chunk-MN77D2F7.js.map +0 -7
- package/dist/chunk-NQLEUHMS.js.map +0 -7
- package/dist/chunk-OIFQB3S4.js +0 -515
- package/dist/chunk-OIFQB3S4.js.map +0 -7
- package/dist/chunk-OWTG2W3A.js +0 -164
- package/dist/chunk-OWTG2W3A.js.map +0 -7
- package/dist/chunk-OZNRLY3E.js.map +0 -7
- package/dist/chunk-QYFKRZQC.js.map +0 -7
- package/dist/chunk-S6HRABTA.js.map +0 -7
- package/dist/chunk-SDGKPKDK.js.map +0 -7
- package/dist/chunk-SRZZFAS7.js.map +0 -7
- package/dist/chunk-UKHTVRJM.js +0 -47
- package/dist/chunk-UKHTVRJM.js.map +0 -7
- package/dist/chunk-UYXEDKOZ.js +0 -24
- package/dist/chunk-UYXEDKOZ.js.map +0 -7
- package/dist/chunk-VBXVYQYY.js +0 -145
- package/dist/chunk-VBXVYQYY.js.map +0 -7
- package/dist/chunk-WVHORZQ5.js +0 -17
- package/dist/chunk-WVHORZQ5.js.map +0 -7
- package/dist/chunk-WWUWDNWW.js +0 -49
- package/dist/chunk-WWUWDNWW.js.map +0 -7
- package/dist/chunk-Z33T5YN5.js +0 -654
- package/dist/chunk-Z33T5YN5.js.map +0 -7
- package/dist/chunk-ZQU3TXLC.js.map +0 -7
- package/dist/cli-SRV2INSL.js.map +0 -7
- package/dist/commands-TWH6PGVG.js +0 -46
- package/dist/context-JQIOOI4W.js +0 -30
- package/dist/costTracker-6SL26FDB.js +0 -19
- package/dist/kodeAgentSessionLoad-6N27AC5K.js +0 -18
- package/dist/kodeAgentSessionResume-HUSAEO24.js +0 -16
- package/dist/kodeAgentStreamJson-NXFN7TXH.js +0 -13
- package/dist/kodeAgentStreamJsonSession-GRWG3SPE.js.map +0 -7
- package/dist/kodeAgentStructuredStdio-HGWJT7CU.js +0 -10
- package/dist/llm-XVXWYOHK.js.map +0 -7
- package/dist/llmLazy-7TD5N7XP.js +0 -15
- package/dist/loader-AUXIJTY6.js +0 -28
- package/dist/mcp-BXJ3K7NZ.js +0 -49
- package/dist/mentionProcessor-YD7YXYGF.js.map +0 -7
- package/dist/model-KPYCXWBK.js +0 -30
- package/dist/pluginRuntime-FPTKK6NY.js.map +0 -7
- package/dist/pluginValidation-DSFXZ4GF.js +0 -17
- package/dist/prompts-LWLAJRS2.js +0 -48
- package/dist/query-HVPWL27C.js +0 -50
- package/dist/responsesStreaming-AW344PQO.js +0 -10
- package/dist/ripgrep-YOPCY2GO.js +0 -17
- package/dist/state-KNRWP3FO.js +0 -16
- package/dist/theme-7S2QN2FO.js +0 -14
- package/dist/toolPermissionSettings-GPOBH4IV.js +0 -18
- package/dist/tools-FZU2FZBD.js +0 -47
- package/dist/userInput-VHNBN2MW.js +0 -311
- package/dist/userInput-VHNBN2MW.js.map +0 -7
- package/dist/uuid-QN2CNKKN.js +0 -9
- /package/dist/{REPL-GIU4ZIXM.js.map → chunks/Doctor-M3J7GRTJ.js.map} +0 -0
- /package/dist/{autoUpdater-DNRMJWFQ.js.map → chunks/REPL-RQ6LO6S7.js.map} +0 -0
- /package/dist/{chunk-JC6NCUG5.js.map → chunks/ResumeConversation-6DMVBEGH.js.map} +0 -0
- /package/dist/{commands-TWH6PGVG.js.map → chunks/agentLoader-FCRG3TFJ.js.map} +0 -0
- /package/dist/{config-6ZMBCL23.js.map → chunks/autoUpdater-CNESBOKO.js.map} +0 -0
- /package/dist/{context-JQIOOI4W.js.map → chunks/chunk-4CRUCZR4.js.map} +0 -0
- /package/dist/{costTracker-6SL26FDB.js.map → chunks/chunk-54KOYG5C.js.map} +0 -0
- /package/dist/{customCommands-DNEJS3ZU.js.map → chunks/chunk-GCQCAXJZ.js.map} +0 -0
- /package/dist/{env-OFAXZ3XG.js.map → chunks/chunk-LB6TCPDI.js.map} +0 -0
- /package/dist/{kodeAgentSessionId-X6XWQW7B.js.map → chunks/client-SILZNM5N.js.map} +0 -0
- /package/dist/{kodeAgentSessionLoad-6N27AC5K.js.map → chunks/config-25HRTPSP.js.map} +0 -0
- /package/dist/{kodeAgentSessionResume-HUSAEO24.js.map → chunks/cost-tracker-Z2UZT2J5.js.map} +0 -0
- /package/dist/{kodeAgentStreamJson-NXFN7TXH.js.map → chunks/customCommands-TYMYZRG5.js.map} +0 -0
- /package/dist/{kodeAgentStructuredStdio-HGWJT7CU.js.map → chunks/engine-MRVF6FK6.js.map} +0 -0
- /package/dist/{kodeHooks-TDMXFWSO.js.map → chunks/env-TJ5NOBEB.js.map} +0 -0
- /package/dist/{llmLazy-7TD5N7XP.js.map → chunks/kodeAgentSessionId-VTNISJ2L.js.map} +0 -0
- /package/dist/{loader-AUXIJTY6.js.map → chunks/kodeAgentSessionLoad-YB2RKBGJ.js.map} +0 -0
- /package/dist/{mcp-BXJ3K7NZ.js.map → chunks/kodeAgentSessionResume-DZSIVKVA.js.map} +0 -0
- /package/dist/{messages-OFUJSPRV.js.map → chunks/kodeAgentStreamJson-X5PLS2S6.js.map} +0 -0
- /package/dist/{model-KPYCXWBK.js.map → chunks/kodeHooks-RVKYRJHG.js.map} +0 -0
- /package/dist/{openai-5G5D5Q4B.js.map → chunks/llmLazy-ZUSSE3ZA.js.map} +0 -0
- /package/dist/{outputStyles-HLDXFQK3.js.map → chunks/messages-EEWWLPHN.js.map} +0 -0
- /package/dist/{pluginValidation-DSFXZ4GF.js.map → chunks/model-5TIEKQPD.js.map} +0 -0
- /package/dist/{prompts-LWLAJRS2.js.map → chunks/openai-XXK3YZG4.js.map} +0 -0
- /package/dist/{query-HVPWL27C.js.map → chunks/outputStyles-FAJTXN2A.js.map} +0 -0
- /package/dist/{responsesStreaming-AW344PQO.js.map → chunks/permissions-HO7INPWM.js.map} +0 -0
- /package/dist/{ripgrep-YOPCY2GO.js.map → chunks/pluginValidation-DAM7WRTC.js.map} +0 -0
- /package/dist/{skillMarketplace-PSNKDINM.js.map → chunks/registry-XYJXMOA5.js.map} +0 -0
- /package/dist/{state-KNRWP3FO.js.map → chunks/responsesStreaming-JNGE2P3D.js.map} +0 -0
- /package/dist/{theme-7S2QN2FO.js.map → chunks/server-REXXF5IK.js.map} +0 -0
- /package/dist/{toolPermissionContext-65L65VEZ.js.map → chunks/skillMarketplace-N4HVHNST.js.map} +0 -0
- /package/dist/{toolPermissionSettings-GPOBH4IV.js.map → chunks/src-OROQIWP3.js.map} +0 -0
- /package/dist/{tools-FZU2FZBD.js.map → chunks/theme-YBJUIMWK.js.map} +0 -0
- /package/dist/{uuid-QN2CNKKN.js.map → chunks/toolPermissionContext-MOCTRR7N.js.map} +0 -0
|
@@ -1,238 +1,73 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
getSessionPlugins
|
|
3
|
+
} from "./chunk-M7P3QNRU.js";
|
|
3
4
|
import {
|
|
4
5
|
getKodeAgentSessionId
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SWQV4KSY.js";
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
logError
|
|
9
|
+
} from "./chunk-3OEJVB5A.js";
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
getCwd
|
|
12
|
+
} from "./chunk-BBJFHTBC.js";
|
|
12
13
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./chunk-MN77D2F7.js";
|
|
14
|
+
loadSettingsWithLegacyFallback
|
|
15
|
+
} from "./chunk-XR2W3MAM.js";
|
|
16
16
|
|
|
17
|
-
// src/
|
|
18
|
-
import {
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
146
|
-
|
|
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
|
|
149
|
-
|
|
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
|
|
152
|
-
|
|
44
|
+
function getHookSystemMessage(json) {
|
|
45
|
+
const systemMessage = json.systemMessage;
|
|
46
|
+
return typeof systemMessage === "string" && systemMessage.trim() ? systemMessage.trim() : null;
|
|
153
47
|
}
|
|
154
|
-
function
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
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
|
|
169
|
-
|
|
170
|
-
|
|
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
|
|
182
|
-
const
|
|
183
|
-
|
|
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
|
|
201
|
-
|
|
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
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
-
|
|
265
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
};
|
|
291
|
-
|
|
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
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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-
|
|
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
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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
|
|
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
|
|
612
|
-
|
|
613
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
544
|
+
mkdirSync(dir, { recursive: true });
|
|
636
545
|
} catch {
|
|
637
546
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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
|
-
|
|
679
|
-
|
|
680
|
-
const
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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 {
|
|
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
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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
|
|
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
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
});
|
|
894
|
-
|
|
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
|
|
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
|
-
|
|
923
|
-
|
|
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
|
|
926
|
-
if (
|
|
927
|
-
|
|
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
|
|
1048
|
+
return { warnings, systemMessages };
|
|
931
1049
|
}
|
|
932
1050
|
async function runStopHooks(args) {
|
|
933
1051
|
const projectDir = args.cwd ?? getCwd();
|
|
934
|
-
const
|
|
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
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
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 {
|
|
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
|
|
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
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
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
|
-
|
|
1239
|
-
|
|
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,
|