@shareai-lab/kode 2.0.1 → 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-7LH4HTNR.js → chunks/agentsValidate-PEWMYN4Q.js} +97 -69
- package/dist/chunks/agentsValidate-PEWMYN4Q.js.map +7 -0
- package/dist/{ask-3NHFFUQG.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-AFFSCMYS.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-ARZSBOAO.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-UHYRLID6.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-YC6LJCDE.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-3IN27HA5.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-73WGVYLQ.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-QVLYOPO5.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-K2CWOTI2.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-RZWOUA25.js → chunks/chunk-HRJ3ICQK.js} +59 -55
- package/dist/chunks/chunk-HRJ3ICQK.js.map +7 -0
- package/dist/{chunk-DZE5YA7L.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-7M2YN6TU.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-W7GRKO7Q.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-7U7L4NMD.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-ZVDRDPII.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-MWRSY4X6.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-STSX7GIX.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-RUSD6G5Y.js → chunks/config-25HRTPSP.js} +48 -10
- package/dist/chunks/cost-tracker-Z2UZT2J5.js +28 -0
- package/dist/{customCommands-TOIJFZAL.js → chunks/customCommands-TYMYZRG5.js} +11 -8
- package/dist/chunks/engine-MRVF6FK6.js +39 -0
- package/dist/{env-XGKBLU3D.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-UGEZJJEB.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-QWM36A3D.js → chunks/kodeHooks-RVKYRJHG.js} +11 -9
- package/dist/{llm-ZUQC4WYM.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-EE3XFHCJ.js → chunks/mentionProcessor-RJW5UPJD.js} +46 -16
- package/dist/chunks/mentionProcessor-RJW5UPJD.js.map +7 -0
- package/dist/{messages-EOYQKPGM.js → chunks/messages-EEWWLPHN.js} +2 -6
- package/dist/chunks/model-5TIEKQPD.js +37 -0
- package/dist/{openai-RRCWW33N.js → chunks/openai-XXK3YZG4.js} +13 -10
- package/dist/{outputStyles-62Q3VH2J.js → chunks/outputStyles-FAJTXN2A.js} +6 -9
- package/dist/chunks/permissions-HO7INPWM.js +27 -0
- package/dist/{pluginRuntime-6ETCZ2LL.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-3RXQBVOL.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-DOPVY2CW.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-CW7AYLVL.js +0 -42
- package/dist/acp-VEPJ74LT.js +0 -1357
- package/dist/acp-VEPJ74LT.js.map +0 -7
- package/dist/agentsValidate-7LH4HTNR.js.map +0 -7
- package/dist/ask-3NHFFUQG.js.map +0 -7
- package/dist/autoUpdater-ITPIHCOI.js +0 -17
- package/dist/chunk-3IN27HA5.js.map +0 -7
- package/dist/chunk-4FX3IVPT.js +0 -164
- package/dist/chunk-4FX3IVPT.js.map +0 -7
- package/dist/chunk-4RTX4AG4.js.map +0 -7
- package/dist/chunk-5PDP7R6N.js +0 -515
- package/dist/chunk-5PDP7R6N.js.map +0 -7
- package/dist/chunk-73WGVYLQ.js.map +0 -7
- package/dist/chunk-7M2YN6TU.js.map +0 -7
- package/dist/chunk-7U7L4NMD.js.map +0 -7
- package/dist/chunk-ABLVTESJ.js.map +0 -7
- package/dist/chunk-AFFSCMYS.js.map +0 -7
- package/dist/chunk-ARZSBOAO.js.map +0 -7
- package/dist/chunk-CIG63V4E.js +0 -72
- package/dist/chunk-CIG63V4E.js.map +0 -7
- package/dist/chunk-CM3EGTG6.js +0 -1609
- package/dist/chunk-CM3EGTG6.js.map +0 -7
- package/dist/chunk-DZE5YA7L.js.map +0 -7
- package/dist/chunk-E6YNABER.js.map +0 -7
- package/dist/chunk-EZXMVTDU.js.map +0 -7
- package/dist/chunk-F2SJXUDI.js +0 -148
- package/dist/chunk-F2SJXUDI.js.map +0 -7
- package/dist/chunk-FC5ZCKBI.js +0 -30167
- package/dist/chunk-FC5ZCKBI.js.map +0 -7
- package/dist/chunk-HCBELH4J.js +0 -145
- package/dist/chunk-HCBELH4J.js.map +0 -7
- package/dist/chunk-HN4E4UUQ.js.map +0 -7
- package/dist/chunk-IZVMU4S2.js +0 -654
- package/dist/chunk-IZVMU4S2.js.map +0 -7
- package/dist/chunk-K2CWOTI2.js.map +0 -7
- package/dist/chunk-LC4TVOCZ.js +0 -835
- package/dist/chunk-LC4TVOCZ.js.map +0 -7
- package/dist/chunk-MIW7N2MY.js +0 -2613
- package/dist/chunk-MIW7N2MY.js.map +0 -7
- package/dist/chunk-MWRSY4X6.js.map +0 -7
- package/dist/chunk-ND3XWFO6.js +0 -34
- package/dist/chunk-ND3XWFO6.js.map +0 -7
- package/dist/chunk-QVLYOPO5.js.map +0 -7
- package/dist/chunk-RZWOUA25.js.map +0 -7
- package/dist/chunk-S6HRABTA.js.map +0 -7
- package/dist/chunk-STSX7GIX.js.map +0 -7
- package/dist/chunk-UHYRLID6.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-W7GRKO7Q.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-YC6LJCDE.js.map +0 -7
- package/dist/chunk-YXYYDIMI.js +0 -2931
- package/dist/chunk-YXYYDIMI.js.map +0 -7
- package/dist/chunk-ZVDRDPII.js.map +0 -7
- package/dist/cli-DOPVY2CW.js.map +0 -7
- package/dist/commands-2BF2CJ3A.js +0 -46
- package/dist/context-6FXPETYH.js +0 -30
- package/dist/costTracker-6SL26FDB.js +0 -19
- package/dist/kodeAgentSessionLoad-MITZADPB.js +0 -18
- package/dist/kodeAgentSessionResume-GVRWB4WO.js +0 -16
- package/dist/kodeAgentStreamJson-NXFN7TXH.js +0 -13
- package/dist/kodeAgentStreamJsonSession-UGEZJJEB.js.map +0 -7
- package/dist/kodeAgentStructuredStdio-HGWJT7CU.js +0 -10
- package/dist/llm-ZUQC4WYM.js.map +0 -7
- package/dist/llmLazy-54QQHA54.js +0 -15
- package/dist/loader-FYHJQES5.js +0 -28
- package/dist/mcp-J332IKT3.js +0 -49
- package/dist/mentionProcessor-EE3XFHCJ.js.map +0 -7
- package/dist/model-FV3JDJKH.js +0 -30
- package/dist/pluginRuntime-6ETCZ2LL.js.map +0 -7
- package/dist/pluginValidation-I4YKUWGS.js +0 -17
- package/dist/prompts-ZLEKDD77.js +0 -48
- package/dist/query-VFRJPBGD.js +0 -50
- package/dist/responsesStreaming-AW344PQO.js +0 -10
- package/dist/ripgrep-3NTIKQYW.js +0 -17
- package/dist/state-P5G6CO5V.js +0 -16
- package/dist/theme-3LWP3BG7.js +0 -14
- package/dist/toolPermissionSettings-3ROBVTUK.js +0 -18
- package/dist/tools-RO7HSSE5.js +0 -47
- package/dist/userInput-JSBJRFSK.js +0 -311
- package/dist/userInput-JSBJRFSK.js.map +0 -7
- package/dist/uuid-QN2CNKKN.js +0 -9
- /package/dist/{REPL-CW7AYLVL.js.map → chunks/Doctor-M3J7GRTJ.js.map} +0 -0
- /package/dist/{autoUpdater-ITPIHCOI.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-2BF2CJ3A.js.map → chunks/agentLoader-FCRG3TFJ.js.map} +0 -0
- /package/dist/{config-RUSD6G5Y.js.map → chunks/autoUpdater-CNESBOKO.js.map} +0 -0
- /package/dist/{context-6FXPETYH.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-TOIJFZAL.js.map → chunks/chunk-GCQCAXJZ.js.map} +0 -0
- /package/dist/{env-XGKBLU3D.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-MITZADPB.js.map → chunks/config-25HRTPSP.js.map} +0 -0
- /package/dist/{kodeAgentSessionResume-GVRWB4WO.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-QWM36A3D.js.map → chunks/env-TJ5NOBEB.js.map} +0 -0
- /package/dist/{llmLazy-54QQHA54.js.map → chunks/kodeAgentSessionId-VTNISJ2L.js.map} +0 -0
- /package/dist/{loader-FYHJQES5.js.map → chunks/kodeAgentSessionLoad-YB2RKBGJ.js.map} +0 -0
- /package/dist/{mcp-J332IKT3.js.map → chunks/kodeAgentSessionResume-DZSIVKVA.js.map} +0 -0
- /package/dist/{messages-EOYQKPGM.js.map → chunks/kodeAgentStreamJson-X5PLS2S6.js.map} +0 -0
- /package/dist/{model-FV3JDJKH.js.map → chunks/kodeHooks-RVKYRJHG.js.map} +0 -0
- /package/dist/{openai-RRCWW33N.js.map → chunks/llmLazy-ZUSSE3ZA.js.map} +0 -0
- /package/dist/{outputStyles-62Q3VH2J.js.map → chunks/messages-EEWWLPHN.js.map} +0 -0
- /package/dist/{pluginValidation-I4YKUWGS.js.map → chunks/model-5TIEKQPD.js.map} +0 -0
- /package/dist/{prompts-ZLEKDD77.js.map → chunks/openai-XXK3YZG4.js.map} +0 -0
- /package/dist/{query-VFRJPBGD.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-3NTIKQYW.js.map → chunks/pluginValidation-DAM7WRTC.js.map} +0 -0
- /package/dist/{skillMarketplace-3RXQBVOL.js.map → chunks/registry-XYJXMOA5.js.map} +0 -0
- /package/dist/{state-P5G6CO5V.js.map → chunks/responsesStreaming-JNGE2P3D.js.map} +0 -0
- /package/dist/{theme-3LWP3BG7.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-3ROBVTUK.js.map → chunks/src-OROQIWP3.js.map} +0 -0
- /package/dist/{tools-RO7HSSE5.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,1647 @@
|
|
|
1
|
+
import "./chunk-U2IHWPCU.js";
|
|
2
|
+
import {
|
|
3
|
+
startKodeDaemon
|
|
4
|
+
} from "./chunk-3JDNWX7W.js";
|
|
5
|
+
import "./chunk-TNGVRTO5.js";
|
|
6
|
+
import "./chunk-HJYOH4HC.js";
|
|
7
|
+
import "./chunk-UNOY3VJ2.js";
|
|
8
|
+
import {
|
|
9
|
+
buildSystemPromptForSession,
|
|
10
|
+
getSessionContext,
|
|
11
|
+
runTurn
|
|
12
|
+
} from "./chunk-4A46ZXMJ.js";
|
|
13
|
+
import "./chunk-6BAS4WY6.js";
|
|
14
|
+
import {
|
|
15
|
+
getTools
|
|
16
|
+
} from "./chunk-77XDJMBP.js";
|
|
17
|
+
import "./chunk-GCQCAXJZ.js";
|
|
18
|
+
import "./chunk-7RRW4NTB.js";
|
|
19
|
+
import {
|
|
20
|
+
getClients
|
|
21
|
+
} from "./chunk-ZBVLKZ5V.js";
|
|
22
|
+
import "./chunk-BTA7SZ26.js";
|
|
23
|
+
import {
|
|
24
|
+
grantReadPermissionForOriginalDir,
|
|
25
|
+
hasPermissionsToUseTool
|
|
26
|
+
} from "./chunk-PPHLQVL7.js";
|
|
27
|
+
import {
|
|
28
|
+
loadToolPermissionContextFromDisk,
|
|
29
|
+
persistToolPermissionUpdateToDisk
|
|
30
|
+
} from "./chunk-2JN5MY67.js";
|
|
31
|
+
import {
|
|
32
|
+
applyToolPermissionContextUpdates
|
|
33
|
+
} from "./chunk-CP6E5UG6.js";
|
|
34
|
+
import "./chunk-TNWB3U5Y.js";
|
|
35
|
+
import "./chunk-UVDJL6ZZ.js";
|
|
36
|
+
import "./chunk-CDGRYGPZ.js";
|
|
37
|
+
import "./chunk-T7RB5V5J.js";
|
|
38
|
+
import "./chunk-53M46S5I.js";
|
|
39
|
+
import "./chunk-HPYNW6TT.js";
|
|
40
|
+
import "./chunk-LOD5ZHCI.js";
|
|
41
|
+
import "./chunk-GELCZWMB.js";
|
|
42
|
+
import "./chunk-3BYE3ME6.js";
|
|
43
|
+
import "./chunk-M7P3QNRU.js";
|
|
44
|
+
import "./chunk-SWQV4KSY.js";
|
|
45
|
+
import "./chunk-LOCXPQNJ.js";
|
|
46
|
+
import "./chunk-ZCLTZIVP.js";
|
|
47
|
+
import "./chunk-4CRUCZR4.js";
|
|
48
|
+
import "./chunk-BHDHXOXB.js";
|
|
49
|
+
import {
|
|
50
|
+
createAssistantMessage,
|
|
51
|
+
createUserMessage
|
|
52
|
+
} from "./chunk-HRJ3ICQK.js";
|
|
53
|
+
import "./chunk-6ZWEOSEI.js";
|
|
54
|
+
import {
|
|
55
|
+
initDebugLogger
|
|
56
|
+
} from "./chunk-YIO5EBMQ.js";
|
|
57
|
+
import {
|
|
58
|
+
PRODUCT_COMMAND,
|
|
59
|
+
getKodeBaseDir,
|
|
60
|
+
logError,
|
|
61
|
+
logMCPError
|
|
62
|
+
} from "./chunk-3OEJVB5A.js";
|
|
63
|
+
import {
|
|
64
|
+
setCwd,
|
|
65
|
+
setOriginalCwd
|
|
66
|
+
} from "./chunk-BBJFHTBC.js";
|
|
67
|
+
import "./chunk-QHQOBUF6.js";
|
|
68
|
+
import {
|
|
69
|
+
MACRO
|
|
70
|
+
} from "./chunk-W5EGGA44.js";
|
|
71
|
+
import "./chunk-DXD76CMV.js";
|
|
72
|
+
import "./chunk-LB6TCPDI.js";
|
|
73
|
+
import {
|
|
74
|
+
enableConfigs
|
|
75
|
+
} from "./chunk-XR2W3MAM.js";
|
|
76
|
+
import "./chunk-B3MW3YGY.js";
|
|
77
|
+
import "./chunk-54KOYG5C.js";
|
|
78
|
+
|
|
79
|
+
// apps/server/src/bootstrapEnv.ts
|
|
80
|
+
import { basename, dirname, join } from "node:path";
|
|
81
|
+
function ensurePackagedRuntimeEnv() {
|
|
82
|
+
if (process.env.KODE_PACKAGED !== void 0) return;
|
|
83
|
+
try {
|
|
84
|
+
const exec = basename(process.execPath || "").toLowerCase();
|
|
85
|
+
if (exec && exec !== "bun" && exec !== "bun.exe" && exec !== "node" && exec !== "node.exe") {
|
|
86
|
+
process.env.KODE_PACKAGED = "1";
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// apps/server/src/index.ts
|
|
93
|
+
import { cwd as processCwd } from "process";
|
|
94
|
+
|
|
95
|
+
// apps/server/src/acp/jsonrpc.ts
|
|
96
|
+
import { format } from "node:util";
|
|
97
|
+
var JsonRpcError = class extends Error {
|
|
98
|
+
code;
|
|
99
|
+
data;
|
|
100
|
+
constructor(code, message, data) {
|
|
101
|
+
super(message);
|
|
102
|
+
this.code = code;
|
|
103
|
+
this.data = data;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var JSONRPC_VERSION = "2.0";
|
|
107
|
+
function isObject(value) {
|
|
108
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
109
|
+
}
|
|
110
|
+
function safeStringify(value) {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.stringify(value);
|
|
113
|
+
} catch {
|
|
114
|
+
return format(value);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function makeErrorResponse(id, code, message, data) {
|
|
118
|
+
return {
|
|
119
|
+
jsonrpc: JSONRPC_VERSION,
|
|
120
|
+
id,
|
|
121
|
+
error: data === void 0 ? { code, message } : { code, message, data }
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function normalizeId(id) {
|
|
125
|
+
return typeof id === "string" || typeof id === "number" ? id : null;
|
|
126
|
+
}
|
|
127
|
+
var JsonRpcPeer = class {
|
|
128
|
+
handlers = /* @__PURE__ */ new Map();
|
|
129
|
+
pending = /* @__PURE__ */ new Map();
|
|
130
|
+
nextId = 1;
|
|
131
|
+
sendLine = null;
|
|
132
|
+
setSend(send) {
|
|
133
|
+
this.sendLine = send;
|
|
134
|
+
}
|
|
135
|
+
registerMethod(method, handler) {
|
|
136
|
+
this.handlers.set(method, handler);
|
|
137
|
+
}
|
|
138
|
+
async handleIncoming(payload) {
|
|
139
|
+
if (Array.isArray(payload)) {
|
|
140
|
+
const responses = [];
|
|
141
|
+
for (const item of payload) {
|
|
142
|
+
const r = await this.handleIncomingOne(item);
|
|
143
|
+
if (r) responses.push(r);
|
|
144
|
+
}
|
|
145
|
+
if (responses.length > 0) {
|
|
146
|
+
this.sendRaw(responses);
|
|
147
|
+
}
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const response = await this.handleIncomingOne(payload);
|
|
151
|
+
if (response) this.sendRaw(response);
|
|
152
|
+
}
|
|
153
|
+
async handleIncomingOne(payload) {
|
|
154
|
+
if (!isObject(payload)) {
|
|
155
|
+
return makeErrorResponse(null, -32600, "Invalid Request");
|
|
156
|
+
}
|
|
157
|
+
const jsonrpc = payload.jsonrpc;
|
|
158
|
+
if (jsonrpc !== JSONRPC_VERSION) {
|
|
159
|
+
return makeErrorResponse(
|
|
160
|
+
normalizeId(payload.id),
|
|
161
|
+
-32600,
|
|
162
|
+
"Invalid Request"
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
const hasMethod = typeof payload.method === "string" && payload.method.length > 0;
|
|
166
|
+
const hasId = typeof payload.id === "string" || typeof payload.id === "number";
|
|
167
|
+
if (!hasMethod && hasId && ("result" in payload || "error" in payload)) {
|
|
168
|
+
this.handleResponse(payload);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
if (!hasMethod) {
|
|
172
|
+
return makeErrorResponse(
|
|
173
|
+
normalizeId(payload.id),
|
|
174
|
+
-32600,
|
|
175
|
+
"Invalid Request"
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const method = String(payload.method);
|
|
179
|
+
const params = "params" in payload ? payload["params"] : void 0;
|
|
180
|
+
const id = hasId ? payload.id : null;
|
|
181
|
+
const handler = this.handlers.get(method);
|
|
182
|
+
if (!handler) {
|
|
183
|
+
if (id === null) return null;
|
|
184
|
+
return makeErrorResponse(id, -32601, `Method not found: ${method}`);
|
|
185
|
+
}
|
|
186
|
+
if (id === null) {
|
|
187
|
+
try {
|
|
188
|
+
await handler(params);
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const result = await handler(params);
|
|
195
|
+
return { jsonrpc: JSONRPC_VERSION, id, result: result ?? null };
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (err instanceof JsonRpcError) {
|
|
198
|
+
return makeErrorResponse(id, err.code, err.message, err.data);
|
|
199
|
+
}
|
|
200
|
+
const message = err instanceof Error ? err.message : safeStringify(err);
|
|
201
|
+
return makeErrorResponse(id, -32603, message);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
handleResponse(msg) {
|
|
205
|
+
const id = normalizeId(msg.id);
|
|
206
|
+
if (id === null) return;
|
|
207
|
+
const pending = this.pending.get(id);
|
|
208
|
+
if (!pending) return;
|
|
209
|
+
this.pending.delete(id);
|
|
210
|
+
if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
211
|
+
const errorValue = msg && typeof msg === "object" ? msg.error : void 0;
|
|
212
|
+
if (isObject(errorValue)) {
|
|
213
|
+
const code = typeof errorValue.code === "number" ? errorValue.code : -32603;
|
|
214
|
+
const message = typeof errorValue.message === "string" ? errorValue.message : "Unknown error";
|
|
215
|
+
pending.reject(new JsonRpcError(code, message, errorValue.data));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
pending.resolve(msg.result);
|
|
219
|
+
}
|
|
220
|
+
sendNotification(method, params) {
|
|
221
|
+
this.sendRaw({
|
|
222
|
+
jsonrpc: JSONRPC_VERSION,
|
|
223
|
+
method,
|
|
224
|
+
...params !== void 0 ? { params } : {}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
sendRequest(args) {
|
|
228
|
+
const id = this.nextId++;
|
|
229
|
+
const timeoutMs = args.timeoutMs;
|
|
230
|
+
const p = new Promise((resolve2, reject) => {
|
|
231
|
+
const entry = { resolve: resolve2, reject, abort: args.signal };
|
|
232
|
+
if (timeoutMs && Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
|
233
|
+
entry.timeoutId = setTimeout(() => {
|
|
234
|
+
this.pending.delete(id);
|
|
235
|
+
reject(new JsonRpcError(-32e3, `Request timed out: ${args.method}`));
|
|
236
|
+
}, timeoutMs);
|
|
237
|
+
}
|
|
238
|
+
if (args.signal) {
|
|
239
|
+
const onAbort = () => {
|
|
240
|
+
this.pending.delete(id);
|
|
241
|
+
if (entry.timeoutId) clearTimeout(entry.timeoutId);
|
|
242
|
+
reject(new JsonRpcError(-32e3, `Request aborted: ${args.method}`));
|
|
243
|
+
};
|
|
244
|
+
if (args.signal.aborted) {
|
|
245
|
+
onAbort();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
args.signal.addEventListener("abort", onAbort, { once: true });
|
|
249
|
+
}
|
|
250
|
+
this.pending.set(id, entry);
|
|
251
|
+
});
|
|
252
|
+
this.sendRaw({
|
|
253
|
+
jsonrpc: JSONRPC_VERSION,
|
|
254
|
+
id,
|
|
255
|
+
method: args.method,
|
|
256
|
+
...args.params !== void 0 ? { params: args.params } : {}
|
|
257
|
+
});
|
|
258
|
+
return p;
|
|
259
|
+
}
|
|
260
|
+
sendRaw(obj) {
|
|
261
|
+
const send = this.sendLine;
|
|
262
|
+
if (!send) {
|
|
263
|
+
throw new Error("JsonRpcPeer send() not configured");
|
|
264
|
+
}
|
|
265
|
+
const line = JSON.stringify(obj);
|
|
266
|
+
send(line);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// apps/server/src/acp/protocol.ts
|
|
271
|
+
var ACP_PROTOCOL_VERSION = 1;
|
|
272
|
+
|
|
273
|
+
// apps/server/src/acp/stdioTransport.ts
|
|
274
|
+
import readline from "node:readline";
|
|
275
|
+
var StdioTransport = class {
|
|
276
|
+
constructor(peer, opts) {
|
|
277
|
+
this.peer = peer;
|
|
278
|
+
this.opts = opts;
|
|
279
|
+
}
|
|
280
|
+
rl = null;
|
|
281
|
+
pending = /* @__PURE__ */ new Set();
|
|
282
|
+
start() {
|
|
283
|
+
if (this.rl) return;
|
|
284
|
+
this.peer.setSend(this.opts.writeLine);
|
|
285
|
+
this.rl = readline.createInterface({
|
|
286
|
+
input: process.stdin,
|
|
287
|
+
crlfDelay: Infinity
|
|
288
|
+
});
|
|
289
|
+
this.rl.on("line", (line) => {
|
|
290
|
+
const trimmed = line.trim();
|
|
291
|
+
if (!trimmed) return;
|
|
292
|
+
try {
|
|
293
|
+
const payload = JSON.parse(trimmed);
|
|
294
|
+
const p = this.peer.handleIncoming(payload).catch(() => {
|
|
295
|
+
});
|
|
296
|
+
this.pending.add(p);
|
|
297
|
+
void p.finally(() => this.pending.delete(p));
|
|
298
|
+
} catch (err) {
|
|
299
|
+
this.opts.writeLine(
|
|
300
|
+
JSON.stringify({
|
|
301
|
+
jsonrpc: "2.0",
|
|
302
|
+
id: null,
|
|
303
|
+
error: { code: -32700, message: "Parse error" }
|
|
304
|
+
})
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
this.rl.on("close", () => {
|
|
309
|
+
void (async () => {
|
|
310
|
+
const pending = Array.from(this.pending);
|
|
311
|
+
if (pending.length > 0) {
|
|
312
|
+
await Promise.allSettled(pending);
|
|
313
|
+
}
|
|
314
|
+
process.exit(0);
|
|
315
|
+
})();
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
stop() {
|
|
319
|
+
this.rl?.close();
|
|
320
|
+
this.rl = null;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// apps/server/src/acp/stdoutGuard.ts
|
|
325
|
+
import { format as format2 } from "node:util";
|
|
326
|
+
function writeTo(write, chunk, encoding, cb) {
|
|
327
|
+
if (typeof encoding === "function") {
|
|
328
|
+
return write(chunk, encoding);
|
|
329
|
+
}
|
|
330
|
+
return write(chunk, encoding, cb);
|
|
331
|
+
}
|
|
332
|
+
function installStdoutGuard() {
|
|
333
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
334
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
335
|
+
const originalConsoleLog = console.log.bind(console);
|
|
336
|
+
const originalConsoleInfo = console.info.bind(console);
|
|
337
|
+
const originalConsoleDebug = console.debug.bind(console);
|
|
338
|
+
const originalConsoleWarn = console.warn.bind(console);
|
|
339
|
+
const originalConsoleError = console.error.bind(console);
|
|
340
|
+
const writeAcpLine = (line) => {
|
|
341
|
+
writeTo(originalStdoutWrite, `${line}
|
|
342
|
+
`);
|
|
343
|
+
};
|
|
344
|
+
const writeLogToStderr = (...args) => {
|
|
345
|
+
writeTo(originalStderrWrite, `${format2(...args)}
|
|
346
|
+
`);
|
|
347
|
+
};
|
|
348
|
+
console.log = writeLogToStderr;
|
|
349
|
+
console.info = writeLogToStderr;
|
|
350
|
+
console.debug = writeLogToStderr;
|
|
351
|
+
console.warn = writeLogToStderr;
|
|
352
|
+
console.error = writeLogToStderr;
|
|
353
|
+
process.stdout.write = (chunk, encoding, cb) => {
|
|
354
|
+
return writeTo(originalStderrWrite, chunk, encoding, cb);
|
|
355
|
+
};
|
|
356
|
+
const restore = () => {
|
|
357
|
+
process.stdout.write = originalStdoutWrite;
|
|
358
|
+
console.log = originalConsoleLog;
|
|
359
|
+
console.info = originalConsoleInfo;
|
|
360
|
+
console.debug = originalConsoleDebug;
|
|
361
|
+
console.warn = originalConsoleWarn;
|
|
362
|
+
console.error = originalConsoleError;
|
|
363
|
+
};
|
|
364
|
+
return { writeAcpLine, restore, originalStdoutWrite };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// apps/server/src/acp/agent/guards.ts
|
|
368
|
+
function isRecord(value) {
|
|
369
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// apps/server/src/acp/agent/handlers/initialize.ts
|
|
373
|
+
function handleInitialize(args) {
|
|
374
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
375
|
+
const clientCapabilities = isRecord(p.clientCapabilities) ? p.clientCapabilities : {};
|
|
376
|
+
args.setClientCapabilities(clientCapabilities);
|
|
377
|
+
return {
|
|
378
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
379
|
+
agentCapabilities: {
|
|
380
|
+
loadSession: true,
|
|
381
|
+
promptCapabilities: {
|
|
382
|
+
image: false,
|
|
383
|
+
audio: false,
|
|
384
|
+
embeddedContext: true,
|
|
385
|
+
embeddedContent: true
|
|
386
|
+
},
|
|
387
|
+
mcpCapabilities: {
|
|
388
|
+
http: true,
|
|
389
|
+
sse: true
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
agentInfo: {
|
|
393
|
+
name: "kode",
|
|
394
|
+
title: "Kode",
|
|
395
|
+
version: MACRO.VERSION || "0.0.0"
|
|
396
|
+
},
|
|
397
|
+
authMethods: []
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function handleAuthenticate() {
|
|
401
|
+
return {};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// apps/server/src/acp/agent/handlers/sessions.ts
|
|
405
|
+
import { nanoid } from "nanoid";
|
|
406
|
+
import { isAbsolute as isAbsolute2 } from "node:path";
|
|
407
|
+
|
|
408
|
+
// apps/server/src/acp/agent/mcp.ts
|
|
409
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
410
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
411
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
412
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
413
|
+
function getConnectionTimeoutMs() {
|
|
414
|
+
const rawTimeout = process.env.MCP_CONNECTION_TIMEOUT_MS;
|
|
415
|
+
const parsedTimeout = rawTimeout ? Number.parseInt(rawTimeout, 10) : NaN;
|
|
416
|
+
return Number.isFinite(parsedTimeout) ? parsedTimeout : 3e4;
|
|
417
|
+
}
|
|
418
|
+
function buildEnv(extra) {
|
|
419
|
+
const env = {};
|
|
420
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
421
|
+
if (typeof value === "string") env[key] = value;
|
|
422
|
+
}
|
|
423
|
+
if (extra) Object.assign(env, extra);
|
|
424
|
+
return env;
|
|
425
|
+
}
|
|
426
|
+
function normalizeHeaders(headers) {
|
|
427
|
+
const out = {};
|
|
428
|
+
for (const h of headers ?? []) {
|
|
429
|
+
if (!h || typeof h !== "object") continue;
|
|
430
|
+
if (typeof h.name === "string" && typeof h.value === "string") {
|
|
431
|
+
out[h.name] = h.value;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return out;
|
|
435
|
+
}
|
|
436
|
+
function normalizeEnvVars(vars) {
|
|
437
|
+
const out = {};
|
|
438
|
+
for (const v of vars ?? []) {
|
|
439
|
+
if (!v || typeof v !== "object") continue;
|
|
440
|
+
if (typeof v.name === "string" && typeof v.value === "string") {
|
|
441
|
+
out[v.name] = v.value;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return out;
|
|
445
|
+
}
|
|
446
|
+
async function connectWithTimeout(client, transport, name, timeoutMs) {
|
|
447
|
+
const connectPromise = client.connect(transport);
|
|
448
|
+
if (timeoutMs <= 0) {
|
|
449
|
+
await connectPromise;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
453
|
+
const timeoutId = setTimeout(() => {
|
|
454
|
+
reject(
|
|
455
|
+
new Error(
|
|
456
|
+
`Connection to MCP server "${name}" timed out after ${timeoutMs}ms`
|
|
457
|
+
)
|
|
458
|
+
);
|
|
459
|
+
}, timeoutMs);
|
|
460
|
+
connectPromise.finally(() => clearTimeout(timeoutId));
|
|
461
|
+
});
|
|
462
|
+
await Promise.race([connectPromise, timeoutPromise]);
|
|
463
|
+
}
|
|
464
|
+
function createCandidates(server) {
|
|
465
|
+
const name = server.name;
|
|
466
|
+
if (!name) return null;
|
|
467
|
+
if (server.type === "http" || server.type === "sse") {
|
|
468
|
+
const url = server.url;
|
|
469
|
+
if (!url) return null;
|
|
470
|
+
let parsedUrl;
|
|
471
|
+
try {
|
|
472
|
+
parsedUrl = new URL(url);
|
|
473
|
+
} catch (e) {
|
|
474
|
+
logError(e);
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
const headers = normalizeHeaders(server.headers);
|
|
478
|
+
const options = Object.keys(headers).length > 0 ? { requestInit: { headers } } : void 0;
|
|
479
|
+
if (server.type === "http") {
|
|
480
|
+
return {
|
|
481
|
+
name,
|
|
482
|
+
candidates: [
|
|
483
|
+
{
|
|
484
|
+
kind: "http",
|
|
485
|
+
transport: new StreamableHTTPClientTransport(parsedUrl, options)
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
kind: "sse",
|
|
489
|
+
transport: new SSEClientTransport(parsedUrl, options)
|
|
490
|
+
}
|
|
491
|
+
]
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
name,
|
|
496
|
+
candidates: [
|
|
497
|
+
{ kind: "sse", transport: new SSEClientTransport(parsedUrl, options) },
|
|
498
|
+
{
|
|
499
|
+
kind: "http",
|
|
500
|
+
transport: new StreamableHTTPClientTransport(parsedUrl, options)
|
|
501
|
+
}
|
|
502
|
+
]
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const envFromParams = normalizeEnvVars(server.env);
|
|
506
|
+
return {
|
|
507
|
+
name,
|
|
508
|
+
candidates: [
|
|
509
|
+
{
|
|
510
|
+
kind: "stdio",
|
|
511
|
+
transport: new StdioClientTransport({
|
|
512
|
+
command: server.command,
|
|
513
|
+
args: server.args,
|
|
514
|
+
env: buildEnv(envFromParams),
|
|
515
|
+
stderr: "pipe"
|
|
516
|
+
})
|
|
517
|
+
}
|
|
518
|
+
]
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
async function connectAcpMcpServers(mcpServers) {
|
|
522
|
+
if (!Array.isArray(mcpServers) || mcpServers.length === 0) return [];
|
|
523
|
+
const timeoutMs = getConnectionTimeoutMs();
|
|
524
|
+
const results = [];
|
|
525
|
+
for (const server of mcpServers) {
|
|
526
|
+
const normalized = createCandidates(server);
|
|
527
|
+
if (!normalized) {
|
|
528
|
+
results.push({ name: "<invalid>", type: "failed" });
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const { name, candidates } = normalized;
|
|
532
|
+
let lastError;
|
|
533
|
+
for (const candidate of candidates) {
|
|
534
|
+
const client = new Client(
|
|
535
|
+
{ name: PRODUCT_COMMAND, version: MACRO.VERSION || "0.0.0" },
|
|
536
|
+
{ capabilities: {} }
|
|
537
|
+
);
|
|
538
|
+
try {
|
|
539
|
+
await connectWithTimeout(client, candidate.transport, name, timeoutMs);
|
|
540
|
+
if (candidate.kind === "stdio") {
|
|
541
|
+
candidate.transport.stderr?.on("data", (data) => {
|
|
542
|
+
const errorText = data.toString().trim();
|
|
543
|
+
if (errorText) logMCPError(name, `Server stderr: ${errorText}`);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
let capabilities = null;
|
|
547
|
+
try {
|
|
548
|
+
capabilities = client.getServerCapabilities() ?? null;
|
|
549
|
+
} catch {
|
|
550
|
+
capabilities = null;
|
|
551
|
+
}
|
|
552
|
+
results.push({ name, client, capabilities, type: "connected" });
|
|
553
|
+
lastError = null;
|
|
554
|
+
break;
|
|
555
|
+
} catch (e) {
|
|
556
|
+
lastError = e;
|
|
557
|
+
try {
|
|
558
|
+
await client.close();
|
|
559
|
+
} catch {
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (lastError) {
|
|
564
|
+
logError(lastError);
|
|
565
|
+
results.push({ name, type: "failed" });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return results;
|
|
569
|
+
}
|
|
570
|
+
function mergeMcpClients(base, extra) {
|
|
571
|
+
const map = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const c of base) map.set(c.name, c);
|
|
573
|
+
for (const c of extra) map.set(c.name, c);
|
|
574
|
+
return Array.from(map.values());
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// apps/server/src/acp/agent/modes.ts
|
|
578
|
+
var MODE_SET = /* @__PURE__ */ new Set([
|
|
579
|
+
"default",
|
|
580
|
+
"acceptEdits",
|
|
581
|
+
"plan",
|
|
582
|
+
"dontAsk",
|
|
583
|
+
"bypassPermissions"
|
|
584
|
+
]);
|
|
585
|
+
function isPermissionMode(value) {
|
|
586
|
+
return typeof value === "string" && MODE_SET.has(value);
|
|
587
|
+
}
|
|
588
|
+
function coercePermissionMode(value) {
|
|
589
|
+
return isPermissionMode(value) ? value : "default";
|
|
590
|
+
}
|
|
591
|
+
function getModeState(currentModeId) {
|
|
592
|
+
const availableModes = [
|
|
593
|
+
{
|
|
594
|
+
id: "default",
|
|
595
|
+
name: "Default",
|
|
596
|
+
description: "Normal permissions (prompt when needed)"
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
id: "acceptEdits",
|
|
600
|
+
name: "Accept Edits",
|
|
601
|
+
description: "Auto-approve safe file edits"
|
|
602
|
+
},
|
|
603
|
+
{ id: "plan", name: "Plan", description: "Read-only planning mode" },
|
|
604
|
+
{
|
|
605
|
+
id: "dontAsk",
|
|
606
|
+
name: "Don't Ask",
|
|
607
|
+
description: "Auto-deny permission prompts"
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
id: "bypassPermissions",
|
|
611
|
+
name: "Bypass",
|
|
612
|
+
description: "Bypass permission prompts (dangerous)"
|
|
613
|
+
}
|
|
614
|
+
];
|
|
615
|
+
const current = coercePermissionMode(currentModeId);
|
|
616
|
+
return { currentModeId: current, availableModes };
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// apps/server/src/acp/agent/sessionStore.ts
|
|
620
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
621
|
+
import { join as join2 } from "node:path";
|
|
622
|
+
var ACP_SESSION_STORE_VERSION = 1;
|
|
623
|
+
function getProjectDirSlug(cwd) {
|
|
624
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
625
|
+
}
|
|
626
|
+
function sanitizeSessionId(sessionId) {
|
|
627
|
+
return sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
628
|
+
}
|
|
629
|
+
function getAcpSessionDir(cwd) {
|
|
630
|
+
return join2(getKodeBaseDir(), getProjectDirSlug(cwd), "acp-sessions");
|
|
631
|
+
}
|
|
632
|
+
function getAcpSessionFilePath(cwd, sessionId) {
|
|
633
|
+
return join2(getAcpSessionDir(cwd), `${sanitizeSessionId(sessionId)}.json`);
|
|
634
|
+
}
|
|
635
|
+
function persistAcpSessionToDisk(session) {
|
|
636
|
+
try {
|
|
637
|
+
const dir = getAcpSessionDir(session.cwd);
|
|
638
|
+
mkdirSync(dir, { recursive: true });
|
|
639
|
+
const payload = {
|
|
640
|
+
version: ACP_SESSION_STORE_VERSION,
|
|
641
|
+
sessionId: session.sessionId,
|
|
642
|
+
cwd: session.cwd,
|
|
643
|
+
mcpServers: session.mcpServers,
|
|
644
|
+
messages: session.messages,
|
|
645
|
+
toolPermissionContext: session.toolPermissionContext,
|
|
646
|
+
readFileTimestamps: session.readFileTimestamps,
|
|
647
|
+
responseState: session.responseState,
|
|
648
|
+
currentModeId: session.currentModeId
|
|
649
|
+
};
|
|
650
|
+
const path = getAcpSessionFilePath(session.cwd, session.sessionId);
|
|
651
|
+
writeFileSync(path, JSON.stringify(payload, null, 2), "utf8");
|
|
652
|
+
} catch (e) {
|
|
653
|
+
logError(e);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
function loadAcpSessionFromDisk(cwd, sessionId) {
|
|
657
|
+
try {
|
|
658
|
+
const path = getAcpSessionFilePath(cwd, sessionId);
|
|
659
|
+
if (!existsSync(path)) return null;
|
|
660
|
+
const raw = readFileSync(path, "utf8");
|
|
661
|
+
const parsed = JSON.parse(raw);
|
|
662
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
663
|
+
if (parsed.sessionId !== sessionId) return null;
|
|
664
|
+
if (typeof parsed.cwd !== "string" || parsed.cwd !== cwd) return null;
|
|
665
|
+
if (!Array.isArray(parsed.messages)) return null;
|
|
666
|
+
return parsed;
|
|
667
|
+
} catch {
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// apps/server/src/acp/agent/notifications.ts
|
|
673
|
+
function sendAvailableCommands(peer, session) {
|
|
674
|
+
const availableCommands = session.commands.filter((c) => !c.isHidden).map((c) => ({
|
|
675
|
+
name: c.userFacingName(),
|
|
676
|
+
description: c.description,
|
|
677
|
+
...c.argumentHint ? { input: { hint: c.argumentHint } } : {}
|
|
678
|
+
}));
|
|
679
|
+
peer.sendNotification("session/update", {
|
|
680
|
+
sessionId: session.sessionId,
|
|
681
|
+
update: {
|
|
682
|
+
sessionUpdate: "available_commands_update",
|
|
683
|
+
availableCommands
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function sendCurrentMode(peer, session) {
|
|
688
|
+
peer.sendNotification("session/update", {
|
|
689
|
+
sessionId: session.sessionId,
|
|
690
|
+
update: {
|
|
691
|
+
sessionUpdate: "current_mode_update",
|
|
692
|
+
currentModeId: session.currentModeId
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function sendUserMessageChunk(peer, sessionId, text) {
|
|
697
|
+
if (!text) return;
|
|
698
|
+
peer.sendNotification("session/update", {
|
|
699
|
+
sessionId,
|
|
700
|
+
update: {
|
|
701
|
+
sessionUpdate: "user_message_chunk",
|
|
702
|
+
content: { type: "text", text }
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
function sendAgentMessageChunk(peer, sessionId, text) {
|
|
707
|
+
if (!text) return;
|
|
708
|
+
peer.sendNotification("session/update", {
|
|
709
|
+
sessionId,
|
|
710
|
+
update: {
|
|
711
|
+
sessionUpdate: "agent_message_chunk",
|
|
712
|
+
content: { type: "text", text }
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function sendAgentThoughtChunk(peer, sessionId, text) {
|
|
717
|
+
if (!text) return;
|
|
718
|
+
peer.sendNotification("session/update", {
|
|
719
|
+
sessionId,
|
|
720
|
+
update: {
|
|
721
|
+
sessionUpdate: "agent_thought_chunk",
|
|
722
|
+
content: { type: "text", text }
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
function sendToolCall(peer, sessionId, toolCall) {
|
|
727
|
+
peer.sendNotification("session/update", {
|
|
728
|
+
sessionId,
|
|
729
|
+
update: toolCall
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
function sendToolCallUpdate(peer, sessionId, update) {
|
|
733
|
+
peer.sendNotification("session/update", {
|
|
734
|
+
sessionId,
|
|
735
|
+
update: {
|
|
736
|
+
sessionUpdate: "tool_call_update",
|
|
737
|
+
...update
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// apps/server/src/acp/agent/content.ts
|
|
743
|
+
function asJsonObject(value) {
|
|
744
|
+
if (!isRecord(value)) return void 0;
|
|
745
|
+
try {
|
|
746
|
+
JSON.stringify(value);
|
|
747
|
+
return value;
|
|
748
|
+
} catch {
|
|
749
|
+
return void 0;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
function toolKindForName(toolName) {
|
|
753
|
+
switch (toolName) {
|
|
754
|
+
case "Read":
|
|
755
|
+
return "read";
|
|
756
|
+
case "Write":
|
|
757
|
+
case "Edit":
|
|
758
|
+
case "MultiEdit":
|
|
759
|
+
case "NotebookEdit":
|
|
760
|
+
return "edit";
|
|
761
|
+
case "Grep":
|
|
762
|
+
case "Glob":
|
|
763
|
+
return "search";
|
|
764
|
+
case "Bash":
|
|
765
|
+
case "TaskOutput":
|
|
766
|
+
case "KillShell":
|
|
767
|
+
return "execute";
|
|
768
|
+
case "SwitchModel":
|
|
769
|
+
return "switch_mode";
|
|
770
|
+
default:
|
|
771
|
+
return "other";
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function titleForToolCall(toolName, input) {
|
|
775
|
+
if (toolName === "Read" && typeof input.file_path === "string") {
|
|
776
|
+
return `Read ${input.file_path}`;
|
|
777
|
+
}
|
|
778
|
+
if ((toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") && typeof input.file_path === "string") {
|
|
779
|
+
return `${toolName} ${input.file_path}`;
|
|
780
|
+
}
|
|
781
|
+
if (toolName === "Bash" && typeof input.command === "string") {
|
|
782
|
+
const cmd = input.command.trim().replace(/\s+/g, " ");
|
|
783
|
+
const clipped = cmd.length > 120 ? `${cmd.slice(0, 117)}...` : cmd;
|
|
784
|
+
return `Run ${clipped}`;
|
|
785
|
+
}
|
|
786
|
+
return toolName;
|
|
787
|
+
}
|
|
788
|
+
function blocksToText(blocks) {
|
|
789
|
+
const parts = [];
|
|
790
|
+
for (const block of blocks) {
|
|
791
|
+
switch (block.type) {
|
|
792
|
+
case "text": {
|
|
793
|
+
const text = typeof block.text === "string" ? block.text : "";
|
|
794
|
+
if (text) parts.push(text);
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
case "resource": {
|
|
798
|
+
const resource = block.resource;
|
|
799
|
+
const uri = resource.uri;
|
|
800
|
+
const mimeType = resource.mimeType?.trim() || "text/plain";
|
|
801
|
+
if (typeof resource.text === "string") {
|
|
802
|
+
parts.push(
|
|
803
|
+
[
|
|
804
|
+
"",
|
|
805
|
+
`@resource ${uri} (${mimeType})`,
|
|
806
|
+
"```",
|
|
807
|
+
resource.text,
|
|
808
|
+
"```"
|
|
809
|
+
].join("\n")
|
|
810
|
+
);
|
|
811
|
+
} else if (typeof resource.blob === "string") {
|
|
812
|
+
parts.push(
|
|
813
|
+
["", `@resource ${uri} (${mimeType}) [base64]`, resource.blob].join(
|
|
814
|
+
"\n"
|
|
815
|
+
)
|
|
816
|
+
);
|
|
817
|
+
} else if (uri) {
|
|
818
|
+
parts.push(`@resource ${uri} (${mimeType})`);
|
|
819
|
+
}
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
case "resource_link": {
|
|
823
|
+
const uri = block.uri;
|
|
824
|
+
const name = block.name;
|
|
825
|
+
const title = block.title ?? "";
|
|
826
|
+
const description = block.description ?? "";
|
|
827
|
+
parts.push(
|
|
828
|
+
[
|
|
829
|
+
"",
|
|
830
|
+
`@resource_link ${name || uri}`,
|
|
831
|
+
...title ? [title] : [],
|
|
832
|
+
...description ? [description] : [],
|
|
833
|
+
...uri ? [uri] : []
|
|
834
|
+
].join("\n")
|
|
835
|
+
);
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
case "image":
|
|
839
|
+
case "audio": {
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
default:
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return parts.join("\n").trim();
|
|
847
|
+
}
|
|
848
|
+
function extractAssistantText(msg) {
|
|
849
|
+
const texts = [];
|
|
850
|
+
for (const block of msg.message.content) {
|
|
851
|
+
if (block.type === "text") texts.push(block.text);
|
|
852
|
+
if (block.type === "thinking") texts.push(block.thinking);
|
|
853
|
+
}
|
|
854
|
+
return texts.join("").trim();
|
|
855
|
+
}
|
|
856
|
+
function isTextBlockParam(value) {
|
|
857
|
+
return isRecord(value) && value.type === "text" && typeof value.text === "string";
|
|
858
|
+
}
|
|
859
|
+
function extractToolResults(msg) {
|
|
860
|
+
const content = msg.message.content;
|
|
861
|
+
if (!Array.isArray(content)) return [];
|
|
862
|
+
const out = [];
|
|
863
|
+
for (const block of content) {
|
|
864
|
+
if (block.type !== "tool_result") continue;
|
|
865
|
+
const toolUseId = block.tool_use_id;
|
|
866
|
+
const isError = Boolean(block.is_error);
|
|
867
|
+
const raw = block.content;
|
|
868
|
+
const text = typeof raw === "string" ? raw : Array.isArray(raw) ? raw.filter(isTextBlockParam).map((x) => x.text).join("") : "";
|
|
869
|
+
if (toolUseId) out.push({ toolUseId, isError, content: text });
|
|
870
|
+
}
|
|
871
|
+
return out;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// apps/server/src/acp/agent/toolCalls.ts
|
|
875
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
876
|
+
import { isAbsolute, resolve } from "node:path";
|
|
877
|
+
var MAX_DIFF_FILE_BYTES = 512e3;
|
|
878
|
+
var MAX_DIFF_TEXT_CHARS = 4e5;
|
|
879
|
+
function readTextFileForDiff(filePath) {
|
|
880
|
+
try {
|
|
881
|
+
const stats = statSync(filePath);
|
|
882
|
+
if (!stats.isFile()) return null;
|
|
883
|
+
if (stats.size > MAX_DIFF_FILE_BYTES) return null;
|
|
884
|
+
return readFileSync2(filePath, "utf8");
|
|
885
|
+
} catch {
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
function truncateDiffText(text) {
|
|
890
|
+
if (text.length <= MAX_DIFF_TEXT_CHARS) return text;
|
|
891
|
+
return `${text.slice(0, MAX_DIFF_TEXT_CHARS)}
|
|
892
|
+
|
|
893
|
+
[truncated ${text.length - MAX_DIFF_TEXT_CHARS} chars]`;
|
|
894
|
+
}
|
|
895
|
+
function captureFileSnapshotForTool(params) {
|
|
896
|
+
const { session, toolUseId, toolName, input } = params;
|
|
897
|
+
if (toolName !== "Write" && toolName !== "MultiEdit") return;
|
|
898
|
+
const filePath = isRecord(input) && typeof input.file_path === "string" ? input.file_path : "";
|
|
899
|
+
if (!filePath) return;
|
|
900
|
+
const absPath = isAbsolute(filePath) ? filePath : resolve(session.cwd, filePath);
|
|
901
|
+
const oldContent = existsSync2(absPath) ? readTextFileForDiff(absPath) : "";
|
|
902
|
+
if (oldContent === null) return;
|
|
903
|
+
const existing = session.toolCalls.get(toolUseId);
|
|
904
|
+
if (existing) {
|
|
905
|
+
existing.fileSnapshot = { path: absPath, content: oldContent };
|
|
906
|
+
session.toolCalls.set(toolUseId, existing);
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
session.toolCalls.set(toolUseId, {
|
|
910
|
+
title: toolName,
|
|
911
|
+
kind: toolKindForName(toolName),
|
|
912
|
+
status: "pending",
|
|
913
|
+
rawInput: asJsonObject(input),
|
|
914
|
+
fileSnapshot: { path: absPath, content: oldContent }
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
function getJsonStringMaybe(obj, key) {
|
|
918
|
+
const value = obj?.[key];
|
|
919
|
+
return typeof value === "string" ? value : void 0;
|
|
920
|
+
}
|
|
921
|
+
function buildDiffContentForToolResult(params) {
|
|
922
|
+
const { session, toolUseId, rawOutput } = params;
|
|
923
|
+
const existing = session.toolCalls.get(toolUseId);
|
|
924
|
+
if (!existing || existing.kind !== "edit") return null;
|
|
925
|
+
const inputFilePath = typeof existing.rawInput?.file_path === "string" ? existing.rawInput.file_path : getJsonStringMaybe(rawOutput, "filePath") ?? "";
|
|
926
|
+
if (!inputFilePath) return null;
|
|
927
|
+
const absPath = isAbsolute(inputFilePath) ? inputFilePath : resolve(session.cwd, inputFilePath);
|
|
928
|
+
const oldText = getJsonStringMaybe(rawOutput, "originalFile") ?? (existing.fileSnapshot && existing.fileSnapshot.path === absPath ? existing.fileSnapshot.content : void 0);
|
|
929
|
+
if (oldText === void 0) return null;
|
|
930
|
+
const newTextFromDisk = readTextFileForDiff(absPath);
|
|
931
|
+
const newTextFromOutput = getJsonStringMaybe(rawOutput, "content");
|
|
932
|
+
const newText = newTextFromDisk ?? newTextFromOutput;
|
|
933
|
+
if (newText === null || newText === void 0) return null;
|
|
934
|
+
return {
|
|
935
|
+
type: "diff",
|
|
936
|
+
path: absPath,
|
|
937
|
+
oldText: truncateDiffText(oldText),
|
|
938
|
+
newText: truncateDiffText(newText)
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// apps/server/src/acp/agent/kodeMessages.ts
|
|
943
|
+
function toInputRecord(value) {
|
|
944
|
+
return isRecord(value) ? value : {};
|
|
945
|
+
}
|
|
946
|
+
function emitAssistantContentBlocks(peer, session, blocks) {
|
|
947
|
+
for (const block of blocks) {
|
|
948
|
+
switch (block.type) {
|
|
949
|
+
case "text":
|
|
950
|
+
sendAgentMessageChunk(peer, session.sessionId, block.text);
|
|
951
|
+
break;
|
|
952
|
+
case "thinking":
|
|
953
|
+
sendAgentThoughtChunk(peer, session.sessionId, block.thinking);
|
|
954
|
+
break;
|
|
955
|
+
case "tool_use": {
|
|
956
|
+
const toolUseId = typeof block.id === "string" ? block.id : "";
|
|
957
|
+
const toolName = typeof block.name === "string" ? block.name : "";
|
|
958
|
+
if (!toolUseId || !toolName) break;
|
|
959
|
+
if (!session.toolCalls.has(toolUseId)) {
|
|
960
|
+
const input = toInputRecord(block.input);
|
|
961
|
+
const kind = toolKindForName(toolName);
|
|
962
|
+
const title = titleForToolCall(toolName, input);
|
|
963
|
+
session.toolCalls.set(toolUseId, {
|
|
964
|
+
title,
|
|
965
|
+
kind,
|
|
966
|
+
status: "pending",
|
|
967
|
+
rawInput: asJsonObject(input)
|
|
968
|
+
});
|
|
969
|
+
sendToolCall(peer, session.sessionId, {
|
|
970
|
+
sessionUpdate: "tool_call",
|
|
971
|
+
toolCallId: toolUseId,
|
|
972
|
+
title,
|
|
973
|
+
kind,
|
|
974
|
+
status: "pending",
|
|
975
|
+
rawInput: asJsonObject(input)
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
default:
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
async function handleKodeMessage(args) {
|
|
986
|
+
const { peer, session, message: m } = args;
|
|
987
|
+
if (!m || typeof m !== "object") return;
|
|
988
|
+
if (m.type === "assistant") {
|
|
989
|
+
session.messages.push(m);
|
|
990
|
+
emitAssistantContentBlocks(peer, session, m.message.content);
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if (m.type === "progress") {
|
|
994
|
+
const toolCallId = m.toolUseID;
|
|
995
|
+
const existing = session.toolCalls.get(toolCallId);
|
|
996
|
+
const title = existing?.title ?? "Tool";
|
|
997
|
+
const kind = existing?.kind ?? "other";
|
|
998
|
+
if (!existing || existing.status === "pending") {
|
|
999
|
+
session.toolCalls.set(toolCallId, {
|
|
1000
|
+
title,
|
|
1001
|
+
kind,
|
|
1002
|
+
status: "in_progress",
|
|
1003
|
+
rawInput: existing?.rawInput
|
|
1004
|
+
});
|
|
1005
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1006
|
+
toolCallId,
|
|
1007
|
+
status: "in_progress"
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
const text = extractAssistantText(m.content);
|
|
1011
|
+
if (text) {
|
|
1012
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1013
|
+
toolCallId,
|
|
1014
|
+
content: [
|
|
1015
|
+
{
|
|
1016
|
+
type: "content",
|
|
1017
|
+
content: { type: "text", text }
|
|
1018
|
+
}
|
|
1019
|
+
]
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
if (m.type === "user") {
|
|
1025
|
+
const toolResults = extractToolResults(m);
|
|
1026
|
+
if (toolResults.length === 0) {
|
|
1027
|
+
session.messages.push(m);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
for (const tr of toolResults) {
|
|
1031
|
+
const existing = session.toolCalls.get(tr.toolUseId);
|
|
1032
|
+
const title = existing?.title ?? "Tool";
|
|
1033
|
+
const kind = existing?.kind ?? "other";
|
|
1034
|
+
if (!existing || existing.status === "pending") {
|
|
1035
|
+
session.toolCalls.set(tr.toolUseId, {
|
|
1036
|
+
title,
|
|
1037
|
+
kind,
|
|
1038
|
+
status: "in_progress",
|
|
1039
|
+
rawInput: existing?.rawInput
|
|
1040
|
+
});
|
|
1041
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1042
|
+
toolCallId: tr.toolUseId,
|
|
1043
|
+
status: "in_progress"
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
const status = tr.isError ? "failed" : "completed";
|
|
1047
|
+
session.toolCalls.set(tr.toolUseId, {
|
|
1048
|
+
title,
|
|
1049
|
+
kind,
|
|
1050
|
+
status,
|
|
1051
|
+
rawInput: existing?.rawInput
|
|
1052
|
+
});
|
|
1053
|
+
const rawOutput = asJsonObject(m.toolUseResult?.data);
|
|
1054
|
+
const content = [];
|
|
1055
|
+
const diffContent = status === "completed" ? buildDiffContentForToolResult({
|
|
1056
|
+
session,
|
|
1057
|
+
toolUseId: tr.toolUseId,
|
|
1058
|
+
rawOutput
|
|
1059
|
+
}) : null;
|
|
1060
|
+
if (diffContent) content.push(diffContent);
|
|
1061
|
+
if (tr.content) {
|
|
1062
|
+
content.push({
|
|
1063
|
+
type: "content",
|
|
1064
|
+
content: { type: "text", text: tr.content }
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1068
|
+
toolCallId: tr.toolUseId,
|
|
1069
|
+
status,
|
|
1070
|
+
...content.length > 0 ? { content } : {},
|
|
1071
|
+
...rawOutput ? { rawOutput } : {}
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
session.messages.push(m);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
function replayConversation(peer, session) {
|
|
1078
|
+
session.toolCalls.clear();
|
|
1079
|
+
for (const m of session.messages) {
|
|
1080
|
+
if (!m || typeof m !== "object") continue;
|
|
1081
|
+
if (m.type === "assistant") {
|
|
1082
|
+
emitAssistantContentBlocks(peer, session, m.message.content);
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
if (m.type === "user") {
|
|
1086
|
+
if (typeof m.message.content === "string" && m.message.content.trim()) {
|
|
1087
|
+
sendUserMessageChunk(peer, session.sessionId, m.message.content);
|
|
1088
|
+
}
|
|
1089
|
+
const toolResults = extractToolResults(m);
|
|
1090
|
+
if (toolResults.length === 0) continue;
|
|
1091
|
+
for (const tr of toolResults) {
|
|
1092
|
+
const existing = session.toolCalls.get(tr.toolUseId);
|
|
1093
|
+
const title = existing?.title ?? "Tool";
|
|
1094
|
+
const kind = existing?.kind ?? "other";
|
|
1095
|
+
if (!existing) {
|
|
1096
|
+
session.toolCalls.set(tr.toolUseId, {
|
|
1097
|
+
title,
|
|
1098
|
+
kind,
|
|
1099
|
+
status: "pending"
|
|
1100
|
+
});
|
|
1101
|
+
sendToolCall(peer, session.sessionId, {
|
|
1102
|
+
sessionUpdate: "tool_call",
|
|
1103
|
+
toolCallId: tr.toolUseId,
|
|
1104
|
+
title,
|
|
1105
|
+
kind,
|
|
1106
|
+
status: "pending"
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
const status = tr.isError ? "failed" : "completed";
|
|
1110
|
+
const contentBlocks = [];
|
|
1111
|
+
if (tr.content) {
|
|
1112
|
+
contentBlocks.push({
|
|
1113
|
+
type: "content",
|
|
1114
|
+
content: { type: "text", text: tr.content }
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
const rawOutput = asJsonObject(m.toolUseResult?.data);
|
|
1118
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1119
|
+
toolCallId: tr.toolUseId,
|
|
1120
|
+
status,
|
|
1121
|
+
...contentBlocks.length > 0 ? { content: contentBlocks } : {},
|
|
1122
|
+
...rawOutput ? { rawOutput } : {}
|
|
1123
|
+
});
|
|
1124
|
+
session.toolCalls.set(tr.toolUseId, {
|
|
1125
|
+
title,
|
|
1126
|
+
kind,
|
|
1127
|
+
status,
|
|
1128
|
+
rawInput: existing?.rawInput
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// apps/server/src/acp/agent/handlers/sessions.ts
|
|
1136
|
+
async function loadSessionDeps() {
|
|
1137
|
+
const [tools, ctx, systemPrompt, configuredMcpClients] = await Promise.all([
|
|
1138
|
+
getTools(),
|
|
1139
|
+
getSessionContext(),
|
|
1140
|
+
buildSystemPromptForSession({ disableSlashCommands: false }),
|
|
1141
|
+
getClients().catch(() => [])
|
|
1142
|
+
]);
|
|
1143
|
+
return {
|
|
1144
|
+
commands: [],
|
|
1145
|
+
tools,
|
|
1146
|
+
context: ctx,
|
|
1147
|
+
systemPrompt,
|
|
1148
|
+
configuredMcpClients
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
async function handleSessionNew(args) {
|
|
1152
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
1153
|
+
const cwd = typeof p.cwd === "string" ? p.cwd : "";
|
|
1154
|
+
if (!cwd) {
|
|
1155
|
+
throw new JsonRpcError(-32602, "Missing required param: cwd");
|
|
1156
|
+
}
|
|
1157
|
+
if (!isAbsolute2(cwd)) {
|
|
1158
|
+
throw new JsonRpcError(-32602, `cwd must be an absolute path: ${cwd}`);
|
|
1159
|
+
}
|
|
1160
|
+
setOriginalCwd(cwd);
|
|
1161
|
+
await setCwd(cwd);
|
|
1162
|
+
grantReadPermissionForOriginalDir();
|
|
1163
|
+
const mcpServers = Array.isArray(p.mcpServers) ? p.mcpServers : [];
|
|
1164
|
+
const { commands, tools, context, systemPrompt, configuredMcpClients } = await loadSessionDeps();
|
|
1165
|
+
const acpMcpClients = await connectAcpMcpServers(mcpServers);
|
|
1166
|
+
const mcpClients = mergeMcpClients(configuredMcpClients, acpMcpClients);
|
|
1167
|
+
const toolPermissionContext = loadToolPermissionContextFromDisk({
|
|
1168
|
+
projectDir: cwd,
|
|
1169
|
+
includeKodeProjectConfig: true,
|
|
1170
|
+
isBypassPermissionsModeAvailable: true
|
|
1171
|
+
});
|
|
1172
|
+
const sessionId = `sess_${nanoid()}`;
|
|
1173
|
+
const currentModeId = toolPermissionContext.mode;
|
|
1174
|
+
const session = {
|
|
1175
|
+
sessionId,
|
|
1176
|
+
cwd,
|
|
1177
|
+
mcpServers,
|
|
1178
|
+
mcpClients,
|
|
1179
|
+
commands,
|
|
1180
|
+
tools,
|
|
1181
|
+
systemPrompt,
|
|
1182
|
+
context,
|
|
1183
|
+
messages: [],
|
|
1184
|
+
toolPermissionContext,
|
|
1185
|
+
readFileTimestamps: {},
|
|
1186
|
+
responseState: {},
|
|
1187
|
+
currentModeId,
|
|
1188
|
+
activeAbortController: null,
|
|
1189
|
+
toolCalls: /* @__PURE__ */ new Map()
|
|
1190
|
+
};
|
|
1191
|
+
args.sessions.set(sessionId, session);
|
|
1192
|
+
sendAvailableCommands(args.peer, session);
|
|
1193
|
+
sendCurrentMode(args.peer, session);
|
|
1194
|
+
persistAcpSessionToDisk(session);
|
|
1195
|
+
return {
|
|
1196
|
+
sessionId,
|
|
1197
|
+
modes: getModeState(session.currentModeId)
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
async function handleSessionLoad(args) {
|
|
1201
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
1202
|
+
const sessionId = typeof p.sessionId === "string" ? p.sessionId : "";
|
|
1203
|
+
const cwd = typeof p.cwd === "string" ? p.cwd : "";
|
|
1204
|
+
if (!sessionId)
|
|
1205
|
+
throw new JsonRpcError(-32602, "Missing required param: sessionId");
|
|
1206
|
+
if (!cwd) throw new JsonRpcError(-32602, "Missing required param: cwd");
|
|
1207
|
+
if (!isAbsolute2(cwd)) {
|
|
1208
|
+
throw new JsonRpcError(-32602, `cwd must be an absolute path: ${cwd}`);
|
|
1209
|
+
}
|
|
1210
|
+
setOriginalCwd(cwd);
|
|
1211
|
+
await setCwd(cwd);
|
|
1212
|
+
grantReadPermissionForOriginalDir();
|
|
1213
|
+
const persisted = loadAcpSessionFromDisk(cwd, sessionId);
|
|
1214
|
+
if (!persisted) {
|
|
1215
|
+
throw new JsonRpcError(-32602, `Session not found: ${sessionId}`);
|
|
1216
|
+
}
|
|
1217
|
+
const mcpServers = Array.isArray(p.mcpServers) ? p.mcpServers : [];
|
|
1218
|
+
const { commands, tools, context, systemPrompt, configuredMcpClients } = await loadSessionDeps();
|
|
1219
|
+
const acpMcpClients = await connectAcpMcpServers(mcpServers);
|
|
1220
|
+
const mcpClients = mergeMcpClients(configuredMcpClients, acpMcpClients);
|
|
1221
|
+
const toolPermissionContext = loadToolPermissionContextFromDisk({
|
|
1222
|
+
projectDir: cwd,
|
|
1223
|
+
includeKodeProjectConfig: true,
|
|
1224
|
+
isBypassPermissionsModeAvailable: true
|
|
1225
|
+
});
|
|
1226
|
+
const currentModeId = coercePermissionMode(
|
|
1227
|
+
typeof persisted.currentModeId === "string" && persisted.currentModeId ? persisted.currentModeId : toolPermissionContext.mode
|
|
1228
|
+
);
|
|
1229
|
+
toolPermissionContext.mode = currentModeId;
|
|
1230
|
+
const session = {
|
|
1231
|
+
sessionId,
|
|
1232
|
+
cwd,
|
|
1233
|
+
mcpServers,
|
|
1234
|
+
mcpClients,
|
|
1235
|
+
commands,
|
|
1236
|
+
tools,
|
|
1237
|
+
systemPrompt,
|
|
1238
|
+
context,
|
|
1239
|
+
messages: Array.isArray(persisted.messages) ? persisted.messages : [],
|
|
1240
|
+
toolPermissionContext,
|
|
1241
|
+
readFileTimestamps: isRecord(persisted.readFileTimestamps) ? persisted.readFileTimestamps : {},
|
|
1242
|
+
responseState: isRecord(persisted.responseState) ? persisted.responseState : {},
|
|
1243
|
+
currentModeId,
|
|
1244
|
+
activeAbortController: null,
|
|
1245
|
+
toolCalls: /* @__PURE__ */ new Map()
|
|
1246
|
+
};
|
|
1247
|
+
args.sessions.set(sessionId, session);
|
|
1248
|
+
sendAvailableCommands(args.peer, session);
|
|
1249
|
+
sendCurrentMode(args.peer, session);
|
|
1250
|
+
replayConversation(args.peer, session);
|
|
1251
|
+
return { modes: getModeState(session.currentModeId) };
|
|
1252
|
+
}
|
|
1253
|
+
async function handleSessionSetMode(args) {
|
|
1254
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
1255
|
+
const sessionId = typeof p.sessionId === "string" ? p.sessionId : "";
|
|
1256
|
+
const modeId = typeof p.modeId === "string" ? p.modeId : "";
|
|
1257
|
+
const session = args.sessions.get(sessionId);
|
|
1258
|
+
if (!session)
|
|
1259
|
+
throw new JsonRpcError(-32602, `Session not found: ${sessionId}`);
|
|
1260
|
+
const allowed = new Set(
|
|
1261
|
+
getModeState(session.currentModeId).availableModes.map((m) => m.id)
|
|
1262
|
+
);
|
|
1263
|
+
if (!allowed.has(modeId)) {
|
|
1264
|
+
throw new JsonRpcError(-32602, `Unknown modeId: ${modeId}`);
|
|
1265
|
+
}
|
|
1266
|
+
const nextMode = coercePermissionMode(modeId);
|
|
1267
|
+
session.currentModeId = nextMode;
|
|
1268
|
+
session.toolPermissionContext.mode = nextMode;
|
|
1269
|
+
sendCurrentMode(args.peer, session);
|
|
1270
|
+
persistAcpSessionToDisk(session);
|
|
1271
|
+
return {};
|
|
1272
|
+
}
|
|
1273
|
+
async function handleSessionCancel(args) {
|
|
1274
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
1275
|
+
const sessionId = typeof p.sessionId === "string" ? p.sessionId : "";
|
|
1276
|
+
const session = args.sessions.get(sessionId);
|
|
1277
|
+
if (!session) return;
|
|
1278
|
+
session.activeAbortController?.abort();
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// apps/server/src/acp/agent/handlers/prompt.ts
|
|
1282
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
1283
|
+
|
|
1284
|
+
// apps/server/src/acp/agent/permissions.ts
|
|
1285
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
1286
|
+
function getPermissionTimeoutMs() {
|
|
1287
|
+
const raw = process.env.KODE_ACP_PERMISSION_TIMEOUT_MS;
|
|
1288
|
+
const parsed = raw ? Number(raw) : Number.NaN;
|
|
1289
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 3e4;
|
|
1290
|
+
}
|
|
1291
|
+
function toPermissionOptions(denied) {
|
|
1292
|
+
const options = [
|
|
1293
|
+
{ optionId: "allow_once", name: "Allow once", kind: "allow_once" },
|
|
1294
|
+
{ optionId: "reject_once", name: "Reject", kind: "reject_once" }
|
|
1295
|
+
];
|
|
1296
|
+
if ((denied.suggestions ?? []).length > 0) {
|
|
1297
|
+
options.splice(1, 0, {
|
|
1298
|
+
optionId: "allow_always",
|
|
1299
|
+
name: "Allow always (remember)",
|
|
1300
|
+
kind: "allow_always"
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
return options;
|
|
1304
|
+
}
|
|
1305
|
+
function createAcpCanUseTool(args) {
|
|
1306
|
+
const timeoutMs = getPermissionTimeoutMs();
|
|
1307
|
+
const { peer, session } = args;
|
|
1308
|
+
return async (tool, input, toolUseContext, assistantMessage) => {
|
|
1309
|
+
const toolUseId = typeof toolUseContext.toolUseId === "string" && toolUseContext.toolUseId ? toolUseContext.toolUseId : `call_${nanoid2()}`;
|
|
1310
|
+
const base = await hasPermissionsToUseTool(
|
|
1311
|
+
tool,
|
|
1312
|
+
input,
|
|
1313
|
+
toolUseContext,
|
|
1314
|
+
assistantMessage
|
|
1315
|
+
);
|
|
1316
|
+
if (base.result === true) {
|
|
1317
|
+
captureFileSnapshotForTool({
|
|
1318
|
+
session,
|
|
1319
|
+
toolUseId,
|
|
1320
|
+
toolName: tool.name,
|
|
1321
|
+
input
|
|
1322
|
+
});
|
|
1323
|
+
return base;
|
|
1324
|
+
}
|
|
1325
|
+
const denied = base;
|
|
1326
|
+
if (denied.shouldPromptUser === false) {
|
|
1327
|
+
return { result: false, message: denied.message };
|
|
1328
|
+
}
|
|
1329
|
+
const title = titleForToolCall(tool.name, input);
|
|
1330
|
+
const kind = toolKindForName(tool.name);
|
|
1331
|
+
if (!session.toolCalls.has(toolUseId)) {
|
|
1332
|
+
session.toolCalls.set(toolUseId, {
|
|
1333
|
+
title,
|
|
1334
|
+
kind,
|
|
1335
|
+
status: "pending",
|
|
1336
|
+
rawInput: asJsonObject(input)
|
|
1337
|
+
});
|
|
1338
|
+
sendToolCall(peer, session.sessionId, {
|
|
1339
|
+
sessionUpdate: "tool_call",
|
|
1340
|
+
toolCallId: toolUseId,
|
|
1341
|
+
title,
|
|
1342
|
+
kind,
|
|
1343
|
+
status: "pending",
|
|
1344
|
+
rawInput: asJsonObject(input)
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
const options = toPermissionOptions(denied);
|
|
1348
|
+
try {
|
|
1349
|
+
const response = await peer.sendRequest({
|
|
1350
|
+
method: "session/request_permission",
|
|
1351
|
+
params: {
|
|
1352
|
+
sessionId: session.sessionId,
|
|
1353
|
+
toolCall: {
|
|
1354
|
+
toolCallId: toolUseId,
|
|
1355
|
+
title,
|
|
1356
|
+
kind,
|
|
1357
|
+
status: "pending",
|
|
1358
|
+
content: [
|
|
1359
|
+
{
|
|
1360
|
+
type: "content",
|
|
1361
|
+
content: { type: "text", text: denied.message }
|
|
1362
|
+
}
|
|
1363
|
+
],
|
|
1364
|
+
rawInput: asJsonObject(input)
|
|
1365
|
+
},
|
|
1366
|
+
options
|
|
1367
|
+
},
|
|
1368
|
+
signal: toolUseContext.abortController.signal,
|
|
1369
|
+
timeoutMs
|
|
1370
|
+
});
|
|
1371
|
+
const outcome = response?.outcome;
|
|
1372
|
+
if (!outcome || outcome.outcome === "cancelled") {
|
|
1373
|
+
toolUseContext.abortController.abort();
|
|
1374
|
+
return {
|
|
1375
|
+
result: false,
|
|
1376
|
+
message: denied.message,
|
|
1377
|
+
shouldPromptUser: false
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
if (outcome.outcome === "selected" && outcome.optionId === "allow_once") {
|
|
1381
|
+
captureFileSnapshotForTool({
|
|
1382
|
+
session,
|
|
1383
|
+
toolUseId,
|
|
1384
|
+
toolName: tool.name,
|
|
1385
|
+
input
|
|
1386
|
+
});
|
|
1387
|
+
return { result: true };
|
|
1388
|
+
}
|
|
1389
|
+
if (outcome.outcome === "selected" && outcome.optionId === "allow_always") {
|
|
1390
|
+
const suggestions = denied.suggestions ?? [];
|
|
1391
|
+
if (suggestions.length > 0) {
|
|
1392
|
+
const next = applyToolPermissionContextUpdates(
|
|
1393
|
+
session.toolPermissionContext,
|
|
1394
|
+
suggestions
|
|
1395
|
+
);
|
|
1396
|
+
session.toolPermissionContext = next;
|
|
1397
|
+
if (toolUseContext.options)
|
|
1398
|
+
toolUseContext.options.toolPermissionContext = next;
|
|
1399
|
+
for (const update of suggestions) {
|
|
1400
|
+
try {
|
|
1401
|
+
persistToolPermissionUpdateToDisk({
|
|
1402
|
+
update,
|
|
1403
|
+
projectDir: session.cwd
|
|
1404
|
+
});
|
|
1405
|
+
} catch (e) {
|
|
1406
|
+
logError(e);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
captureFileSnapshotForTool({
|
|
1411
|
+
session,
|
|
1412
|
+
toolUseId,
|
|
1413
|
+
toolName: tool.name,
|
|
1414
|
+
input
|
|
1415
|
+
});
|
|
1416
|
+
return { result: true };
|
|
1417
|
+
}
|
|
1418
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1419
|
+
toolCallId: toolUseId,
|
|
1420
|
+
status: "failed"
|
|
1421
|
+
});
|
|
1422
|
+
return { result: false, message: denied.message };
|
|
1423
|
+
} catch (e) {
|
|
1424
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1425
|
+
sendToolCallUpdate(peer, session.sessionId, {
|
|
1426
|
+
toolCallId: toolUseId,
|
|
1427
|
+
status: "failed"
|
|
1428
|
+
});
|
|
1429
|
+
return {
|
|
1430
|
+
result: false,
|
|
1431
|
+
message: `Permission prompt failed: ${msg}`,
|
|
1432
|
+
shouldPromptUser: false
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// apps/server/src/acp/agent/handlers/prompt.ts
|
|
1439
|
+
async function handleSessionPrompt(args) {
|
|
1440
|
+
const p = isRecord(args.params) ? args.params : {};
|
|
1441
|
+
const sessionId = typeof p.sessionId === "string" ? p.sessionId : "";
|
|
1442
|
+
const blocks = Array.isArray(p.prompt) ? p.prompt : Array.isArray(p.content) ? p.content : [];
|
|
1443
|
+
const session = args.sessions.get(sessionId);
|
|
1444
|
+
if (!session)
|
|
1445
|
+
throw new JsonRpcError(-32602, `Session not found: ${sessionId}`);
|
|
1446
|
+
if (session.activeAbortController) {
|
|
1447
|
+
throw new JsonRpcError(
|
|
1448
|
+
-32e3,
|
|
1449
|
+
`Session already has an active prompt: ${sessionId}`
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
if (!session.cwd || !isAbsolute3(session.cwd)) {
|
|
1453
|
+
throw new JsonRpcError(-32602, `Invalid session cwd: ${session.cwd}`);
|
|
1454
|
+
}
|
|
1455
|
+
setOriginalCwd(session.cwd);
|
|
1456
|
+
await setCwd(session.cwd);
|
|
1457
|
+
grantReadPermissionForOriginalDir();
|
|
1458
|
+
const promptText = blocksToText(blocks);
|
|
1459
|
+
const userMsg = createUserMessage(promptText);
|
|
1460
|
+
const baseMessages = [...session.messages, userMsg];
|
|
1461
|
+
session.messages.push(userMsg);
|
|
1462
|
+
if (process.env.KODE_ACP_ECHO === "1") {
|
|
1463
|
+
await handleKodeMessage({
|
|
1464
|
+
peer: args.peer,
|
|
1465
|
+
session,
|
|
1466
|
+
message: createAssistantMessage(promptText)
|
|
1467
|
+
});
|
|
1468
|
+
persistAcpSessionToDisk(session);
|
|
1469
|
+
return { stopReason: "end_turn" };
|
|
1470
|
+
}
|
|
1471
|
+
const abortController = new AbortController();
|
|
1472
|
+
session.activeAbortController = abortController;
|
|
1473
|
+
const canUseTool = createAcpCanUseTool({ peer: args.peer, session });
|
|
1474
|
+
const options = {
|
|
1475
|
+
commands: session.commands,
|
|
1476
|
+
tools: session.tools,
|
|
1477
|
+
verbose: false,
|
|
1478
|
+
safeMode: false,
|
|
1479
|
+
forkNumber: 0,
|
|
1480
|
+
messageLogName: session.sessionId,
|
|
1481
|
+
maxThinkingTokens: 0,
|
|
1482
|
+
persistSession: false,
|
|
1483
|
+
toolPermissionContext: session.toolPermissionContext,
|
|
1484
|
+
mcpClients: session.mcpClients,
|
|
1485
|
+
shouldAvoidPermissionPrompts: false
|
|
1486
|
+
};
|
|
1487
|
+
let stopReason = "end_turn";
|
|
1488
|
+
try {
|
|
1489
|
+
for await (const m of runTurn({
|
|
1490
|
+
messages: baseMessages,
|
|
1491
|
+
systemPrompt: session.systemPrompt,
|
|
1492
|
+
context: session.context,
|
|
1493
|
+
canUseTool,
|
|
1494
|
+
toolUseContext: {
|
|
1495
|
+
options,
|
|
1496
|
+
abortController,
|
|
1497
|
+
messageId: void 0,
|
|
1498
|
+
readFileTimestamps: session.readFileTimestamps,
|
|
1499
|
+
setToolJSX: () => {
|
|
1500
|
+
},
|
|
1501
|
+
agentId: "main",
|
|
1502
|
+
responseState: session.responseState
|
|
1503
|
+
}
|
|
1504
|
+
})) {
|
|
1505
|
+
if (abortController.signal.aborted) stopReason = "cancelled";
|
|
1506
|
+
await handleKodeMessage({ peer: args.peer, session, message: m });
|
|
1507
|
+
}
|
|
1508
|
+
if (abortController.signal.aborted) stopReason = "cancelled";
|
|
1509
|
+
} catch (err) {
|
|
1510
|
+
if (abortController.signal.aborted) {
|
|
1511
|
+
stopReason = "cancelled";
|
|
1512
|
+
} else {
|
|
1513
|
+
logError(err);
|
|
1514
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1515
|
+
sendAgentMessageChunk(args.peer, session.sessionId, msg);
|
|
1516
|
+
stopReason = "end_turn";
|
|
1517
|
+
}
|
|
1518
|
+
} finally {
|
|
1519
|
+
session.activeAbortController = null;
|
|
1520
|
+
persistAcpSessionToDisk(session);
|
|
1521
|
+
}
|
|
1522
|
+
return { stopReason };
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// apps/server/src/acp/kodeAcpAgent.ts
|
|
1526
|
+
var KodeAcpAgent = class {
|
|
1527
|
+
constructor(peer) {
|
|
1528
|
+
this.peer = peer;
|
|
1529
|
+
this.registerMethods();
|
|
1530
|
+
}
|
|
1531
|
+
clientCapabilities = {};
|
|
1532
|
+
sessions = /* @__PURE__ */ new Map();
|
|
1533
|
+
registerMethods() {
|
|
1534
|
+
this.peer.registerMethod("initialize", this.onInitialize.bind(this));
|
|
1535
|
+
this.peer.registerMethod("authenticate", this.onAuthenticate.bind(this));
|
|
1536
|
+
this.peer.registerMethod("session/new", this.onSessionNew.bind(this));
|
|
1537
|
+
this.peer.registerMethod("session/load", this.onSessionLoad.bind(this));
|
|
1538
|
+
this.peer.registerMethod("session/prompt", this.onSessionPrompt.bind(this));
|
|
1539
|
+
this.peer.registerMethod(
|
|
1540
|
+
"session/set_mode",
|
|
1541
|
+
this.onSessionSetMode.bind(this)
|
|
1542
|
+
);
|
|
1543
|
+
this.peer.registerMethod("session/cancel", this.onSessionCancel.bind(this));
|
|
1544
|
+
}
|
|
1545
|
+
onInitialize(params) {
|
|
1546
|
+
return handleInitialize({
|
|
1547
|
+
params,
|
|
1548
|
+
setClientCapabilities: (caps) => {
|
|
1549
|
+
this.clientCapabilities = caps;
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
onAuthenticate() {
|
|
1554
|
+
return handleAuthenticate();
|
|
1555
|
+
}
|
|
1556
|
+
onSessionNew(params) {
|
|
1557
|
+
return handleSessionNew({
|
|
1558
|
+
peer: this.peer,
|
|
1559
|
+
sessions: this.sessions,
|
|
1560
|
+
params
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
onSessionLoad(params) {
|
|
1564
|
+
return handleSessionLoad({
|
|
1565
|
+
peer: this.peer,
|
|
1566
|
+
sessions: this.sessions,
|
|
1567
|
+
params
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
onSessionSetMode(params) {
|
|
1571
|
+
return handleSessionSetMode({
|
|
1572
|
+
peer: this.peer,
|
|
1573
|
+
sessions: this.sessions,
|
|
1574
|
+
params
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
onSessionCancel(params) {
|
|
1578
|
+
return handleSessionCancel({ sessions: this.sessions, params });
|
|
1579
|
+
}
|
|
1580
|
+
onSessionPrompt(params) {
|
|
1581
|
+
return handleSessionPrompt({
|
|
1582
|
+
peer: this.peer,
|
|
1583
|
+
sessions: this.sessions,
|
|
1584
|
+
params
|
|
1585
|
+
});
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1589
|
+
// apps/server/src/acp/runAcpStdio.ts
|
|
1590
|
+
function runAcpStdio() {
|
|
1591
|
+
const { writeAcpLine } = installStdoutGuard();
|
|
1592
|
+
initDebugLogger();
|
|
1593
|
+
try {
|
|
1594
|
+
enableConfigs();
|
|
1595
|
+
} catch (error) {
|
|
1596
|
+
logError(error);
|
|
1597
|
+
}
|
|
1598
|
+
const peer = new JsonRpcPeer();
|
|
1599
|
+
new KodeAcpAgent(peer);
|
|
1600
|
+
const transport = new StdioTransport(peer, { writeLine: writeAcpLine });
|
|
1601
|
+
transport.start();
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// apps/server/src/index.ts
|
|
1605
|
+
ensurePackagedRuntimeEnv();
|
|
1606
|
+
if (process.argv.includes("--acp")) {
|
|
1607
|
+
runAcpStdio();
|
|
1608
|
+
} else {
|
|
1609
|
+
let getArgValue = function(flag) {
|
|
1610
|
+
const idx = process.argv.indexOf(flag);
|
|
1611
|
+
if (idx >= 0) {
|
|
1612
|
+
const v = process.argv[idx + 1];
|
|
1613
|
+
if (typeof v === "string") return v;
|
|
1614
|
+
}
|
|
1615
|
+
const withEq = process.argv.find((a) => a.startsWith(flag + "="));
|
|
1616
|
+
if (withEq) return withEq.slice(flag.length + 1);
|
|
1617
|
+
return null;
|
|
1618
|
+
};
|
|
1619
|
+
initDebugLogger();
|
|
1620
|
+
try {
|
|
1621
|
+
enableConfigs();
|
|
1622
|
+
} catch (e) {
|
|
1623
|
+
logError(e);
|
|
1624
|
+
}
|
|
1625
|
+
const host = getArgValue("--host") ?? process.env.KODE_DAEMON_HOST ?? "127.0.0.1";
|
|
1626
|
+
const portRaw = getArgValue("--port") ?? process.env.KODE_DAEMON_PORT ?? "";
|
|
1627
|
+
const port = portRaw ? Number(portRaw) : 0;
|
|
1628
|
+
const cwd = getArgValue("--cwd") ?? process.env.KODE_DAEMON_CWD ?? processCwd();
|
|
1629
|
+
const token = getArgValue("--token") ?? process.env.KODE_DAEMON_TOKEN ?? void 0;
|
|
1630
|
+
const echo = process.argv.includes("--echo") || process.env.KODE_DAEMON_ECHO === "1";
|
|
1631
|
+
const daemon = await startKodeDaemon({
|
|
1632
|
+
host,
|
|
1633
|
+
port: Number.isFinite(port) ? port : 0,
|
|
1634
|
+
cwd,
|
|
1635
|
+
token,
|
|
1636
|
+
echo
|
|
1637
|
+
});
|
|
1638
|
+
console.log(daemon.url);
|
|
1639
|
+
process.on("SIGINT", () => {
|
|
1640
|
+
daemon.stop();
|
|
1641
|
+
process.exit(0);
|
|
1642
|
+
});
|
|
1643
|
+
process.on("SIGTERM", () => {
|
|
1644
|
+
daemon.stop();
|
|
1645
|
+
process.exit(0);
|
|
1646
|
+
});
|
|
1647
|
+
}
|