newcraw 1.0.2 → 1.0.4
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/dist/REPL-DECTPCL5.js +50 -0
- package/dist/{acp-J4WDYGRX.js → acp-HA476EHW.js} +69 -40
- package/dist/acp-HA476EHW.js.map +7 -0
- package/dist/{agentsValidate-UBOER2IN.js → agentsValidate-EDPFUUMG.js} +13 -10
- package/dist/{agentsValidate-UBOER2IN.js.map → agentsValidate-EDPFUUMG.js.map} +1 -1
- package/dist/{ask-MGUO3L35.js → ask-5SP4YYRD.js} +62 -52
- package/dist/ask-5SP4YYRD.js.map +7 -0
- package/dist/{autoUpdater-2GS6LRPK.js → autoUpdater-FFMM2DR7.js} +5 -4
- package/dist/chunk-2BVCVKKB.js +135 -0
- package/dist/chunk-2BVCVKKB.js.map +7 -0
- package/dist/{chunk-2C43OXE7.js → chunk-2JCTO2EY.js} +38 -59
- package/dist/chunk-2JCTO2EY.js.map +7 -0
- package/dist/{chunk-OJIMOLIC.js → chunk-3CKC4ABU.js} +3631 -7464
- package/dist/chunk-3CKC4ABU.js.map +7 -0
- package/dist/chunk-ARCEUG3V.js +88 -0
- package/dist/chunk-ARCEUG3V.js.map +7 -0
- package/dist/{chunk-RUXIBQ3B.js → chunk-BJYXLCRS.js} +4 -4
- package/dist/{chunk-VKI7ORIO.js → chunk-BMKE6FT5.js} +37 -18
- package/dist/{chunk-VKI7ORIO.js.map → chunk-BMKE6FT5.js.map} +1 -1
- package/dist/chunk-BQCOSNM3.js +93 -0
- package/dist/chunk-BQCOSNM3.js.map +7 -0
- package/dist/chunk-CHB5K4GI.js +107 -0
- package/dist/chunk-CHB5K4GI.js.map +7 -0
- package/dist/chunk-D4OZACS2.js +35 -0
- package/dist/chunk-EHQ2M5B4.js +166 -0
- package/dist/{chunk-ZYSVG4X3.js.map → chunk-EHQ2M5B4.js.map} +2 -2
- package/dist/chunk-EUBZGAIN.js +372 -0
- package/dist/chunk-EUBZGAIN.js.map +7 -0
- package/dist/{chunk-UYRR6F5S.js → chunk-FIMCETCB.js} +9 -3
- package/dist/{chunk-UYRR6F5S.js.map → chunk-FIMCETCB.js.map} +1 -1
- package/dist/{chunk-DEF3KFP7.js → chunk-GVLJUD6R.js} +4 -2
- package/dist/{chunk-DEF3KFP7.js.map → chunk-GVLJUD6R.js.map} +1 -1
- package/dist/chunk-HLBLZKZH.js +45 -0
- package/dist/chunk-HLBLZKZH.js.map +7 -0
- package/dist/{chunk-XS6PU75S.js → chunk-IVWPPTDM.js} +1 -1
- package/dist/{chunk-A7X6OCZE.js → chunk-IXFBUXQW.js} +1 -1
- package/dist/{chunk-HSJ6HYAO.js → chunk-IZZTKEZH.js} +18 -10
- package/dist/chunk-IZZTKEZH.js.map +7 -0
- package/dist/{chunk-2EFL22PV.js → chunk-JI4HCLK7.js} +7 -3
- package/dist/chunk-JI4HCLK7.js.map +7 -0
- package/dist/chunk-JLVECHVJ.js +36 -0
- package/dist/chunk-JLVECHVJ.js.map +7 -0
- package/dist/{chunk-XXU2NVOE.js → chunk-KJTPUTU7.js} +30 -6
- package/dist/chunk-KJTPUTU7.js.map +7 -0
- package/dist/{chunk-V5U6BHT2.js → chunk-KS646CDL.js} +7 -3
- package/dist/{chunk-V5U6BHT2.js.map → chunk-KS646CDL.js.map} +1 -1
- package/dist/{chunk-53A4JHFW.js → chunk-MJ3MLGVB.js} +23 -4
- package/dist/chunk-MJ3MLGVB.js.map +7 -0
- package/dist/chunk-MJLWBVZP.js +822 -0
- package/dist/chunk-MJLWBVZP.js.map +7 -0
- package/dist/chunk-MMF5RMLU.js +65 -0
- package/dist/chunk-MMF5RMLU.js.map +7 -0
- package/dist/{chunk-QH2M65BR.js → chunk-MUW3J7CP.js} +7 -3
- package/dist/{chunk-QH2M65BR.js.map → chunk-MUW3J7CP.js.map} +1 -1
- package/dist/{chunk-3LMXSKZ7.js → chunk-NFXLN6FJ.js} +1 -1
- package/dist/chunk-NT7RDVDA.js +33 -0
- package/dist/{chunk-KQSHIOZK.js.map → chunk-NT7RDVDA.js.map} +1 -1
- package/dist/{chunk-OZHBEG7U.js → chunk-O4EKE3YR.js} +15 -5
- package/dist/{chunk-OZHBEG7U.js.map → chunk-O4EKE3YR.js.map} +1 -1
- package/dist/chunk-Q2OBTLBI.js +5473 -0
- package/dist/chunk-Q2OBTLBI.js.map +7 -0
- package/dist/{chunk-WWDVA4NV.js → chunk-QJ7MQIHN.js} +22 -6
- package/dist/{chunk-WWDVA4NV.js.map → chunk-QJ7MQIHN.js.map} +1 -1
- package/dist/{chunk-N5OHRWG2.js → chunk-QSRXXZO7.js} +4 -2
- package/dist/{chunk-N5OHRWG2.js.map → chunk-QSRXXZO7.js.map} +1 -1
- package/dist/{chunk-GZTCXXSS.js → chunk-QT5GS374.js} +57 -46
- package/dist/{chunk-GZTCXXSS.js.map → chunk-QT5GS374.js.map} +1 -1
- package/dist/chunk-QX5Y5CE5.js +683 -0
- package/dist/{chunk-F3COCCAE.js.map → chunk-QX5Y5CE5.js.map} +1 -1
- package/dist/{chunk-IIFUDVGS.js → chunk-U6IF5D3J.js} +310 -177
- package/dist/chunk-U6IF5D3J.js.map +7 -0
- package/dist/{chunk-VQSCECTS.js → chunk-UPRKGNBR.js} +6 -4
- package/dist/{chunk-VQSCECTS.js.map → chunk-UPRKGNBR.js.map} +1 -1
- package/dist/chunk-UUCRNFMH.js +62 -0
- package/dist/chunk-UUCRNFMH.js.map +7 -0
- package/dist/chunk-UYWZQVH5.js +35 -0
- package/dist/chunk-UYWZQVH5.js.map +7 -0
- package/dist/{chunk-XMGUQHMF.js → chunk-VSSVN6WG.js} +11 -1
- package/dist/chunk-VSSVN6WG.js.map +7 -0
- package/dist/{chunk-VHS2MZQS.js → chunk-W7Q3VYAB.js} +9 -6
- package/dist/{chunk-VHS2MZQS.js.map → chunk-W7Q3VYAB.js.map} +1 -1
- package/dist/{chunk-JWXQNBBA.js → chunk-WAXMRSVR.js} +7 -1
- package/dist/{chunk-JWXQNBBA.js.map → chunk-WAXMRSVR.js.map} +1 -1
- package/dist/{chunk-BWYKUDJR.js → chunk-X3NER6FY.js} +14 -8
- package/dist/{chunk-BWYKUDJR.js.map → chunk-X3NER6FY.js.map} +1 -1
- package/dist/{chunk-IM33F5CM.js → chunk-XYQZLDRB.js} +1668 -1623
- package/dist/chunk-XYQZLDRB.js.map +7 -0
- package/dist/{chunk-LOIZNQOU.js → chunk-ZM5FMRLS.js} +9 -3
- package/dist/{chunk-LOIZNQOU.js.map → chunk-ZM5FMRLS.js.map} +1 -1
- package/dist/{chunk-755HIAI3.js → chunk-ZMO4E7IW.js} +3 -42
- package/dist/chunk-ZMO4E7IW.js.map +7 -0
- package/dist/{cli-KZGF3FV5.js → cli-4KO6TA5J.js} +251 -485
- package/dist/cli-4KO6TA5J.js.map +7 -0
- package/dist/commands-JSY7CGSU.js +54 -0
- package/dist/{config-GTJWCNPF.js → config-DQEFVW3Y.js} +9 -6
- package/dist/{context-WF3TTXQU.js → context-HVQCTO5R.js} +8 -7
- package/dist/{costTracker-2G3ZI2JF.js → costTracker-VSWW7SRT.js} +3 -2
- package/dist/{customCommands-QOWK57EX.js → customCommands-XCINU5TG.js} +6 -5
- package/dist/{env-37BAP7QF.js → env-ZOPEXWMF.js} +10 -7
- package/dist/{gateway-IZYO6YFJ.js → gateway-SUXSILQL.js} +542 -96
- package/dist/gateway-SUXSILQL.js.map +7 -0
- package/dist/identity-3KZQQVBG.js +16 -0
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/{kodeAgentSessionId-KTGFX2BE.js → kodeAgentSessionId-4SH24DVH.js} +1 -1
- package/dist/{kodeAgentSessionLoad-6F7SJXBC.js → kodeAgentSessionLoad-HB3BYVNG.js} +6 -5
- package/dist/{kodeAgentSessionResume-UEEDRJ3N.js → kodeAgentSessionResume-IGSZZY3G.js} +6 -5
- package/dist/{kodeAgentStreamJson-VIXFTYL5.js → kodeAgentStreamJson-4ZKIWKS3.js} +4 -2
- package/dist/{kodeAgentStreamJsonSession-XC3IPREZ.js → kodeAgentStreamJsonSession-4L76UC75.js} +15 -4
- package/dist/kodeAgentStreamJsonSession-4L76UC75.js.map +7 -0
- package/dist/{kodeAgentStructuredStdio-SI5C7AAD.js → kodeAgentStructuredStdio-5DCUC6V6.js} +3 -3
- package/dist/{kodeHooks-V36SHCTC.js → kodeHooks-H6DMC3XX.js} +6 -5
- package/dist/{llm-CYUDKJNR.js → llm-OJZ6DZVC.js} +306 -60
- package/dist/llm-OJZ6DZVC.js.map +7 -0
- package/dist/{llmLazy-IXVVBRTN.js → llmLazy-TDLZZDPL.js} +2 -2
- package/dist/{loader-OEJ6C3TN.js → loader-MOVYZ76M.js} +6 -5
- package/dist/{mcp-KE3SILMX.js → mcp-DUYSIR5L.js} +10 -9
- package/dist/{mentionProcessor-GAU2WAYB.js → mentionProcessor-EKVLXJN4.js} +14 -7
- package/dist/{mentionProcessor-GAU2WAYB.js.map → mentionProcessor-EKVLXJN4.js.map} +1 -1
- package/dist/{messages-WCSGGSEU.js → messages-23ICFVMC.js} +2 -2
- package/dist/{model-4TQIV5J2.js → model-FUBCTRTV.js} +10 -7
- package/dist/{openai-KTZV6F7N.js → openai-SMYIAIO4.js} +8 -7
- package/dist/{outputStyles-WX5RYQOA.js → outputStyles-HBOYJFBE.js} +6 -5
- package/dist/{pluginRuntime-JXMJZ2LC.js → pluginRuntime-ATZMDZA7.js} +11 -8
- package/dist/{pluginRuntime-JXMJZ2LC.js.map → pluginRuntime-ATZMDZA7.js.map} +1 -1
- package/dist/{pluginValidation-JNQZYLUP.js → pluginValidation-7CGOMT6F.js} +8 -7
- package/dist/prompts-MFESKNYZ.js +58 -0
- package/dist/query-BFEFOX4S.js +58 -0
- package/dist/{responsesStreaming-2AIT6GHG.js → responsesStreaming-JORGEFQC.js} +1 -1
- package/dist/{ripgrep-KDPQAMB2.js → ripgrep-KNJBCJIQ.js} +5 -4
- package/dist/sandbox-P3FR4G4D.js +63 -0
- package/dist/{skillMarketplace-IXAGP3Q2.js → skillMarketplace-PCMKVV4O.js} +5 -4
- package/dist/{state-MSCYLB6Y.js → state-XBYIQ7R4.js} +6 -3
- package/dist/structuredOutput-KAVFUV2Z.js +9 -0
- package/dist/theme-4ZSXUILR.js +15 -0
- package/dist/thinking-TTNUZUB3.js +18 -0
- package/dist/{toolPermissionContext-I3IXPVED.js → toolPermissionContext-JCQ5MFUT.js} +1 -1
- package/dist/toolPermissionContext-JCQ5MFUT.js.map +7 -0
- package/dist/toolPermissionContextState-R6ZGMKP6.js +24 -0
- package/dist/toolPermissionContextState-R6ZGMKP6.js.map +7 -0
- package/dist/{toolPermissionSettings-EUZKGZU2.js → toolPermissionSettings-GMEYTJEA.js} +9 -8
- package/dist/toolPermissionSettings-GMEYTJEA.js.map +7 -0
- package/dist/tools-7FVKB7BG.js +55 -0
- package/dist/tools-7FVKB7BG.js.map +7 -0
- package/dist/{userInput-LJL4CVOB.js → userInput-SZEUY5J6.js} +49 -34
- package/dist/{userInput-LJL4CVOB.js.map → userInput-SZEUY5J6.js.map} +1 -1
- package/dist/{uuid-VA3KVASX.js → uuid-RQH3OZ3W.js} +1 -1
- package/dist/uuid-RQH3OZ3W.js.map +7 -0
- package/dist/workspace-EP63OB5S.js +21 -0
- package/dist/workspace-EP63OB5S.js.map +7 -0
- package/package.json +2 -2
- package/web/dist/assets/index-XuLVvSQF.js +251 -0
- package/web/dist/assets/index-pSid9IlY.css +10 -0
- package/web/dist/index.html +2 -2
- package/dist/REPL-IAK7ZN2Z.js +0 -42
- package/dist/acp-J4WDYGRX.js.map +0 -7
- package/dist/ask-MGUO3L35.js.map +0 -7
- package/dist/chunk-2C43OXE7.js.map +0 -7
- package/dist/chunk-2EFL22PV.js.map +0 -7
- package/dist/chunk-53A4JHFW.js.map +0 -7
- package/dist/chunk-755HIAI3.js.map +0 -7
- package/dist/chunk-AXWJI6N5.js +0 -11
- package/dist/chunk-F3COCCAE.js +0 -654
- package/dist/chunk-HSJ6HYAO.js.map +0 -7
- package/dist/chunk-IIFUDVGS.js.map +0 -7
- package/dist/chunk-IM33F5CM.js.map +0 -7
- package/dist/chunk-KQSHIOZK.js +0 -24
- package/dist/chunk-OJIMOLIC.js.map +0 -7
- package/dist/chunk-XMGUQHMF.js.map +0 -7
- package/dist/chunk-XXU2NVOE.js.map +0 -7
- package/dist/chunk-ZYSVG4X3.js +0 -151
- package/dist/cli-KZGF3FV5.js.map +0 -7
- package/dist/commands-AVEBLFVS.js +0 -46
- package/dist/gateway-IZYO6YFJ.js.map +0 -7
- package/dist/kodeAgentStreamJsonSession-XC3IPREZ.js.map +0 -7
- package/dist/llm-CYUDKJNR.js.map +0 -7
- package/dist/prompts-LE6GK75N.js +0 -48
- package/dist/query-GGIP6PWG.js +0 -50
- package/dist/theme-GAMFOLBW.js +0 -14
- package/dist/tools-3HOUIDM3.js +0 -47
- package/web/dist/assets/index-COAJqX1Z.css +0 -1
- package/web/dist/assets/index-CzS_4LmC.js +0 -179
- /package/dist/{REPL-IAK7ZN2Z.js.map → REPL-DECTPCL5.js.map} +0 -0
- /package/dist/{autoUpdater-2GS6LRPK.js.map → autoUpdater-FFMM2DR7.js.map} +0 -0
- /package/dist/{chunk-RUXIBQ3B.js.map → chunk-BJYXLCRS.js.map} +0 -0
- /package/dist/{chunk-AXWJI6N5.js.map → chunk-D4OZACS2.js.map} +0 -0
- /package/dist/{chunk-XS6PU75S.js.map → chunk-IVWPPTDM.js.map} +0 -0
- /package/dist/{chunk-A7X6OCZE.js.map → chunk-IXFBUXQW.js.map} +0 -0
- /package/dist/{chunk-3LMXSKZ7.js.map → chunk-NFXLN6FJ.js.map} +0 -0
- /package/dist/{commands-AVEBLFVS.js.map → commands-JSY7CGSU.js.map} +0 -0
- /package/dist/{config-GTJWCNPF.js.map → config-DQEFVW3Y.js.map} +0 -0
- /package/dist/{context-WF3TTXQU.js.map → context-HVQCTO5R.js.map} +0 -0
- /package/dist/{costTracker-2G3ZI2JF.js.map → costTracker-VSWW7SRT.js.map} +0 -0
- /package/dist/{customCommands-QOWK57EX.js.map → customCommands-XCINU5TG.js.map} +0 -0
- /package/dist/{env-37BAP7QF.js.map → env-ZOPEXWMF.js.map} +0 -0
- /package/dist/{kodeAgentSessionId-KTGFX2BE.js.map → identity-3KZQQVBG.js.map} +0 -0
- /package/dist/{kodeAgentSessionLoad-6F7SJXBC.js.map → kodeAgentSessionId-4SH24DVH.js.map} +0 -0
- /package/dist/{kodeAgentSessionResume-UEEDRJ3N.js.map → kodeAgentSessionLoad-HB3BYVNG.js.map} +0 -0
- /package/dist/{kodeAgentStreamJson-VIXFTYL5.js.map → kodeAgentSessionResume-IGSZZY3G.js.map} +0 -0
- /package/dist/{kodeAgentStructuredStdio-SI5C7AAD.js.map → kodeAgentStreamJson-4ZKIWKS3.js.map} +0 -0
- /package/dist/{kodeHooks-V36SHCTC.js.map → kodeAgentStructuredStdio-5DCUC6V6.js.map} +0 -0
- /package/dist/{llmLazy-IXVVBRTN.js.map → kodeHooks-H6DMC3XX.js.map} +0 -0
- /package/dist/{loader-OEJ6C3TN.js.map → llmLazy-TDLZZDPL.js.map} +0 -0
- /package/dist/{mcp-KE3SILMX.js.map → loader-MOVYZ76M.js.map} +0 -0
- /package/dist/{messages-WCSGGSEU.js.map → mcp-DUYSIR5L.js.map} +0 -0
- /package/dist/{model-4TQIV5J2.js.map → messages-23ICFVMC.js.map} +0 -0
- /package/dist/{openai-KTZV6F7N.js.map → model-FUBCTRTV.js.map} +0 -0
- /package/dist/{outputStyles-WX5RYQOA.js.map → openai-SMYIAIO4.js.map} +0 -0
- /package/dist/{pluginValidation-JNQZYLUP.js.map → outputStyles-HBOYJFBE.js.map} +0 -0
- /package/dist/{prompts-LE6GK75N.js.map → pluginValidation-7CGOMT6F.js.map} +0 -0
- /package/dist/{query-GGIP6PWG.js.map → prompts-MFESKNYZ.js.map} +0 -0
- /package/dist/{responsesStreaming-2AIT6GHG.js.map → query-BFEFOX4S.js.map} +0 -0
- /package/dist/{ripgrep-KDPQAMB2.js.map → responsesStreaming-JORGEFQC.js.map} +0 -0
- /package/dist/{skillMarketplace-IXAGP3Q2.js.map → ripgrep-KNJBCJIQ.js.map} +0 -0
- /package/dist/{state-MSCYLB6Y.js.map → sandbox-P3FR4G4D.js.map} +0 -0
- /package/dist/{theme-GAMFOLBW.js.map → skillMarketplace-PCMKVV4O.js.map} +0 -0
- /package/dist/{toolPermissionContext-I3IXPVED.js.map → state-XBYIQ7R4.js.map} +0 -0
- /package/dist/{toolPermissionSettings-EUZKGZU2.js.map → structuredOutput-KAVFUV2Z.js.map} +0 -0
- /package/dist/{tools-3HOUIDM3.js.map → theme-4ZSXUILR.js.map} +0 -0
- /package/dist/{uuid-VA3KVASX.js.map → thinking-TTNUZUB3.js.map} +0 -0
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
import { createRequire as __newcrawCreateRequire } from "node:module";
|
|
2
|
+
const require = __newcrawCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
debug,
|
|
5
|
+
init_debugLogger
|
|
6
|
+
} from "./chunk-QT5GS374.js";
|
|
7
|
+
import {
|
|
8
|
+
init_log,
|
|
9
|
+
logError
|
|
10
|
+
} from "./chunk-XYQZLDRB.js";
|
|
11
|
+
import {
|
|
12
|
+
__esm,
|
|
13
|
+
__export
|
|
14
|
+
} from "./chunk-D4OZACS2.js";
|
|
15
|
+
|
|
16
|
+
// src/services/sandbox/types.ts
|
|
17
|
+
var DEFAULT_SANDBOX_CONFIG;
|
|
18
|
+
var init_types = __esm({
|
|
19
|
+
"src/services/sandbox/types.ts"() {
|
|
20
|
+
DEFAULT_SANDBOX_CONFIG = {
|
|
21
|
+
engine: "podman",
|
|
22
|
+
fallbackEngine: "docker",
|
|
23
|
+
poolSize: 2,
|
|
24
|
+
poolIdleTimeoutMs: 3e5,
|
|
25
|
+
defaultTimeoutMs: 6e4,
|
|
26
|
+
defaultMemoryLimitMb: 512,
|
|
27
|
+
defaultCpuLimit: 1,
|
|
28
|
+
networkEnabled: false
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// src/services/sandbox/runtimeImages.ts
|
|
34
|
+
function getRuntimeImage(runtime) {
|
|
35
|
+
return RUNTIME_IMAGES[runtime];
|
|
36
|
+
}
|
|
37
|
+
function getImageFullName(runtime) {
|
|
38
|
+
return RUNTIME_IMAGES[runtime].fullName;
|
|
39
|
+
}
|
|
40
|
+
function getAllRuntimeImages() {
|
|
41
|
+
return Object.values(RUNTIME_IMAGES);
|
|
42
|
+
}
|
|
43
|
+
function resolveImage(runtime, customImage) {
|
|
44
|
+
if (customImage) return customImage;
|
|
45
|
+
return getImageFullName(runtime);
|
|
46
|
+
}
|
|
47
|
+
var RUNTIME_IMAGES;
|
|
48
|
+
var init_runtimeImages = __esm({
|
|
49
|
+
"src/services/sandbox/runtimeImages.ts"() {
|
|
50
|
+
RUNTIME_IMAGES = {
|
|
51
|
+
python: {
|
|
52
|
+
runtime: "python",
|
|
53
|
+
image: "python",
|
|
54
|
+
tag: "3.11-alpine",
|
|
55
|
+
fullName: "python:3.11-alpine",
|
|
56
|
+
preInstallCommands: ["pip install --no-cache-dir --upgrade pip"]
|
|
57
|
+
},
|
|
58
|
+
node: {
|
|
59
|
+
runtime: "node",
|
|
60
|
+
image: "node",
|
|
61
|
+
tag: "20-alpine",
|
|
62
|
+
fullName: "node:20-alpine"
|
|
63
|
+
},
|
|
64
|
+
bash: {
|
|
65
|
+
runtime: "bash",
|
|
66
|
+
image: "alpine",
|
|
67
|
+
tag: "3.19",
|
|
68
|
+
fullName: "alpine:3.19",
|
|
69
|
+
preInstallCommands: ["apk add --no-cache bash curl jq"]
|
|
70
|
+
},
|
|
71
|
+
custom: {
|
|
72
|
+
runtime: "custom",
|
|
73
|
+
image: "alpine",
|
|
74
|
+
tag: "3.19",
|
|
75
|
+
fullName: "alpine:3.19"
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// src/services/sandbox/podmanEngine.ts
|
|
82
|
+
import { spawn } from "child_process";
|
|
83
|
+
import { randomUUID } from "crypto";
|
|
84
|
+
import which from "which";
|
|
85
|
+
function whichSync(bin) {
|
|
86
|
+
try {
|
|
87
|
+
return which.sync(bin, { nothrow: true }) ?? null;
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async function detectContainerEngine() {
|
|
93
|
+
for (const engine of ["podman", "docker"]) {
|
|
94
|
+
const binary = whichSync(engine);
|
|
95
|
+
if (!binary) continue;
|
|
96
|
+
try {
|
|
97
|
+
const version = await execSimple([binary, "--version"]);
|
|
98
|
+
const rootless = engine === "podman" ? await checkPodmanRootless(binary) : false;
|
|
99
|
+
detectedEngine = engine;
|
|
100
|
+
detectedBinary = binary;
|
|
101
|
+
return {
|
|
102
|
+
name: engine,
|
|
103
|
+
available: true,
|
|
104
|
+
rootless,
|
|
105
|
+
version: version.trim()
|
|
106
|
+
};
|
|
107
|
+
} catch {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
detectedEngine = "none";
|
|
112
|
+
detectedBinary = null;
|
|
113
|
+
return { name: "none", available: false, rootless: false };
|
|
114
|
+
}
|
|
115
|
+
async function checkPodmanRootless(binary) {
|
|
116
|
+
try {
|
|
117
|
+
const info = await execSimple([binary, "info", "--format", "{{.Host.Security.Rootless}}"]);
|
|
118
|
+
return info.trim().toLowerCase() === "true";
|
|
119
|
+
} catch {
|
|
120
|
+
return process.getuid?.() !== 0;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function getEngineBinary() {
|
|
124
|
+
if (detectedBinary) return detectedBinary;
|
|
125
|
+
const podman = whichSync("podman");
|
|
126
|
+
if (podman) {
|
|
127
|
+
detectedEngine = "podman";
|
|
128
|
+
detectedBinary = podman;
|
|
129
|
+
return podman;
|
|
130
|
+
}
|
|
131
|
+
const docker = whichSync("docker");
|
|
132
|
+
if (docker) {
|
|
133
|
+
detectedEngine = "docker";
|
|
134
|
+
detectedBinary = docker;
|
|
135
|
+
return docker;
|
|
136
|
+
}
|
|
137
|
+
throw new Error(
|
|
138
|
+
"No container engine found. Install Podman (preferred) or Docker."
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
function getEngineType() {
|
|
142
|
+
if (detectedEngine) return detectedEngine;
|
|
143
|
+
getEngineBinary();
|
|
144
|
+
return detectedEngine;
|
|
145
|
+
}
|
|
146
|
+
function execSimple(cmd) {
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
const child = spawn(cmd[0], cmd.slice(1), {
|
|
149
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
150
|
+
windowsHide: true
|
|
151
|
+
});
|
|
152
|
+
let stdout = "";
|
|
153
|
+
let stderr = "";
|
|
154
|
+
child.stdout?.on("data", (d) => {
|
|
155
|
+
stdout += d.toString();
|
|
156
|
+
});
|
|
157
|
+
child.stderr?.on("data", (d) => {
|
|
158
|
+
stderr += d.toString();
|
|
159
|
+
});
|
|
160
|
+
child.on("close", (code) => {
|
|
161
|
+
if (code === 0) resolve(stdout);
|
|
162
|
+
else reject(new Error(`Command failed (${code}): ${stderr}`));
|
|
163
|
+
});
|
|
164
|
+
child.on("error", reject);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function buildRunArgs(config) {
|
|
168
|
+
const binary = getEngineBinary();
|
|
169
|
+
const image = resolveImage(config.runtime, config.image);
|
|
170
|
+
const name = `kode-sandbox-${randomUUID().slice(0, 8)}`;
|
|
171
|
+
const args = [
|
|
172
|
+
binary,
|
|
173
|
+
"run",
|
|
174
|
+
"--name",
|
|
175
|
+
name,
|
|
176
|
+
"--detach",
|
|
177
|
+
"--init"
|
|
178
|
+
];
|
|
179
|
+
if (!config.networkEnabled) {
|
|
180
|
+
args.push("--network", "none");
|
|
181
|
+
}
|
|
182
|
+
if (config.memoryLimitMb) {
|
|
183
|
+
args.push("--memory", `${config.memoryLimitMb}m`);
|
|
184
|
+
}
|
|
185
|
+
if (config.cpuLimit) {
|
|
186
|
+
args.push("--cpus", String(config.cpuLimit));
|
|
187
|
+
}
|
|
188
|
+
if (config.workDir) {
|
|
189
|
+
args.push("--workdir", config.workDir);
|
|
190
|
+
}
|
|
191
|
+
for (const mount of config.mountPaths ?? []) {
|
|
192
|
+
const opt = mount.readOnly ? `${mount.hostPath}:${mount.containerPath}:ro` : `${mount.hostPath}:${mount.containerPath}`;
|
|
193
|
+
args.push("-v", opt);
|
|
194
|
+
}
|
|
195
|
+
for (const [key, value] of Object.entries(config.env ?? {})) {
|
|
196
|
+
args.push("-e", `${key}=${value}`);
|
|
197
|
+
}
|
|
198
|
+
args.push(image, "sleep", "infinity");
|
|
199
|
+
return args;
|
|
200
|
+
}
|
|
201
|
+
async function createContainer(config) {
|
|
202
|
+
const args = buildRunArgs(config);
|
|
203
|
+
const binary = args[0];
|
|
204
|
+
const runArgs = args.slice(1);
|
|
205
|
+
const output = await execSimple([binary, ...runArgs]);
|
|
206
|
+
const containerId = output.trim().slice(0, 12);
|
|
207
|
+
const name = runArgs[runArgs.indexOf("--name") + 1];
|
|
208
|
+
return {
|
|
209
|
+
id: containerId,
|
|
210
|
+
name,
|
|
211
|
+
image: resolveImage(config.runtime, config.image),
|
|
212
|
+
status: "ready",
|
|
213
|
+
runtime: config.runtime,
|
|
214
|
+
createdAt: Date.now(),
|
|
215
|
+
lastUsedAt: Date.now()
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
async function execInContainer(containerId, options) {
|
|
219
|
+
const binary = getEngineBinary();
|
|
220
|
+
const startTime = Date.now();
|
|
221
|
+
const args = [binary, "exec"];
|
|
222
|
+
if (options.cwd) {
|
|
223
|
+
args.push("--workdir", options.cwd);
|
|
224
|
+
}
|
|
225
|
+
for (const [key, value] of Object.entries(options.env ?? {})) {
|
|
226
|
+
args.push("-e", `${key}=${value}`);
|
|
227
|
+
}
|
|
228
|
+
args.push(containerId, ...options.command);
|
|
229
|
+
return new Promise((resolve, reject) => {
|
|
230
|
+
const child = spawn(args[0], args.slice(1), {
|
|
231
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
232
|
+
windowsHide: true
|
|
233
|
+
});
|
|
234
|
+
let stdout = "";
|
|
235
|
+
let stderr = "";
|
|
236
|
+
let timedOut = false;
|
|
237
|
+
let timer;
|
|
238
|
+
if (options.timeoutMs) {
|
|
239
|
+
timer = setTimeout(() => {
|
|
240
|
+
timedOut = true;
|
|
241
|
+
child.kill("SIGKILL");
|
|
242
|
+
}, options.timeoutMs);
|
|
243
|
+
}
|
|
244
|
+
child.stdout?.on("data", (d) => {
|
|
245
|
+
stdout += d.toString();
|
|
246
|
+
});
|
|
247
|
+
child.stderr?.on("data", (d) => {
|
|
248
|
+
stderr += d.toString();
|
|
249
|
+
});
|
|
250
|
+
if (options.stdin) {
|
|
251
|
+
child.stdin?.write(options.stdin);
|
|
252
|
+
child.stdin?.end();
|
|
253
|
+
} else {
|
|
254
|
+
child.stdin?.end();
|
|
255
|
+
}
|
|
256
|
+
child.on("close", (code) => {
|
|
257
|
+
if (timer) clearTimeout(timer);
|
|
258
|
+
resolve({
|
|
259
|
+
stdout,
|
|
260
|
+
stderr,
|
|
261
|
+
exitCode: code ?? (timedOut ? 137 : 1),
|
|
262
|
+
durationMs: Date.now() - startTime,
|
|
263
|
+
timedOut
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
child.on("error", (err) => {
|
|
267
|
+
if (timer) clearTimeout(timer);
|
|
268
|
+
reject(err);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function removeContainer(containerId) {
|
|
273
|
+
const binary = getEngineBinary();
|
|
274
|
+
try {
|
|
275
|
+
await execSimple([binary, "rm", "-f", containerId]);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
logError(err);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
async function stopContainer(containerId) {
|
|
281
|
+
const binary = getEngineBinary();
|
|
282
|
+
try {
|
|
283
|
+
await execSimple([binary, "stop", "-t", "3", containerId]);
|
|
284
|
+
} catch (err) {
|
|
285
|
+
logError(err);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
async function getContainerStatus(containerId) {
|
|
289
|
+
const binary = getEngineBinary();
|
|
290
|
+
try {
|
|
291
|
+
const output = await execSimple([
|
|
292
|
+
binary,
|
|
293
|
+
"inspect",
|
|
294
|
+
"--format",
|
|
295
|
+
"{{.State.Status}}",
|
|
296
|
+
containerId
|
|
297
|
+
]);
|
|
298
|
+
const status = output.trim().toLowerCase();
|
|
299
|
+
switch (status) {
|
|
300
|
+
case "running":
|
|
301
|
+
return "running";
|
|
302
|
+
case "created":
|
|
303
|
+
return "creating";
|
|
304
|
+
case "exited":
|
|
305
|
+
case "stopped":
|
|
306
|
+
return "stopped";
|
|
307
|
+
default:
|
|
308
|
+
return "error";
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
return "destroyed";
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function pullImage(image) {
|
|
315
|
+
const binary = getEngineBinary();
|
|
316
|
+
await execSimple([binary, "pull", image]);
|
|
317
|
+
}
|
|
318
|
+
async function imageExists(image) {
|
|
319
|
+
const binary = getEngineBinary();
|
|
320
|
+
try {
|
|
321
|
+
await execSimple([binary, "image", "inspect", image]);
|
|
322
|
+
return true;
|
|
323
|
+
} catch {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
var detectedEngine, detectedBinary;
|
|
328
|
+
var init_podmanEngine = __esm({
|
|
329
|
+
"src/services/sandbox/podmanEngine.ts"() {
|
|
330
|
+
init_log();
|
|
331
|
+
init_runtimeImages();
|
|
332
|
+
detectedEngine = null;
|
|
333
|
+
detectedBinary = null;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// src/services/sandbox/containerLifecycle.ts
|
|
338
|
+
function getContainerLifecycleManager() {
|
|
339
|
+
if (!globalLifecycleManager) {
|
|
340
|
+
globalLifecycleManager = new ContainerLifecycleManager();
|
|
341
|
+
}
|
|
342
|
+
return globalLifecycleManager;
|
|
343
|
+
}
|
|
344
|
+
var ContainerLifecycleManager, globalLifecycleManager;
|
|
345
|
+
var init_containerLifecycle = __esm({
|
|
346
|
+
"src/services/sandbox/containerLifecycle.ts"() {
|
|
347
|
+
init_log();
|
|
348
|
+
init_podmanEngine();
|
|
349
|
+
init_runtimeImages();
|
|
350
|
+
init_types();
|
|
351
|
+
ContainerLifecycleManager = class {
|
|
352
|
+
activeContainers = /* @__PURE__ */ new Map();
|
|
353
|
+
async ensureImage(runtime, customImage) {
|
|
354
|
+
const image = resolveImage(runtime, customImage);
|
|
355
|
+
const exists = await imageExists(image);
|
|
356
|
+
if (!exists) {
|
|
357
|
+
await pullImage(image);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async spawn(config) {
|
|
361
|
+
const mergedConfig = {
|
|
362
|
+
timeoutMs: DEFAULT_SANDBOX_CONFIG.defaultTimeoutMs,
|
|
363
|
+
memoryLimitMb: DEFAULT_SANDBOX_CONFIG.defaultMemoryLimitMb,
|
|
364
|
+
cpuLimit: DEFAULT_SANDBOX_CONFIG.defaultCpuLimit,
|
|
365
|
+
networkEnabled: DEFAULT_SANDBOX_CONFIG.networkEnabled,
|
|
366
|
+
...config
|
|
367
|
+
};
|
|
368
|
+
await this.ensureImage(mergedConfig.runtime, mergedConfig.image);
|
|
369
|
+
const info = await createContainer(mergedConfig);
|
|
370
|
+
this.activeContainers.set(info.id, info);
|
|
371
|
+
return info;
|
|
372
|
+
}
|
|
373
|
+
async exec(containerId, options) {
|
|
374
|
+
const info = this.activeContainers.get(containerId);
|
|
375
|
+
if (info) {
|
|
376
|
+
info.lastUsedAt = Date.now();
|
|
377
|
+
info.status = "running";
|
|
378
|
+
}
|
|
379
|
+
const result = await execInContainer(containerId, {
|
|
380
|
+
timeoutMs: DEFAULT_SANDBOX_CONFIG.defaultTimeoutMs,
|
|
381
|
+
...options
|
|
382
|
+
});
|
|
383
|
+
if (info) {
|
|
384
|
+
info.status = "ready";
|
|
385
|
+
}
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
async destroy(containerId) {
|
|
389
|
+
try {
|
|
390
|
+
await stopContainer(containerId);
|
|
391
|
+
await removeContainer(containerId);
|
|
392
|
+
} catch (err) {
|
|
393
|
+
logError(err);
|
|
394
|
+
} finally {
|
|
395
|
+
this.activeContainers.delete(containerId);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async destroyAll() {
|
|
399
|
+
const ids = Array.from(this.activeContainers.keys());
|
|
400
|
+
await Promise.allSettled(ids.map((id) => this.destroy(id)));
|
|
401
|
+
}
|
|
402
|
+
getActive() {
|
|
403
|
+
return Array.from(this.activeContainers.values());
|
|
404
|
+
}
|
|
405
|
+
getContainer(containerId) {
|
|
406
|
+
return this.activeContainers.get(containerId);
|
|
407
|
+
}
|
|
408
|
+
get activeCount() {
|
|
409
|
+
return this.activeContainers.size;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
globalLifecycleManager = null;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// src/services/sandbox/containerPool.ts
|
|
417
|
+
var ContainerPool;
|
|
418
|
+
var init_containerPool = __esm({
|
|
419
|
+
"src/services/sandbox/containerPool.ts"() {
|
|
420
|
+
init_log();
|
|
421
|
+
init_types();
|
|
422
|
+
ContainerPool = class {
|
|
423
|
+
pool = /* @__PURE__ */ new Map();
|
|
424
|
+
lifecycle;
|
|
425
|
+
config;
|
|
426
|
+
constructor(lifecycle, config = {}) {
|
|
427
|
+
this.lifecycle = lifecycle;
|
|
428
|
+
this.config = { ...DEFAULT_SANDBOX_CONFIG, ...config };
|
|
429
|
+
}
|
|
430
|
+
async warmup(runtime, count) {
|
|
431
|
+
const n = count ?? this.config.poolSize;
|
|
432
|
+
const existing = this.getIdleByRuntime(runtime);
|
|
433
|
+
const needed = Math.max(0, n - existing.length);
|
|
434
|
+
const promises = [];
|
|
435
|
+
for (let i = 0; i < needed; i++) {
|
|
436
|
+
promises.push(this.spawnPoolEntry(runtime));
|
|
437
|
+
}
|
|
438
|
+
await Promise.allSettled(promises);
|
|
439
|
+
}
|
|
440
|
+
async acquire(runtime, config) {
|
|
441
|
+
const idle = this.getIdleByRuntime(runtime);
|
|
442
|
+
if (idle.length > 0) {
|
|
443
|
+
const entry = idle[0];
|
|
444
|
+
entry.inUse = true;
|
|
445
|
+
if (entry.idleTimer) {
|
|
446
|
+
clearTimeout(entry.idleTimer);
|
|
447
|
+
entry.idleTimer = void 0;
|
|
448
|
+
}
|
|
449
|
+
entry.container.lastUsedAt = Date.now();
|
|
450
|
+
return entry.container;
|
|
451
|
+
}
|
|
452
|
+
const containerConfig = {
|
|
453
|
+
runtime,
|
|
454
|
+
networkEnabled: this.config.networkEnabled,
|
|
455
|
+
memoryLimitMb: this.config.defaultMemoryLimitMb,
|
|
456
|
+
cpuLimit: this.config.defaultCpuLimit,
|
|
457
|
+
timeoutMs: this.config.defaultTimeoutMs,
|
|
458
|
+
...config
|
|
459
|
+
};
|
|
460
|
+
const info = await this.lifecycle.spawn(containerConfig);
|
|
461
|
+
this.pool.set(info.id, {
|
|
462
|
+
container: info,
|
|
463
|
+
runtime,
|
|
464
|
+
inUse: true
|
|
465
|
+
});
|
|
466
|
+
return info;
|
|
467
|
+
}
|
|
468
|
+
release(containerId) {
|
|
469
|
+
const entry = this.pool.get(containerId);
|
|
470
|
+
if (!entry) return;
|
|
471
|
+
entry.inUse = false;
|
|
472
|
+
entry.container.lastUsedAt = Date.now();
|
|
473
|
+
const idleCount = this.getIdleByRuntime(entry.runtime).length;
|
|
474
|
+
if (idleCount > this.config.poolSize) {
|
|
475
|
+
void this.evict(containerId);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
entry.idleTimer = setTimeout(() => {
|
|
479
|
+
void this.evict(containerId);
|
|
480
|
+
}, this.config.poolIdleTimeoutMs);
|
|
481
|
+
}
|
|
482
|
+
async exec(containerId, options) {
|
|
483
|
+
return this.lifecycle.exec(containerId, options);
|
|
484
|
+
}
|
|
485
|
+
async evict(containerId) {
|
|
486
|
+
const entry = this.pool.get(containerId);
|
|
487
|
+
if (!entry) return;
|
|
488
|
+
if (entry.inUse) return;
|
|
489
|
+
if (entry.idleTimer) {
|
|
490
|
+
clearTimeout(entry.idleTimer);
|
|
491
|
+
}
|
|
492
|
+
this.pool.delete(containerId);
|
|
493
|
+
try {
|
|
494
|
+
await this.lifecycle.destroy(containerId);
|
|
495
|
+
} catch (err) {
|
|
496
|
+
logError(err);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
async spawnPoolEntry(runtime) {
|
|
500
|
+
try {
|
|
501
|
+
const info = await this.lifecycle.spawn({
|
|
502
|
+
runtime,
|
|
503
|
+
networkEnabled: this.config.networkEnabled,
|
|
504
|
+
memoryLimitMb: this.config.defaultMemoryLimitMb,
|
|
505
|
+
cpuLimit: this.config.defaultCpuLimit,
|
|
506
|
+
timeoutMs: this.config.defaultTimeoutMs
|
|
507
|
+
});
|
|
508
|
+
const entry = {
|
|
509
|
+
container: info,
|
|
510
|
+
runtime,
|
|
511
|
+
inUse: false
|
|
512
|
+
};
|
|
513
|
+
entry.idleTimer = setTimeout(() => {
|
|
514
|
+
void this.evict(info.id);
|
|
515
|
+
}, this.config.poolIdleTimeoutMs);
|
|
516
|
+
this.pool.set(info.id, entry);
|
|
517
|
+
} catch (err) {
|
|
518
|
+
logError(err);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
getIdleByRuntime(runtime) {
|
|
522
|
+
return Array.from(this.pool.values()).filter(
|
|
523
|
+
(e) => e.runtime === runtime && !e.inUse
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
async shutdown() {
|
|
527
|
+
for (const entry of this.pool.values()) {
|
|
528
|
+
if (entry.idleTimer) clearTimeout(entry.idleTimer);
|
|
529
|
+
}
|
|
530
|
+
const ids = Array.from(this.pool.keys());
|
|
531
|
+
await Promise.allSettled(ids.map((id) => this.lifecycle.destroy(id)));
|
|
532
|
+
this.pool.clear();
|
|
533
|
+
}
|
|
534
|
+
get stats() {
|
|
535
|
+
const entries = Array.from(this.pool.values());
|
|
536
|
+
return {
|
|
537
|
+
total: entries.length,
|
|
538
|
+
idle: entries.filter((e) => !e.inUse).length,
|
|
539
|
+
inUse: entries.filter((e) => e.inUse).length,
|
|
540
|
+
byRuntime: Object.fromEntries(
|
|
541
|
+
["python", "node", "bash"].map((rt) => [
|
|
542
|
+
rt,
|
|
543
|
+
{
|
|
544
|
+
total: entries.filter((e) => e.runtime === rt).length,
|
|
545
|
+
idle: entries.filter((e) => e.runtime === rt && !e.inUse).length,
|
|
546
|
+
inUse: entries.filter((e) => e.runtime === rt && e.inUse).length
|
|
547
|
+
}
|
|
548
|
+
])
|
|
549
|
+
)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// src/services/sandbox/skillExecutor.ts
|
|
557
|
+
async function executeSkillInSandbox(request) {
|
|
558
|
+
const pool = getSandboxPool();
|
|
559
|
+
if (!pool) {
|
|
560
|
+
debug.warn("SKILL_SANDBOX_NOT_AVAILABLE", {
|
|
561
|
+
skillDir: request.skillDir,
|
|
562
|
+
runtime: request.runtime
|
|
563
|
+
});
|
|
564
|
+
throw new Error(
|
|
565
|
+
"Sandbox pool not initialized. Ensure container engine (Podman/Docker) is available."
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
const containerConfig = {
|
|
569
|
+
runtime: request.runtime,
|
|
570
|
+
workDir: "/workspace",
|
|
571
|
+
mountPaths: [
|
|
572
|
+
{
|
|
573
|
+
hostPath: request.skillDir,
|
|
574
|
+
containerPath: "/workspace/skill",
|
|
575
|
+
readOnly: true
|
|
576
|
+
},
|
|
577
|
+
...request.workDir ? [{
|
|
578
|
+
hostPath: request.workDir,
|
|
579
|
+
containerPath: "/workspace/project",
|
|
580
|
+
readOnly: false
|
|
581
|
+
}] : []
|
|
582
|
+
],
|
|
583
|
+
env: request.env,
|
|
584
|
+
timeoutMs: request.timeoutMs ?? 12e4
|
|
585
|
+
};
|
|
586
|
+
const container = await pool.acquire(request.runtime, containerConfig);
|
|
587
|
+
try {
|
|
588
|
+
if (request.dependencies) {
|
|
589
|
+
const installResult = await installDependencies(
|
|
590
|
+
container.id,
|
|
591
|
+
request.runtime,
|
|
592
|
+
request.dependencies,
|
|
593
|
+
request.skillDir
|
|
594
|
+
);
|
|
595
|
+
if (installResult.exitCode !== 0) {
|
|
596
|
+
debug.warn("SKILL_DEPENDENCY_INSTALL_FAILED", {
|
|
597
|
+
stderr: installResult.stderr.slice(0, 500)
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const command = buildExecCommand(request);
|
|
602
|
+
const result = await pool.exec(container.id, {
|
|
603
|
+
command,
|
|
604
|
+
cwd: "/workspace",
|
|
605
|
+
env: request.env,
|
|
606
|
+
timeoutMs: request.timeoutMs ?? 12e4
|
|
607
|
+
});
|
|
608
|
+
const outputFiles = await collectOutputFiles(pool, container.id);
|
|
609
|
+
return {
|
|
610
|
+
stdout: result.stdout,
|
|
611
|
+
stderr: result.stderr,
|
|
612
|
+
exitCode: result.exitCode,
|
|
613
|
+
durationMs: result.durationMs,
|
|
614
|
+
outputFiles
|
|
615
|
+
};
|
|
616
|
+
} catch (err) {
|
|
617
|
+
logError(err);
|
|
618
|
+
throw err;
|
|
619
|
+
} finally {
|
|
620
|
+
pool.release(container.id);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async function installDependencies(containerId, runtime, dependenciesFile, skillDir) {
|
|
624
|
+
const lifecycle = getContainerLifecycleManager();
|
|
625
|
+
const depsPath = `/workspace/skill/${dependenciesFile}`;
|
|
626
|
+
let command;
|
|
627
|
+
switch (runtime) {
|
|
628
|
+
case "python":
|
|
629
|
+
command = ["pip", "install", "--no-cache-dir", "-r", depsPath];
|
|
630
|
+
break;
|
|
631
|
+
case "node":
|
|
632
|
+
command = ["npm", "install", "--prefix", "/workspace/skill"];
|
|
633
|
+
break;
|
|
634
|
+
default:
|
|
635
|
+
return { stdout: "", stderr: "", exitCode: 0, durationMs: 0, timedOut: false };
|
|
636
|
+
}
|
|
637
|
+
return lifecycle.exec(containerId, {
|
|
638
|
+
command,
|
|
639
|
+
cwd: "/workspace",
|
|
640
|
+
timeoutMs: 6e4
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
function buildExecCommand(request) {
|
|
644
|
+
const scriptPath = `/workspace/skill/${request.executionScript}`;
|
|
645
|
+
switch (request.runtime) {
|
|
646
|
+
case "python":
|
|
647
|
+
return ["python", scriptPath, ...request.args ? [request.args] : []];
|
|
648
|
+
case "node":
|
|
649
|
+
return ["node", scriptPath, ...request.args ? [request.args] : []];
|
|
650
|
+
case "bash":
|
|
651
|
+
return ["bash", scriptPath, ...request.args ? [request.args] : []];
|
|
652
|
+
default:
|
|
653
|
+
return ["sh", scriptPath, ...request.args ? [request.args] : []];
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async function collectOutputFiles(pool, containerId) {
|
|
657
|
+
try {
|
|
658
|
+
const lsResult = await pool.exec(containerId, {
|
|
659
|
+
command: ["find", "/workspace/project", "-maxdepth", "2", "-type", "f", "-newer", "/workspace/skill", "-name", "*.*"],
|
|
660
|
+
cwd: "/workspace",
|
|
661
|
+
timeoutMs: 5e3
|
|
662
|
+
});
|
|
663
|
+
if (lsResult.exitCode !== 0 || !lsResult.stdout.trim()) return [];
|
|
664
|
+
return lsResult.stdout.trim().split("\n").filter((f) => {
|
|
665
|
+
const ext = f.slice(f.lastIndexOf(".")).toLowerCase();
|
|
666
|
+
return OUTPUT_EXTENSIONS.has(ext);
|
|
667
|
+
});
|
|
668
|
+
} catch {
|
|
669
|
+
return [];
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
function canExecuteInSandbox(skill) {
|
|
673
|
+
return !!(skill.runtime && skill.executionScript);
|
|
674
|
+
}
|
|
675
|
+
var OUTPUT_EXTENSIONS;
|
|
676
|
+
var init_skillExecutor = __esm({
|
|
677
|
+
"src/services/sandbox/skillExecutor.ts"() {
|
|
678
|
+
init_log();
|
|
679
|
+
init_debugLogger();
|
|
680
|
+
init_sandbox();
|
|
681
|
+
init_containerLifecycle();
|
|
682
|
+
OUTPUT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
683
|
+
".png",
|
|
684
|
+
".jpg",
|
|
685
|
+
".jpeg",
|
|
686
|
+
".gif",
|
|
687
|
+
".svg",
|
|
688
|
+
".webp",
|
|
689
|
+
".html",
|
|
690
|
+
".htm",
|
|
691
|
+
".csv",
|
|
692
|
+
".json",
|
|
693
|
+
".xml",
|
|
694
|
+
".md",
|
|
695
|
+
".txt",
|
|
696
|
+
".py",
|
|
697
|
+
".js",
|
|
698
|
+
".ts"
|
|
699
|
+
]);
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// src/services/sandbox/index.ts
|
|
704
|
+
var sandbox_exports = {};
|
|
705
|
+
__export(sandbox_exports, {
|
|
706
|
+
ContainerLifecycleManager: () => ContainerLifecycleManager,
|
|
707
|
+
ContainerPool: () => ContainerPool,
|
|
708
|
+
DEFAULT_SANDBOX_CONFIG: () => DEFAULT_SANDBOX_CONFIG,
|
|
709
|
+
canExecuteInSandbox: () => canExecuteInSandbox,
|
|
710
|
+
createContainer: () => createContainer,
|
|
711
|
+
detectContainerEngine: () => detectContainerEngine,
|
|
712
|
+
execInContainer: () => execInContainer,
|
|
713
|
+
executeSkillInSandbox: () => executeSkillInSandbox,
|
|
714
|
+
getAllRuntimeImages: () => getAllRuntimeImages,
|
|
715
|
+
getContainerLifecycleManager: () => getContainerLifecycleManager,
|
|
716
|
+
getContainerStatus: () => getContainerStatus,
|
|
717
|
+
getEngineBinary: () => getEngineBinary,
|
|
718
|
+
getEngineType: () => getEngineType,
|
|
719
|
+
getImageFullName: () => getImageFullName,
|
|
720
|
+
getRuntimeImage: () => getRuntimeImage,
|
|
721
|
+
getSandboxCapabilities: () => getSandboxCapabilities,
|
|
722
|
+
getSandboxPool: () => getSandboxPool,
|
|
723
|
+
imageExists: () => imageExists,
|
|
724
|
+
initSandboxPool: () => initSandboxPool,
|
|
725
|
+
pullImage: () => pullImage,
|
|
726
|
+
removeContainer: () => removeContainer,
|
|
727
|
+
resolveImage: () => resolveImage,
|
|
728
|
+
shutdownSandboxPool: () => shutdownSandboxPool,
|
|
729
|
+
stopContainer: () => stopContainer,
|
|
730
|
+
tryInitSandboxPool: () => tryInitSandboxPool
|
|
731
|
+
});
|
|
732
|
+
async function initSandboxPool(config) {
|
|
733
|
+
const capabilities = await detectContainerEngine();
|
|
734
|
+
detectedCapabilities = capabilities;
|
|
735
|
+
if (!capabilities.available) {
|
|
736
|
+
throw new Error(
|
|
737
|
+
`No container engine available. Install Podman (rootless preferred) or Docker.
|
|
738
|
+
Podman: https://podman.io/docs/installation
|
|
739
|
+
Docker: https://docs.docker.com/get-docker/`
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
const lifecycle = getContainerLifecycleManager();
|
|
743
|
+
globalPool = new ContainerPool(lifecycle, config);
|
|
744
|
+
return globalPool;
|
|
745
|
+
}
|
|
746
|
+
async function tryInitSandboxPool(config) {
|
|
747
|
+
try {
|
|
748
|
+
const capabilities = await detectContainerEngine();
|
|
749
|
+
detectedCapabilities = capabilities;
|
|
750
|
+
if (!capabilities.available) {
|
|
751
|
+
return { pool: null, capabilities };
|
|
752
|
+
}
|
|
753
|
+
const lifecycle = getContainerLifecycleManager();
|
|
754
|
+
globalPool = new ContainerPool(lifecycle, config);
|
|
755
|
+
return { pool: globalPool, capabilities };
|
|
756
|
+
} catch {
|
|
757
|
+
return {
|
|
758
|
+
pool: null,
|
|
759
|
+
capabilities: { name: "none", available: false, rootless: false }
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function getSandboxPool() {
|
|
764
|
+
return globalPool;
|
|
765
|
+
}
|
|
766
|
+
function getSandboxCapabilities() {
|
|
767
|
+
return detectedCapabilities;
|
|
768
|
+
}
|
|
769
|
+
async function shutdownSandboxPool() {
|
|
770
|
+
if (globalPool) {
|
|
771
|
+
await globalPool.shutdown();
|
|
772
|
+
globalPool = null;
|
|
773
|
+
}
|
|
774
|
+
const lifecycle = getContainerLifecycleManager();
|
|
775
|
+
await lifecycle.destroyAll();
|
|
776
|
+
}
|
|
777
|
+
var globalPool, detectedCapabilities;
|
|
778
|
+
var init_sandbox = __esm({
|
|
779
|
+
"src/services/sandbox/index.ts"() {
|
|
780
|
+
init_types();
|
|
781
|
+
init_podmanEngine();
|
|
782
|
+
init_runtimeImages();
|
|
783
|
+
init_containerLifecycle();
|
|
784
|
+
init_containerPool();
|
|
785
|
+
init_skillExecutor();
|
|
786
|
+
init_containerPool();
|
|
787
|
+
init_containerLifecycle();
|
|
788
|
+
init_podmanEngine();
|
|
789
|
+
globalPool = null;
|
|
790
|
+
detectedCapabilities = null;
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
export {
|
|
795
|
+
DEFAULT_SANDBOX_CONFIG,
|
|
796
|
+
getRuntimeImage,
|
|
797
|
+
getImageFullName,
|
|
798
|
+
getAllRuntimeImages,
|
|
799
|
+
resolveImage,
|
|
800
|
+
detectContainerEngine,
|
|
801
|
+
getEngineBinary,
|
|
802
|
+
getEngineType,
|
|
803
|
+
createContainer,
|
|
804
|
+
execInContainer,
|
|
805
|
+
removeContainer,
|
|
806
|
+
stopContainer,
|
|
807
|
+
getContainerStatus,
|
|
808
|
+
pullImage,
|
|
809
|
+
imageExists,
|
|
810
|
+
ContainerLifecycleManager,
|
|
811
|
+
getContainerLifecycleManager,
|
|
812
|
+
ContainerPool,
|
|
813
|
+
executeSkillInSandbox,
|
|
814
|
+
canExecuteInSandbox,
|
|
815
|
+
initSandboxPool,
|
|
816
|
+
tryInitSandboxPool,
|
|
817
|
+
getSandboxPool,
|
|
818
|
+
getSandboxCapabilities,
|
|
819
|
+
shutdownSandboxPool,
|
|
820
|
+
sandbox_exports,
|
|
821
|
+
init_sandbox
|
|
822
|
+
};
|