@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
|
@@ -0,0 +1,2077 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendSessionJsonlFromMessage
|
|
3
|
+
} from "./chunk-UVDJL6ZZ.js";
|
|
4
|
+
import {
|
|
5
|
+
kodeMessageToSdkMessage
|
|
6
|
+
} from "./chunk-CDGRYGPZ.js";
|
|
7
|
+
import {
|
|
8
|
+
formatSystemPromptWithContext,
|
|
9
|
+
getCodeStyle,
|
|
10
|
+
getContext
|
|
11
|
+
} from "./chunk-HPYNW6TT.js";
|
|
12
|
+
import {
|
|
13
|
+
emitReminderEvent,
|
|
14
|
+
getAgentFilePath,
|
|
15
|
+
systemReminderService
|
|
16
|
+
} from "./chunk-LOD5ZHCI.js";
|
|
17
|
+
import {
|
|
18
|
+
asRecord,
|
|
19
|
+
drainHookSystemPromptAdditions,
|
|
20
|
+
getHookTranscriptPath,
|
|
21
|
+
queueHookAdditionalContexts,
|
|
22
|
+
queueHookSystemMessages,
|
|
23
|
+
runPostToolUseHooks,
|
|
24
|
+
runPreToolUseHooks,
|
|
25
|
+
runStopHooks,
|
|
26
|
+
runUserPromptSubmitHooks,
|
|
27
|
+
updateHookTranscriptForMessages
|
|
28
|
+
} from "./chunk-3BYE3ME6.js";
|
|
29
|
+
import {
|
|
30
|
+
setRequestStatus
|
|
31
|
+
} from "./chunk-LOCXPQNJ.js";
|
|
32
|
+
import {
|
|
33
|
+
queryLLM
|
|
34
|
+
} from "./chunk-BHDHXOXB.js";
|
|
35
|
+
import {
|
|
36
|
+
INTERRUPT_MESSAGE,
|
|
37
|
+
INTERRUPT_MESSAGE_FOR_TOOL_USE,
|
|
38
|
+
REJECT_MESSAGE,
|
|
39
|
+
SYNTHETIC_ASSISTANT_MESSAGES,
|
|
40
|
+
createAssistantMessage,
|
|
41
|
+
createProgressMessage,
|
|
42
|
+
createUserMessage,
|
|
43
|
+
normalizeMessagesForAPI
|
|
44
|
+
} from "./chunk-HRJ3ICQK.js";
|
|
45
|
+
import {
|
|
46
|
+
getModelManager
|
|
47
|
+
} from "./chunk-6ZWEOSEI.js";
|
|
48
|
+
import {
|
|
49
|
+
debug,
|
|
50
|
+
getCurrentRequest,
|
|
51
|
+
logUserFriendly,
|
|
52
|
+
markPhase
|
|
53
|
+
} from "./chunk-YIO5EBMQ.js";
|
|
54
|
+
import {
|
|
55
|
+
execFileNoThrow,
|
|
56
|
+
getPlanModeSystemPromptAdditions,
|
|
57
|
+
hydratePlanSlugFromMessages,
|
|
58
|
+
logError
|
|
59
|
+
} from "./chunk-3OEJVB5A.js";
|
|
60
|
+
import {
|
|
61
|
+
getCwd
|
|
62
|
+
} from "./chunk-BBJFHTBC.js";
|
|
63
|
+
import {
|
|
64
|
+
BunShell,
|
|
65
|
+
renderBackgroundShellStatusAttachment,
|
|
66
|
+
renderBashNotification
|
|
67
|
+
} from "./chunk-B3MW3YGY.js";
|
|
68
|
+
|
|
69
|
+
// packages/core/src/utils/tokens.ts
|
|
70
|
+
function countTokens(messages) {
|
|
71
|
+
let i = messages.length - 1;
|
|
72
|
+
while (i >= 0) {
|
|
73
|
+
const message = messages[i];
|
|
74
|
+
if (message?.type === "assistant" && "usage" in message.message && !(message.message.content[0]?.type === "text" && SYNTHETIC_ASSISTANT_MESSAGES.has(message.message.content[0].text))) {
|
|
75
|
+
const { usage } = message.message;
|
|
76
|
+
return usage.input_tokens + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0) + usage.output_tokens;
|
|
77
|
+
}
|
|
78
|
+
i--;
|
|
79
|
+
}
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// packages/core/src/messages.ts
|
|
84
|
+
var getMessages = () => [];
|
|
85
|
+
var setMessages = () => {
|
|
86
|
+
};
|
|
87
|
+
function setMessagesGetter(getter) {
|
|
88
|
+
getMessages = getter;
|
|
89
|
+
}
|
|
90
|
+
function getMessagesGetter() {
|
|
91
|
+
return getMessages;
|
|
92
|
+
}
|
|
93
|
+
function setMessagesSetter(setter) {
|
|
94
|
+
setMessages = setter;
|
|
95
|
+
}
|
|
96
|
+
function getMessagesSetter() {
|
|
97
|
+
return setMessages;
|
|
98
|
+
}
|
|
99
|
+
var onModelConfigChange = null;
|
|
100
|
+
function setModelConfigChangeHandler(handler) {
|
|
101
|
+
onModelConfigChange = handler;
|
|
102
|
+
}
|
|
103
|
+
function triggerModelConfigChange() {
|
|
104
|
+
if (onModelConfigChange) {
|
|
105
|
+
onModelConfigChange();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// packages/core/src/services/fileFreshness.ts
|
|
110
|
+
import { statSync, existsSync, watchFile, unwatchFile } from "fs";
|
|
111
|
+
var FileFreshnessService = class {
|
|
112
|
+
state = {
|
|
113
|
+
readTimestamps: /* @__PURE__ */ new Map(),
|
|
114
|
+
editConflicts: /* @__PURE__ */ new Set(),
|
|
115
|
+
sessionFiles: /* @__PURE__ */ new Set(),
|
|
116
|
+
watchedTodoFiles: /* @__PURE__ */ new Map()
|
|
117
|
+
};
|
|
118
|
+
constructor() {
|
|
119
|
+
this.setupEventListeners();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Setup event listeners for session management
|
|
123
|
+
*/
|
|
124
|
+
setupEventListeners() {
|
|
125
|
+
systemReminderService.addEventListener(
|
|
126
|
+
"session:startup",
|
|
127
|
+
(context) => {
|
|
128
|
+
this.resetSession();
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Record file read operation with timestamp tracking
|
|
134
|
+
*/
|
|
135
|
+
recordFileRead(filePath) {
|
|
136
|
+
try {
|
|
137
|
+
if (!existsSync(filePath)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const stats = statSync(filePath);
|
|
141
|
+
const timestamp = {
|
|
142
|
+
path: filePath,
|
|
143
|
+
lastRead: Date.now(),
|
|
144
|
+
lastModified: stats.mtimeMs,
|
|
145
|
+
size: stats.size
|
|
146
|
+
};
|
|
147
|
+
this.state.readTimestamps.set(filePath, timestamp);
|
|
148
|
+
this.state.sessionFiles.add(filePath);
|
|
149
|
+
emitReminderEvent("file:read", {
|
|
150
|
+
filePath,
|
|
151
|
+
timestamp: timestamp.lastRead,
|
|
152
|
+
size: timestamp.size,
|
|
153
|
+
modified: timestamp.lastModified
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
logError(error);
|
|
157
|
+
debug.warn("FILE_FRESHNESS_RECORD_READ_FAILED", {
|
|
158
|
+
filePath,
|
|
159
|
+
error: error instanceof Error ? error.message : String(error)
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if file has been modified since last read
|
|
165
|
+
*/
|
|
166
|
+
checkFileFreshness(filePath) {
|
|
167
|
+
const recorded = this.state.readTimestamps.get(filePath);
|
|
168
|
+
if (!recorded) {
|
|
169
|
+
return { isFresh: true, conflict: false };
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
if (!existsSync(filePath)) {
|
|
173
|
+
return { isFresh: false, conflict: true };
|
|
174
|
+
}
|
|
175
|
+
const currentStats = statSync(filePath);
|
|
176
|
+
const isFresh = currentStats.mtimeMs <= recorded.lastModified;
|
|
177
|
+
const conflict = !isFresh;
|
|
178
|
+
if (conflict) {
|
|
179
|
+
this.state.editConflicts.add(filePath);
|
|
180
|
+
emitReminderEvent("file:conflict", {
|
|
181
|
+
filePath,
|
|
182
|
+
lastRead: recorded.lastRead,
|
|
183
|
+
lastModified: recorded.lastModified,
|
|
184
|
+
currentModified: currentStats.mtimeMs,
|
|
185
|
+
sizeDiff: currentStats.size - recorded.size
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
isFresh,
|
|
190
|
+
lastRead: recorded.lastRead,
|
|
191
|
+
currentModified: currentStats.mtimeMs,
|
|
192
|
+
conflict
|
|
193
|
+
};
|
|
194
|
+
} catch (error) {
|
|
195
|
+
logError(error);
|
|
196
|
+
debug.warn("FILE_FRESHNESS_CHECK_FAILED", {
|
|
197
|
+
filePath,
|
|
198
|
+
error: error instanceof Error ? error.message : String(error)
|
|
199
|
+
});
|
|
200
|
+
return { isFresh: false, conflict: true };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Record file edit operation by Agent
|
|
205
|
+
*/
|
|
206
|
+
recordFileEdit(filePath, content) {
|
|
207
|
+
try {
|
|
208
|
+
const now = Date.now();
|
|
209
|
+
if (existsSync(filePath)) {
|
|
210
|
+
const stats = statSync(filePath);
|
|
211
|
+
const existing = this.state.readTimestamps.get(filePath);
|
|
212
|
+
if (existing) {
|
|
213
|
+
existing.lastModified = stats.mtimeMs;
|
|
214
|
+
existing.size = stats.size;
|
|
215
|
+
existing.lastAgentEdit = now;
|
|
216
|
+
this.state.readTimestamps.set(filePath, existing);
|
|
217
|
+
} else {
|
|
218
|
+
const timestamp = {
|
|
219
|
+
path: filePath,
|
|
220
|
+
lastRead: now,
|
|
221
|
+
lastModified: stats.mtimeMs,
|
|
222
|
+
size: stats.size,
|
|
223
|
+
lastAgentEdit: now
|
|
224
|
+
};
|
|
225
|
+
this.state.readTimestamps.set(filePath, timestamp);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
this.state.editConflicts.delete(filePath);
|
|
229
|
+
emitReminderEvent("file:edited", {
|
|
230
|
+
filePath,
|
|
231
|
+
timestamp: now,
|
|
232
|
+
contentLength: content?.length || 0,
|
|
233
|
+
source: "agent"
|
|
234
|
+
});
|
|
235
|
+
} catch (error) {
|
|
236
|
+
logError(error);
|
|
237
|
+
debug.warn("FILE_FRESHNESS_RECORD_EDIT_FAILED", {
|
|
238
|
+
filePath,
|
|
239
|
+
error: error instanceof Error ? error.message : String(error)
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
generateFileModificationReminder(filePath) {
|
|
244
|
+
const recorded = this.state.readTimestamps.get(filePath);
|
|
245
|
+
if (!recorded) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
if (!existsSync(filePath)) {
|
|
250
|
+
return `Note: ${filePath} was deleted since last read.`;
|
|
251
|
+
}
|
|
252
|
+
const currentStats = statSync(filePath);
|
|
253
|
+
const isModified = currentStats.mtimeMs > recorded.lastModified;
|
|
254
|
+
if (!isModified) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const TIME_TOLERANCE_MS = 100;
|
|
258
|
+
if (recorded.lastAgentEdit && recorded.lastAgentEdit >= recorded.lastModified - TIME_TOLERANCE_MS) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return `Note: ${filePath} was modified externally since last read. The file may have changed outside of this session.`;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
logError(error);
|
|
264
|
+
debug.warn("FILE_FRESHNESS_CHECK_MODIFICATION_FAILED", {
|
|
265
|
+
filePath,
|
|
266
|
+
error: error instanceof Error ? error.message : String(error)
|
|
267
|
+
});
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
getConflictedFiles() {
|
|
272
|
+
return Array.from(this.state.editConflicts);
|
|
273
|
+
}
|
|
274
|
+
getSessionFiles() {
|
|
275
|
+
return Array.from(this.state.sessionFiles);
|
|
276
|
+
}
|
|
277
|
+
resetSession() {
|
|
278
|
+
this.state.watchedTodoFiles.forEach((filePath) => {
|
|
279
|
+
try {
|
|
280
|
+
unwatchFile(filePath);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
logError(error);
|
|
283
|
+
debug.warn("FILE_FRESHNESS_UNWATCH_FAILED", {
|
|
284
|
+
filePath,
|
|
285
|
+
error: error instanceof Error ? error.message : String(error)
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
this.state = {
|
|
290
|
+
readTimestamps: /* @__PURE__ */ new Map(),
|
|
291
|
+
editConflicts: /* @__PURE__ */ new Set(),
|
|
292
|
+
sessionFiles: /* @__PURE__ */ new Set(),
|
|
293
|
+
watchedTodoFiles: /* @__PURE__ */ new Map()
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Start watching todo file for an agent
|
|
298
|
+
*/
|
|
299
|
+
startWatchingTodoFile(agentId) {
|
|
300
|
+
try {
|
|
301
|
+
const filePath = getAgentFilePath(agentId);
|
|
302
|
+
if (this.state.watchedTodoFiles.has(agentId)) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
this.state.watchedTodoFiles.set(agentId, filePath);
|
|
306
|
+
if (existsSync(filePath)) {
|
|
307
|
+
this.recordFileRead(filePath);
|
|
308
|
+
}
|
|
309
|
+
watchFile(filePath, { interval: 1e3 }, (curr, prev) => {
|
|
310
|
+
const reminder = this.generateFileModificationReminder(filePath);
|
|
311
|
+
if (reminder) {
|
|
312
|
+
emitReminderEvent("todo:file_changed", {
|
|
313
|
+
agentId,
|
|
314
|
+
filePath,
|
|
315
|
+
reminder,
|
|
316
|
+
timestamp: Date.now(),
|
|
317
|
+
currentStats: { mtime: curr.mtime, size: curr.size },
|
|
318
|
+
previousStats: { mtime: prev.mtime, size: prev.size }
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
} catch (error) {
|
|
323
|
+
logError(error);
|
|
324
|
+
debug.warn("FILE_FRESHNESS_TODO_WATCH_START_FAILED", {
|
|
325
|
+
agentId,
|
|
326
|
+
error: error instanceof Error ? error.message : String(error)
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Stop watching todo file for an agent
|
|
332
|
+
*/
|
|
333
|
+
stopWatchingTodoFile(agentId) {
|
|
334
|
+
try {
|
|
335
|
+
const filePath = this.state.watchedTodoFiles.get(agentId);
|
|
336
|
+
if (filePath) {
|
|
337
|
+
unwatchFile(filePath);
|
|
338
|
+
this.state.watchedTodoFiles.delete(agentId);
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
logError(error);
|
|
342
|
+
debug.warn("FILE_FRESHNESS_TODO_WATCH_STOP_FAILED", {
|
|
343
|
+
agentId,
|
|
344
|
+
error: error instanceof Error ? error.message : String(error)
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
getFileInfo(filePath) {
|
|
349
|
+
return this.state.readTimestamps.get(filePath) || null;
|
|
350
|
+
}
|
|
351
|
+
isFileTracked(filePath) {
|
|
352
|
+
return this.state.readTimestamps.has(filePath);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Retrieves files prioritized for recovery during conversation compression
|
|
356
|
+
*
|
|
357
|
+
* Selects recently accessed files based on:
|
|
358
|
+
* - File access recency (most recent first)
|
|
359
|
+
* - File type relevance (excludes dependencies, build artifacts)
|
|
360
|
+
* - Development workflow importance
|
|
361
|
+
*
|
|
362
|
+
* Used to maintain coding context when conversation history is compressed
|
|
363
|
+
*/
|
|
364
|
+
getImportantFiles(maxFiles = 5) {
|
|
365
|
+
return Array.from(this.state.readTimestamps.entries()).map(([path2, info]) => ({
|
|
366
|
+
path: path2,
|
|
367
|
+
timestamp: info.lastRead,
|
|
368
|
+
size: info.size
|
|
369
|
+
})).filter((file) => this.isValidForRecovery(file.path)).sort((a, b) => b.timestamp - a.timestamp).slice(0, maxFiles);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Determines which files are suitable for automatic recovery
|
|
373
|
+
*
|
|
374
|
+
* Excludes files that are typically not relevant for development context:
|
|
375
|
+
* - Build artifacts and generated files
|
|
376
|
+
* - Dependencies and cached files
|
|
377
|
+
* - Temporary files and system directories
|
|
378
|
+
*/
|
|
379
|
+
isValidForRecovery(filePath) {
|
|
380
|
+
return !filePath.includes("node_modules") && !filePath.includes(".git") && !filePath.startsWith("/tmp") && !filePath.includes(".cache") && !filePath.includes("dist/") && !filePath.includes("build/");
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
var fileFreshnessService = new FileFreshnessService();
|
|
384
|
+
var recordFileRead = (filePath) => fileFreshnessService.recordFileRead(filePath);
|
|
385
|
+
var recordFileEdit = (filePath, content) => fileFreshnessService.recordFileEdit(filePath, content);
|
|
386
|
+
var generateFileModificationReminder = (filePath) => fileFreshnessService.generateFileModificationReminder(filePath);
|
|
387
|
+
var resetFileFreshnessSession = () => fileFreshnessService.resetSession();
|
|
388
|
+
var startWatchingTodoFile = (agentId) => fileFreshnessService.startWatchingTodoFile(agentId);
|
|
389
|
+
|
|
390
|
+
// packages/core/src/utils/file.ts
|
|
391
|
+
import {
|
|
392
|
+
readFileSync,
|
|
393
|
+
writeFileSync,
|
|
394
|
+
openSync,
|
|
395
|
+
readSync,
|
|
396
|
+
closeSync,
|
|
397
|
+
existsSync as existsSync3,
|
|
398
|
+
readdirSync
|
|
399
|
+
} from "fs";
|
|
400
|
+
import {
|
|
401
|
+
isAbsolute,
|
|
402
|
+
normalize,
|
|
403
|
+
resolve as resolve2,
|
|
404
|
+
resolve as resolvePath,
|
|
405
|
+
relative,
|
|
406
|
+
sep,
|
|
407
|
+
basename,
|
|
408
|
+
dirname as dirname2,
|
|
409
|
+
extname,
|
|
410
|
+
join as join2
|
|
411
|
+
} from "path";
|
|
412
|
+
import { cwd } from "process";
|
|
413
|
+
|
|
414
|
+
// packages/core/src/utils/ripgrep.ts
|
|
415
|
+
import { findActualExecutable } from "spawn-rx";
|
|
416
|
+
import { memoize } from "lodash-es";
|
|
417
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
418
|
+
import { createRequire } from "node:module";
|
|
419
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
420
|
+
import * as path from "path";
|
|
421
|
+
import { execFile } from "child_process";
|
|
422
|
+
import debug2 from "debug";
|
|
423
|
+
import { quote } from "shell-quote";
|
|
424
|
+
var d = debug2("kode:ripgrep");
|
|
425
|
+
function getCurrentModuleUrl() {
|
|
426
|
+
if (typeof __filename === "string" && __filename) {
|
|
427
|
+
return pathToFileURL(__filename).href;
|
|
428
|
+
}
|
|
429
|
+
return import.meta.url;
|
|
430
|
+
}
|
|
431
|
+
function getVscodeRipgrepPathOrThrow() {
|
|
432
|
+
try {
|
|
433
|
+
const req = createRequire(getCurrentModuleUrl());
|
|
434
|
+
const mod = req("@vscode/ripgrep");
|
|
435
|
+
if (typeof mod?.rgPath === "string" && mod.rgPath.trim()) return mod.rgPath;
|
|
436
|
+
} catch (err) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
[
|
|
439
|
+
"@vscode/ripgrep is required but could not be loaded.",
|
|
440
|
+
"Fix:",
|
|
441
|
+
"- Reinstall dependencies: bun install",
|
|
442
|
+
"- Or install ripgrep system-wide and ensure `rg` is on PATH",
|
|
443
|
+
err instanceof Error ? `Reason: ${err.message}` : ""
|
|
444
|
+
].filter(Boolean).join("\n")
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
throw new Error("Invalid @vscode/ripgrep export: rgPath missing");
|
|
448
|
+
}
|
|
449
|
+
function findRipgrepVendorRoot() {
|
|
450
|
+
const explicit = process.env.KODE_RIPGREP_VENDOR_ROOT;
|
|
451
|
+
if (explicit && existsSync2(explicit)) {
|
|
452
|
+
return explicit;
|
|
453
|
+
}
|
|
454
|
+
const startDir = path.dirname(fileURLToPath(getCurrentModuleUrl()));
|
|
455
|
+
let dir = startDir;
|
|
456
|
+
for (let i = 0; i < 8; i++) {
|
|
457
|
+
const direct = path.join(dir, "vendor", "ripgrep");
|
|
458
|
+
if (existsSync2(direct)) return direct;
|
|
459
|
+
const distVendor = path.join(dir, "dist", "vendor", "ripgrep");
|
|
460
|
+
if (existsSync2(distVendor)) return distVendor;
|
|
461
|
+
const parent = path.dirname(dir);
|
|
462
|
+
if (parent === dir) break;
|
|
463
|
+
dir = parent;
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
function resolveExplicitRipgrepPathOrThrow() {
|
|
468
|
+
const explicit = process.env.KODE_RIPGREP_PATH;
|
|
469
|
+
if (!explicit) return null;
|
|
470
|
+
if (!existsSync2(explicit)) {
|
|
471
|
+
throw new Error(`KODE_RIPGREP_PATH points to a missing file: ${explicit}`);
|
|
472
|
+
}
|
|
473
|
+
return explicit;
|
|
474
|
+
}
|
|
475
|
+
function resolveVendorRipgrepPathOrNull() {
|
|
476
|
+
const rgRoot = findRipgrepVendorRoot();
|
|
477
|
+
if (!rgRoot) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
if (process.platform === "win32") {
|
|
481
|
+
const candidates = [`${process.arch}-win32`, "x64-win32"];
|
|
482
|
+
for (const dirName of candidates) {
|
|
483
|
+
const p = path.resolve(rgRoot, dirName, "rg.exe");
|
|
484
|
+
if (existsSync2(p)) {
|
|
485
|
+
d("internal ripgrep resolved as: %s", p);
|
|
486
|
+
return p;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
const ret = path.resolve(rgRoot, `${process.arch}-${process.platform}`, "rg");
|
|
492
|
+
if (!existsSync2(ret)) {
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
d("internal ripgrep resolved as: %s", ret);
|
|
496
|
+
return ret;
|
|
497
|
+
}
|
|
498
|
+
var getRipgrepPath = memoize(() => {
|
|
499
|
+
const explicit = resolveExplicitRipgrepPathOrThrow();
|
|
500
|
+
if (explicit) return explicit;
|
|
501
|
+
const vscodeRgPath = getVscodeRipgrepPathOrThrow();
|
|
502
|
+
const useBuiltinRipgrep = !!process.env.USE_BUILTIN_RIPGREP;
|
|
503
|
+
if (useBuiltinRipgrep) {
|
|
504
|
+
d("Using builtin ripgrep because USE_BUILTIN_RIPGREP is set");
|
|
505
|
+
const vendor2 = resolveVendorRipgrepPathOrNull();
|
|
506
|
+
if (vendor2) return vendor2;
|
|
507
|
+
return vscodeRgPath;
|
|
508
|
+
}
|
|
509
|
+
const { cmd } = findActualExecutable("rg", []);
|
|
510
|
+
d(`ripgrep initially resolved as: ${cmd}`);
|
|
511
|
+
if (cmd !== "rg") return cmd;
|
|
512
|
+
const vendor = resolveVendorRipgrepPathOrNull();
|
|
513
|
+
if (vendor) return vendor;
|
|
514
|
+
return vscodeRgPath;
|
|
515
|
+
});
|
|
516
|
+
async function ripGrep(args, target, abortSignal, options) {
|
|
517
|
+
await codesignRipgrepIfNecessary();
|
|
518
|
+
const rg = getRipgrepPath();
|
|
519
|
+
d("ripgrep called: %s %o", rg, target, args);
|
|
520
|
+
if (options?.sandbox?.enabled === true) {
|
|
521
|
+
const cmd = quote([rg, ...args, target]);
|
|
522
|
+
const result = await BunShell.getInstance().exec(cmd, abortSignal, 1e4, {
|
|
523
|
+
sandbox: options.sandbox
|
|
524
|
+
});
|
|
525
|
+
if (result.code === 1) return [];
|
|
526
|
+
if (result.code !== 0) {
|
|
527
|
+
logError(`ripgrep failed with exit code ${result.code}: ${result.stderr}`);
|
|
528
|
+
return [];
|
|
529
|
+
}
|
|
530
|
+
return result.stdout.trim().split("\n").filter(Boolean);
|
|
531
|
+
}
|
|
532
|
+
return new Promise((resolve3) => {
|
|
533
|
+
execFile(
|
|
534
|
+
getRipgrepPath(),
|
|
535
|
+
[...args, target],
|
|
536
|
+
{
|
|
537
|
+
maxBuffer: 1e6,
|
|
538
|
+
signal: abortSignal,
|
|
539
|
+
timeout: 1e4
|
|
540
|
+
},
|
|
541
|
+
(error, stdout) => {
|
|
542
|
+
if (error) {
|
|
543
|
+
if (error.code !== 1) {
|
|
544
|
+
d("ripgrep error: %o", error);
|
|
545
|
+
logError(error);
|
|
546
|
+
}
|
|
547
|
+
resolve3([]);
|
|
548
|
+
} else {
|
|
549
|
+
d("ripgrep succeeded with %s", stdout);
|
|
550
|
+
resolve3(stdout.trim().split("\n").filter(Boolean));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
async function listAllContentFiles(path2, abortSignal, limit) {
|
|
557
|
+
try {
|
|
558
|
+
d("listAllContentFiles called: %s", path2);
|
|
559
|
+
return (await ripGrep(["-l", ".", path2], path2, abortSignal)).slice(0, limit);
|
|
560
|
+
} catch (e) {
|
|
561
|
+
d("listAllContentFiles failed: %o", e);
|
|
562
|
+
logError(e);
|
|
563
|
+
return [];
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
var alreadyDoneSignCheck = false;
|
|
567
|
+
async function codesignRipgrepIfNecessary() {
|
|
568
|
+
if (process.platform !== "darwin" || alreadyDoneSignCheck) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
alreadyDoneSignCheck = true;
|
|
572
|
+
d("checking if ripgrep is already signed");
|
|
573
|
+
const lines = (await execFileNoThrow(
|
|
574
|
+
"codesign",
|
|
575
|
+
["-vv", "-d", getRipgrepPath()],
|
|
576
|
+
void 0,
|
|
577
|
+
void 0,
|
|
578
|
+
false
|
|
579
|
+
)).stdout.split("\n");
|
|
580
|
+
const needsSigned = lines.find((line) => line.includes("linker-signed"));
|
|
581
|
+
if (!needsSigned) {
|
|
582
|
+
d("seems to be already signed");
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
try {
|
|
586
|
+
d("signing ripgrep");
|
|
587
|
+
const signResult = await execFileNoThrow("codesign", [
|
|
588
|
+
"--sign",
|
|
589
|
+
"-",
|
|
590
|
+
"--force",
|
|
591
|
+
"--preserve-metadata=entitlements,requirements,flags,runtime",
|
|
592
|
+
getRipgrepPath()
|
|
593
|
+
]);
|
|
594
|
+
if (signResult.code !== 0) {
|
|
595
|
+
d("failed to sign ripgrep: %o", signResult);
|
|
596
|
+
logError(
|
|
597
|
+
`Failed to sign ripgrep: ${signResult.stdout} ${signResult.stderr}`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
d("removing quarantine");
|
|
601
|
+
const quarantineResult = await execFileNoThrow("xattr", [
|
|
602
|
+
"-d",
|
|
603
|
+
"com.apple.quarantine",
|
|
604
|
+
getRipgrepPath()
|
|
605
|
+
]);
|
|
606
|
+
if (quarantineResult.code !== 0) {
|
|
607
|
+
d("failed to remove quarantine: %o", quarantineResult);
|
|
608
|
+
logError(
|
|
609
|
+
`Failed to remove quarantine: ${quarantineResult.stdout} ${quarantineResult.stderr}`
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
} catch (e) {
|
|
613
|
+
d("failed during sign: %o", e);
|
|
614
|
+
logError(e);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// packages/core/src/utils/file.ts
|
|
619
|
+
import { LRUCache } from "lru-cache";
|
|
620
|
+
|
|
621
|
+
// packages/core/src/utils/file/glob.ts
|
|
622
|
+
import { glob as globLib } from "glob";
|
|
623
|
+
|
|
624
|
+
// packages/runtime/src/searcher.ts
|
|
625
|
+
import { glob } from "glob";
|
|
626
|
+
|
|
627
|
+
// packages/core/src/utils/file.ts
|
|
628
|
+
function isInDirectory(relativePath, relativeCwd) {
|
|
629
|
+
if (relativePath === ".") {
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
if (relativePath.startsWith("~")) {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
if (relativePath.includes("\0") || relativeCwd.includes("\0")) {
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
638
|
+
let normalizedPath = normalize(relativePath);
|
|
639
|
+
let normalizedCwd = normalize(relativeCwd);
|
|
640
|
+
normalizedPath = normalizedPath.endsWith(sep) ? normalizedPath : normalizedPath + sep;
|
|
641
|
+
normalizedCwd = normalizedCwd.endsWith(sep) ? normalizedCwd : normalizedCwd + sep;
|
|
642
|
+
const fullPath = resolvePath(cwd(), normalizedCwd, normalizedPath);
|
|
643
|
+
const fullCwd = resolvePath(cwd(), normalizedCwd);
|
|
644
|
+
const rel = relative(fullCwd, fullPath);
|
|
645
|
+
if (!rel || rel === "") return true;
|
|
646
|
+
if (rel.startsWith("..")) return false;
|
|
647
|
+
if (isAbsolute(rel)) return false;
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
function readTextContent(filePath, offset = 0, maxLines) {
|
|
651
|
+
const enc = detectFileEncoding(filePath);
|
|
652
|
+
const content = readFileSync(filePath, enc);
|
|
653
|
+
const lines = content.split(/\r?\n/);
|
|
654
|
+
const toReturn = maxLines !== void 0 && lines.length - offset > maxLines ? lines.slice(offset, offset + maxLines) : lines.slice(offset);
|
|
655
|
+
return {
|
|
656
|
+
content: toReturn.join("\n"),
|
|
657
|
+
// NOTE: Normalizes line endings to LF for display/LLM consumption.
|
|
658
|
+
lineCount: toReturn.length,
|
|
659
|
+
totalLines: lines.length
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function writeTextContent(filePath, content, encoding, endings) {
|
|
663
|
+
let toWrite = content;
|
|
664
|
+
if (endings === "CRLF") {
|
|
665
|
+
toWrite = content.split("\n").join("\r\n");
|
|
666
|
+
}
|
|
667
|
+
writeFileSync(filePath, toWrite, { encoding, flush: true });
|
|
668
|
+
}
|
|
669
|
+
var repoEndingCache = new LRUCache({
|
|
670
|
+
fetchMethod: (path2) => detectRepoLineEndingsDirect(path2),
|
|
671
|
+
ttl: 5 * 60 * 1e3,
|
|
672
|
+
ttlAutopurge: false,
|
|
673
|
+
max: 1e3
|
|
674
|
+
});
|
|
675
|
+
async function detectRepoLineEndings(filePath) {
|
|
676
|
+
return repoEndingCache.fetch(resolve2(filePath));
|
|
677
|
+
}
|
|
678
|
+
async function detectRepoLineEndingsDirect(cwd2) {
|
|
679
|
+
const abortController = new AbortController();
|
|
680
|
+
setTimeout(() => {
|
|
681
|
+
abortController.abort();
|
|
682
|
+
}, 1e3);
|
|
683
|
+
const allFiles = await listAllContentFiles(cwd2, abortController.signal, 15);
|
|
684
|
+
let crlfCount = 0;
|
|
685
|
+
for (const file of allFiles) {
|
|
686
|
+
const lineEnding = detectLineEndings(file);
|
|
687
|
+
if (lineEnding === "CRLF") {
|
|
688
|
+
crlfCount++;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return crlfCount > 3 ? "CRLF" : "LF";
|
|
692
|
+
}
|
|
693
|
+
function fetch(cache, key, value) {
|
|
694
|
+
if (cache.has(key)) {
|
|
695
|
+
return cache.get(key);
|
|
696
|
+
}
|
|
697
|
+
const v = value();
|
|
698
|
+
cache.set(key, v);
|
|
699
|
+
return v;
|
|
700
|
+
}
|
|
701
|
+
var fileEncodingCache = new LRUCache({
|
|
702
|
+
fetchMethod: (path2) => detectFileEncodingDirect(path2),
|
|
703
|
+
ttl: 5 * 60 * 1e3,
|
|
704
|
+
ttlAutopurge: false,
|
|
705
|
+
max: 1e3
|
|
706
|
+
});
|
|
707
|
+
function detectFileEncoding(filePath) {
|
|
708
|
+
const k = resolve2(filePath);
|
|
709
|
+
return fetch(fileEncodingCache, k, () => detectFileEncodingDirect(k));
|
|
710
|
+
}
|
|
711
|
+
function detectFileEncodingDirect(filePath) {
|
|
712
|
+
const BUFFER_SIZE = 4096;
|
|
713
|
+
const buffer = Buffer.alloc(BUFFER_SIZE);
|
|
714
|
+
let fd = void 0;
|
|
715
|
+
try {
|
|
716
|
+
fd = openSync(filePath, "r");
|
|
717
|
+
const bytesRead = readSync(fd, buffer, 0, BUFFER_SIZE, 0);
|
|
718
|
+
if (bytesRead >= 2) {
|
|
719
|
+
if (buffer[0] === 255 && buffer[1] === 254) return "utf16le";
|
|
720
|
+
}
|
|
721
|
+
if (bytesRead >= 3 && buffer[0] === 239 && buffer[1] === 187 && buffer[2] === 191) {
|
|
722
|
+
return "utf8";
|
|
723
|
+
}
|
|
724
|
+
const isUtf8 = buffer.slice(0, bytesRead).toString("utf8").length > 0;
|
|
725
|
+
return isUtf8 ? "utf8" : "ascii";
|
|
726
|
+
} catch (error) {
|
|
727
|
+
logError(`Error detecting encoding for file ${filePath}: ${error}`);
|
|
728
|
+
return "utf8";
|
|
729
|
+
} finally {
|
|
730
|
+
if (fd) closeSync(fd);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
var lineEndingCache = new LRUCache({
|
|
734
|
+
fetchMethod: (path2) => detectLineEndingsDirect(path2),
|
|
735
|
+
ttl: 5 * 60 * 1e3,
|
|
736
|
+
ttlAutopurge: false,
|
|
737
|
+
max: 1e3
|
|
738
|
+
});
|
|
739
|
+
function detectLineEndings(filePath) {
|
|
740
|
+
const k = resolve2(filePath);
|
|
741
|
+
return fetch(lineEndingCache, k, () => detectLineEndingsDirect(k));
|
|
742
|
+
}
|
|
743
|
+
function detectLineEndingsDirect(filePath, encoding = "utf8") {
|
|
744
|
+
try {
|
|
745
|
+
const buffer = Buffer.alloc(4096);
|
|
746
|
+
const fd = openSync(filePath, "r");
|
|
747
|
+
const bytesRead = readSync(fd, buffer, 0, 4096, 0);
|
|
748
|
+
closeSync(fd);
|
|
749
|
+
const content = buffer.toString(encoding, 0, bytesRead);
|
|
750
|
+
let crlfCount = 0;
|
|
751
|
+
let lfCount = 0;
|
|
752
|
+
for (let i = 0; i < content.length; i++) {
|
|
753
|
+
if (content[i] === "\n") {
|
|
754
|
+
if (i > 0 && content[i - 1] === "\r") {
|
|
755
|
+
crlfCount++;
|
|
756
|
+
} else {
|
|
757
|
+
lfCount++;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return crlfCount > lfCount ? "CRLF" : "LF";
|
|
762
|
+
} catch (error) {
|
|
763
|
+
logError(`Error detecting line endings for file ${filePath}: ${error}`);
|
|
764
|
+
return "LF";
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
function normalizeFilePath(filePath) {
|
|
768
|
+
const absoluteFilePath = isAbsolute(filePath) ? filePath : resolve2(getCwd(), filePath);
|
|
769
|
+
if (absoluteFilePath.endsWith(" AM.png")) {
|
|
770
|
+
return absoluteFilePath.replace(
|
|
771
|
+
" AM.png",
|
|
772
|
+
`${String.fromCharCode(8239)}AM.png`
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
if (absoluteFilePath.endsWith(" PM.png")) {
|
|
776
|
+
return absoluteFilePath.replace(
|
|
777
|
+
" PM.png",
|
|
778
|
+
`${String.fromCharCode(8239)}PM.png`
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
return absoluteFilePath;
|
|
782
|
+
}
|
|
783
|
+
function getAbsolutePath(path2) {
|
|
784
|
+
return path2 ? isAbsolute(path2) ? path2 : resolve2(getCwd(), path2) : void 0;
|
|
785
|
+
}
|
|
786
|
+
function getAbsoluteAndRelativePaths(path2) {
|
|
787
|
+
const absolutePath = getAbsolutePath(path2);
|
|
788
|
+
const relativePath = absolutePath ? relative(getCwd(), absolutePath) : void 0;
|
|
789
|
+
return { absolutePath, relativePath };
|
|
790
|
+
}
|
|
791
|
+
function findSimilarFile(filePath) {
|
|
792
|
+
try {
|
|
793
|
+
const dir = dirname2(filePath);
|
|
794
|
+
const fileBaseName = basename(filePath, extname(filePath));
|
|
795
|
+
if (!existsSync3(dir)) {
|
|
796
|
+
return void 0;
|
|
797
|
+
}
|
|
798
|
+
const files = readdirSync(dir);
|
|
799
|
+
const similarFiles = files.filter(
|
|
800
|
+
(file) => basename(file, extname(file)) === fileBaseName && join2(dir, file) !== filePath
|
|
801
|
+
);
|
|
802
|
+
const firstMatch = similarFiles[0];
|
|
803
|
+
if (firstMatch) {
|
|
804
|
+
return firstMatch;
|
|
805
|
+
}
|
|
806
|
+
return void 0;
|
|
807
|
+
} catch (error) {
|
|
808
|
+
logError(`Error finding similar file for ${filePath}: ${error}`);
|
|
809
|
+
return void 0;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
function addLineNumbers({
|
|
813
|
+
content,
|
|
814
|
+
// 1-indexed
|
|
815
|
+
startLine
|
|
816
|
+
}) {
|
|
817
|
+
if (!content) {
|
|
818
|
+
return "";
|
|
819
|
+
}
|
|
820
|
+
return content.split(/\r?\n/).map((line, index) => {
|
|
821
|
+
const lineNum = index + startLine;
|
|
822
|
+
const numStr = String(lineNum);
|
|
823
|
+
if (numStr.length >= 6) {
|
|
824
|
+
return `${numStr}\u2192${line}`;
|
|
825
|
+
}
|
|
826
|
+
return `${numStr.padStart(6, " ")}\u2192${line}`;
|
|
827
|
+
}).join("\n");
|
|
828
|
+
}
|
|
829
|
+
function isDirEmpty(dirPath) {
|
|
830
|
+
try {
|
|
831
|
+
const entries = readdirSync(dirPath);
|
|
832
|
+
return entries.length === 0;
|
|
833
|
+
} catch (error) {
|
|
834
|
+
logError(`Error checking directory: ${error}`);
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// packages/core/src/utils/fileRecoveryCore.ts
|
|
840
|
+
var MAX_FILES_TO_RECOVER = 5;
|
|
841
|
+
var MAX_TOKENS_PER_FILE = 1e4;
|
|
842
|
+
var MAX_TOTAL_FILE_TOKENS = 5e4;
|
|
843
|
+
async function selectAndReadFiles() {
|
|
844
|
+
const importantFiles = fileFreshnessService.getImportantFiles(MAX_FILES_TO_RECOVER);
|
|
845
|
+
const results = [];
|
|
846
|
+
let totalTokens = 0;
|
|
847
|
+
for (const fileInfo of importantFiles) {
|
|
848
|
+
try {
|
|
849
|
+
const { content } = readTextContent(fileInfo.path);
|
|
850
|
+
const estimatedTokens = Math.ceil(content.length * 0.25);
|
|
851
|
+
let finalContent = content;
|
|
852
|
+
let truncated = false;
|
|
853
|
+
if (estimatedTokens > MAX_TOKENS_PER_FILE) {
|
|
854
|
+
const maxChars = Math.floor(MAX_TOKENS_PER_FILE / 0.25);
|
|
855
|
+
finalContent = content.substring(0, maxChars);
|
|
856
|
+
truncated = true;
|
|
857
|
+
}
|
|
858
|
+
const finalTokens = Math.min(estimatedTokens, MAX_TOKENS_PER_FILE);
|
|
859
|
+
if (totalTokens + finalTokens > MAX_TOTAL_FILE_TOKENS) {
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
totalTokens += finalTokens;
|
|
863
|
+
results.push({
|
|
864
|
+
path: fileInfo.path,
|
|
865
|
+
content: finalContent,
|
|
866
|
+
tokens: finalTokens,
|
|
867
|
+
truncated
|
|
868
|
+
});
|
|
869
|
+
} catch (error) {
|
|
870
|
+
logError(error);
|
|
871
|
+
debug.warn("FILE_RECOVERY_READ_FAILED", {
|
|
872
|
+
path: fileInfo.path,
|
|
873
|
+
error: error instanceof Error ? error.message : String(error)
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return results;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// packages/core/src/utils/autoCompactThreshold.ts
|
|
881
|
+
var AUTO_COMPACT_THRESHOLD_RATIO = 0.9;
|
|
882
|
+
function calculateAutoCompactThresholds(tokenCount, contextLimit, ratio = AUTO_COMPACT_THRESHOLD_RATIO) {
|
|
883
|
+
const safeContextLimit = Number.isFinite(contextLimit) && contextLimit > 0 ? contextLimit : 1;
|
|
884
|
+
const autoCompactThreshold = safeContextLimit * ratio;
|
|
885
|
+
return {
|
|
886
|
+
isAboveAutoCompactThreshold: tokenCount >= autoCompactThreshold,
|
|
887
|
+
percentUsed: Math.round(tokenCount / safeContextLimit * 100),
|
|
888
|
+
tokensRemaining: Math.max(0, autoCompactThreshold - tokenCount),
|
|
889
|
+
contextLimit: safeContextLimit,
|
|
890
|
+
autoCompactThreshold,
|
|
891
|
+
ratio
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// packages/core/src/utils/autoCompactCore.ts
|
|
896
|
+
async function getMainConversationContextLimit() {
|
|
897
|
+
try {
|
|
898
|
+
const modelManager = getModelManager();
|
|
899
|
+
const resolution = modelManager.resolveModelWithInfo("main");
|
|
900
|
+
const modelProfile = resolution.success ? resolution.profile : null;
|
|
901
|
+
if (modelProfile?.contextLength) {
|
|
902
|
+
return modelProfile.contextLength;
|
|
903
|
+
}
|
|
904
|
+
return 2e5;
|
|
905
|
+
} catch (error) {
|
|
906
|
+
return 2e5;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
var COMPRESSION_PROMPT = `Please provide a comprehensive summary of our conversation structured as follows:
|
|
910
|
+
|
|
911
|
+
## Technical Context
|
|
912
|
+
Development environment, tools, frameworks, and configurations in use. Programming languages, libraries, and technical constraints. File structure, directory organization, and project architecture.
|
|
913
|
+
|
|
914
|
+
## Project Overview
|
|
915
|
+
Main project goals, features, and scope. Key components, modules, and their relationships. Data models, APIs, and integration patterns.
|
|
916
|
+
|
|
917
|
+
## Code Changes
|
|
918
|
+
Files created, modified, or analyzed during our conversation. Specific code implementations, functions, and algorithms added. Configuration changes and structural modifications.
|
|
919
|
+
|
|
920
|
+
## Debugging & Issues
|
|
921
|
+
Problems encountered and their root causes. Solutions implemented and their effectiveness. Error messages, logs, and diagnostic information.
|
|
922
|
+
|
|
923
|
+
## Current Status
|
|
924
|
+
What we just completed successfully. Current state of the codebase and any ongoing work. Test results, validation steps, and verification performed.
|
|
925
|
+
|
|
926
|
+
## Pending Tasks
|
|
927
|
+
Immediate next steps and priorities. Planned features, improvements, and refactoring. Known issues, technical debt, and areas needing attention.
|
|
928
|
+
|
|
929
|
+
## User Preferences
|
|
930
|
+
Coding style, formatting, and organizational preferences. Communication patterns and feedback style. Tool choices and workflow preferences.
|
|
931
|
+
|
|
932
|
+
## Key Decisions
|
|
933
|
+
Important technical decisions made and their rationale. Alternative approaches considered and why they were rejected. Trade-offs accepted and their implications.
|
|
934
|
+
|
|
935
|
+
Focus on information essential for continuing the conversation effectively, including specific details about code, files, errors, and plans.`;
|
|
936
|
+
async function calculateThresholds(tokenCount) {
|
|
937
|
+
const contextLimit = await getMainConversationContextLimit();
|
|
938
|
+
return calculateAutoCompactThresholds(
|
|
939
|
+
tokenCount,
|
|
940
|
+
contextLimit,
|
|
941
|
+
AUTO_COMPACT_THRESHOLD_RATIO
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
async function shouldAutoCompact(messages) {
|
|
945
|
+
if (messages.length < 3) return false;
|
|
946
|
+
const tokenCount = countTokens(messages);
|
|
947
|
+
const { isAboveAutoCompactThreshold } = await calculateThresholds(tokenCount);
|
|
948
|
+
return isAboveAutoCompactThreshold;
|
|
949
|
+
}
|
|
950
|
+
async function checkAutoCompact(messages, toolUseContext) {
|
|
951
|
+
if (!await shouldAutoCompact(messages)) {
|
|
952
|
+
return { messages, wasCompacted: false };
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
const compactedMessages = await executeAutoCompact(messages, toolUseContext);
|
|
956
|
+
return {
|
|
957
|
+
messages: compactedMessages,
|
|
958
|
+
wasCompacted: true
|
|
959
|
+
};
|
|
960
|
+
} catch (error) {
|
|
961
|
+
logError(error);
|
|
962
|
+
debug.warn("AUTO_COMPACT_FAILED", {
|
|
963
|
+
error: error instanceof Error ? error.message : String(error)
|
|
964
|
+
});
|
|
965
|
+
return { messages, wasCompacted: false };
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
async function executeAutoCompact(messages, toolUseContext) {
|
|
969
|
+
const summaryRequest = createUserMessage(COMPRESSION_PROMPT);
|
|
970
|
+
const tokenCount = countTokens(messages);
|
|
971
|
+
const modelManager = getModelManager();
|
|
972
|
+
const compactResolution = modelManager.resolveModelWithInfo("compact");
|
|
973
|
+
const mainResolution = modelManager.resolveModelWithInfo("main");
|
|
974
|
+
let compressionModelPointer = "compact";
|
|
975
|
+
let compressionNotice = null;
|
|
976
|
+
if (!compactResolution.success || !compactResolution.profile) {
|
|
977
|
+
compressionModelPointer = "main";
|
|
978
|
+
compressionNotice = compactResolution.error || "Compression model pointer 'compact' is not configured.";
|
|
979
|
+
} else {
|
|
980
|
+
const compactBudget = Math.floor(
|
|
981
|
+
compactResolution.profile.contextLength * 0.9
|
|
982
|
+
);
|
|
983
|
+
if (compactBudget > 0 && tokenCount > compactBudget) {
|
|
984
|
+
compressionModelPointer = "main";
|
|
985
|
+
compressionNotice = `Compression model '${compactResolution.profile.name}' does not fit current context (~${Math.round(tokenCount / 1e3)}k tokens).`;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (compressionModelPointer === "main" && (!mainResolution.success || !mainResolution.profile)) {
|
|
989
|
+
throw new Error(
|
|
990
|
+
mainResolution.error || "Compression fallback failed: model pointer 'main' is not configured."
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
const summaryResponse = await queryLLM(
|
|
994
|
+
normalizeMessagesForAPI([...messages, summaryRequest]),
|
|
995
|
+
[
|
|
996
|
+
"You are a helpful AI assistant tasked with creating comprehensive conversation summaries that preserve all essential context for continuing development work."
|
|
997
|
+
],
|
|
998
|
+
0,
|
|
999
|
+
[],
|
|
1000
|
+
toolUseContext.abortController.signal,
|
|
1001
|
+
{
|
|
1002
|
+
safeMode: false,
|
|
1003
|
+
model: compressionModelPointer,
|
|
1004
|
+
prependCLISysprompt: true
|
|
1005
|
+
}
|
|
1006
|
+
);
|
|
1007
|
+
const content = summaryResponse.message.content;
|
|
1008
|
+
const summary = typeof content === "string" ? content : content.length > 0 && content[0]?.type === "text" ? content[0].text : null;
|
|
1009
|
+
if (!summary) {
|
|
1010
|
+
throw new Error(
|
|
1011
|
+
"Failed to generate conversation summary - response did not contain valid text content"
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
summaryResponse.message.usage = {
|
|
1015
|
+
input_tokens: 0,
|
|
1016
|
+
output_tokens: summaryResponse.message.usage.output_tokens,
|
|
1017
|
+
cache_creation_input_tokens: 0,
|
|
1018
|
+
cache_read_input_tokens: 0
|
|
1019
|
+
};
|
|
1020
|
+
const recoveredFiles = await selectAndReadFiles();
|
|
1021
|
+
const compactedMessages = [
|
|
1022
|
+
createUserMessage(
|
|
1023
|
+
compressionNotice ? `Context automatically compressed due to token limit. ${compressionNotice} Using '${compressionModelPointer}' for compression.` : `Context automatically compressed due to token limit. Using '${compressionModelPointer}' for compression.`
|
|
1024
|
+
),
|
|
1025
|
+
summaryResponse
|
|
1026
|
+
];
|
|
1027
|
+
if (recoveredFiles.length > 0) {
|
|
1028
|
+
for (const file of recoveredFiles) {
|
|
1029
|
+
const contentWithLines = addLineNumbers({
|
|
1030
|
+
content: file.content,
|
|
1031
|
+
startLine: 1
|
|
1032
|
+
});
|
|
1033
|
+
const recoveryMessage = createUserMessage(
|
|
1034
|
+
`**Recovered File: ${file.path}**
|
|
1035
|
+
|
|
1036
|
+
\`\`\`
|
|
1037
|
+
${contentWithLines}
|
|
1038
|
+
\`\`\`
|
|
1039
|
+
|
|
1040
|
+
*Automatically recovered (${file.tokens} tokens)${file.truncated ? " [truncated]" : ""}*`
|
|
1041
|
+
);
|
|
1042
|
+
compactedMessages.push(recoveryMessage);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
getMessagesSetter()([]);
|
|
1046
|
+
getContext.cache.clear?.();
|
|
1047
|
+
getCodeStyle.cache.clear?.();
|
|
1048
|
+
resetFileFreshnessSession();
|
|
1049
|
+
return compactedMessages;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// packages/core/src/feedback/binaryFeedback.ts
|
|
1053
|
+
import { isEqual, zip } from "lodash-es";
|
|
1054
|
+
async function getBinaryFeedbackConfig() {
|
|
1055
|
+
return { sampleFrequency: 0 };
|
|
1056
|
+
}
|
|
1057
|
+
function textContentBlocksEqual(cb1, cb2) {
|
|
1058
|
+
return cb1.text === cb2.text;
|
|
1059
|
+
}
|
|
1060
|
+
function contentBlocksEqual(cb1, cb2) {
|
|
1061
|
+
if (cb1.type !== cb2.type) {
|
|
1062
|
+
return false;
|
|
1063
|
+
}
|
|
1064
|
+
if (cb1.type === "text") {
|
|
1065
|
+
return textContentBlocksEqual(cb1, cb2);
|
|
1066
|
+
}
|
|
1067
|
+
cb2 = cb2;
|
|
1068
|
+
return cb1.name === cb2.name && isEqual(cb1.input, cb2.input);
|
|
1069
|
+
}
|
|
1070
|
+
function allContentBlocksEqual(content1, content2) {
|
|
1071
|
+
if (content1.length !== content2.length) {
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
return zip(content1, content2).every(
|
|
1075
|
+
([cb1, cb2]) => contentBlocksEqual(cb1, cb2)
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
async function shouldUseBinaryFeedback() {
|
|
1079
|
+
if (process.env.DISABLE_BINARY_FEEDBACK) {
|
|
1080
|
+
return false;
|
|
1081
|
+
}
|
|
1082
|
+
if (process.env.FORCE_BINARY_FEEDBACK) {
|
|
1083
|
+
return true;
|
|
1084
|
+
}
|
|
1085
|
+
if (process.env.USER_TYPE !== "ant") {
|
|
1086
|
+
return false;
|
|
1087
|
+
}
|
|
1088
|
+
if (process.env.NODE_ENV === "test") {
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
const config = await getBinaryFeedbackConfig();
|
|
1092
|
+
if (config.sampleFrequency === 0) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
if (Math.random() > config.sampleFrequency) {
|
|
1096
|
+
return false;
|
|
1097
|
+
}
|
|
1098
|
+
return true;
|
|
1099
|
+
}
|
|
1100
|
+
function messagePairValidForBinaryFeedback(m1, m2) {
|
|
1101
|
+
const logPass = () => {
|
|
1102
|
+
};
|
|
1103
|
+
const logFail = (_reason) => {
|
|
1104
|
+
};
|
|
1105
|
+
const nonThinkingBlocks1 = m1.message.content.filter(
|
|
1106
|
+
(b) => b.type !== "thinking" && b.type !== "redacted_thinking"
|
|
1107
|
+
);
|
|
1108
|
+
const nonThinkingBlocks2 = m2.message.content.filter(
|
|
1109
|
+
(b) => b.type !== "thinking" && b.type !== "redacted_thinking"
|
|
1110
|
+
);
|
|
1111
|
+
const hasToolUse = nonThinkingBlocks1.some((b) => b.type === "tool_use") || nonThinkingBlocks2.some((b) => b.type === "tool_use");
|
|
1112
|
+
if (!hasToolUse) {
|
|
1113
|
+
if (allContentBlocksEqual(nonThinkingBlocks1, nonThinkingBlocks2)) {
|
|
1114
|
+
logFail("contents_identical");
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
logPass();
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1120
|
+
if (allContentBlocksEqual(
|
|
1121
|
+
nonThinkingBlocks1.filter((b) => b.type === "tool_use"),
|
|
1122
|
+
nonThinkingBlocks2.filter((b) => b.type === "tool_use")
|
|
1123
|
+
)) {
|
|
1124
|
+
logFail("contents_identical");
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
logPass();
|
|
1128
|
+
return true;
|
|
1129
|
+
}
|
|
1130
|
+
function getBinaryFeedbackResultForChoice(m1, m2, choice) {
|
|
1131
|
+
switch (choice) {
|
|
1132
|
+
case "prefer-left":
|
|
1133
|
+
return { message: m1, shouldSkipPermissionCheck: true };
|
|
1134
|
+
case "prefer-right":
|
|
1135
|
+
return { message: m2, shouldSkipPermissionCheck: true };
|
|
1136
|
+
case "no-preference":
|
|
1137
|
+
return {
|
|
1138
|
+
message: Math.random() < 0.5 ? m1 : m2,
|
|
1139
|
+
shouldSkipPermissionCheck: false
|
|
1140
|
+
};
|
|
1141
|
+
case "neither":
|
|
1142
|
+
return { message: null, shouldSkipPermissionCheck: false };
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
async function logBinaryFeedbackEvent(_m1, _m2, _choice) {
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// packages/core/src/engine/query-executor.ts
|
|
1149
|
+
async function queryWithBinaryFeedback(toolUseContext, getAssistantResponse, getBinaryFeedbackResponse) {
|
|
1150
|
+
if (process.env.USER_TYPE !== "ant" || !getBinaryFeedbackResponse || !await shouldUseBinaryFeedback()) {
|
|
1151
|
+
const assistantMessage = await getAssistantResponse();
|
|
1152
|
+
if (toolUseContext.abortController.signal.aborted) {
|
|
1153
|
+
return { message: null, shouldSkipPermissionCheck: false };
|
|
1154
|
+
}
|
|
1155
|
+
return { message: assistantMessage, shouldSkipPermissionCheck: false };
|
|
1156
|
+
}
|
|
1157
|
+
const [m1, m2] = await Promise.all([
|
|
1158
|
+
getAssistantResponse(),
|
|
1159
|
+
getAssistantResponse()
|
|
1160
|
+
]);
|
|
1161
|
+
if (toolUseContext.abortController.signal.aborted) {
|
|
1162
|
+
return { message: null, shouldSkipPermissionCheck: false };
|
|
1163
|
+
}
|
|
1164
|
+
if (m2.isApiErrorMessage) {
|
|
1165
|
+
return { message: m1, shouldSkipPermissionCheck: false };
|
|
1166
|
+
}
|
|
1167
|
+
if (m1.isApiErrorMessage) {
|
|
1168
|
+
return { message: m2, shouldSkipPermissionCheck: false };
|
|
1169
|
+
}
|
|
1170
|
+
if (!messagePairValidForBinaryFeedback(m1, m2)) {
|
|
1171
|
+
return { message: m1, shouldSkipPermissionCheck: false };
|
|
1172
|
+
}
|
|
1173
|
+
return await getBinaryFeedbackResponse(m1, m2);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// packages/core/src/utils/toolNameAliases.ts
|
|
1177
|
+
function resolveToolNameAlias(name) {
|
|
1178
|
+
const originalName = name;
|
|
1179
|
+
const resolvedName = name === "AgentOutputTool" ? "TaskOutput" : name === "BashOutputTool" ? "TaskOutput" : name === "BashOutput" ? "TaskOutput" : name === "TaskOutputTool" ? "TaskOutput" : name;
|
|
1180
|
+
return {
|
|
1181
|
+
originalName,
|
|
1182
|
+
resolvedName,
|
|
1183
|
+
wasAliased: resolvedName !== originalName
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// packages/core/src/engine/pipeline/tool-input.ts
|
|
1188
|
+
function normalizeToolInput(tool, input) {
|
|
1189
|
+
if (tool.name === "Bash") {
|
|
1190
|
+
const parsed = tool.inputSchema.parse(input);
|
|
1191
|
+
const command = parsed.command;
|
|
1192
|
+
const timeout = parsed.timeout;
|
|
1193
|
+
const description = parsed.description;
|
|
1194
|
+
const run_in_background = parsed.run_in_background;
|
|
1195
|
+
const dangerouslyDisableSandbox = parsed.dangerouslyDisableSandbox;
|
|
1196
|
+
return {
|
|
1197
|
+
command: String(command).replace(`cd ${getCwd()} && `, "").replace(/\\\\;/g, "\\;"),
|
|
1198
|
+
...typeof timeout === "number" ? { timeout } : {},
|
|
1199
|
+
...typeof description === "string" && description ? { description } : {},
|
|
1200
|
+
...typeof run_in_background === "boolean" && run_in_background ? { run_in_background } : {},
|
|
1201
|
+
...typeof dangerouslyDisableSandbox === "boolean" && dangerouslyDisableSandbox ? { dangerouslyDisableSandbox } : {}
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
return input;
|
|
1205
|
+
}
|
|
1206
|
+
function preprocessToolInput(tool, input) {
|
|
1207
|
+
if (tool.name === "TaskOutput") {
|
|
1208
|
+
const task_id = typeof input.task_id === "string" && input.task_id || typeof input.agentId === "string" && input.agentId || typeof input.bash_id === "string" && input.bash_id || "";
|
|
1209
|
+
const block = typeof input.block === "boolean" ? input.block : true;
|
|
1210
|
+
const timeout = typeof input.timeout === "number" ? input.timeout : typeof input.wait_up_to === "number" ? input.wait_up_to * 1e3 : void 0;
|
|
1211
|
+
return {
|
|
1212
|
+
task_id,
|
|
1213
|
+
block,
|
|
1214
|
+
...timeout !== void 0 ? { timeout } : {}
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
return input;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// packages/core/src/engine/pipeline/tool-call.ts
|
|
1221
|
+
function asRecord2(value) {
|
|
1222
|
+
if (!value || typeof value !== "object") return null;
|
|
1223
|
+
return value;
|
|
1224
|
+
}
|
|
1225
|
+
function isPipelineMessage(value) {
|
|
1226
|
+
const record = asRecord2(value);
|
|
1227
|
+
if (!record) return false;
|
|
1228
|
+
return record.type === "user" || record.type === "assistant" || record.type === "progress";
|
|
1229
|
+
}
|
|
1230
|
+
function toToolResultContent(value) {
|
|
1231
|
+
if (typeof value === "string") return value;
|
|
1232
|
+
if (Array.isArray(value)) return value;
|
|
1233
|
+
return String(value);
|
|
1234
|
+
}
|
|
1235
|
+
async function* checkPermissionsAndCallTool(tool, toolUseID, siblingToolUseIDs, input, context, canUseTool, assistantMessage, shouldSkipPermissionCheck) {
|
|
1236
|
+
const preprocessedInput = preprocessToolInput(tool, input);
|
|
1237
|
+
const isValidInput = tool.inputSchema.safeParse(preprocessedInput);
|
|
1238
|
+
if (!isValidInput.success) {
|
|
1239
|
+
let errorMessage = `InputValidationError: ${isValidInput.error.message}`;
|
|
1240
|
+
if (tool.name === "Read" && Object.keys(preprocessedInput).length === 0) {
|
|
1241
|
+
errorMessage = `Error: The Read tool requires a 'file_path' parameter to specify which file to read. Please provide the absolute path to the file you want to read. For example: {"file_path": "/path/to/file.txt"}`;
|
|
1242
|
+
}
|
|
1243
|
+
yield createUserMessage([
|
|
1244
|
+
{
|
|
1245
|
+
type: "tool_result",
|
|
1246
|
+
content: errorMessage,
|
|
1247
|
+
is_error: true,
|
|
1248
|
+
tool_use_id: toolUseID
|
|
1249
|
+
}
|
|
1250
|
+
]);
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
let normalizedInput = normalizeToolInput(tool, isValidInput.data);
|
|
1254
|
+
const isValidCall = await tool.validateInput?.(
|
|
1255
|
+
normalizedInput,
|
|
1256
|
+
context
|
|
1257
|
+
);
|
|
1258
|
+
if (isValidCall?.result === false) {
|
|
1259
|
+
yield createUserMessage([
|
|
1260
|
+
{
|
|
1261
|
+
type: "tool_result",
|
|
1262
|
+
content: isValidCall.message,
|
|
1263
|
+
is_error: true,
|
|
1264
|
+
tool_use_id: toolUseID
|
|
1265
|
+
}
|
|
1266
|
+
]);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
const hookOutcome = await runPreToolUseHooks({
|
|
1270
|
+
toolName: tool.name,
|
|
1271
|
+
toolInput: normalizedInput,
|
|
1272
|
+
toolUseId: toolUseID,
|
|
1273
|
+
permissionMode: context.options?.toolPermissionContext?.mode,
|
|
1274
|
+
cwd: getCwd(),
|
|
1275
|
+
transcriptPath: getHookTranscriptPath(context),
|
|
1276
|
+
safeMode: context.options?.safeMode ?? false,
|
|
1277
|
+
signal: context.abortController.signal
|
|
1278
|
+
});
|
|
1279
|
+
if (hookOutcome.kind === "block") {
|
|
1280
|
+
yield createUserMessage([
|
|
1281
|
+
{
|
|
1282
|
+
type: "tool_result",
|
|
1283
|
+
content: hookOutcome.message,
|
|
1284
|
+
is_error: true,
|
|
1285
|
+
tool_use_id: toolUseID
|
|
1286
|
+
}
|
|
1287
|
+
]);
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
if (hookOutcome.warnings.length > 0) {
|
|
1291
|
+
const warningText = hookOutcome.warnings.join("\n");
|
|
1292
|
+
yield createProgressMessage(
|
|
1293
|
+
toolUseID,
|
|
1294
|
+
siblingToolUseIDs,
|
|
1295
|
+
createAssistantMessage(warningText),
|
|
1296
|
+
[],
|
|
1297
|
+
context.options?.tools ?? []
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
if (hookOutcome.systemMessages && hookOutcome.systemMessages.length > 0) {
|
|
1301
|
+
queueHookSystemMessages(context, hookOutcome.systemMessages);
|
|
1302
|
+
}
|
|
1303
|
+
if (hookOutcome.additionalContexts && hookOutcome.additionalContexts.length > 0) {
|
|
1304
|
+
queueHookAdditionalContexts(context, hookOutcome.additionalContexts);
|
|
1305
|
+
}
|
|
1306
|
+
if (hookOutcome.updatedInput) {
|
|
1307
|
+
const merged = { ...normalizedInput, ...hookOutcome.updatedInput };
|
|
1308
|
+
const parsed = tool.inputSchema.safeParse(merged);
|
|
1309
|
+
if (!parsed.success) {
|
|
1310
|
+
yield createUserMessage([
|
|
1311
|
+
{
|
|
1312
|
+
type: "tool_result",
|
|
1313
|
+
content: `Hook updatedInput failed validation: ${parsed.error.message}`,
|
|
1314
|
+
is_error: true,
|
|
1315
|
+
tool_use_id: toolUseID
|
|
1316
|
+
}
|
|
1317
|
+
]);
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
normalizedInput = normalizeToolInput(tool, parsed.data);
|
|
1321
|
+
const isValidUpdate = await tool.validateInput?.(
|
|
1322
|
+
normalizedInput,
|
|
1323
|
+
context
|
|
1324
|
+
);
|
|
1325
|
+
if (isValidUpdate?.result === false) {
|
|
1326
|
+
yield createUserMessage([
|
|
1327
|
+
{
|
|
1328
|
+
type: "tool_result",
|
|
1329
|
+
content: isValidUpdate.message,
|
|
1330
|
+
is_error: true,
|
|
1331
|
+
tool_use_id: toolUseID
|
|
1332
|
+
}
|
|
1333
|
+
]);
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
const hookPermissionDecision = hookOutcome.kind === "allow" ? hookOutcome.permissionDecision : void 0;
|
|
1338
|
+
const effectiveShouldSkipPermissionCheck = hookPermissionDecision === "allow" ? true : hookPermissionDecision === "ask" ? false : shouldSkipPermissionCheck;
|
|
1339
|
+
const permissionContextForCall = hookPermissionDecision === "ask" && context.options?.toolPermissionContext && context.options.toolPermissionContext.mode !== "default" ? {
|
|
1340
|
+
...context,
|
|
1341
|
+
options: {
|
|
1342
|
+
...context.options,
|
|
1343
|
+
toolPermissionContext: {
|
|
1344
|
+
...context.options.toolPermissionContext,
|
|
1345
|
+
mode: "default"
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
} : context;
|
|
1349
|
+
const permissionResult = effectiveShouldSkipPermissionCheck ? { result: true } : await canUseTool(
|
|
1350
|
+
tool,
|
|
1351
|
+
normalizedInput,
|
|
1352
|
+
{ ...permissionContextForCall, toolUseId: toolUseID },
|
|
1353
|
+
assistantMessage
|
|
1354
|
+
);
|
|
1355
|
+
if (permissionResult.result === false) {
|
|
1356
|
+
yield createUserMessage([
|
|
1357
|
+
{
|
|
1358
|
+
type: "tool_result",
|
|
1359
|
+
content: permissionResult.message,
|
|
1360
|
+
is_error: true,
|
|
1361
|
+
tool_use_id: toolUseID
|
|
1362
|
+
}
|
|
1363
|
+
]);
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
try {
|
|
1367
|
+
const generator = tool.call(normalizedInput, {
|
|
1368
|
+
...context,
|
|
1369
|
+
toolUseId: toolUseID
|
|
1370
|
+
});
|
|
1371
|
+
for await (const result of generator) {
|
|
1372
|
+
switch (result.type) {
|
|
1373
|
+
case "result": {
|
|
1374
|
+
const rawContent = result.resultForAssistant ?? tool.renderResultForAssistant(result.data);
|
|
1375
|
+
const content = toToolResultContent(rawContent);
|
|
1376
|
+
const newMessages = Array.isArray(result.newMessages) ? result.newMessages.filter(isPipelineMessage) : [];
|
|
1377
|
+
const postOutcome = await runPostToolUseHooks({
|
|
1378
|
+
toolName: tool.name,
|
|
1379
|
+
toolInput: normalizedInput,
|
|
1380
|
+
toolResult: result.data,
|
|
1381
|
+
toolUseId: toolUseID,
|
|
1382
|
+
permissionMode: context.options?.toolPermissionContext?.mode,
|
|
1383
|
+
cwd: getCwd(),
|
|
1384
|
+
transcriptPath: getHookTranscriptPath(context),
|
|
1385
|
+
safeMode: context.options?.safeMode ?? false,
|
|
1386
|
+
signal: context.abortController.signal
|
|
1387
|
+
});
|
|
1388
|
+
if (postOutcome.systemMessages.length > 0) {
|
|
1389
|
+
queueHookSystemMessages(context, postOutcome.systemMessages);
|
|
1390
|
+
}
|
|
1391
|
+
if (postOutcome.additionalContexts.length > 0) {
|
|
1392
|
+
queueHookAdditionalContexts(context, postOutcome.additionalContexts);
|
|
1393
|
+
}
|
|
1394
|
+
if (postOutcome.warnings.length > 0) {
|
|
1395
|
+
const warningText = postOutcome.warnings.join("\n");
|
|
1396
|
+
yield createProgressMessage(
|
|
1397
|
+
toolUseID,
|
|
1398
|
+
siblingToolUseIDs,
|
|
1399
|
+
createAssistantMessage(warningText),
|
|
1400
|
+
[],
|
|
1401
|
+
context.options?.tools ?? []
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
yield createUserMessage(
|
|
1405
|
+
[
|
|
1406
|
+
{
|
|
1407
|
+
type: "tool_result",
|
|
1408
|
+
content,
|
|
1409
|
+
tool_use_id: toolUseID
|
|
1410
|
+
}
|
|
1411
|
+
],
|
|
1412
|
+
{
|
|
1413
|
+
data: result.data,
|
|
1414
|
+
resultForAssistant: content,
|
|
1415
|
+
...newMessages.length > 0 ? { newMessages } : {},
|
|
1416
|
+
...result.contextModifier ? { contextModifier: result.contextModifier } : {}
|
|
1417
|
+
}
|
|
1418
|
+
);
|
|
1419
|
+
for (const message of newMessages) {
|
|
1420
|
+
yield message;
|
|
1421
|
+
}
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
case "progress":
|
|
1425
|
+
yield createProgressMessage(
|
|
1426
|
+
toolUseID,
|
|
1427
|
+
siblingToolUseIDs,
|
|
1428
|
+
result.content,
|
|
1429
|
+
result.normalizedMessages || [],
|
|
1430
|
+
result.tools || []
|
|
1431
|
+
);
|
|
1432
|
+
break;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
const content = formatError(error);
|
|
1437
|
+
logError(error);
|
|
1438
|
+
yield createUserMessage([
|
|
1439
|
+
{
|
|
1440
|
+
type: "tool_result",
|
|
1441
|
+
content,
|
|
1442
|
+
is_error: true,
|
|
1443
|
+
tool_use_id: toolUseID
|
|
1444
|
+
}
|
|
1445
|
+
]);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
function formatError(error) {
|
|
1449
|
+
if (!(error instanceof Error)) return String(error);
|
|
1450
|
+
const parts = [error.message];
|
|
1451
|
+
if ("stderr" in error && typeof error.stderr === "string") {
|
|
1452
|
+
parts.push(error.stderr);
|
|
1453
|
+
}
|
|
1454
|
+
if ("stdout" in error && typeof error.stdout === "string") {
|
|
1455
|
+
parts.push(error.stdout);
|
|
1456
|
+
}
|
|
1457
|
+
const fullMessage = parts.filter(Boolean).join("\n");
|
|
1458
|
+
if (fullMessage.length <= 1e4) return fullMessage;
|
|
1459
|
+
const halfLength = 5e3;
|
|
1460
|
+
const start = fullMessage.slice(0, halfLength);
|
|
1461
|
+
const end = fullMessage.slice(-halfLength);
|
|
1462
|
+
return `${start}
|
|
1463
|
+
|
|
1464
|
+
... [${fullMessage.length - 1e4} characters truncated] ...
|
|
1465
|
+
|
|
1466
|
+
${end}`;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
// packages/core/src/engine/pipeline/tool-use.ts
|
|
1470
|
+
async function* runToolUse(toolUse, siblingToolUseIDs, assistantMessage, canUseTool, toolUseContext, shouldSkipPermissionCheck) {
|
|
1471
|
+
const currentRequest = getCurrentRequest();
|
|
1472
|
+
const aliasResolution = resolveToolNameAlias(toolUse.name);
|
|
1473
|
+
setRequestStatus({ kind: "tool", detail: aliasResolution.resolvedName });
|
|
1474
|
+
debug.flow("TOOL_USE_START", {
|
|
1475
|
+
toolName: toolUse.name,
|
|
1476
|
+
toolUseID: toolUse.id,
|
|
1477
|
+
inputSize: JSON.stringify(toolUse.input).length,
|
|
1478
|
+
siblingToolCount: siblingToolUseIDs.size,
|
|
1479
|
+
shouldSkipPermissionCheck: Boolean(shouldSkipPermissionCheck),
|
|
1480
|
+
requestId: currentRequest?.id
|
|
1481
|
+
});
|
|
1482
|
+
logUserFriendly(
|
|
1483
|
+
"TOOL_EXECUTION",
|
|
1484
|
+
{
|
|
1485
|
+
toolName: toolUse.name,
|
|
1486
|
+
action: "Starting",
|
|
1487
|
+
target: toolUse.input ? Object.keys(toolUse.input).join(", ") : ""
|
|
1488
|
+
},
|
|
1489
|
+
currentRequest?.id
|
|
1490
|
+
);
|
|
1491
|
+
const toolName = aliasResolution.resolvedName;
|
|
1492
|
+
const tool = toolUseContext.options.tools.find((t) => t.name === toolName);
|
|
1493
|
+
if (!tool) {
|
|
1494
|
+
debug.error("TOOL_NOT_FOUND", {
|
|
1495
|
+
requestedTool: toolName,
|
|
1496
|
+
availableTools: toolUseContext.options.tools.map((t) => t.name),
|
|
1497
|
+
toolUseID: toolUse.id,
|
|
1498
|
+
requestId: currentRequest?.id
|
|
1499
|
+
});
|
|
1500
|
+
yield createUserMessage([
|
|
1501
|
+
{
|
|
1502
|
+
type: "tool_result",
|
|
1503
|
+
content: `Error: No such tool available: ${toolName}`,
|
|
1504
|
+
is_error: true,
|
|
1505
|
+
tool_use_id: toolUse.id
|
|
1506
|
+
}
|
|
1507
|
+
]);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
const toolInput = toolUse.input;
|
|
1511
|
+
debug.flow("TOOL_VALIDATION_START", {
|
|
1512
|
+
toolName: tool.name,
|
|
1513
|
+
toolUseID: toolUse.id,
|
|
1514
|
+
inputKeys: Object.keys(toolInput),
|
|
1515
|
+
requestId: currentRequest?.id
|
|
1516
|
+
});
|
|
1517
|
+
try {
|
|
1518
|
+
for await (const message of checkPermissionsAndCallTool(
|
|
1519
|
+
tool,
|
|
1520
|
+
toolUse.id,
|
|
1521
|
+
siblingToolUseIDs,
|
|
1522
|
+
toolInput,
|
|
1523
|
+
toolUseContext,
|
|
1524
|
+
canUseTool,
|
|
1525
|
+
assistantMessage,
|
|
1526
|
+
shouldSkipPermissionCheck
|
|
1527
|
+
)) {
|
|
1528
|
+
yield message;
|
|
1529
|
+
}
|
|
1530
|
+
} catch (e) {
|
|
1531
|
+
logError(e);
|
|
1532
|
+
yield createUserMessage([
|
|
1533
|
+
{
|
|
1534
|
+
type: "tool_result",
|
|
1535
|
+
content: `Tool execution failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
1536
|
+
is_error: true,
|
|
1537
|
+
tool_use_id: toolUse.id
|
|
1538
|
+
}
|
|
1539
|
+
]);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// packages/core/src/engine/pipeline/tool-use-queue.ts
|
|
1544
|
+
function createSyntheticToolUseErrorMessage(toolUseId, reason) {
|
|
1545
|
+
if (reason === "user_interrupted") {
|
|
1546
|
+
return createUserMessage([
|
|
1547
|
+
{
|
|
1548
|
+
type: "tool_result",
|
|
1549
|
+
content: REJECT_MESSAGE,
|
|
1550
|
+
is_error: true,
|
|
1551
|
+
tool_use_id: toolUseId
|
|
1552
|
+
}
|
|
1553
|
+
]);
|
|
1554
|
+
}
|
|
1555
|
+
return createUserMessage([
|
|
1556
|
+
{
|
|
1557
|
+
type: "tool_result",
|
|
1558
|
+
content: "<tool_use_error>Sibling tool call errored</tool_use_error>",
|
|
1559
|
+
is_error: true,
|
|
1560
|
+
tool_use_id: toolUseId
|
|
1561
|
+
}
|
|
1562
|
+
]);
|
|
1563
|
+
}
|
|
1564
|
+
var ToolUseQueue = class {
|
|
1565
|
+
toolDefinitions;
|
|
1566
|
+
canUseTool;
|
|
1567
|
+
tools = [];
|
|
1568
|
+
toolUseContext;
|
|
1569
|
+
hasErrored = false;
|
|
1570
|
+
progressAvailableResolve;
|
|
1571
|
+
siblingToolUseIDs;
|
|
1572
|
+
shouldSkipPermissionCheck;
|
|
1573
|
+
constructor(options) {
|
|
1574
|
+
this.toolDefinitions = options.toolDefinitions;
|
|
1575
|
+
this.canUseTool = options.canUseTool;
|
|
1576
|
+
this.toolUseContext = options.toolUseContext;
|
|
1577
|
+
this.siblingToolUseIDs = options.siblingToolUseIDs;
|
|
1578
|
+
this.shouldSkipPermissionCheck = options.shouldSkipPermissionCheck;
|
|
1579
|
+
}
|
|
1580
|
+
addTool(toolUse, assistantMessage) {
|
|
1581
|
+
const resolvedToolName = resolveToolNameAlias(toolUse.name).resolvedName;
|
|
1582
|
+
const toolDefinition = this.toolDefinitions.find(
|
|
1583
|
+
(t) => t.name === resolvedToolName
|
|
1584
|
+
);
|
|
1585
|
+
const parsedInput = toolDefinition?.inputSchema.safeParse(toolUse.input);
|
|
1586
|
+
const isConcurrencySafe = toolDefinition && parsedInput?.success ? toolDefinition.isConcurrencySafe(parsedInput.data) : false;
|
|
1587
|
+
this.tools.push({
|
|
1588
|
+
id: toolUse.id,
|
|
1589
|
+
block: toolUse,
|
|
1590
|
+
assistantMessage,
|
|
1591
|
+
status: "queued",
|
|
1592
|
+
isConcurrencySafe,
|
|
1593
|
+
pendingProgress: [],
|
|
1594
|
+
queuedProgressEmitted: false
|
|
1595
|
+
});
|
|
1596
|
+
void this.processQueue();
|
|
1597
|
+
}
|
|
1598
|
+
canExecuteTool(isConcurrencySafe) {
|
|
1599
|
+
const executing = this.tools.filter((t) => t.status === "executing");
|
|
1600
|
+
return executing.length === 0 || isConcurrencySafe && executing.every((t) => t.isConcurrencySafe);
|
|
1601
|
+
}
|
|
1602
|
+
async processQueue() {
|
|
1603
|
+
for (const entry of this.tools) {
|
|
1604
|
+
if (entry.status !== "queued") continue;
|
|
1605
|
+
if (this.canExecuteTool(entry.isConcurrencySafe)) {
|
|
1606
|
+
await this.executeTool(entry);
|
|
1607
|
+
} else {
|
|
1608
|
+
if (!entry.queuedProgressEmitted) {
|
|
1609
|
+
entry.queuedProgressEmitted = true;
|
|
1610
|
+
entry.pendingProgress.push(
|
|
1611
|
+
createProgressMessage(
|
|
1612
|
+
entry.id,
|
|
1613
|
+
this.siblingToolUseIDs,
|
|
1614
|
+
createAssistantMessage("<tool-progress>Waiting\u2026</tool-progress>"),
|
|
1615
|
+
[],
|
|
1616
|
+
this.toolUseContext.options.tools
|
|
1617
|
+
)
|
|
1618
|
+
);
|
|
1619
|
+
if (this.progressAvailableResolve) {
|
|
1620
|
+
this.progressAvailableResolve();
|
|
1621
|
+
this.progressAvailableResolve = void 0;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
if (!entry.isConcurrencySafe) {
|
|
1625
|
+
break;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
getAbortReason() {
|
|
1631
|
+
if (this.hasErrored) return "sibling_error";
|
|
1632
|
+
if (this.toolUseContext.abortController.signal.aborted)
|
|
1633
|
+
return "user_interrupted";
|
|
1634
|
+
return null;
|
|
1635
|
+
}
|
|
1636
|
+
async executeTool(entry) {
|
|
1637
|
+
entry.status = "executing";
|
|
1638
|
+
const results = [];
|
|
1639
|
+
const contextModifiers = [];
|
|
1640
|
+
const promise = (async () => {
|
|
1641
|
+
const abortReason = this.getAbortReason();
|
|
1642
|
+
if (abortReason) {
|
|
1643
|
+
results.push(createSyntheticToolUseErrorMessage(entry.id, abortReason));
|
|
1644
|
+
entry.results = results;
|
|
1645
|
+
entry.contextModifiers = contextModifiers;
|
|
1646
|
+
entry.status = "completed";
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
const generator = runToolUse(
|
|
1650
|
+
entry.block,
|
|
1651
|
+
this.siblingToolUseIDs,
|
|
1652
|
+
entry.assistantMessage,
|
|
1653
|
+
this.canUseTool,
|
|
1654
|
+
this.toolUseContext,
|
|
1655
|
+
this.shouldSkipPermissionCheck
|
|
1656
|
+
);
|
|
1657
|
+
let toolErrored = false;
|
|
1658
|
+
for await (const message of generator) {
|
|
1659
|
+
const reason = this.getAbortReason();
|
|
1660
|
+
if (reason && !toolErrored) {
|
|
1661
|
+
results.push(createSyntheticToolUseErrorMessage(entry.id, reason));
|
|
1662
|
+
break;
|
|
1663
|
+
}
|
|
1664
|
+
if (message.type === "user" && Array.isArray(message.message.content) && message.message.content.some(
|
|
1665
|
+
(block) => block.type === "tool_result" && block.is_error === true
|
|
1666
|
+
)) {
|
|
1667
|
+
this.hasErrored = true;
|
|
1668
|
+
toolErrored = true;
|
|
1669
|
+
}
|
|
1670
|
+
if (message.type === "progress") {
|
|
1671
|
+
entry.pendingProgress.push(message);
|
|
1672
|
+
if (this.progressAvailableResolve) {
|
|
1673
|
+
this.progressAvailableResolve();
|
|
1674
|
+
this.progressAvailableResolve = void 0;
|
|
1675
|
+
}
|
|
1676
|
+
} else {
|
|
1677
|
+
results.push(message);
|
|
1678
|
+
if (message.type === "user" && message.toolUseResult?.contextModifier) {
|
|
1679
|
+
contextModifiers.push(
|
|
1680
|
+
message.toolUseResult.contextModifier.modifyContext
|
|
1681
|
+
);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
entry.results = results;
|
|
1686
|
+
entry.contextModifiers = contextModifiers;
|
|
1687
|
+
entry.status = "completed";
|
|
1688
|
+
if (!entry.isConcurrencySafe && contextModifiers.length > 0) {
|
|
1689
|
+
for (const modifyContext of contextModifiers) {
|
|
1690
|
+
this.toolUseContext = modifyContext(this.toolUseContext);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
})();
|
|
1694
|
+
entry.promise = promise;
|
|
1695
|
+
promise.finally(() => {
|
|
1696
|
+
void this.processQueue();
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
*getCompletedResults() {
|
|
1700
|
+
let barrierExecuting = false;
|
|
1701
|
+
for (const entry of this.tools) {
|
|
1702
|
+
while (entry.pendingProgress.length > 0) {
|
|
1703
|
+
yield entry.pendingProgress.shift();
|
|
1704
|
+
}
|
|
1705
|
+
if (entry.status === "yielded") continue;
|
|
1706
|
+
if (barrierExecuting) continue;
|
|
1707
|
+
if (entry.status === "completed" && entry.results) {
|
|
1708
|
+
entry.status = "yielded";
|
|
1709
|
+
for (const message of entry.results) {
|
|
1710
|
+
yield message;
|
|
1711
|
+
}
|
|
1712
|
+
} else if (entry.status === "executing" && !entry.isConcurrencySafe) {
|
|
1713
|
+
barrierExecuting = true;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
hasPendingProgress() {
|
|
1718
|
+
return this.tools.some((t) => t.pendingProgress.length > 0);
|
|
1719
|
+
}
|
|
1720
|
+
hasCompletedResults() {
|
|
1721
|
+
return this.tools.some((t) => t.status === "completed");
|
|
1722
|
+
}
|
|
1723
|
+
hasExecutingTools() {
|
|
1724
|
+
return this.tools.some((t) => t.status === "executing");
|
|
1725
|
+
}
|
|
1726
|
+
hasUnfinishedTools() {
|
|
1727
|
+
return this.tools.some((t) => t.status !== "yielded");
|
|
1728
|
+
}
|
|
1729
|
+
async *getRemainingResults() {
|
|
1730
|
+
while (this.hasUnfinishedTools()) {
|
|
1731
|
+
await this.processQueue();
|
|
1732
|
+
for (const message of this.getCompletedResults()) {
|
|
1733
|
+
yield message;
|
|
1734
|
+
}
|
|
1735
|
+
if (this.hasExecutingTools() && !this.hasCompletedResults() && !this.hasPendingProgress()) {
|
|
1736
|
+
const promises = this.tools.filter((t) => t.status === "executing" && t.promise).map((t) => t.promise);
|
|
1737
|
+
const progressPromise = new Promise((resolve3) => {
|
|
1738
|
+
this.progressAvailableResolve = resolve3;
|
|
1739
|
+
});
|
|
1740
|
+
if (promises.length > 0) {
|
|
1741
|
+
await Promise.race([...promises, progressPromise]);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
for (const message of this.getCompletedResults()) {
|
|
1746
|
+
yield message;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
getUpdatedContext() {
|
|
1750
|
+
return this.toolUseContext;
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
// packages/core/src/engine/pipeline/types.ts
|
|
1755
|
+
function isToolUseLikeBlock(block) {
|
|
1756
|
+
return block && typeof block === "object" && (block.type === "tool_use" || block.type === "server_tool_use" || block.type === "mcp_tool_use");
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
// packages/core/src/query/agentEvents.ts
|
|
1760
|
+
function messageToAgentEvent(message, sessionId) {
|
|
1761
|
+
return kodeMessageToSdkMessage(
|
|
1762
|
+
message,
|
|
1763
|
+
sessionId
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
async function* messagesToAgentEvents(args) {
|
|
1767
|
+
for await (const message of args.source) {
|
|
1768
|
+
const event = messageToAgentEvent(message, args.sessionId);
|
|
1769
|
+
if (event) yield event;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// packages/core/src/engine/message-pipeline.ts
|
|
1774
|
+
async function* messagePipeline(messages, systemPrompt, context, canUseTool, toolUseContext, getBinaryFeedbackResponse) {
|
|
1775
|
+
yield* messagePipelineCore(
|
|
1776
|
+
messages,
|
|
1777
|
+
systemPrompt,
|
|
1778
|
+
context,
|
|
1779
|
+
canUseTool,
|
|
1780
|
+
toolUseContext,
|
|
1781
|
+
getBinaryFeedbackResponse
|
|
1782
|
+
);
|
|
1783
|
+
}
|
|
1784
|
+
async function* messagePipelineCore(messages, systemPrompt, context, canUseTool, toolUseContext, getBinaryFeedbackResponse, hookState) {
|
|
1785
|
+
setRequestStatus({ kind: "thinking" });
|
|
1786
|
+
try {
|
|
1787
|
+
let getAssistantResponse = function() {
|
|
1788
|
+
return queryLLM(
|
|
1789
|
+
normalizeMessagesForAPI(messages),
|
|
1790
|
+
fullSystemPrompt,
|
|
1791
|
+
toolUseContext.options.maxThinkingTokens,
|
|
1792
|
+
toolUseContext.options.tools,
|
|
1793
|
+
toolUseContext.abortController.signal,
|
|
1794
|
+
{
|
|
1795
|
+
safeMode: toolUseContext.options.safeMode ?? false,
|
|
1796
|
+
model: toolUseContext.options.model || "main",
|
|
1797
|
+
prependCLISysprompt: true,
|
|
1798
|
+
toolUseContext
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1801
|
+
};
|
|
1802
|
+
markPhase("QUERY_INIT");
|
|
1803
|
+
const stopHookActive = hookState?.stopHookActive === true;
|
|
1804
|
+
const stopHookAttempts = hookState?.stopHookAttempts ?? 0;
|
|
1805
|
+
const { messages: processedMessages, wasCompacted } = await checkAutoCompact(messages, toolUseContext);
|
|
1806
|
+
if (wasCompacted) {
|
|
1807
|
+
messages = processedMessages;
|
|
1808
|
+
}
|
|
1809
|
+
if (toolUseContext.agentId === "main") {
|
|
1810
|
+
const shell = BunShell.getInstance();
|
|
1811
|
+
const notifications = shell.flushBashNotifications();
|
|
1812
|
+
for (const notification of notifications) {
|
|
1813
|
+
const text = renderBashNotification(notification);
|
|
1814
|
+
if (text.trim().length === 0) continue;
|
|
1815
|
+
const msg = createAssistantMessage(text);
|
|
1816
|
+
messages = [...messages, msg];
|
|
1817
|
+
yield msg;
|
|
1818
|
+
}
|
|
1819
|
+
const attachments = shell.flushBackgroundShellStatusAttachments();
|
|
1820
|
+
for (const attachment of attachments) {
|
|
1821
|
+
const text = renderBackgroundShellStatusAttachment(attachment);
|
|
1822
|
+
if (text.trim().length === 0) continue;
|
|
1823
|
+
const msg = createAssistantMessage(
|
|
1824
|
+
`<tool-progress>${text}</tool-progress>`
|
|
1825
|
+
);
|
|
1826
|
+
messages = [...messages, msg];
|
|
1827
|
+
yield msg;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
updateHookTranscriptForMessages(toolUseContext, messages);
|
|
1831
|
+
{
|
|
1832
|
+
const last = messages[messages.length - 1];
|
|
1833
|
+
let userPromptText = null;
|
|
1834
|
+
if (last?.type === "user") {
|
|
1835
|
+
const content = last.message.content;
|
|
1836
|
+
if (typeof content === "string") {
|
|
1837
|
+
userPromptText = content;
|
|
1838
|
+
} else if (Array.isArray(content)) {
|
|
1839
|
+
const hasToolResult = content.some(
|
|
1840
|
+
(b) => b && typeof b === "object" && b.type === "tool_result"
|
|
1841
|
+
);
|
|
1842
|
+
if (!hasToolResult) {
|
|
1843
|
+
userPromptText = content.filter(
|
|
1844
|
+
(b) => b && typeof b === "object" && b.type === "text"
|
|
1845
|
+
).map((b) => String(b.text ?? "")).join("");
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
if (userPromptText !== null) {
|
|
1850
|
+
toolUseContext.options.lastUserPrompt = userPromptText;
|
|
1851
|
+
const promptOutcome = await runUserPromptSubmitHooks({
|
|
1852
|
+
prompt: userPromptText,
|
|
1853
|
+
permissionMode: toolUseContext.options?.toolPermissionContext?.mode,
|
|
1854
|
+
cwd: getCwd(),
|
|
1855
|
+
transcriptPath: getHookTranscriptPath(toolUseContext),
|
|
1856
|
+
safeMode: toolUseContext.options?.safeMode ?? false,
|
|
1857
|
+
signal: toolUseContext.abortController.signal
|
|
1858
|
+
});
|
|
1859
|
+
queueHookSystemMessages(toolUseContext, promptOutcome.systemMessages);
|
|
1860
|
+
queueHookAdditionalContexts(
|
|
1861
|
+
toolUseContext,
|
|
1862
|
+
promptOutcome.additionalContexts
|
|
1863
|
+
);
|
|
1864
|
+
if (promptOutcome.decision === "block") {
|
|
1865
|
+
yield createAssistantMessage(promptOutcome.message);
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
markPhase("SYSTEM_PROMPT_BUILD");
|
|
1871
|
+
hydratePlanSlugFromMessages(messages, toolUseContext);
|
|
1872
|
+
const { systemPrompt: fullSystemPrompt, reminders } = formatSystemPromptWithContext(
|
|
1873
|
+
systemPrompt,
|
|
1874
|
+
context,
|
|
1875
|
+
toolUseContext.agentId
|
|
1876
|
+
);
|
|
1877
|
+
const planModeAdditions = getPlanModeSystemPromptAdditions(
|
|
1878
|
+
messages,
|
|
1879
|
+
toolUseContext
|
|
1880
|
+
);
|
|
1881
|
+
if (planModeAdditions.length > 0) {
|
|
1882
|
+
fullSystemPrompt.push(...planModeAdditions);
|
|
1883
|
+
}
|
|
1884
|
+
const hookAdditions = drainHookSystemPromptAdditions(toolUseContext);
|
|
1885
|
+
if (hookAdditions.length > 0) {
|
|
1886
|
+
fullSystemPrompt.push(...hookAdditions);
|
|
1887
|
+
}
|
|
1888
|
+
if (toolUseContext.agentId === "main") {
|
|
1889
|
+
const customAdditions = toolUseContext.options.getCustomSystemPromptAdditions?.() ?? [];
|
|
1890
|
+
if (customAdditions.length > 0) {
|
|
1891
|
+
fullSystemPrompt.push(...customAdditions);
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
emitReminderEvent("session:startup", {
|
|
1895
|
+
agentId: toolUseContext.agentId,
|
|
1896
|
+
messages: messages.length,
|
|
1897
|
+
timestamp: Date.now()
|
|
1898
|
+
});
|
|
1899
|
+
if (reminders && messages.length > 0) {
|
|
1900
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1901
|
+
const msg = messages[i];
|
|
1902
|
+
if (msg?.type === "user") {
|
|
1903
|
+
const lastUserMessage = msg;
|
|
1904
|
+
messages[i] = {
|
|
1905
|
+
...lastUserMessage,
|
|
1906
|
+
message: {
|
|
1907
|
+
...lastUserMessage.message,
|
|
1908
|
+
content: typeof lastUserMessage.message.content === "string" ? reminders + lastUserMessage.message.content : [
|
|
1909
|
+
...Array.isArray(lastUserMessage.message.content) ? lastUserMessage.message.content : [],
|
|
1910
|
+
{ type: "text", text: reminders }
|
|
1911
|
+
]
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
break;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
markPhase("LLM_PREPARATION");
|
|
1919
|
+
const result = await queryWithBinaryFeedback(
|
|
1920
|
+
toolUseContext,
|
|
1921
|
+
getAssistantResponse,
|
|
1922
|
+
getBinaryFeedbackResponse
|
|
1923
|
+
);
|
|
1924
|
+
if (toolUseContext.abortController.signal.aborted) {
|
|
1925
|
+
yield createAssistantMessage(INTERRUPT_MESSAGE);
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1928
|
+
if (result.message === null) {
|
|
1929
|
+
yield createAssistantMessage(INTERRUPT_MESSAGE);
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
const assistantMessage = result.message;
|
|
1933
|
+
const shouldSkipPermissionCheck = result.shouldSkipPermissionCheck;
|
|
1934
|
+
const toolUseMessages = assistantMessage.message.content.filter(isToolUseLikeBlock);
|
|
1935
|
+
if (!toolUseMessages.length) {
|
|
1936
|
+
const stopHookEvent = toolUseContext.agentId && toolUseContext.agentId !== "main" ? "SubagentStop" : "Stop";
|
|
1937
|
+
const record = asRecord(assistantMessage.message);
|
|
1938
|
+
const stopReason = (record && typeof record.stop_reason === "string" ? record.stop_reason : "") || (record && typeof record.stopReason === "string" ? record.stopReason : "") || "end_turn";
|
|
1939
|
+
const stopOutcome = await runStopHooks({
|
|
1940
|
+
hookEvent: stopHookEvent,
|
|
1941
|
+
reason: String(stopReason ?? ""),
|
|
1942
|
+
agentId: toolUseContext.agentId,
|
|
1943
|
+
permissionMode: toolUseContext.options?.toolPermissionContext?.mode,
|
|
1944
|
+
cwd: getCwd(),
|
|
1945
|
+
transcriptPath: getHookTranscriptPath(toolUseContext),
|
|
1946
|
+
safeMode: toolUseContext.options?.safeMode ?? false,
|
|
1947
|
+
stopHookActive,
|
|
1948
|
+
signal: toolUseContext.abortController.signal
|
|
1949
|
+
});
|
|
1950
|
+
if (stopOutcome.systemMessages.length > 0) {
|
|
1951
|
+
queueHookSystemMessages(toolUseContext, stopOutcome.systemMessages);
|
|
1952
|
+
}
|
|
1953
|
+
if (stopOutcome.additionalContexts.length > 0) {
|
|
1954
|
+
queueHookAdditionalContexts(
|
|
1955
|
+
toolUseContext,
|
|
1956
|
+
stopOutcome.additionalContexts
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
if (stopOutcome.decision === "block") {
|
|
1960
|
+
queueHookSystemMessages(toolUseContext, [stopOutcome.message]);
|
|
1961
|
+
const MAX_STOP_HOOK_ATTEMPTS = 5;
|
|
1962
|
+
if (stopHookAttempts < MAX_STOP_HOOK_ATTEMPTS) {
|
|
1963
|
+
yield* await messagePipelineCore(
|
|
1964
|
+
[...messages, assistantMessage],
|
|
1965
|
+
systemPrompt,
|
|
1966
|
+
context,
|
|
1967
|
+
canUseTool,
|
|
1968
|
+
toolUseContext,
|
|
1969
|
+
getBinaryFeedbackResponse,
|
|
1970
|
+
{
|
|
1971
|
+
stopHookActive: true,
|
|
1972
|
+
stopHookAttempts: stopHookAttempts + 1
|
|
1973
|
+
}
|
|
1974
|
+
);
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
yield assistantMessage;
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
yield assistantMessage;
|
|
1982
|
+
const siblingToolUseIDs = new Set(toolUseMessages.map((_) => _.id));
|
|
1983
|
+
const toolQueue = new ToolUseQueue({
|
|
1984
|
+
toolDefinitions: toolUseContext.options.tools,
|
|
1985
|
+
canUseTool,
|
|
1986
|
+
toolUseContext,
|
|
1987
|
+
siblingToolUseIDs,
|
|
1988
|
+
shouldSkipPermissionCheck
|
|
1989
|
+
});
|
|
1990
|
+
for (const toolUse of toolUseMessages) {
|
|
1991
|
+
toolQueue.addTool(toolUse, assistantMessage);
|
|
1992
|
+
}
|
|
1993
|
+
const toolMessagesForNextTurn = [];
|
|
1994
|
+
for await (const message of toolQueue.getRemainingResults()) {
|
|
1995
|
+
yield message;
|
|
1996
|
+
if (message.type !== "progress") {
|
|
1997
|
+
toolMessagesForNextTurn.push(message);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
toolUseContext = toolQueue.getUpdatedContext();
|
|
2001
|
+
if (toolUseContext.abortController.signal.aborted) {
|
|
2002
|
+
yield createAssistantMessage(INTERRUPT_MESSAGE_FOR_TOOL_USE);
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
try {
|
|
2006
|
+
yield* await messagePipelineCore(
|
|
2007
|
+
[...messages, assistantMessage, ...toolMessagesForNextTurn],
|
|
2008
|
+
systemPrompt,
|
|
2009
|
+
context,
|
|
2010
|
+
canUseTool,
|
|
2011
|
+
toolUseContext,
|
|
2012
|
+
getBinaryFeedbackResponse,
|
|
2013
|
+
hookState
|
|
2014
|
+
);
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
throw error;
|
|
2017
|
+
}
|
|
2018
|
+
} finally {
|
|
2019
|
+
setRequestStatus({ kind: "idle" });
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
// packages/core/src/engine/orchestrator.ts
|
|
2024
|
+
async function* query(messages, systemPrompt, context, canUseTool, toolUseContext, getBinaryFeedbackResponse) {
|
|
2025
|
+
const shouldPersistSession = toolUseContext.options?.persistSession !== false && process.env.NODE_ENV !== "test";
|
|
2026
|
+
const cwd2 = shouldPersistSession ? getCwd() : null;
|
|
2027
|
+
for await (const message of messagePipeline(
|
|
2028
|
+
messages,
|
|
2029
|
+
systemPrompt,
|
|
2030
|
+
context,
|
|
2031
|
+
canUseTool,
|
|
2032
|
+
toolUseContext,
|
|
2033
|
+
getBinaryFeedbackResponse
|
|
2034
|
+
)) {
|
|
2035
|
+
if (shouldPersistSession) {
|
|
2036
|
+
appendSessionJsonlFromMessage({
|
|
2037
|
+
cwd: cwd2 ?? getCwd(),
|
|
2038
|
+
message,
|
|
2039
|
+
toolUseContext
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
yield message;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
export {
|
|
2047
|
+
ripGrep,
|
|
2048
|
+
isInDirectory,
|
|
2049
|
+
readTextContent,
|
|
2050
|
+
writeTextContent,
|
|
2051
|
+
detectRepoLineEndings,
|
|
2052
|
+
detectFileEncoding,
|
|
2053
|
+
detectLineEndings,
|
|
2054
|
+
normalizeFilePath,
|
|
2055
|
+
getAbsolutePath,
|
|
2056
|
+
getAbsoluteAndRelativePaths,
|
|
2057
|
+
findSimilarFile,
|
|
2058
|
+
addLineNumbers,
|
|
2059
|
+
isDirEmpty,
|
|
2060
|
+
recordFileRead,
|
|
2061
|
+
recordFileEdit,
|
|
2062
|
+
generateFileModificationReminder,
|
|
2063
|
+
resetFileFreshnessSession,
|
|
2064
|
+
startWatchingTodoFile,
|
|
2065
|
+
countTokens,
|
|
2066
|
+
setMessagesGetter,
|
|
2067
|
+
getMessagesGetter,
|
|
2068
|
+
setMessagesSetter,
|
|
2069
|
+
getMessagesSetter,
|
|
2070
|
+
setModelConfigChangeHandler,
|
|
2071
|
+
triggerModelConfigChange,
|
|
2072
|
+
getBinaryFeedbackResultForChoice,
|
|
2073
|
+
logBinaryFeedbackEvent,
|
|
2074
|
+
resolveToolNameAlias,
|
|
2075
|
+
messagesToAgentEvents,
|
|
2076
|
+
query
|
|
2077
|
+
};
|