@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,1409 @@
|
|
|
1
|
+
// packages/runtime/src/shell/BunShell.ts
|
|
2
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3
|
+
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "path";
|
|
4
|
+
|
|
5
|
+
// packages/runtime/src/shell/state.ts
|
|
6
|
+
function createInitialState(cwd) {
|
|
7
|
+
return {
|
|
8
|
+
cwd,
|
|
9
|
+
isAlive: true,
|
|
10
|
+
currentProcess: null,
|
|
11
|
+
abortController: null,
|
|
12
|
+
backgroundProcesses: /* @__PURE__ */ new Map()
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// packages/runtime/src/shell/exec.ts
|
|
17
|
+
import { spawn } from "node:child_process";
|
|
18
|
+
|
|
19
|
+
// packages/runtime/src/shell/sandboxCommand.ts
|
|
20
|
+
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
21
|
+
import which from "which";
|
|
22
|
+
|
|
23
|
+
// packages/runtime/src/shell/linuxSandbox.ts
|
|
24
|
+
import { existsSync, realpathSync, statSync } from "fs";
|
|
25
|
+
import { homedir } from "os";
|
|
26
|
+
import { dirname, isAbsolute, resolve } from "path";
|
|
27
|
+
function hasGlobPattern(value) {
|
|
28
|
+
return value.includes("*") || value.includes("?") || value.includes("[") || value.includes("]");
|
|
29
|
+
}
|
|
30
|
+
function normalizeLinuxSandboxPath(input, options) {
|
|
31
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
32
|
+
const homeDir = options?.homeDir ?? homedir();
|
|
33
|
+
let resolved = input;
|
|
34
|
+
if (input === "~") resolved = homeDir;
|
|
35
|
+
else if (input.startsWith("~/")) resolved = homeDir + input.slice(1);
|
|
36
|
+
else if (input.startsWith("./") || input.startsWith("../"))
|
|
37
|
+
resolved = resolve(cwd, input);
|
|
38
|
+
else if (!isAbsolute(input)) resolved = resolve(cwd, input);
|
|
39
|
+
if (hasGlobPattern(resolved)) {
|
|
40
|
+
const prefix = resolved.split(/[*?[\]]/)[0];
|
|
41
|
+
if (prefix && prefix !== "/") {
|
|
42
|
+
const dir = prefix.endsWith("/") ? prefix.slice(0, -1) : dirname(prefix);
|
|
43
|
+
try {
|
|
44
|
+
const real = realpathSync(dir);
|
|
45
|
+
const suffix = resolved.slice(dir.length);
|
|
46
|
+
return real + suffix;
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return resolved;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
resolved = realpathSync(resolved);
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
return resolved;
|
|
57
|
+
}
|
|
58
|
+
function buildLinuxBwrapFilesystemArgs(options) {
|
|
59
|
+
const cwd = options.cwd ?? process.cwd();
|
|
60
|
+
const homeDir = options.homeDir ?? homedir();
|
|
61
|
+
const args = [];
|
|
62
|
+
const writeConfig = options.writeConfig;
|
|
63
|
+
if (writeConfig) {
|
|
64
|
+
args.push("--ro-bind", "/", "/");
|
|
65
|
+
const allowedRoots = [];
|
|
66
|
+
if (existsSync("/tmp/kode")) {
|
|
67
|
+
args.push("--bind", "/tmp/kode", "/tmp/kode");
|
|
68
|
+
allowedRoots.push("/tmp/kode");
|
|
69
|
+
}
|
|
70
|
+
for (const raw of writeConfig.allowOnly ?? []) {
|
|
71
|
+
const resolved = normalizeLinuxSandboxPath(raw, { cwd, homeDir });
|
|
72
|
+
if (resolved.startsWith("/dev/")) continue;
|
|
73
|
+
if (!existsSync(resolved)) continue;
|
|
74
|
+
args.push("--bind", resolved, resolved);
|
|
75
|
+
allowedRoots.push(resolved);
|
|
76
|
+
}
|
|
77
|
+
const denyWithinAllow = [
|
|
78
|
+
...writeConfig.denyWithinAllow ?? [],
|
|
79
|
+
...options.extraDenyWithinAllow ?? []
|
|
80
|
+
];
|
|
81
|
+
for (const raw of denyWithinAllow) {
|
|
82
|
+
const resolved = normalizeLinuxSandboxPath(raw, { cwd, homeDir });
|
|
83
|
+
if (resolved.startsWith("/dev/")) continue;
|
|
84
|
+
if (!existsSync(resolved)) continue;
|
|
85
|
+
const withinAllowed = allowedRoots.some(
|
|
86
|
+
(root) => resolved === root || resolved.startsWith(root + "/")
|
|
87
|
+
);
|
|
88
|
+
if (!withinAllowed) continue;
|
|
89
|
+
args.push("--ro-bind", resolved, resolved);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
args.push("--bind", "/", "/");
|
|
93
|
+
}
|
|
94
|
+
const denyRead = [...options.readConfig?.denyOnly ?? []];
|
|
95
|
+
if (existsSync("/etc/ssh/ssh_config.d"))
|
|
96
|
+
denyRead.push("/etc/ssh/ssh_config.d");
|
|
97
|
+
for (const raw of denyRead) {
|
|
98
|
+
const resolved = normalizeLinuxSandboxPath(raw, { cwd, homeDir });
|
|
99
|
+
if (resolved.startsWith("/dev/")) continue;
|
|
100
|
+
if (!existsSync(resolved)) continue;
|
|
101
|
+
if (statSync(resolved).isDirectory()) args.push("--tmpfs", resolved);
|
|
102
|
+
else args.push("--ro-bind", "/dev/null", resolved);
|
|
103
|
+
}
|
|
104
|
+
return args;
|
|
105
|
+
}
|
|
106
|
+
function buildLinuxBwrapCommand(options) {
|
|
107
|
+
const args = [];
|
|
108
|
+
args.push(
|
|
109
|
+
"--die-with-parent",
|
|
110
|
+
"--new-session",
|
|
111
|
+
"--unshare-pid",
|
|
112
|
+
"--unshare-uts",
|
|
113
|
+
"--unshare-ipc"
|
|
114
|
+
);
|
|
115
|
+
if (options.needsNetworkRestriction) args.push("--unshare-net");
|
|
116
|
+
args.push(
|
|
117
|
+
...buildLinuxBwrapFilesystemArgs({
|
|
118
|
+
cwd: options.cwd,
|
|
119
|
+
homeDir: options.homeDir,
|
|
120
|
+
readConfig: options.readConfig,
|
|
121
|
+
writeConfig: options.writeConfig
|
|
122
|
+
})
|
|
123
|
+
);
|
|
124
|
+
args.push(
|
|
125
|
+
"--dev",
|
|
126
|
+
"/dev",
|
|
127
|
+
"--setenv",
|
|
128
|
+
"SANDBOX_RUNTIME",
|
|
129
|
+
"1",
|
|
130
|
+
"--setenv",
|
|
131
|
+
"TMPDIR",
|
|
132
|
+
"/tmp/kode"
|
|
133
|
+
);
|
|
134
|
+
if (!options.enableWeakerNestedSandbox) args.push("--proc", "/proc");
|
|
135
|
+
args.push("--", options.binShellPath, "-c", options.command);
|
|
136
|
+
return [options.bwrapPath, ...args];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// packages/runtime/src/shell/macosSandbox.ts
|
|
140
|
+
import { dirname as dirname2 } from "path";
|
|
141
|
+
function buildSandboxEnvAssignments(options) {
|
|
142
|
+
const httpProxyPort = options?.httpProxyPort;
|
|
143
|
+
const socksProxyPort = options?.socksProxyPort;
|
|
144
|
+
const platform = options?.platform ?? process.platform;
|
|
145
|
+
const env = ["SANDBOX_RUNTIME=1", "TMPDIR=/tmp/kode"];
|
|
146
|
+
if (!httpProxyPort && !socksProxyPort) return env;
|
|
147
|
+
const noProxy = [
|
|
148
|
+
"localhost",
|
|
149
|
+
"127.0.0.1",
|
|
150
|
+
"::1",
|
|
151
|
+
"*.local",
|
|
152
|
+
".local",
|
|
153
|
+
"169.254.0.0/16",
|
|
154
|
+
"10.0.0.0/8",
|
|
155
|
+
"172.16.0.0/12",
|
|
156
|
+
"192.168.0.0/16"
|
|
157
|
+
].join(",");
|
|
158
|
+
env.push(`NO_PROXY=${noProxy}`);
|
|
159
|
+
env.push(`no_proxy=${noProxy}`);
|
|
160
|
+
if (httpProxyPort) {
|
|
161
|
+
env.push(`HTTP_PROXY=http://localhost:${httpProxyPort}`);
|
|
162
|
+
env.push(`HTTPS_PROXY=http://localhost:${httpProxyPort}`);
|
|
163
|
+
env.push(`http_proxy=http://localhost:${httpProxyPort}`);
|
|
164
|
+
env.push(`https_proxy=http://localhost:${httpProxyPort}`);
|
|
165
|
+
}
|
|
166
|
+
if (socksProxyPort) {
|
|
167
|
+
env.push(`ALL_PROXY=socks5h://localhost:${socksProxyPort}`);
|
|
168
|
+
env.push(`all_proxy=socks5h://localhost:${socksProxyPort}`);
|
|
169
|
+
if (platform === "darwin") {
|
|
170
|
+
env.push(
|
|
171
|
+
`GIT_SSH_COMMAND="ssh -o ProxyCommand='nc -X 5 -x localhost:${socksProxyPort} %h %p'"`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
env.push(`FTP_PROXY=socks5h://localhost:${socksProxyPort}`);
|
|
175
|
+
env.push(`ftp_proxy=socks5h://localhost:${socksProxyPort}`);
|
|
176
|
+
env.push(`RSYNC_PROXY=localhost:${socksProxyPort}`);
|
|
177
|
+
env.push(
|
|
178
|
+
`DOCKER_HTTP_PROXY=http://localhost:${httpProxyPort || socksProxyPort}`
|
|
179
|
+
);
|
|
180
|
+
env.push(
|
|
181
|
+
`DOCKER_HTTPS_PROXY=http://localhost:${httpProxyPort || socksProxyPort}`
|
|
182
|
+
);
|
|
183
|
+
if (httpProxyPort) {
|
|
184
|
+
env.push("CLOUDSDK_PROXY_TYPE=https");
|
|
185
|
+
env.push("CLOUDSDK_PROXY_ADDRESS=localhost");
|
|
186
|
+
env.push(`CLOUDSDK_PROXY_PORT=${httpProxyPort}`);
|
|
187
|
+
}
|
|
188
|
+
env.push(`GRPC_PROXY=socks5h://localhost:${socksProxyPort}`);
|
|
189
|
+
env.push(`grpc_proxy=socks5h://localhost:${socksProxyPort}`);
|
|
190
|
+
}
|
|
191
|
+
return env;
|
|
192
|
+
}
|
|
193
|
+
function escapeRegexForSandboxGlobPattern(pattern) {
|
|
194
|
+
return "^" + pattern.replace(/[.^$+{}()|\\]/g, "\\$&").replace(/\[([^\]]*?)$/g, "\\[$1").replace(/\*\*\//g, "__GLOBSTAR_SLASH__").replace(/\*\*/g, "__GLOBSTAR__").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/__GLOBSTAR_SLASH__/g, "(.*/)?").replace(/__GLOBSTAR__/g, ".*") + "$";
|
|
195
|
+
}
|
|
196
|
+
function getMacosTmpDirWriteAllowPaths() {
|
|
197
|
+
const tmpdirValue = process.env.TMPDIR;
|
|
198
|
+
if (!tmpdirValue) return [];
|
|
199
|
+
if (!tmpdirValue.match(/^\/(private\/)?var\/folders\/[^/]{2}\/[^/]+\/T\/?$/))
|
|
200
|
+
return [];
|
|
201
|
+
const base = tmpdirValue.replace(/\/T\/?$/, "");
|
|
202
|
+
if (base.startsWith("/private/var/"))
|
|
203
|
+
return [base, base.replace("/private", "")];
|
|
204
|
+
if (base.startsWith("/var/")) return [base, "/private" + base];
|
|
205
|
+
return [base];
|
|
206
|
+
}
|
|
207
|
+
function buildMacosSandboxDenyUnlinkRules(paths, logTag) {
|
|
208
|
+
const lines = [];
|
|
209
|
+
for (const raw of paths) {
|
|
210
|
+
const normalized = normalizeLinuxSandboxPath(raw);
|
|
211
|
+
if (hasGlobPattern(normalized)) {
|
|
212
|
+
const regex = escapeRegexForSandboxGlobPattern(normalized);
|
|
213
|
+
lines.push(
|
|
214
|
+
"(deny file-write-unlink",
|
|
215
|
+
` (regex ${JSON.stringify(regex)})`,
|
|
216
|
+
` (with message "${logTag}"))`
|
|
217
|
+
);
|
|
218
|
+
const prefix = normalized.split(/[*?[\]]/)[0];
|
|
219
|
+
if (prefix && prefix !== "/") {
|
|
220
|
+
const literal = prefix.endsWith("/") ? prefix.slice(0, -1) : dirname2(prefix);
|
|
221
|
+
lines.push(
|
|
222
|
+
"(deny file-write-unlink",
|
|
223
|
+
` (literal ${JSON.stringify(literal)})`,
|
|
224
|
+
` (with message "${logTag}"))`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
lines.push(
|
|
230
|
+
"(deny file-write-unlink",
|
|
231
|
+
` (subpath ${JSON.stringify(normalized)})`,
|
|
232
|
+
` (with message "${logTag}"))`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return lines;
|
|
236
|
+
}
|
|
237
|
+
function buildMacosSandboxFileReadRules(readConfig, logTag) {
|
|
238
|
+
if (!readConfig) return ["(allow file-read*)"];
|
|
239
|
+
const lines = ["(allow file-read*)"];
|
|
240
|
+
for (const raw of readConfig.denyOnly ?? []) {
|
|
241
|
+
const normalized = normalizeLinuxSandboxPath(raw);
|
|
242
|
+
if (hasGlobPattern(normalized)) {
|
|
243
|
+
const regex = escapeRegexForSandboxGlobPattern(normalized);
|
|
244
|
+
lines.push(
|
|
245
|
+
"(deny file-read*",
|
|
246
|
+
` (regex ${JSON.stringify(regex)})`,
|
|
247
|
+
` (with message "${logTag}"))`
|
|
248
|
+
);
|
|
249
|
+
} else {
|
|
250
|
+
lines.push(
|
|
251
|
+
"(deny file-read*",
|
|
252
|
+
` (subpath ${JSON.stringify(normalized)})`,
|
|
253
|
+
` (with message "${logTag}"))`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
lines.push(
|
|
258
|
+
...buildMacosSandboxDenyUnlinkRules(readConfig.denyOnly ?? [], logTag)
|
|
259
|
+
);
|
|
260
|
+
return lines;
|
|
261
|
+
}
|
|
262
|
+
function buildMacosSandboxFileWriteRules(writeConfig, logTag) {
|
|
263
|
+
if (!writeConfig) return ["(allow file-write*)"];
|
|
264
|
+
const lines = [];
|
|
265
|
+
lines.push(
|
|
266
|
+
"(allow file-write*",
|
|
267
|
+
` (literal "/dev/null")`,
|
|
268
|
+
` (with message "${logTag}"))`
|
|
269
|
+
);
|
|
270
|
+
for (const raw of getMacosTmpDirWriteAllowPaths()) {
|
|
271
|
+
const normalized = normalizeLinuxSandboxPath(raw);
|
|
272
|
+
lines.push(
|
|
273
|
+
"(allow file-write*",
|
|
274
|
+
` (subpath ${JSON.stringify(normalized)})`,
|
|
275
|
+
` (with message "${logTag}"))`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
for (const raw of writeConfig.allowOnly ?? []) {
|
|
279
|
+
const normalized = normalizeLinuxSandboxPath(raw);
|
|
280
|
+
if (hasGlobPattern(normalized)) {
|
|
281
|
+
const regex = escapeRegexForSandboxGlobPattern(normalized);
|
|
282
|
+
lines.push(
|
|
283
|
+
"(allow file-write*",
|
|
284
|
+
` (regex ${JSON.stringify(regex)})`,
|
|
285
|
+
` (with message "${logTag}"))`
|
|
286
|
+
);
|
|
287
|
+
} else {
|
|
288
|
+
lines.push(
|
|
289
|
+
"(allow file-write*",
|
|
290
|
+
` (subpath ${JSON.stringify(normalized)})`,
|
|
291
|
+
` (with message "${logTag}"))`
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
for (const raw of writeConfig.denyWithinAllow ?? []) {
|
|
296
|
+
const normalized = normalizeLinuxSandboxPath(raw);
|
|
297
|
+
if (hasGlobPattern(normalized)) {
|
|
298
|
+
const regex = escapeRegexForSandboxGlobPattern(normalized);
|
|
299
|
+
lines.push(
|
|
300
|
+
"(deny file-write*",
|
|
301
|
+
` (regex ${JSON.stringify(regex)})`,
|
|
302
|
+
` (with message "${logTag}"))`
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
lines.push(
|
|
306
|
+
"(deny file-write*",
|
|
307
|
+
` (subpath ${JSON.stringify(normalized)})`,
|
|
308
|
+
` (with message "${logTag}"))`
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
lines.push(
|
|
313
|
+
...buildMacosSandboxDenyUnlinkRules(
|
|
314
|
+
writeConfig.denyWithinAllow ?? [],
|
|
315
|
+
logTag
|
|
316
|
+
)
|
|
317
|
+
);
|
|
318
|
+
return lines;
|
|
319
|
+
}
|
|
320
|
+
function buildMacosSandboxExecCommand(options) {
|
|
321
|
+
const logTag = "KODE_SANDBOX";
|
|
322
|
+
const profileLines = [
|
|
323
|
+
"(version 1)",
|
|
324
|
+
`(deny default (with message "${logTag}"))`,
|
|
325
|
+
"",
|
|
326
|
+
"; Kode sandbox-exec profile (reference CLI compatible)",
|
|
327
|
+
"",
|
|
328
|
+
// Keep this permissive enough for typical CLI tools (git, node, etc).
|
|
329
|
+
"(allow process*)",
|
|
330
|
+
"(allow sysctl-read)",
|
|
331
|
+
"(allow mach-lookup)",
|
|
332
|
+
"",
|
|
333
|
+
"; Network"
|
|
334
|
+
];
|
|
335
|
+
const allowUnixSockets = options.allowUnixSockets ?? [];
|
|
336
|
+
if (!options.needsNetworkRestriction) {
|
|
337
|
+
profileLines.push("(allow network*)");
|
|
338
|
+
} else {
|
|
339
|
+
if (options.allowLocalBinding) {
|
|
340
|
+
profileLines.push('(allow network-bind (local ip "localhost:*"))');
|
|
341
|
+
profileLines.push('(allow network-inbound (local ip "localhost:*"))');
|
|
342
|
+
profileLines.push('(allow network-outbound (local ip "localhost:*"))');
|
|
343
|
+
}
|
|
344
|
+
if (options.allowAllUnixSockets) {
|
|
345
|
+
profileLines.push('(allow network* (subpath "/"))');
|
|
346
|
+
} else if (allowUnixSockets.length > 0) {
|
|
347
|
+
for (const socketPath of allowUnixSockets) {
|
|
348
|
+
const normalized = normalizeLinuxSandboxPath(socketPath);
|
|
349
|
+
profileLines.push(
|
|
350
|
+
`(allow network* (subpath ${JSON.stringify(normalized)}))`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (options.httpProxyPort !== void 0) {
|
|
355
|
+
profileLines.push(
|
|
356
|
+
`(allow network-bind (local ip "localhost:${options.httpProxyPort}"))`
|
|
357
|
+
);
|
|
358
|
+
profileLines.push(
|
|
359
|
+
`(allow network-inbound (local ip "localhost:${options.httpProxyPort}"))`
|
|
360
|
+
);
|
|
361
|
+
profileLines.push(
|
|
362
|
+
`(allow network-outbound (remote ip "localhost:${options.httpProxyPort}"))`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
if (options.socksProxyPort !== void 0) {
|
|
366
|
+
profileLines.push(
|
|
367
|
+
`(allow network-bind (local ip "localhost:${options.socksProxyPort}"))`
|
|
368
|
+
);
|
|
369
|
+
profileLines.push(
|
|
370
|
+
`(allow network-inbound (local ip "localhost:${options.socksProxyPort}"))`
|
|
371
|
+
);
|
|
372
|
+
profileLines.push(
|
|
373
|
+
`(allow network-outbound (remote ip "localhost:${options.socksProxyPort}"))`
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
profileLines.push("");
|
|
378
|
+
profileLines.push("; File read");
|
|
379
|
+
profileLines.push(
|
|
380
|
+
...buildMacosSandboxFileReadRules(options.readConfig, logTag)
|
|
381
|
+
);
|
|
382
|
+
profileLines.push("");
|
|
383
|
+
profileLines.push("; File write");
|
|
384
|
+
profileLines.push(
|
|
385
|
+
...buildMacosSandboxFileWriteRules(options.writeConfig, logTag)
|
|
386
|
+
);
|
|
387
|
+
const profile = profileLines.join("\n");
|
|
388
|
+
const envAssignments = buildSandboxEnvAssignments({
|
|
389
|
+
httpProxyPort: options.httpProxyPort,
|
|
390
|
+
socksProxyPort: options.socksProxyPort,
|
|
391
|
+
platform: "darwin"
|
|
392
|
+
});
|
|
393
|
+
const envPrefix = envAssignments.length ? `export ${envAssignments.join(" ")} && ` : "";
|
|
394
|
+
return [
|
|
395
|
+
options.sandboxExecPath,
|
|
396
|
+
"-p",
|
|
397
|
+
profile,
|
|
398
|
+
options.binShellPath,
|
|
399
|
+
"-c",
|
|
400
|
+
`${envPrefix}${options.command}`
|
|
401
|
+
];
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// packages/runtime/src/shell/sandboxCommand.ts
|
|
405
|
+
function maybeAnnotateMacosSandboxStderr(stderr, sandbox) {
|
|
406
|
+
if (!stderr) return stderr;
|
|
407
|
+
if (!sandbox || sandbox.enabled !== true) return stderr;
|
|
408
|
+
const platform = sandbox.__platformOverride ?? process.platform;
|
|
409
|
+
if (platform !== "darwin") return stderr;
|
|
410
|
+
if (stderr.includes("[sandbox]")) return stderr;
|
|
411
|
+
const lower = stderr.toLowerCase();
|
|
412
|
+
const looksLikeSandboxViolation = stderr.includes("KODE_SANDBOX") || lower.includes("sandbox-exec") && (lower.includes("deny") || lower.includes("operation not permitted")) || lower.includes("operation not permitted") && lower.includes("sandbox");
|
|
413
|
+
if (!looksLikeSandboxViolation) return stderr;
|
|
414
|
+
return [
|
|
415
|
+
stderr.trimEnd(),
|
|
416
|
+
"",
|
|
417
|
+
"[sandbox] This failure looks like a macOS sandbox denial. Adjust sandbox settings (e.g. /sandbox or .kode/settings.json) to grant the minimal required access."
|
|
418
|
+
].join("\n");
|
|
419
|
+
}
|
|
420
|
+
function isSandboxInitFailure(stderr) {
|
|
421
|
+
const s = stderr.toLowerCase();
|
|
422
|
+
return s.includes("bwrap:") || s.includes("bubblewrap") || s.includes("namespace") && s.includes("failed");
|
|
423
|
+
}
|
|
424
|
+
function buildSandboxCommand(options) {
|
|
425
|
+
const sandbox = options.sandbox;
|
|
426
|
+
if (!sandbox.enabled) return null;
|
|
427
|
+
const platform = sandbox.__platformOverride ?? process.platform;
|
|
428
|
+
const needsNetworkRestriction = sandbox.needsNetworkRestriction !== void 0 ? sandbox.needsNetworkRestriction : sandbox.allowNetwork === true ? false : true;
|
|
429
|
+
const writeConfig = sandbox.writeConfig ?? (sandbox.writableRoots && sandbox.writableRoots.length > 0 ? { allowOnly: sandbox.writableRoots.filter(Boolean) } : void 0);
|
|
430
|
+
const readConfig = sandbox.readConfig;
|
|
431
|
+
const hasReadRestrictions = (readConfig?.denyOnly?.length ?? 0) > 0;
|
|
432
|
+
const hasWriteRestrictions = writeConfig !== void 0;
|
|
433
|
+
const hasNetworkRestrictions = needsNetworkRestriction === true;
|
|
434
|
+
if (!hasReadRestrictions && !hasWriteRestrictions && !hasNetworkRestrictions) {
|
|
435
|
+
return null;
|
|
436
|
+
}
|
|
437
|
+
const binShell = sandbox.binShell ?? (which.sync("bash", { nothrow: true }) ? "bash" : "sh");
|
|
438
|
+
const binShellPath = which.sync(binShell, { nothrow: true }) ?? binShell;
|
|
439
|
+
const cwd = sandbox.chdir || options.cwd;
|
|
440
|
+
if (platform === "linux") {
|
|
441
|
+
const bwrapPath = sandbox.__bwrapPathOverride !== void 0 ? sandbox.__bwrapPathOverride : which.sync("bwrap", { nothrow: true }) ?? which.sync("bubblewrap", { nothrow: true });
|
|
442
|
+
if (!bwrapPath) return null;
|
|
443
|
+
try {
|
|
444
|
+
mkdirSync("/tmp/kode", { recursive: true });
|
|
445
|
+
} catch {
|
|
446
|
+
}
|
|
447
|
+
const cmd = buildLinuxBwrapCommand({
|
|
448
|
+
bwrapPath,
|
|
449
|
+
command: options.command,
|
|
450
|
+
needsNetworkRestriction,
|
|
451
|
+
readConfig,
|
|
452
|
+
writeConfig,
|
|
453
|
+
enableWeakerNestedSandbox: sandbox.enableWeakerNestedSandbox,
|
|
454
|
+
binShellPath,
|
|
455
|
+
cwd
|
|
456
|
+
});
|
|
457
|
+
return { cmd };
|
|
458
|
+
}
|
|
459
|
+
if (platform === "darwin") {
|
|
460
|
+
const sandboxExecPath = sandbox.__sandboxExecPathOverride !== void 0 ? sandbox.__sandboxExecPathOverride : existsSync2("/usr/bin/sandbox-exec") ? "/usr/bin/sandbox-exec" : which.sync("sandbox-exec", { nothrow: true });
|
|
461
|
+
if (!sandboxExecPath) return null;
|
|
462
|
+
try {
|
|
463
|
+
mkdirSync("/tmp/kode", { recursive: true });
|
|
464
|
+
} catch {
|
|
465
|
+
}
|
|
466
|
+
try {
|
|
467
|
+
mkdirSync("/private/tmp/kode", { recursive: true });
|
|
468
|
+
} catch {
|
|
469
|
+
}
|
|
470
|
+
return {
|
|
471
|
+
cmd: buildMacosSandboxExecCommand({
|
|
472
|
+
sandboxExecPath,
|
|
473
|
+
binShellPath,
|
|
474
|
+
command: options.command,
|
|
475
|
+
needsNetworkRestriction,
|
|
476
|
+
httpProxyPort: sandbox.httpProxyPort,
|
|
477
|
+
socksProxyPort: sandbox.socksProxyPort,
|
|
478
|
+
allowUnixSockets: sandbox.allowUnixSockets,
|
|
479
|
+
allowAllUnixSockets: sandbox.allowAllUnixSockets,
|
|
480
|
+
allowLocalBinding: sandbox.allowLocalBinding,
|
|
481
|
+
readConfig,
|
|
482
|
+
writeConfig
|
|
483
|
+
})
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// packages/runtime/src/shell/streamReaders.ts
|
|
490
|
+
function logError(error) {
|
|
491
|
+
if (process.env.NODE_ENV === "test") {
|
|
492
|
+
console.error(error);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function startStreamReader(stream, append) {
|
|
496
|
+
if (!stream) return;
|
|
497
|
+
try {
|
|
498
|
+
stream.setEncoding("utf8");
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
stream.on("data", (chunk) => {
|
|
502
|
+
const text = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
503
|
+
if (text) append(text);
|
|
504
|
+
});
|
|
505
|
+
stream.on("error", (err) => {
|
|
506
|
+
logError(
|
|
507
|
+
`Stream read error: ${err instanceof Error ? err.message : String(err)}`
|
|
508
|
+
);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
function createCancellableTextCollector(stream, options) {
|
|
512
|
+
let text = "";
|
|
513
|
+
const collectText = options?.collectText !== false;
|
|
514
|
+
if (!stream) {
|
|
515
|
+
return {
|
|
516
|
+
getText: () => text,
|
|
517
|
+
done: Promise.resolve(),
|
|
518
|
+
cancel: async () => {
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
let doneResolve = null;
|
|
523
|
+
const done = new Promise((resolve3) => {
|
|
524
|
+
doneResolve = resolve3;
|
|
525
|
+
});
|
|
526
|
+
let finished = false;
|
|
527
|
+
let cancelled = false;
|
|
528
|
+
const finish = () => {
|
|
529
|
+
if (finished) return;
|
|
530
|
+
finished = true;
|
|
531
|
+
cleanup();
|
|
532
|
+
doneResolve?.();
|
|
533
|
+
doneResolve = null;
|
|
534
|
+
};
|
|
535
|
+
const onData = (chunk) => {
|
|
536
|
+
const value = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
|
|
537
|
+
if (!value) return;
|
|
538
|
+
if (collectText) text += value;
|
|
539
|
+
options?.onChunk?.(value);
|
|
540
|
+
};
|
|
541
|
+
const onError = (err) => {
|
|
542
|
+
if (!cancelled) {
|
|
543
|
+
logError(
|
|
544
|
+
`Stream read error: ${err instanceof Error ? err.message : String(err)}`
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
finish();
|
|
548
|
+
};
|
|
549
|
+
const onEnd = () => finish();
|
|
550
|
+
const onClose = () => finish();
|
|
551
|
+
const hasDestroy = (value) => {
|
|
552
|
+
return typeof value.destroy === "function";
|
|
553
|
+
};
|
|
554
|
+
const cleanup = () => {
|
|
555
|
+
stream.removeListener("data", onData);
|
|
556
|
+
stream.removeListener("error", onError);
|
|
557
|
+
stream.removeListener("end", onEnd);
|
|
558
|
+
stream.removeListener("close", onClose);
|
|
559
|
+
};
|
|
560
|
+
try {
|
|
561
|
+
stream.setEncoding("utf8");
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
stream.on("data", onData);
|
|
565
|
+
stream.on("error", onError);
|
|
566
|
+
stream.on("end", onEnd);
|
|
567
|
+
stream.on("close", onClose);
|
|
568
|
+
return {
|
|
569
|
+
getText: () => text,
|
|
570
|
+
done,
|
|
571
|
+
cancel: async () => {
|
|
572
|
+
cancelled = true;
|
|
573
|
+
try {
|
|
574
|
+
if (hasDestroy(stream)) {
|
|
575
|
+
stream.destroy();
|
|
576
|
+
}
|
|
577
|
+
} catch {
|
|
578
|
+
}
|
|
579
|
+
finish();
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// packages/runtime/src/shell/shellCmd.ts
|
|
585
|
+
import { existsSync as existsSync3 } from "fs";
|
|
586
|
+
function getShellCmdForPlatform(platform, command, env = process.env) {
|
|
587
|
+
if (platform === "win32") {
|
|
588
|
+
const comspec = typeof env.ComSpec === "string" && env.ComSpec.length > 0 ? env.ComSpec : "cmd";
|
|
589
|
+
return [comspec, "/c", command];
|
|
590
|
+
}
|
|
591
|
+
const sh = existsSync3("/bin/sh") ? "/bin/sh" : "sh";
|
|
592
|
+
return [sh, "-c", command];
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// packages/runtime/src/shell/exec.ts
|
|
596
|
+
function logError2(error) {
|
|
597
|
+
if (process.env.NODE_ENV === "test") {
|
|
598
|
+
console.error(error);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function normalizeExitCode(exitCode, interrupted) {
|
|
602
|
+
if (typeof exitCode === "number" && Number.isFinite(exitCode)) return exitCode;
|
|
603
|
+
return interrupted ? 143 : 0;
|
|
604
|
+
}
|
|
605
|
+
async function exec(state, command, abortSignal, timeout, options) {
|
|
606
|
+
const DEFAULT_TIMEOUT = 12e4;
|
|
607
|
+
const commandTimeout = timeout ?? DEFAULT_TIMEOUT;
|
|
608
|
+
state.abortController = new AbortController();
|
|
609
|
+
let wasAborted = false;
|
|
610
|
+
const onAbort = () => {
|
|
611
|
+
wasAborted = true;
|
|
612
|
+
try {
|
|
613
|
+
state.abortController?.abort();
|
|
614
|
+
} catch {
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
state.currentProcess?.kill();
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
if (abortSignal) {
|
|
622
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
623
|
+
}
|
|
624
|
+
const sandbox = options?.sandbox;
|
|
625
|
+
const shouldAttemptSandbox = sandbox?.enabled === true;
|
|
626
|
+
const executionCwd = shouldAttemptSandbox && sandbox?.chdir ? sandbox.chdir : state.cwd;
|
|
627
|
+
const runOnce = async (cmd, cwdOverride) => {
|
|
628
|
+
state.currentProcess = spawn(cmd[0], cmd.slice(1), {
|
|
629
|
+
cwd: cwdOverride ?? executionCwd,
|
|
630
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
631
|
+
});
|
|
632
|
+
const processRef = state.currentProcess;
|
|
633
|
+
const exitPromise = new Promise((resolve3) => {
|
|
634
|
+
processRef.once("exit", (code) => resolve3({ kind: "exit", code }));
|
|
635
|
+
processRef.once("error", (error) => resolve3({ kind: "error", error }));
|
|
636
|
+
});
|
|
637
|
+
const stdoutCollector = createCancellableTextCollector(processRef.stdout, {
|
|
638
|
+
onChunk: options?.onStdoutChunk
|
|
639
|
+
});
|
|
640
|
+
const stderrCollector = createCancellableTextCollector(processRef.stderr, {
|
|
641
|
+
onChunk: options?.onStderrChunk
|
|
642
|
+
});
|
|
643
|
+
let timeoutHandle = null;
|
|
644
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
645
|
+
timeoutHandle = setTimeout(() => resolve3("timeout"), commandTimeout);
|
|
646
|
+
});
|
|
647
|
+
const result = await Promise.race([
|
|
648
|
+
exitPromise.then(() => "completed"),
|
|
649
|
+
timeoutPromise
|
|
650
|
+
]);
|
|
651
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
652
|
+
if (result === "timeout") {
|
|
653
|
+
try {
|
|
654
|
+
processRef.kill();
|
|
655
|
+
} catch {
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
state.abortController?.abort();
|
|
659
|
+
} catch {
|
|
660
|
+
}
|
|
661
|
+
try {
|
|
662
|
+
await exitPromise;
|
|
663
|
+
} catch {
|
|
664
|
+
}
|
|
665
|
+
await Promise.race([
|
|
666
|
+
Promise.allSettled([stdoutCollector.done, stderrCollector.done]),
|
|
667
|
+
new Promise((resolve3) => setTimeout(resolve3, 250))
|
|
668
|
+
]);
|
|
669
|
+
await Promise.allSettled([
|
|
670
|
+
stdoutCollector.cancel(),
|
|
671
|
+
stderrCollector.cancel()
|
|
672
|
+
]);
|
|
673
|
+
return {
|
|
674
|
+
stdout: "",
|
|
675
|
+
stderr: "Command timed out",
|
|
676
|
+
code: 143,
|
|
677
|
+
interrupted: true
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
await Promise.race([
|
|
681
|
+
Promise.allSettled([stdoutCollector.done, stderrCollector.done]),
|
|
682
|
+
new Promise((resolve3) => setTimeout(resolve3, 250))
|
|
683
|
+
]);
|
|
684
|
+
await Promise.allSettled([
|
|
685
|
+
stdoutCollector.cancel(),
|
|
686
|
+
stderrCollector.cancel()
|
|
687
|
+
]);
|
|
688
|
+
const stdout = stdoutCollector.getText();
|
|
689
|
+
let stderr = stderrCollector.getText();
|
|
690
|
+
const interrupted = wasAborted || abortSignal?.aborted === true || state.abortController?.signal.aborted === true;
|
|
691
|
+
const exitOutcome = await exitPromise;
|
|
692
|
+
if (exitOutcome.kind === "error") {
|
|
693
|
+
stderr = [stderr, exitOutcome.error.message].filter(Boolean).join("\n");
|
|
694
|
+
}
|
|
695
|
+
let exitCode = exitOutcome.kind === "exit" ? exitOutcome.code : null;
|
|
696
|
+
if (exitOutcome.kind === "error") exitCode = 2;
|
|
697
|
+
return {
|
|
698
|
+
stdout,
|
|
699
|
+
stderr,
|
|
700
|
+
code: normalizeExitCode(exitCode, interrupted),
|
|
701
|
+
interrupted
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
try {
|
|
705
|
+
if (shouldAttemptSandbox) {
|
|
706
|
+
const sandboxCmd = buildSandboxCommand({
|
|
707
|
+
command,
|
|
708
|
+
sandbox,
|
|
709
|
+
cwd: state.cwd
|
|
710
|
+
});
|
|
711
|
+
if (!sandboxCmd) {
|
|
712
|
+
if (sandbox?.require) {
|
|
713
|
+
return {
|
|
714
|
+
stdout: "",
|
|
715
|
+
stderr: "System sandbox is required but unavailable (missing bubblewrap or unsupported platform).",
|
|
716
|
+
code: 2,
|
|
717
|
+
interrupted: false
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
const fallback = await runOnce(
|
|
721
|
+
getShellCmdForPlatform(process.platform, command, process.env)
|
|
722
|
+
);
|
|
723
|
+
return {
|
|
724
|
+
...fallback,
|
|
725
|
+
stderr: `[sandbox] unavailable, ran without isolation.
|
|
726
|
+
${fallback.stderr}`.trim()
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
const sandboxed = await runOnce(sandboxCmd.cmd);
|
|
730
|
+
sandboxed.stderr = maybeAnnotateMacosSandboxStderr(
|
|
731
|
+
sandboxed.stderr,
|
|
732
|
+
sandbox
|
|
733
|
+
);
|
|
734
|
+
if (!sandboxed.interrupted && sandboxed.code !== 0 && isSandboxInitFailure(sandboxed.stderr) && !sandbox?.require) {
|
|
735
|
+
const fallback = await runOnce(
|
|
736
|
+
getShellCmdForPlatform(process.platform, command, process.env)
|
|
737
|
+
);
|
|
738
|
+
return {
|
|
739
|
+
...fallback,
|
|
740
|
+
stderr: `[sandbox] failed to start, ran without isolation.
|
|
741
|
+
${fallback.stderr}`.trim()
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
return sandboxed;
|
|
745
|
+
}
|
|
746
|
+
return await runOnce(
|
|
747
|
+
getShellCmdForPlatform(process.platform, command, process.env)
|
|
748
|
+
);
|
|
749
|
+
} catch (error) {
|
|
750
|
+
if (state.abortController?.signal.aborted) {
|
|
751
|
+
state.currentProcess?.kill();
|
|
752
|
+
return {
|
|
753
|
+
stdout: "",
|
|
754
|
+
stderr: "Command was interrupted",
|
|
755
|
+
code: 143,
|
|
756
|
+
interrupted: true
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
const errorStr = error instanceof Error ? error.message : String(error);
|
|
760
|
+
logError2(`Shell execution error: ${errorStr}`);
|
|
761
|
+
return {
|
|
762
|
+
stdout: "",
|
|
763
|
+
stderr: errorStr,
|
|
764
|
+
code: 2,
|
|
765
|
+
interrupted: false
|
|
766
|
+
};
|
|
767
|
+
} finally {
|
|
768
|
+
if (abortSignal) {
|
|
769
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
770
|
+
}
|
|
771
|
+
state.currentProcess = null;
|
|
772
|
+
state.abortController = null;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// packages/runtime/src/shell/execPromotable.ts
|
|
777
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
778
|
+
|
|
779
|
+
// packages/runtime/src/taskOutputStore.ts
|
|
780
|
+
import {
|
|
781
|
+
appendFileSync,
|
|
782
|
+
existsSync as existsSync4,
|
|
783
|
+
mkdirSync as mkdirSync2,
|
|
784
|
+
readFileSync,
|
|
785
|
+
statSync as statSync2,
|
|
786
|
+
writeFileSync
|
|
787
|
+
} from "fs";
|
|
788
|
+
import { dirname as dirname3, join } from "path";
|
|
789
|
+
import { homedir as homedir2 } from "os";
|
|
790
|
+
function getKodeBaseDir() {
|
|
791
|
+
return process.env.KODE_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR ?? join(homedir2(), ".kode");
|
|
792
|
+
}
|
|
793
|
+
function getProjectDir(cwd) {
|
|
794
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
795
|
+
}
|
|
796
|
+
var PROJECT_ROOT = process.cwd();
|
|
797
|
+
function getTaskOutputsDir() {
|
|
798
|
+
return join(getKodeBaseDir(), getProjectDir(PROJECT_ROOT), "tasks");
|
|
799
|
+
}
|
|
800
|
+
function getTaskOutputFilePath(taskId) {
|
|
801
|
+
return join(getTaskOutputsDir(), `${taskId}.output`);
|
|
802
|
+
}
|
|
803
|
+
function ensureTaskOutputsDirExists() {
|
|
804
|
+
const dir = getTaskOutputsDir();
|
|
805
|
+
if (existsSync4(dir)) return;
|
|
806
|
+
mkdirSync2(dir, { recursive: true });
|
|
807
|
+
}
|
|
808
|
+
function touchTaskOutputFile(taskId) {
|
|
809
|
+
ensureTaskOutputsDirExists();
|
|
810
|
+
const filePath = getTaskOutputFilePath(taskId);
|
|
811
|
+
if (!existsSync4(filePath)) {
|
|
812
|
+
const parent = dirname3(filePath);
|
|
813
|
+
if (!existsSync4(parent)) mkdirSync2(parent, { recursive: true });
|
|
814
|
+
writeFileSync(filePath, "", "utf8");
|
|
815
|
+
}
|
|
816
|
+
return filePath;
|
|
817
|
+
}
|
|
818
|
+
function appendTaskOutput(taskId, chunk) {
|
|
819
|
+
try {
|
|
820
|
+
ensureTaskOutputsDirExists();
|
|
821
|
+
appendFileSync(getTaskOutputFilePath(taskId), chunk, "utf8");
|
|
822
|
+
} catch {
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function readTaskOutput(taskId) {
|
|
826
|
+
try {
|
|
827
|
+
const filePath = getTaskOutputFilePath(taskId);
|
|
828
|
+
if (!existsSync4(filePath)) return "";
|
|
829
|
+
return readFileSync(filePath, "utf8");
|
|
830
|
+
} catch {
|
|
831
|
+
return "";
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// packages/runtime/src/shell/ids.ts
|
|
836
|
+
import { randomUUID } from "crypto";
|
|
837
|
+
function makeBackgroundTaskId() {
|
|
838
|
+
return `b${randomUUID().replace(/-/g, "").slice(0, 6)}`;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// packages/runtime/src/shell/execPromotable.ts
|
|
842
|
+
function normalizeExitCode2(code, interrupted) {
|
|
843
|
+
if (typeof code === "number" && Number.isFinite(code)) return code;
|
|
844
|
+
return interrupted ? 143 : 0;
|
|
845
|
+
}
|
|
846
|
+
function execPromotable(state, command, abortSignal, timeout, options) {
|
|
847
|
+
const DEFAULT_TIMEOUT = 12e4;
|
|
848
|
+
const commandTimeout = timeout ?? DEFAULT_TIMEOUT;
|
|
849
|
+
const startedAt = Date.now();
|
|
850
|
+
const sandbox = options?.sandbox;
|
|
851
|
+
const shouldAttemptSandbox = sandbox?.enabled === true;
|
|
852
|
+
const executionCwd = shouldAttemptSandbox && sandbox?.chdir ? sandbox.chdir : state.cwd;
|
|
853
|
+
if (abortSignal?.aborted) {
|
|
854
|
+
return {
|
|
855
|
+
get status() {
|
|
856
|
+
return "killed";
|
|
857
|
+
},
|
|
858
|
+
background: () => null,
|
|
859
|
+
kill: () => {
|
|
860
|
+
},
|
|
861
|
+
result: Promise.resolve({
|
|
862
|
+
stdout: "",
|
|
863
|
+
stderr: "Command aborted before execution",
|
|
864
|
+
code: 145,
|
|
865
|
+
interrupted: true
|
|
866
|
+
})
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
const sandboxCmd = shouldAttemptSandbox ? buildSandboxCommand({ command, sandbox, cwd: state.cwd }) : null;
|
|
870
|
+
if (shouldAttemptSandbox && sandbox?.require && !sandboxCmd) {
|
|
871
|
+
return {
|
|
872
|
+
get status() {
|
|
873
|
+
return "killed";
|
|
874
|
+
},
|
|
875
|
+
background: () => null,
|
|
876
|
+
kill: () => {
|
|
877
|
+
},
|
|
878
|
+
result: Promise.resolve({
|
|
879
|
+
stdout: "",
|
|
880
|
+
stderr: "System sandbox is required but unavailable (missing bubblewrap or unsupported platform).",
|
|
881
|
+
code: 2,
|
|
882
|
+
interrupted: false
|
|
883
|
+
})
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
const cmdToRun = sandboxCmd ? sandboxCmd.cmd : getShellCmdForPlatform(process.platform, command, process.env);
|
|
887
|
+
const internalAbortController = new AbortController();
|
|
888
|
+
state.abortController = internalAbortController;
|
|
889
|
+
let status = "running";
|
|
890
|
+
let backgroundProcess = null;
|
|
891
|
+
let backgroundTaskId = null;
|
|
892
|
+
let stdout = "";
|
|
893
|
+
let stderr = "";
|
|
894
|
+
let wasAborted = false;
|
|
895
|
+
let wasBackgrounded = false;
|
|
896
|
+
let timeoutHandle = null;
|
|
897
|
+
let timedOut = false;
|
|
898
|
+
let onTimeoutCb = null;
|
|
899
|
+
const countNonEmptyLines = (chunk) => chunk.split("\n").filter((line) => line.length > 0).length;
|
|
900
|
+
const spawnedProcess = spawn2(cmdToRun[0], cmdToRun.slice(1), {
|
|
901
|
+
cwd: executionCwd,
|
|
902
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
903
|
+
});
|
|
904
|
+
state.currentProcess = spawnedProcess;
|
|
905
|
+
const exitPromise = new Promise((resolve3) => {
|
|
906
|
+
spawnedProcess.once("exit", (code) => resolve3({ kind: "exit", code }));
|
|
907
|
+
spawnedProcess.once("error", (error) => resolve3({ kind: "error", error }));
|
|
908
|
+
});
|
|
909
|
+
const onAbort = () => {
|
|
910
|
+
if (status === "backgrounded") return;
|
|
911
|
+
wasAborted = true;
|
|
912
|
+
try {
|
|
913
|
+
internalAbortController.abort();
|
|
914
|
+
} catch {
|
|
915
|
+
}
|
|
916
|
+
try {
|
|
917
|
+
spawnedProcess.kill();
|
|
918
|
+
} catch {
|
|
919
|
+
}
|
|
920
|
+
if (backgroundProcess) backgroundProcess.interrupted = true;
|
|
921
|
+
};
|
|
922
|
+
const clearForegroundGuards = () => {
|
|
923
|
+
if (timeoutHandle) {
|
|
924
|
+
clearTimeout(timeoutHandle);
|
|
925
|
+
timeoutHandle = null;
|
|
926
|
+
}
|
|
927
|
+
if (abortSignal) {
|
|
928
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
if (abortSignal) {
|
|
932
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
933
|
+
if (abortSignal.aborted) onAbort();
|
|
934
|
+
}
|
|
935
|
+
const stdoutCollector = createCancellableTextCollector(
|
|
936
|
+
spawnedProcess.stdout,
|
|
937
|
+
{
|
|
938
|
+
collectText: false,
|
|
939
|
+
onChunk: (chunk) => {
|
|
940
|
+
stdout += chunk;
|
|
941
|
+
options?.onStdoutChunk?.(chunk);
|
|
942
|
+
if (backgroundProcess) {
|
|
943
|
+
backgroundProcess.stdout = stdout;
|
|
944
|
+
appendTaskOutput(backgroundProcess.id, chunk);
|
|
945
|
+
backgroundProcess.stdoutLineCount += countNonEmptyLines(chunk);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
);
|
|
950
|
+
const stderrCollector = createCancellableTextCollector(
|
|
951
|
+
spawnedProcess.stderr,
|
|
952
|
+
{
|
|
953
|
+
collectText: false,
|
|
954
|
+
onChunk: (chunk) => {
|
|
955
|
+
stderr += chunk;
|
|
956
|
+
options?.onStderrChunk?.(chunk);
|
|
957
|
+
if (backgroundProcess) {
|
|
958
|
+
backgroundProcess.stderr = stderr;
|
|
959
|
+
appendTaskOutput(backgroundProcess.id, chunk);
|
|
960
|
+
backgroundProcess.stderrLineCount += countNonEmptyLines(chunk);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
);
|
|
965
|
+
timeoutHandle = setTimeout(() => {
|
|
966
|
+
if (status !== "running") return;
|
|
967
|
+
if (onTimeoutCb) {
|
|
968
|
+
onTimeoutCb(background);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
timedOut = true;
|
|
972
|
+
try {
|
|
973
|
+
spawnedProcess.kill();
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
try {
|
|
977
|
+
internalAbortController.abort();
|
|
978
|
+
} catch {
|
|
979
|
+
}
|
|
980
|
+
}, commandTimeout);
|
|
981
|
+
const background = (bashId) => {
|
|
982
|
+
if (backgroundTaskId) return { bashId: backgroundTaskId };
|
|
983
|
+
if (status !== "running") return null;
|
|
984
|
+
backgroundTaskId = bashId ?? makeBackgroundTaskId();
|
|
985
|
+
const outputFile = touchTaskOutputFile(backgroundTaskId);
|
|
986
|
+
if (stdout) appendTaskOutput(backgroundTaskId, stdout);
|
|
987
|
+
if (stderr) appendTaskOutput(backgroundTaskId, stderr);
|
|
988
|
+
status = "backgrounded";
|
|
989
|
+
wasBackgrounded = true;
|
|
990
|
+
clearForegroundGuards();
|
|
991
|
+
backgroundProcess = {
|
|
992
|
+
id: backgroundTaskId,
|
|
993
|
+
command,
|
|
994
|
+
stdout,
|
|
995
|
+
stderr,
|
|
996
|
+
stdoutCursor: 0,
|
|
997
|
+
stderrCursor: 0,
|
|
998
|
+
stdoutLineCount: countNonEmptyLines(stdout),
|
|
999
|
+
stderrLineCount: countNonEmptyLines(stderr),
|
|
1000
|
+
lastReportedStdoutLines: 0,
|
|
1001
|
+
lastReportedStderrLines: 0,
|
|
1002
|
+
code: null,
|
|
1003
|
+
interrupted: false,
|
|
1004
|
+
killed: false,
|
|
1005
|
+
timedOut: false,
|
|
1006
|
+
completionStatusSentInAttachment: false,
|
|
1007
|
+
notified: false,
|
|
1008
|
+
startedAt,
|
|
1009
|
+
timeoutAt: Number.POSITIVE_INFINITY,
|
|
1010
|
+
process: spawnedProcess,
|
|
1011
|
+
abortController: internalAbortController,
|
|
1012
|
+
timeoutHandle: null,
|
|
1013
|
+
cwd: executionCwd,
|
|
1014
|
+
outputFile
|
|
1015
|
+
};
|
|
1016
|
+
state.backgroundProcesses.set(backgroundTaskId, backgroundProcess);
|
|
1017
|
+
state.currentProcess = null;
|
|
1018
|
+
state.abortController = null;
|
|
1019
|
+
return { bashId: backgroundTaskId };
|
|
1020
|
+
};
|
|
1021
|
+
const kill = () => {
|
|
1022
|
+
status = "killed";
|
|
1023
|
+
try {
|
|
1024
|
+
spawnedProcess.kill();
|
|
1025
|
+
} catch {
|
|
1026
|
+
}
|
|
1027
|
+
try {
|
|
1028
|
+
internalAbortController.abort();
|
|
1029
|
+
} catch {
|
|
1030
|
+
}
|
|
1031
|
+
if (backgroundProcess) {
|
|
1032
|
+
backgroundProcess.interrupted = true;
|
|
1033
|
+
backgroundProcess.killed = true;
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
const result = (async () => {
|
|
1037
|
+
try {
|
|
1038
|
+
const exitOutcome = await exitPromise;
|
|
1039
|
+
if (exitOutcome.kind === "error") {
|
|
1040
|
+
stderr = [stderr, exitOutcome.error.message].filter(Boolean).join("\n");
|
|
1041
|
+
}
|
|
1042
|
+
if (status === "running" || status === "backgrounded")
|
|
1043
|
+
status = "completed";
|
|
1044
|
+
if (backgroundProcess) {
|
|
1045
|
+
backgroundProcess.code = exitOutcome.kind === "exit" ? exitOutcome.code ?? 0 : 2;
|
|
1046
|
+
backgroundProcess.interrupted = backgroundProcess.interrupted || wasAborted || internalAbortController.signal.aborted;
|
|
1047
|
+
}
|
|
1048
|
+
if (!wasBackgrounded) {
|
|
1049
|
+
await Promise.race([
|
|
1050
|
+
Promise.allSettled([stdoutCollector.done, stderrCollector.done]),
|
|
1051
|
+
new Promise((resolve3) => setTimeout(resolve3, 250))
|
|
1052
|
+
]);
|
|
1053
|
+
await Promise.allSettled([
|
|
1054
|
+
stdoutCollector.cancel(),
|
|
1055
|
+
stderrCollector.cancel()
|
|
1056
|
+
]);
|
|
1057
|
+
}
|
|
1058
|
+
const interrupted = wasAborted || abortSignal?.aborted === true || internalAbortController.signal.aborted === true || timedOut;
|
|
1059
|
+
let code = exitOutcome.kind === "exit" ? exitOutcome.code : null;
|
|
1060
|
+
if (exitOutcome.kind === "error") code = 2;
|
|
1061
|
+
const stderrWithTimeout = timedOut ? [`Command timed out`, stderr].filter(Boolean).join("\n") : stderr;
|
|
1062
|
+
const stderrAnnotated = sandboxCmd ? maybeAnnotateMacosSandboxStderr(stderrWithTimeout, sandbox) : stderrWithTimeout;
|
|
1063
|
+
return {
|
|
1064
|
+
stdout,
|
|
1065
|
+
stderr: stderrAnnotated,
|
|
1066
|
+
code: normalizeExitCode2(code, interrupted),
|
|
1067
|
+
interrupted
|
|
1068
|
+
};
|
|
1069
|
+
} finally {
|
|
1070
|
+
clearForegroundGuards();
|
|
1071
|
+
if (state.currentProcess === spawnedProcess) {
|
|
1072
|
+
state.currentProcess = null;
|
|
1073
|
+
state.abortController = null;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
})();
|
|
1077
|
+
const execHandle = {
|
|
1078
|
+
get status() {
|
|
1079
|
+
return status;
|
|
1080
|
+
},
|
|
1081
|
+
background,
|
|
1082
|
+
kill,
|
|
1083
|
+
result
|
|
1084
|
+
};
|
|
1085
|
+
execHandle.onTimeout = (cb) => {
|
|
1086
|
+
onTimeoutCb = cb;
|
|
1087
|
+
};
|
|
1088
|
+
result.then((r) => {
|
|
1089
|
+
if (!backgroundProcess || !backgroundTaskId) return;
|
|
1090
|
+
backgroundProcess.code = r.code;
|
|
1091
|
+
backgroundProcess.interrupted = r.interrupted;
|
|
1092
|
+
}).catch(() => {
|
|
1093
|
+
if (!backgroundProcess) return;
|
|
1094
|
+
backgroundProcess.code = backgroundProcess.code ?? 2;
|
|
1095
|
+
});
|
|
1096
|
+
return execHandle;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// packages/runtime/src/shell/background.ts
|
|
1100
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
1101
|
+
function execInBackground(state, command, timeout, options) {
|
|
1102
|
+
const DEFAULT_TIMEOUT = 12e4;
|
|
1103
|
+
const commandTimeout = timeout ?? DEFAULT_TIMEOUT;
|
|
1104
|
+
const abortController = new AbortController();
|
|
1105
|
+
const sandbox = options?.sandbox;
|
|
1106
|
+
const sandboxCmd = sandbox?.enabled === true ? buildSandboxCommand({ command, sandbox, cwd: state.cwd }) : null;
|
|
1107
|
+
const executionCwd = sandbox?.enabled === true && sandbox?.chdir ? sandbox.chdir : state.cwd;
|
|
1108
|
+
if (sandbox?.enabled === true && sandbox?.require && !sandboxCmd) {
|
|
1109
|
+
throw new Error(
|
|
1110
|
+
"System sandbox is required but unavailable (missing bubblewrap or unsupported platform)."
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
const cmdToRun = sandboxCmd ? sandboxCmd.cmd : getShellCmdForPlatform(process.platform, command, process.env);
|
|
1114
|
+
const bashId = makeBackgroundTaskId();
|
|
1115
|
+
const outputFile = touchTaskOutputFile(bashId);
|
|
1116
|
+
const childProcess = spawn3(cmdToRun[0], cmdToRun.slice(1), {
|
|
1117
|
+
cwd: executionCwd,
|
|
1118
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1119
|
+
});
|
|
1120
|
+
const exitPromise = new Promise((resolve3) => {
|
|
1121
|
+
childProcess.once("exit", (code) => resolve3({ kind: "exit", code }));
|
|
1122
|
+
childProcess.once("error", (error) => resolve3({ kind: "error", error }));
|
|
1123
|
+
});
|
|
1124
|
+
const timeoutHandle = setTimeout(() => {
|
|
1125
|
+
abortController.abort();
|
|
1126
|
+
backgroundProcess.timedOut = true;
|
|
1127
|
+
childProcess.kill();
|
|
1128
|
+
}, commandTimeout);
|
|
1129
|
+
const backgroundProcess = {
|
|
1130
|
+
id: bashId,
|
|
1131
|
+
command,
|
|
1132
|
+
stdout: "",
|
|
1133
|
+
stderr: "",
|
|
1134
|
+
stdoutCursor: 0,
|
|
1135
|
+
stderrCursor: 0,
|
|
1136
|
+
stdoutLineCount: 0,
|
|
1137
|
+
stderrLineCount: 0,
|
|
1138
|
+
lastReportedStdoutLines: 0,
|
|
1139
|
+
lastReportedStderrLines: 0,
|
|
1140
|
+
code: null,
|
|
1141
|
+
interrupted: false,
|
|
1142
|
+
killed: false,
|
|
1143
|
+
timedOut: false,
|
|
1144
|
+
completionStatusSentInAttachment: false,
|
|
1145
|
+
notified: false,
|
|
1146
|
+
startedAt: Date.now(),
|
|
1147
|
+
timeoutAt: Date.now() + commandTimeout,
|
|
1148
|
+
process: childProcess,
|
|
1149
|
+
abortController,
|
|
1150
|
+
timeoutHandle,
|
|
1151
|
+
cwd: executionCwd,
|
|
1152
|
+
outputFile
|
|
1153
|
+
};
|
|
1154
|
+
const countNonEmptyLines = (chunk) => chunk.split("\n").filter((line) => line.length > 0).length;
|
|
1155
|
+
startStreamReader(childProcess.stdout, (chunk) => {
|
|
1156
|
+
backgroundProcess.stdout += chunk;
|
|
1157
|
+
appendTaskOutput(bashId, chunk);
|
|
1158
|
+
backgroundProcess.stdoutLineCount += countNonEmptyLines(chunk);
|
|
1159
|
+
});
|
|
1160
|
+
startStreamReader(childProcess.stderr, (chunk) => {
|
|
1161
|
+
backgroundProcess.stderr += chunk;
|
|
1162
|
+
appendTaskOutput(bashId, chunk);
|
|
1163
|
+
backgroundProcess.stderrLineCount += countNonEmptyLines(chunk);
|
|
1164
|
+
});
|
|
1165
|
+
exitPromise.then((exitOutcome) => {
|
|
1166
|
+
backgroundProcess.code = exitOutcome.kind === "exit" ? exitOutcome.code ?? 0 : 2;
|
|
1167
|
+
if (exitOutcome.kind === "error") {
|
|
1168
|
+
backgroundProcess.stderr = [
|
|
1169
|
+
backgroundProcess.stderr,
|
|
1170
|
+
exitOutcome.error.message
|
|
1171
|
+
].filter(Boolean).join("\n");
|
|
1172
|
+
}
|
|
1173
|
+
backgroundProcess.interrupted = backgroundProcess.interrupted || abortController.signal.aborted;
|
|
1174
|
+
if (sandbox?.enabled === true) {
|
|
1175
|
+
backgroundProcess.stderr = maybeAnnotateMacosSandboxStderr(
|
|
1176
|
+
backgroundProcess.stderr,
|
|
1177
|
+
sandbox
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
if (backgroundProcess.timeoutHandle) {
|
|
1181
|
+
clearTimeout(backgroundProcess.timeoutHandle);
|
|
1182
|
+
backgroundProcess.timeoutHandle = null;
|
|
1183
|
+
}
|
|
1184
|
+
});
|
|
1185
|
+
state.backgroundProcesses.set(bashId, backgroundProcess);
|
|
1186
|
+
return { bashId };
|
|
1187
|
+
}
|
|
1188
|
+
function getBackgroundOutput(state, shellId) {
|
|
1189
|
+
const proc = state.backgroundProcesses.get(shellId);
|
|
1190
|
+
if (!proc) return null;
|
|
1191
|
+
const running = proc.code === null && !proc.interrupted;
|
|
1192
|
+
return {
|
|
1193
|
+
stdout: proc.stdout,
|
|
1194
|
+
stderr: proc.stderr,
|
|
1195
|
+
code: proc.code,
|
|
1196
|
+
interrupted: proc.interrupted,
|
|
1197
|
+
killed: proc.killed,
|
|
1198
|
+
timedOut: proc.timedOut,
|
|
1199
|
+
running,
|
|
1200
|
+
command: proc.command,
|
|
1201
|
+
cwd: proc.cwd,
|
|
1202
|
+
startedAt: proc.startedAt,
|
|
1203
|
+
timeoutAt: proc.timeoutAt,
|
|
1204
|
+
outputFile: proc.outputFile
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function readBackgroundOutput(state, bashId, options) {
|
|
1208
|
+
const proc = state.backgroundProcesses.get(bashId);
|
|
1209
|
+
if (!proc) return null;
|
|
1210
|
+
const stdoutDelta = proc.stdout.slice(proc.stdoutCursor);
|
|
1211
|
+
const stderrDelta = proc.stderr.slice(proc.stderrCursor);
|
|
1212
|
+
proc.stdoutCursor = proc.stdout.length;
|
|
1213
|
+
proc.stderrCursor = proc.stderr.length;
|
|
1214
|
+
const stdoutLines = stdoutDelta === "" ? 0 : stdoutDelta.split("\n").length;
|
|
1215
|
+
const stderrLines = stderrDelta === "" ? 0 : stderrDelta.split("\n").length;
|
|
1216
|
+
let stdoutToReturn = stdoutDelta;
|
|
1217
|
+
let stderrToReturn = stderrDelta;
|
|
1218
|
+
const filter = options?.filter?.trim();
|
|
1219
|
+
if (filter) {
|
|
1220
|
+
const regex = new RegExp(filter, "i");
|
|
1221
|
+
stdoutToReturn = stdoutDelta.split("\n").filter((line) => regex.test(line)).join("\n");
|
|
1222
|
+
stderrToReturn = stderrDelta.split("\n").filter((line) => regex.test(line)).join("\n");
|
|
1223
|
+
}
|
|
1224
|
+
const status = proc.killed ? "killed" : proc.code === null ? "running" : proc.code === 0 ? "completed" : "failed";
|
|
1225
|
+
return {
|
|
1226
|
+
shellId: bashId,
|
|
1227
|
+
command: proc.command,
|
|
1228
|
+
cwd: proc.cwd,
|
|
1229
|
+
startedAt: proc.startedAt,
|
|
1230
|
+
timeoutAt: proc.timeoutAt,
|
|
1231
|
+
status,
|
|
1232
|
+
exitCode: proc.code,
|
|
1233
|
+
stdout: stdoutToReturn,
|
|
1234
|
+
stderr: stderrToReturn,
|
|
1235
|
+
stdoutLines,
|
|
1236
|
+
stderrLines,
|
|
1237
|
+
...filter ? { filterPattern: filter } : {}
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
function killBackgroundShell(state, shellId) {
|
|
1241
|
+
const proc = state.backgroundProcesses.get(shellId);
|
|
1242
|
+
if (!proc) return false;
|
|
1243
|
+
try {
|
|
1244
|
+
proc.interrupted = true;
|
|
1245
|
+
proc.killed = true;
|
|
1246
|
+
proc.abortController.abort();
|
|
1247
|
+
proc.process.kill();
|
|
1248
|
+
if (proc.timeoutHandle) {
|
|
1249
|
+
clearTimeout(proc.timeoutHandle);
|
|
1250
|
+
proc.timeoutHandle = null;
|
|
1251
|
+
}
|
|
1252
|
+
return true;
|
|
1253
|
+
} catch {
|
|
1254
|
+
return false;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function listBackgroundShells(state) {
|
|
1258
|
+
return Array.from(state.backgroundProcesses.values());
|
|
1259
|
+
}
|
|
1260
|
+
function flushBashNotifications(state) {
|
|
1261
|
+
const processes = Array.from(state.backgroundProcesses.values());
|
|
1262
|
+
const statusFor = (proc) => proc.killed ? "killed" : proc.code === null ? "running" : proc.code === 0 ? "completed" : "failed";
|
|
1263
|
+
const notifications = [];
|
|
1264
|
+
for (const proc of processes) {
|
|
1265
|
+
if (proc.notified) continue;
|
|
1266
|
+
const status = statusFor(proc);
|
|
1267
|
+
if (status === "running") continue;
|
|
1268
|
+
notifications.push({
|
|
1269
|
+
type: "bash_notification",
|
|
1270
|
+
taskId: proc.id,
|
|
1271
|
+
description: proc.command,
|
|
1272
|
+
outputFile: proc.outputFile || getTaskOutputFilePath(proc.id),
|
|
1273
|
+
status,
|
|
1274
|
+
...proc.code !== null ? { exitCode: proc.code } : {}
|
|
1275
|
+
});
|
|
1276
|
+
proc.notified = true;
|
|
1277
|
+
}
|
|
1278
|
+
return notifications;
|
|
1279
|
+
}
|
|
1280
|
+
function flushBackgroundShellStatusAttachments(state) {
|
|
1281
|
+
const processes = Array.from(state.backgroundProcesses.values());
|
|
1282
|
+
const statusFor = (proc) => proc.killed ? "killed" : proc.code === null ? "running" : proc.code === 0 ? "completed" : "failed";
|
|
1283
|
+
const progressAttachments = [];
|
|
1284
|
+
for (const proc of processes) {
|
|
1285
|
+
if (statusFor(proc) !== "running") continue;
|
|
1286
|
+
const stdoutDelta = proc.stdoutLineCount - proc.lastReportedStdoutLines;
|
|
1287
|
+
const stderrDelta = proc.stderrLineCount - proc.lastReportedStderrLines;
|
|
1288
|
+
if (stdoutDelta === 0 && stderrDelta === 0) continue;
|
|
1289
|
+
proc.lastReportedStdoutLines = proc.stdoutLineCount;
|
|
1290
|
+
proc.lastReportedStderrLines = proc.stderrLineCount;
|
|
1291
|
+
progressAttachments.push({
|
|
1292
|
+
type: "task_progress",
|
|
1293
|
+
taskId: proc.id,
|
|
1294
|
+
stdoutLineDelta: stdoutDelta,
|
|
1295
|
+
stderrLineDelta: stderrDelta,
|
|
1296
|
+
outputFile: proc.outputFile || getTaskOutputFilePath(proc.id)
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
return progressAttachments;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// packages/runtime/src/shell/BunShell.ts
|
|
1303
|
+
var BunShell = class _BunShell {
|
|
1304
|
+
state;
|
|
1305
|
+
constructor(cwd) {
|
|
1306
|
+
this.state = createInitialState(cwd);
|
|
1307
|
+
}
|
|
1308
|
+
static instance = null;
|
|
1309
|
+
static restart() {
|
|
1310
|
+
if (_BunShell.instance) {
|
|
1311
|
+
_BunShell.instance.close();
|
|
1312
|
+
_BunShell.instance = null;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
static getInstance() {
|
|
1316
|
+
if (!_BunShell.instance || !_BunShell.instance.state.isAlive) {
|
|
1317
|
+
_BunShell.instance = new _BunShell(process.cwd());
|
|
1318
|
+
}
|
|
1319
|
+
return _BunShell.instance;
|
|
1320
|
+
}
|
|
1321
|
+
static getShellCmdForPlatform(platform, command, env = process.env) {
|
|
1322
|
+
return getShellCmdForPlatform(platform, command, env);
|
|
1323
|
+
}
|
|
1324
|
+
execPromotable(command, abortSignal, timeout, options) {
|
|
1325
|
+
return execPromotable(this.state, command, abortSignal, timeout, options);
|
|
1326
|
+
}
|
|
1327
|
+
async exec(command, abortSignal, timeout, options) {
|
|
1328
|
+
return exec(this.state, command, abortSignal, timeout, options);
|
|
1329
|
+
}
|
|
1330
|
+
execInBackground(command, timeout, options) {
|
|
1331
|
+
return execInBackground(this.state, command, timeout, options);
|
|
1332
|
+
}
|
|
1333
|
+
getBackgroundOutput(shellId) {
|
|
1334
|
+
return getBackgroundOutput(this.state, shellId);
|
|
1335
|
+
}
|
|
1336
|
+
readBackgroundOutput(bashId, options) {
|
|
1337
|
+
return readBackgroundOutput(this.state, bashId, options);
|
|
1338
|
+
}
|
|
1339
|
+
killBackgroundShell(shellId) {
|
|
1340
|
+
return killBackgroundShell(this.state, shellId);
|
|
1341
|
+
}
|
|
1342
|
+
listBackgroundShells() {
|
|
1343
|
+
return listBackgroundShells(this.state);
|
|
1344
|
+
}
|
|
1345
|
+
pwd() {
|
|
1346
|
+
return this.state.cwd;
|
|
1347
|
+
}
|
|
1348
|
+
async setCwd(cwd) {
|
|
1349
|
+
const resolved = isAbsolute2(cwd) ? cwd : resolve2(this.state.cwd, cwd);
|
|
1350
|
+
if (!existsSync5(resolved)) {
|
|
1351
|
+
throw new Error(`Path "${resolved}" does not exist`);
|
|
1352
|
+
}
|
|
1353
|
+
this.state.cwd = resolved;
|
|
1354
|
+
}
|
|
1355
|
+
killChildren() {
|
|
1356
|
+
this.state.abortController?.abort();
|
|
1357
|
+
this.state.currentProcess?.kill();
|
|
1358
|
+
for (const bg of Array.from(this.state.backgroundProcesses.keys())) {
|
|
1359
|
+
killBackgroundShell(this.state, bg);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
close() {
|
|
1363
|
+
this.state.isAlive = false;
|
|
1364
|
+
this.killChildren();
|
|
1365
|
+
}
|
|
1366
|
+
flushBashNotifications() {
|
|
1367
|
+
return flushBashNotifications(this.state);
|
|
1368
|
+
}
|
|
1369
|
+
flushBackgroundShellStatusAttachments() {
|
|
1370
|
+
return flushBackgroundShellStatusAttachments(this.state);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
// packages/runtime/src/shell/notifications.ts
|
|
1375
|
+
function renderBackgroundShellStatusAttachment(attachment) {
|
|
1376
|
+
const parts = [];
|
|
1377
|
+
if (attachment.stdoutLineDelta > 0) {
|
|
1378
|
+
const n = attachment.stdoutLineDelta;
|
|
1379
|
+
parts.push(`${n} line${n > 1 ? "s" : ""} of stdout`);
|
|
1380
|
+
}
|
|
1381
|
+
if (attachment.stderrLineDelta > 0) {
|
|
1382
|
+
const n = attachment.stderrLineDelta;
|
|
1383
|
+
parts.push(`${n} line${n > 1 ? "s" : ""} of stderr`);
|
|
1384
|
+
}
|
|
1385
|
+
if (parts.length === 0) return "";
|
|
1386
|
+
return `Background bash ${attachment.taskId} has new output: ${parts.join(", ")}. Read ${attachment.outputFile} to see output.`;
|
|
1387
|
+
}
|
|
1388
|
+
function renderBashNotification(notification) {
|
|
1389
|
+
const status = notification.status;
|
|
1390
|
+
const exitCode = notification.exitCode;
|
|
1391
|
+
const summarySuffix = status === "completed" ? `completed${exitCode !== void 0 ? ` (exit code ${exitCode})` : ""}` : status === "failed" ? `failed${exitCode !== void 0 ? ` with exit code ${exitCode}` : ""}` : "was killed";
|
|
1392
|
+
return [
|
|
1393
|
+
"<bash-notification>",
|
|
1394
|
+
`<shell-id>${notification.taskId}</shell-id>`,
|
|
1395
|
+
`<output-file>${notification.outputFile || getTaskOutputFilePath(notification.taskId)}</output-file>`,
|
|
1396
|
+
`<status>${status}</status>`,
|
|
1397
|
+
`<summary>Background command "${notification.description}" ${summarySuffix}.</summary>`,
|
|
1398
|
+
"Read the output file to retrieve the output.",
|
|
1399
|
+
"</bash-notification>"
|
|
1400
|
+
].join("\n");
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
export {
|
|
1404
|
+
getTaskOutputFilePath,
|
|
1405
|
+
readTaskOutput,
|
|
1406
|
+
renderBackgroundShellStatusAttachment,
|
|
1407
|
+
renderBashNotification,
|
|
1408
|
+
BunShell
|
|
1409
|
+
};
|