@voidrun/sdk 0.0.17 → 0.0.18
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/CodeInterpreter.d.ts +26 -46
- package/dist/CodeInterpreter.d.ts.map +1 -1
- package/dist/CodeInterpreter.js +181 -273
- package/dist/CodeInterpreter.js.map +1 -1
- package/dist/Commands.d.ts +62 -0
- package/dist/Commands.d.ts.map +1 -0
- package/dist/Commands.js +179 -0
- package/dist/Commands.js.map +1 -0
- package/dist/PtySession.d.ts +1 -1
- package/dist/PtySession.d.ts.map +1 -1
- package/dist/PtySession.js +2 -41
- package/dist/PtySession.js.map +1 -1
- package/dist/Sandbox.d.ts +8 -3
- package/dist/Sandbox.d.ts.map +1 -1
- package/dist/Sandbox.js +93 -2
- package/dist/Sandbox.js.map +1 -1
- package/dist/api-client/apis/ExecutionApi.d.ts +84 -1
- package/dist/api-client/apis/ExecutionApi.d.ts.map +1 -1
- package/dist/api-client/apis/ExecutionApi.js +222 -1
- package/dist/api-client/apis/ExecutionApi.js.map +1 -1
- package/dist/api-client/models/CommandKillResponse.d.ts +39 -0
- package/dist/api-client/models/CommandKillResponse.d.ts.map +1 -0
- package/dist/api-client/models/CommandKillResponse.js +44 -0
- package/dist/api-client/models/CommandKillResponse.js.map +1 -0
- package/dist/api-client/models/CommandListResponse.d.ts +40 -0
- package/dist/api-client/models/CommandListResponse.d.ts.map +1 -0
- package/dist/api-client/models/CommandListResponse.js +45 -0
- package/dist/api-client/models/CommandListResponse.js.map +1 -0
- package/dist/api-client/models/CommandRunResponse.d.ts +45 -0
- package/dist/api-client/models/CommandRunResponse.d.ts.map +1 -0
- package/dist/api-client/models/CommandRunResponse.js +46 -0
- package/dist/api-client/models/CommandRunResponse.js.map +1 -0
- package/dist/api-client/models/CommandWaitResponse.d.ts +45 -0
- package/dist/api-client/models/CommandWaitResponse.d.ts.map +1 -0
- package/dist/api-client/models/CommandWaitResponse.js +46 -0
- package/dist/api-client/models/CommandWaitResponse.js.map +1 -0
- package/dist/api-client/models/ExecRequest.d.ts +7 -1
- package/dist/api-client/models/ExecRequest.d.ts.map +1 -1
- package/dist/api-client/models/ExecRequest.js +2 -0
- package/dist/api-client/models/ExecRequest.js.map +1 -1
- package/dist/api-client/models/KillBackgroundProcessRequest.d.ts +33 -0
- package/dist/api-client/models/KillBackgroundProcessRequest.d.ts.map +1 -0
- package/dist/api-client/models/KillBackgroundProcessRequest.js +44 -0
- package/dist/api-client/models/KillBackgroundProcessRequest.js.map +1 -0
- package/dist/api-client/models/ProcessInfo.d.ts +57 -0
- package/dist/api-client/models/ProcessInfo.d.ts.map +1 -0
- package/dist/api-client/models/ProcessInfo.js +50 -0
- package/dist/api-client/models/ProcessInfo.js.map +1 -0
- package/dist/api-client/models/RunBackgroundCommandRequest.d.ts +53 -0
- package/dist/api-client/models/RunBackgroundCommandRequest.d.ts.map +1 -0
- package/dist/api-client/models/RunBackgroundCommandRequest.js +50 -0
- package/dist/api-client/models/RunBackgroundCommandRequest.js.map +1 -0
- package/dist/api-client/models/index.d.ts +7 -0
- package/dist/api-client/models/index.d.ts.map +1 -1
- package/dist/api-client/models/index.js +7 -0
- package/dist/api-client/models/index.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -1,77 +1,57 @@
|
|
|
1
1
|
import { Configuration } from './api-client/index.js';
|
|
2
|
-
export type SupportedLanguage = 'python' | 'javascript' | '
|
|
2
|
+
export type SupportedLanguage = 'python' | 'javascript' | 'typescript' | 'node' | 'bash' | 'sh';
|
|
3
3
|
export interface CodeExecutionOptions {
|
|
4
|
+
language?: SupportedLanguage;
|
|
4
5
|
timeout?: number;
|
|
5
6
|
cwd?: string;
|
|
6
7
|
env?: Record<string, string>;
|
|
8
|
+
onStdout?: (data: string) => void;
|
|
9
|
+
onStderr?: (data: string) => void;
|
|
10
|
+
onError?: (error: Error) => void;
|
|
7
11
|
}
|
|
8
12
|
export interface CodeExecutionResult {
|
|
9
13
|
success: boolean;
|
|
10
|
-
|
|
14
|
+
results: any;
|
|
15
|
+
stdout: string;
|
|
16
|
+
stderr: string;
|
|
11
17
|
error?: string;
|
|
12
18
|
exitCode?: number;
|
|
19
|
+
logs: {
|
|
20
|
+
stdout: string[];
|
|
21
|
+
stderr: string[];
|
|
22
|
+
};
|
|
13
23
|
}
|
|
14
24
|
/**
|
|
15
|
-
* CodeInterpreter provides
|
|
16
|
-
*
|
|
25
|
+
* CodeInterpreter provides E2B-style code execution API
|
|
26
|
+
* Executes code snippets in different languages with streaming support
|
|
17
27
|
*/
|
|
18
28
|
export declare class CodeInterpreter {
|
|
19
29
|
private sandboxId;
|
|
20
30
|
private config;
|
|
21
|
-
private
|
|
22
|
-
private currentLanguage;
|
|
23
|
-
private isInitialized;
|
|
24
|
-
private readonly languageConfigs;
|
|
31
|
+
private execApi;
|
|
25
32
|
/**
|
|
26
33
|
* @internal
|
|
27
34
|
*/
|
|
28
35
|
constructor(sandboxId: string, config: Configuration);
|
|
29
36
|
/**
|
|
30
|
-
*
|
|
31
|
-
* @param language The programming language to use
|
|
32
|
-
* @param sessionId Optional existing PTY session ID
|
|
33
|
-
*/
|
|
34
|
-
initialize(language: SupportedLanguage, sessionId?: string): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Execute code in the initialized interpreter
|
|
37
|
+
* Execute code and return results (E2B-style API)
|
|
37
38
|
* @param code The code to execute
|
|
38
|
-
* @param options Execution options
|
|
39
|
-
* @returns
|
|
40
|
-
*/
|
|
41
|
-
execute(code: string, options?: CodeExecutionOptions): Promise<CodeExecutionResult>;
|
|
42
|
-
/**
|
|
43
|
-
* Execute multiple code snippets sequentially
|
|
44
|
-
* @param codeSnippets Array of code snippets to execute
|
|
45
|
-
* @param options Execution options
|
|
46
|
-
* @returns Array of execution results
|
|
47
|
-
*/
|
|
48
|
-
executeMultiple(codeSnippets: string[], options?: CodeExecutionOptions): Promise<CodeExecutionResult[]>;
|
|
49
|
-
/**
|
|
50
|
-
* Execute code from a file
|
|
51
|
-
* @param filePath Path to the file containing code
|
|
52
|
-
* @param options Execution options
|
|
53
|
-
* @returns The execution result
|
|
54
|
-
*/
|
|
55
|
-
executeFile(filePath: string, options?: CodeExecutionOptions): Promise<CodeExecutionResult>;
|
|
56
|
-
/**
|
|
57
|
-
* Get the current language
|
|
58
|
-
*/
|
|
59
|
-
getCurrentLanguage(): SupportedLanguage | null;
|
|
60
|
-
/**
|
|
61
|
-
* Check if interpreter is initialized
|
|
39
|
+
* @param options Execution options including language and handlers
|
|
40
|
+
* @returns Execution result with stdout, stderr, and parsed results
|
|
62
41
|
*/
|
|
63
|
-
|
|
42
|
+
runCode(code: string, options?: CodeExecutionOptions): Promise<CodeExecutionResult>;
|
|
64
43
|
/**
|
|
65
|
-
*
|
|
44
|
+
* Execute code with streaming handlers
|
|
66
45
|
*/
|
|
67
|
-
|
|
46
|
+
private executeStreaming;
|
|
68
47
|
/**
|
|
69
|
-
*
|
|
48
|
+
* Build execution command for the given language
|
|
70
49
|
*/
|
|
71
|
-
|
|
50
|
+
private buildCommand;
|
|
72
51
|
/**
|
|
73
|
-
*
|
|
52
|
+
* Parse execution results from output
|
|
53
|
+
* Tries to extract the last expression result for REPLs
|
|
74
54
|
*/
|
|
75
|
-
private
|
|
55
|
+
private parseResults;
|
|
76
56
|
}
|
|
77
57
|
//# sourceMappingURL=CodeInterpreter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeInterpreter.d.ts","sourceRoot":"","sources":["../src/CodeInterpreter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CodeInterpreter.d.ts","sourceRoot":"","sources":["../src/CodeInterpreter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA6B,MAAM,uBAAuB,CAAC;AAGjF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAEhG,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE;QACF,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,MAAM,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACL;AAED;;;GAGG;AACH,qBAAa,eAAe;IAOpB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,MAAM;IAPlB,OAAO,CAAC,OAAO,CAAe;IAE9B;;OAEG;gBAES,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa;IAKjC;;;;;OAKG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA8D7F;;OAEG;YACW,gBAAgB;IA6F9B;;OAEG;IACH,OAAO,CAAC,YAAY;IA2CpB;;;OAGG;IACH,OAAO,CAAC,YAAY;CAoBvB"}
|
package/dist/CodeInterpreter.js
CHANGED
|
@@ -1,323 +1,231 @@
|
|
|
1
|
+
import { ExecutionApi } from './api-client/index.js';
|
|
2
|
+
import { wrapRequest } from './utils/runtime.js';
|
|
1
3
|
/**
|
|
2
|
-
* CodeInterpreter provides
|
|
3
|
-
*
|
|
4
|
+
* CodeInterpreter provides E2B-style code execution API
|
|
5
|
+
* Executes code snippets in different languages with streaming support
|
|
4
6
|
*/
|
|
5
7
|
export class CodeInterpreter {
|
|
6
8
|
sandboxId;
|
|
7
9
|
config;
|
|
8
|
-
|
|
9
|
-
currentLanguage = null;
|
|
10
|
-
isInitialized = false;
|
|
11
|
-
languageConfigs = {
|
|
12
|
-
python: {
|
|
13
|
-
command: 'python',
|
|
14
|
-
interactivePrompt: /(?:>>>|\.\.\.) $/,
|
|
15
|
-
startScript: '',
|
|
16
|
-
endScript: '',
|
|
17
|
-
timeout: 30000,
|
|
18
|
-
},
|
|
19
|
-
javascript: {
|
|
20
|
-
command: 'node',
|
|
21
|
-
interactivePrompt: /(?:^|\n)(?:>|\.\.\.) $/,
|
|
22
|
-
startScript: '',
|
|
23
|
-
endScript: '',
|
|
24
|
-
timeout: 30000,
|
|
25
|
-
},
|
|
26
|
-
node: {
|
|
27
|
-
command: 'node',
|
|
28
|
-
interactivePrompt: /(?:^|\n)(?:>|\.\.\.) $/,
|
|
29
|
-
startScript: '',
|
|
30
|
-
endScript: '',
|
|
31
|
-
timeout: 30000,
|
|
32
|
-
},
|
|
33
|
-
bash: {
|
|
34
|
-
command: 'bash',
|
|
35
|
-
interactivePrompt: /[$#] $/,
|
|
36
|
-
startScript: '',
|
|
37
|
-
endScript: '',
|
|
38
|
-
timeout: 30000,
|
|
39
|
-
},
|
|
40
|
-
go: {
|
|
41
|
-
command: 'go run',
|
|
42
|
-
interactivePrompt: /^[\s\S]*$/,
|
|
43
|
-
startScript: '',
|
|
44
|
-
endScript: '',
|
|
45
|
-
timeout: 30000,
|
|
46
|
-
},
|
|
47
|
-
ruby: {
|
|
48
|
-
command: 'irb',
|
|
49
|
-
interactivePrompt: 'irb(main):',
|
|
50
|
-
startScript: '',
|
|
51
|
-
endScript: 'exit',
|
|
52
|
-
timeout: 30000,
|
|
53
|
-
},
|
|
54
|
-
java: {
|
|
55
|
-
command: 'jshell',
|
|
56
|
-
interactivePrompt: 'jshell>',
|
|
57
|
-
startScript: '',
|
|
58
|
-
endScript: '/exit',
|
|
59
|
-
timeout: 30000,
|
|
60
|
-
},
|
|
61
|
-
csharp: {
|
|
62
|
-
command: 'csharp',
|
|
63
|
-
interactivePrompt: 'csharp> ',
|
|
64
|
-
startScript: '',
|
|
65
|
-
endScript: 'exit;',
|
|
66
|
-
timeout: 30000,
|
|
67
|
-
},
|
|
68
|
-
};
|
|
10
|
+
execApi;
|
|
69
11
|
/**
|
|
70
12
|
* @internal
|
|
71
13
|
*/
|
|
72
14
|
constructor(sandboxId, config) {
|
|
73
15
|
this.sandboxId = sandboxId;
|
|
74
16
|
this.config = config;
|
|
17
|
+
this.execApi = new ExecutionApi(config);
|
|
75
18
|
}
|
|
76
19
|
/**
|
|
77
|
-
*
|
|
78
|
-
* @param
|
|
79
|
-
* @param
|
|
20
|
+
* Execute code and return results (E2B-style API)
|
|
21
|
+
* @param code The code to execute
|
|
22
|
+
* @param options Execution options including language and handlers
|
|
23
|
+
* @returns Execution result with stdout, stderr, and parsed results
|
|
80
24
|
*/
|
|
81
|
-
async
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
25
|
+
async runCode(code, options = {}) {
|
|
26
|
+
const language = options.language || 'python';
|
|
27
|
+
const timeout = options.timeout || 60;
|
|
28
|
+
const { onStdout, onStderr, onError } = options;
|
|
29
|
+
// Build the execution command based on language
|
|
30
|
+
const { command, tempFile } = this.buildCommand(code, language);
|
|
31
|
+
const stdoutLines = [];
|
|
32
|
+
const stderrLines = [];
|
|
33
|
+
let exitCode = 0;
|
|
34
|
+
let hasError = false;
|
|
35
|
+
// Use streaming execution if handlers are provided
|
|
36
|
+
if (onStdout || onStderr || onError) {
|
|
37
|
+
await this.executeStreaming(command, timeout, options, stdoutLines, stderrLines);
|
|
87
38
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
39
|
+
else {
|
|
40
|
+
// Non-streaming execution
|
|
41
|
+
try {
|
|
42
|
+
const result = await wrapRequest(this.execApi.execCommand({
|
|
43
|
+
id: this.sandboxId,
|
|
44
|
+
execRequest: {
|
|
45
|
+
command,
|
|
46
|
+
timeout,
|
|
47
|
+
cwd: options.cwd,
|
|
48
|
+
env: options.env,
|
|
49
|
+
}
|
|
50
|
+
}));
|
|
51
|
+
if (result.data) {
|
|
52
|
+
stdoutLines.push(result.data.stdout || '');
|
|
53
|
+
stderrLines.push(result.data.stderr || '');
|
|
54
|
+
exitCode = result.data.exitCode || 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
hasError = true;
|
|
59
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
60
|
+
stderrLines.push(errorMsg);
|
|
61
|
+
(options.onError ?? (() => { }))(error instanceof Error ? error : new Error(errorMsg));
|
|
62
|
+
}
|
|
107
63
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
64
|
+
const stdout = stdoutLines.join('');
|
|
65
|
+
const stderr = stderrLines.join('');
|
|
66
|
+
// Parse results from stdout
|
|
67
|
+
const results = this.parseResults(stdout, language);
|
|
68
|
+
return {
|
|
69
|
+
success: exitCode === 0 && !hasError,
|
|
70
|
+
results,
|
|
71
|
+
stdout,
|
|
72
|
+
stderr,
|
|
73
|
+
error: stderr || undefined,
|
|
74
|
+
exitCode,
|
|
75
|
+
logs: {
|
|
76
|
+
stdout: stdoutLines,
|
|
77
|
+
stderr: stderrLines,
|
|
78
|
+
}
|
|
79
|
+
};
|
|
113
80
|
}
|
|
114
81
|
/**
|
|
115
|
-
* Execute code
|
|
116
|
-
* @param code The code to execute
|
|
117
|
-
* @param options Execution options
|
|
118
|
-
* @returns The execution result
|
|
82
|
+
* Execute code with streaming handlers
|
|
119
83
|
*/
|
|
120
|
-
async
|
|
121
|
-
|
|
122
|
-
|
|
84
|
+
async executeStreaming(command, timeout, options, stdoutLines, stderrLines) {
|
|
85
|
+
const fetchApi = this.config.fetchApi ?? fetch;
|
|
86
|
+
const headers = {
|
|
87
|
+
'Content-Type': 'application/json',
|
|
88
|
+
'Accept': 'text/event-stream'
|
|
89
|
+
};
|
|
90
|
+
if (this.config.apiKey) {
|
|
91
|
+
headers['X-API-Key'] = await this.config.apiKey('X-API-Key');
|
|
123
92
|
}
|
|
124
|
-
const
|
|
125
|
-
|
|
93
|
+
const url = `${this.config.basePath}/sandboxes/${this.sandboxId}/exec-stream`;
|
|
94
|
+
const execRequest = {
|
|
95
|
+
command,
|
|
96
|
+
timeout,
|
|
97
|
+
cwd: options.cwd,
|
|
98
|
+
env: options.env,
|
|
99
|
+
};
|
|
126
100
|
try {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
101
|
+
const response = await fetchApi(url, {
|
|
102
|
+
method: 'POST',
|
|
103
|
+
headers,
|
|
104
|
+
body: JSON.stringify(execRequest),
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) {
|
|
107
|
+
const text = await response.text();
|
|
108
|
+
throw new Error(text || `Exec failed with status ${response.status}`);
|
|
109
|
+
}
|
|
110
|
+
if (!response.body) {
|
|
111
|
+
throw new Error('Response has no body');
|
|
112
|
+
}
|
|
113
|
+
const reader = response.body.getReader();
|
|
114
|
+
const decoder = new TextDecoder('utf-8');
|
|
115
|
+
let buffer = '';
|
|
116
|
+
while (true) {
|
|
117
|
+
const { value, done } = await reader.read();
|
|
118
|
+
if (done)
|
|
119
|
+
break;
|
|
120
|
+
buffer += decoder.decode(value, { stream: true });
|
|
121
|
+
const parts = buffer.split('\n\n');
|
|
122
|
+
buffer = parts.pop() || '';
|
|
123
|
+
for (const part of parts) {
|
|
124
|
+
const lines = part.split('\n');
|
|
125
|
+
let event = 'message';
|
|
126
|
+
const dataLines = [];
|
|
138
127
|
for (const line of lines) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
bracketCount += (trimmedLine.match(/{/g) || []).length;
|
|
142
|
-
bracketCount -= (trimmedLine.match(/}/g) || []).length;
|
|
143
|
-
statementBuffer += (statementBuffer ? '\n' : '') + line;
|
|
144
|
-
// If braces are balanced and line is not empty, we may have a complete statement
|
|
145
|
-
if (bracketCount === 0 && trimmedLine && !trimmedLine.endsWith('{')) {
|
|
146
|
-
// Check if this looks like a complete statement
|
|
147
|
-
if (trimmedLine.endsWith(';') ||
|
|
148
|
-
trimmedLine.endsWith(')') ||
|
|
149
|
-
trimmedLine === '}' ||
|
|
150
|
-
trimmedLine.match(/^return\s/) ||
|
|
151
|
-
bracketCount < 0) {
|
|
152
|
-
statements.push(statementBuffer.trim());
|
|
153
|
-
statementBuffer = '';
|
|
154
|
-
bracketCount = 0;
|
|
155
|
-
}
|
|
128
|
+
if (line.startsWith('event:')) {
|
|
129
|
+
event = line.slice(6).trim();
|
|
156
130
|
}
|
|
131
|
+
else if (line.startsWith('data:')) {
|
|
132
|
+
dataLines.push(line.slice(5).trimEnd());
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const data = dataLines.join('\n');
|
|
136
|
+
if (!data)
|
|
137
|
+
continue;
|
|
138
|
+
if (event === 'stdout') {
|
|
139
|
+
stdoutLines.push(data);
|
|
140
|
+
options.onStdout?.(data);
|
|
157
141
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
142
|
+
else if (event === 'stderr') {
|
|
143
|
+
stderrLines.push(data);
|
|
144
|
+
options.onStderr?.(data);
|
|
161
145
|
}
|
|
162
|
-
|
|
163
|
-
for (const stmt of statements) {
|
|
146
|
+
else if (event === 'exit') {
|
|
164
147
|
try {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
timeout,
|
|
168
|
-
});
|
|
169
|
-
allOutput += (allOutput ? '\n' : '') + output;
|
|
148
|
+
const exitData = JSON.parse(data);
|
|
149
|
+
// Store exit code if needed
|
|
170
150
|
}
|
|
171
151
|
catch (err) {
|
|
172
|
-
//
|
|
173
|
-
allOutput += (allOutput ? '\n' : '') + String(err);
|
|
152
|
+
// Ignore parse errors
|
|
174
153
|
}
|
|
175
154
|
}
|
|
176
|
-
return {
|
|
177
|
-
success: true,
|
|
178
|
-
output: this.cleanOutput(allOutput, trimmedCode),
|
|
179
|
-
};
|
|
180
155
|
}
|
|
181
156
|
}
|
|
182
|
-
const output = await this.ptySession.runCommand(trimmedCode, {
|
|
183
|
-
prompt,
|
|
184
|
-
timeout,
|
|
185
|
-
});
|
|
186
|
-
return {
|
|
187
|
-
success: true,
|
|
188
|
-
output: this.cleanOutput(output, trimmedCode),
|
|
189
|
-
};
|
|
190
157
|
}
|
|
191
158
|
catch (error) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
error: errorMessage,
|
|
197
|
-
};
|
|
159
|
+
if (options.onError) {
|
|
160
|
+
options.onError(error instanceof Error ? error : new Error(String(error)));
|
|
161
|
+
}
|
|
162
|
+
throw error;
|
|
198
163
|
}
|
|
199
164
|
}
|
|
200
165
|
/**
|
|
201
|
-
*
|
|
202
|
-
* @param codeSnippets Array of code snippets to execute
|
|
203
|
-
* @param options Execution options
|
|
204
|
-
* @returns Array of execution results
|
|
166
|
+
* Build execution command for the given language
|
|
205
167
|
*/
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
168
|
+
buildCommand(code, language) {
|
|
169
|
+
const timestamp = Date.now();
|
|
170
|
+
switch (language) {
|
|
171
|
+
case 'python': {
|
|
172
|
+
// For Python, use -c for short snippets, temp file for longer code
|
|
173
|
+
if (code.length < 1000 && !code.includes('\n\n')) {
|
|
174
|
+
// Escape single quotes and use python -c
|
|
175
|
+
const escapedCode = code.replace(/'/g, "'\\''");
|
|
176
|
+
return { command: `python3 -c '${escapedCode}'` };
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// Write to temp file for complex code
|
|
180
|
+
const tempFile = `/tmp/code_${timestamp}.py`;
|
|
181
|
+
const writeCmd = `cat > ${tempFile} << 'EOFPYTHON'\n${code}\nEOFPYTHON`;
|
|
182
|
+
return {
|
|
183
|
+
command: `${writeCmd} && python3 ${tempFile} && rm -f ${tempFile}`,
|
|
184
|
+
tempFile
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
case 'javascript':
|
|
189
|
+
case 'node':
|
|
190
|
+
case 'typescript': {
|
|
191
|
+
const tempFile = `/tmp/code_${timestamp}.js`;
|
|
192
|
+
const writeCmd = `cat > ${tempFile} << 'EOFJS'\n${code}\nEOFJS`;
|
|
193
|
+
return {
|
|
194
|
+
command: `${writeCmd} && node ${tempFile} && rm -f ${tempFile}`,
|
|
195
|
+
tempFile
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
case 'bash':
|
|
199
|
+
case 'sh': {
|
|
200
|
+
const escapedCode = code.replace(/'/g, "'\\''");
|
|
201
|
+
return { command: `bash -c '${escapedCode}'` };
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
throw new Error(`Unsupported language: ${language}`);
|
|
210
205
|
}
|
|
211
|
-
return results;
|
|
212
206
|
}
|
|
213
207
|
/**
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* @param options Execution options
|
|
217
|
-
* @returns The execution result
|
|
208
|
+
* Parse execution results from output
|
|
209
|
+
* Tries to extract the last expression result for REPLs
|
|
218
210
|
*/
|
|
219
|
-
|
|
220
|
-
if (!
|
|
221
|
-
|
|
211
|
+
parseResults(output, language) {
|
|
212
|
+
if (!output || !output.trim()) {
|
|
213
|
+
return null;
|
|
222
214
|
}
|
|
215
|
+
// For Python/Node REPL-style output, try to get the last value
|
|
216
|
+
const lines = output.trim().split('\n');
|
|
217
|
+
const lastLine = lines[lines.length - 1];
|
|
218
|
+
// Try to parse as JSON first
|
|
223
219
|
try {
|
|
224
|
-
|
|
225
|
-
const FS = (await import('./FS.js')).FS;
|
|
226
|
-
const fsManager = new FS(this.sandboxId, this.config);
|
|
227
|
-
const buffer = await fsManager.downloadFile(filePath);
|
|
228
|
-
const content = buffer.toString('utf-8');
|
|
229
|
-
return await this.execute(content, options);
|
|
220
|
+
return JSON.parse(lastLine);
|
|
230
221
|
}
|
|
231
|
-
catch
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
output: '',
|
|
236
|
-
error: errorMessage,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Get the current language
|
|
242
|
-
*/
|
|
243
|
-
getCurrentLanguage() {
|
|
244
|
-
return this.currentLanguage;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Check if interpreter is initialized
|
|
248
|
-
*/
|
|
249
|
-
isReady() {
|
|
250
|
-
return this.isInitialized;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Clean up the interpreter session
|
|
254
|
-
*/
|
|
255
|
-
async close() {
|
|
256
|
-
if (this.ptySession) {
|
|
257
|
-
this.ptySession.close();
|
|
258
|
-
this.ptySession = null;
|
|
259
|
-
}
|
|
260
|
-
this.isInitialized = false;
|
|
261
|
-
this.currentLanguage = null;
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* Reset the interpreter for a new language
|
|
265
|
-
*/
|
|
266
|
-
async reset(newLanguage) {
|
|
267
|
-
await this.close();
|
|
268
|
-
if (newLanguage) {
|
|
269
|
-
await this.initialize(newLanguage);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Clean output by removing the input command and extra prompts
|
|
274
|
-
*/
|
|
275
|
-
cleanOutput(output, input) {
|
|
276
|
-
let cleaned = output;
|
|
277
|
-
// Remove ANSI escape codes
|
|
278
|
-
cleaned = cleaned.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
279
|
-
// Remove carriage returns
|
|
280
|
-
cleaned = cleaned.replace(/\r/g, '');
|
|
281
|
-
// Split into lines
|
|
282
|
-
const lines = cleaned.split('\n');
|
|
283
|
-
const inputLines = input.split('\n').map(l => l.trim());
|
|
284
|
-
// Find all actual output lines (not prompts, not input echoes, not continuation indicators)
|
|
285
|
-
const outputLines = [];
|
|
286
|
-
for (const line of lines) {
|
|
287
|
-
const trimmed = line.trim();
|
|
288
|
-
// Skip empty lines
|
|
289
|
-
if (!trimmed) {
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
// Skip prompts
|
|
293
|
-
if (trimmed.match(/^(?:>>>|\.\.\.|\$|#|>)$/)) {
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
// Skip Node.js continuation indicators (lines starting with |)
|
|
297
|
-
if (trimmed.startsWith('|')) {
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
// Skip input echo lines
|
|
301
|
-
let isInputEcho = false;
|
|
302
|
-
for (const inputLine of inputLines) {
|
|
303
|
-
if (inputLine && trimmed === inputLine) {
|
|
304
|
-
isInputEcho = true;
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
if (!isInputEcho) {
|
|
309
|
-
// Remove trailing prompts from lines
|
|
310
|
-
const cleanedLine = trimmed
|
|
311
|
-
.replace(/>>>\s*$/, '')
|
|
312
|
-
.replace(/\.\.\.\s*$/, '')
|
|
313
|
-
.replace(/>\s*$/, '')
|
|
314
|
-
.replace(/[$#]\s*$/, '');
|
|
315
|
-
if (cleanedLine) {
|
|
316
|
-
outputLines.push(cleanedLine);
|
|
317
|
-
}
|
|
222
|
+
catch {
|
|
223
|
+
// If not JSON, return the last line or full output
|
|
224
|
+
if (lastLine && lastLine !== 'undefined' && lastLine !== 'None') {
|
|
225
|
+
return lastLine;
|
|
318
226
|
}
|
|
227
|
+
return output.trim();
|
|
319
228
|
}
|
|
320
|
-
return outputLines.join('\n').trim();
|
|
321
229
|
}
|
|
322
230
|
}
|
|
323
231
|
//# sourceMappingURL=CodeInterpreter.js.map
|