@doccident/doccident 0.0.3 → 0.0.5

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.
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fortranHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ const fortranHandler = (code, _snippet, config, sandbox, isSharedSandbox) => {
9
+ let success = false;
10
+ let stack = "";
11
+ const context = sandbox;
12
+ let fortranCode = code;
13
+ // Handle shared state
14
+ if (isSharedSandbox) {
15
+ if (!context._fortranCode) {
16
+ context._fortranCode = "";
17
+ }
18
+ context._fortranCode += code + "\n";
19
+ fortranCode = context._fortranCode;
20
+ }
21
+ let finalSource = "";
22
+ // Parse modules vs program
23
+ // We want to lift modules to the top, before the program block
24
+ if (!isSharedSandbox) {
25
+ // Legacy/Single snippet mode
26
+ if (!fortranCode.toLowerCase().includes('program ')) {
27
+ finalSource = `program main
28
+ ${fortranCode}
29
+ end program main`;
30
+ }
31
+ else {
32
+ finalSource = fortranCode;
33
+ }
34
+ }
35
+ else {
36
+ // Shared state mode
37
+ // We need to separate modules, subroutines/functions (external), and the main program body.
38
+ // However, standard Fortran requires:
39
+ // MODULES
40
+ // PROGRAM
41
+ //
42
+ // If the user provides snippets that are just code (print *, ...), they belong in PROGRAM.
43
+ // If they provide MODULE ..., it belongs at top level.
44
+ // If they provide SUBROUTINE ... inside a module or program?
45
+ //
46
+ // Strategy:
47
+ // 1. Extract MODULE blocks.
48
+ // 2. Extract SUBROUTINE/FUNCTION blocks that are top-level? Or assume they are contained?
49
+ // Actually, simple subroutines can be outside/after program if using CONTAINS?
50
+ // No, simplest structure is:
51
+ // MODULES...
52
+ // PROGRAM main
53
+ // USE modules...
54
+ // IMPLICIT NONE
55
+ // ... statements ...
56
+ // END PROGRAM main
57
+ // Let's implement a simple parser that looks for MODULE ... END MODULE blocks.
58
+ const lines = fortranCode.split('\n');
59
+ const modules = [];
60
+ const programBody = [];
61
+ let inModule = false;
62
+ let moduleBuffer = [];
63
+ for (const line of lines) {
64
+ const trimmed = line.trim().toLowerCase();
65
+ if (trimmed.startsWith('module ') && !trimmed.startsWith('module procedure') && !inModule) {
66
+ inModule = true;
67
+ moduleBuffer.push(line);
68
+ }
69
+ else if (inModule) {
70
+ moduleBuffer.push(line);
71
+ if (trimmed.startsWith('end module')) {
72
+ inModule = false;
73
+ modules.push(moduleBuffer.join('\n'));
74
+ moduleBuffer = [];
75
+ }
76
+ }
77
+ else {
78
+ // If it's a "use" statement, it should be at the top of program?
79
+ // Or "implicit none"?
80
+ // We'll just dump everything else into the program body for now.
81
+ // NOTE: If users provide a full PROGRAM block in shared mode, this breaks.
82
+ // We assume shared mode = snippets building up a program.
83
+ if (!trimmed.startsWith('program ') && !trimmed.startsWith('end program')) {
84
+ programBody.push(line);
85
+ }
86
+ }
87
+ }
88
+ // If we have open module buffer (unclosed), dump it to body? Or fail?
89
+ // Or assume it's just code.
90
+ if (inModule) {
91
+ // Fallback
92
+ programBody.push(...moduleBuffer);
93
+ }
94
+ // Detect dependencies (USE statements)
95
+ // Move USE statements to the top of the program body
96
+ const useStatements = [];
97
+ const otherStatements = [];
98
+ for (const line of programBody) {
99
+ const trimmed = line.trim().toLowerCase();
100
+ if (trimmed.startsWith('use ')) {
101
+ useStatements.push(line);
102
+ }
103
+ else {
104
+ otherStatements.push(line);
105
+ }
106
+ }
107
+ finalSource = `${modules.join('\n\n')}
108
+
109
+ program main
110
+ ${useStatements.join('\n')}
111
+ implicit none
112
+ ${otherStatements.join('\n')}
113
+ end program main`;
114
+ }
115
+ const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
116
+ const tempSourceFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_fortran_${uniqueId}.f90`);
117
+ const tempExeFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_fortran_${uniqueId}`);
118
+ const timeout = config.timeout || 30000;
119
+ try {
120
+ (0, fs_1.writeFileSync)(tempSourceFile, finalSource);
121
+ // Compile with gfortran
122
+ const compileResult = (0, child_process_1.spawnSync)('gfortran', [tempSourceFile, '-o', tempExeFile], { encoding: 'utf-8', timeout });
123
+ if (compileResult.status !== 0) {
124
+ stack = compileResult.stderr || "Fortran compilation failed";
125
+ if (isSharedSandbox) {
126
+ stack += `\n\nGenerated Source:\n${finalSource}`;
127
+ }
128
+ }
129
+ else {
130
+ // Run
131
+ const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8', timeout });
132
+ if (runResult.error && runResult.error.code === 'ETIMEDOUT') {
133
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
134
+ }
135
+ if (runResult.status === 0) {
136
+ success = true;
137
+ }
138
+ else {
139
+ stack = runResult.stderr || "Fortran execution failed with non-zero exit code";
140
+ }
141
+ return { success, stack, output: runResult.stdout };
142
+ }
143
+ }
144
+ catch (e) {
145
+ stack = e.message || "Failed to execute gfortran or run binary";
146
+ }
147
+ finally {
148
+ try {
149
+ if ((0, fs_1.existsSync)(tempSourceFile))
150
+ (0, fs_1.unlinkSync)(tempSourceFile);
151
+ if ((0, fs_1.existsSync)(tempExeFile))
152
+ (0, fs_1.unlinkSync)(tempExeFile);
153
+ // Cleanup .mod files generated by modules
154
+ // They are usually in the cwd (tmpdir)
155
+ // We can try to clean them up if we know the module names, or just ignore for now as tmpdir is cleaned by OS eventually?
156
+ // Actually, we are running in tmpdir, so .mod files will pollute it?
157
+ // Better to run in a specific subdir like other handlers to avoid collisions.
158
+ }
159
+ catch {
160
+ // Ignore cleanup error
161
+ }
162
+ }
163
+ return { success, stack };
164
+ };
165
+ exports.fortranHandler = fortranHandler;
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.goHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ // Helper to parse Go code into imports, top-level decls, and main body
9
+ function parseGoCode(fullCode) {
10
+ const lines = fullCode.split('\n');
11
+ const imports = [];
12
+ let topLevel = "";
13
+ let mainBody = "";
14
+ let state = 'NORMAL';
15
+ let braceCount = 0;
16
+ for (const line of lines) {
17
+ const trimmed = line.trim();
18
+ // Skip package main lines in shared snippets
19
+ if (trimmed.startsWith('package main'))
20
+ continue;
21
+ if (state === 'NORMAL') {
22
+ if (trimmed.startsWith('import')) {
23
+ if (trimmed.includes('(')) {
24
+ state = 'IN_IMPORT_BLOCK';
25
+ imports.push(line);
26
+ }
27
+ else {
28
+ imports.push(line);
29
+ }
30
+ }
31
+ else if (trimmed.startsWith('func ') ||
32
+ trimmed.startsWith('type ') ||
33
+ trimmed.startsWith('const ') ||
34
+ trimmed.startsWith('var ')) {
35
+ // Heuristic: Top level declaration
36
+ topLevel += line + "\n";
37
+ // Count braces
38
+ const open = (line.match(/\{/g) || []).length;
39
+ const close = (line.match(/\}/g) || []).length;
40
+ braceCount = open - close;
41
+ if (braceCount > 0) {
42
+ state = 'IN_BRACE_BLOCK';
43
+ }
44
+ }
45
+ else {
46
+ mainBody += line + "\n";
47
+ }
48
+ }
49
+ else if (state === 'IN_IMPORT_BLOCK') {
50
+ imports.push(line);
51
+ if (trimmed.includes(')')) {
52
+ state = 'NORMAL';
53
+ }
54
+ }
55
+ else if (state === 'IN_BRACE_BLOCK') {
56
+ topLevel += line + "\n";
57
+ const open = (line.match(/\{/g) || []).length;
58
+ const close = (line.match(/\}/g) || []).length;
59
+ braceCount += open - close;
60
+ if (braceCount <= 0) {
61
+ state = 'NORMAL';
62
+ braceCount = 0;
63
+ }
64
+ }
65
+ }
66
+ return { imports, topLevel, mainBody };
67
+ }
68
+ const goHandler = (code, _snippet, config, sandbox, isSharedSandbox) => {
69
+ let success = false;
70
+ let stack = "";
71
+ const context = sandbox;
72
+ let fullCode = code;
73
+ // Handle shared state
74
+ if (isSharedSandbox) {
75
+ if (!context._goCode) {
76
+ context._goCode = "";
77
+ }
78
+ context._goCode += code + "\n";
79
+ fullCode = context._goCode;
80
+ }
81
+ let finalSource = "";
82
+ // If explicit package main is present, use as is (unless shared?)
83
+ if (fullCode.includes('package main') && !isSharedSandbox) {
84
+ finalSource = fullCode;
85
+ }
86
+ else {
87
+ const { imports, topLevel, mainBody } = parseGoCode(fullCode);
88
+ // Auto-add fmt if used but not imported
89
+ const importsStr = imports.join('\n');
90
+ let autoImports = "";
91
+ if (!importsStr.includes('"fmt"') && (topLevel.includes('fmt.') || mainBody.includes('fmt.'))) {
92
+ autoImports = 'import "fmt"';
93
+ }
94
+ finalSource = `package main
95
+ ${autoImports}
96
+ ${importsStr}
97
+
98
+ ${topLevel}
99
+
100
+ func main() {
101
+ ${mainBody}
102
+ }`;
103
+ }
104
+ const tempFile = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_go_${Date.now()}_${Math.random().toString(36).substring(7)}.go`);
105
+ const timeout = config.timeout || 30000;
106
+ try {
107
+ (0, fs_1.writeFileSync)(tempFile, finalSource);
108
+ let result = (0, child_process_1.spawnSync)('go', ['run', tempFile], { encoding: 'utf-8', timeout });
109
+ // Retry logic for unused imports
110
+ if (result.status !== 0 && result.stderr && result.stderr.includes("imported and not used")) {
111
+ const lines = finalSource.split('\n');
112
+ const errorLines = result.stderr.split('\n');
113
+ let modified = false;
114
+ errorLines.forEach(err => {
115
+ const match = err.match(/:(\d+):\d+: "(.+)" imported and not used/);
116
+ if (match) {
117
+ const lineNum = parseInt(match[1], 10);
118
+ // Comment out the unused import line (using 1-based index from error)
119
+ if (lines[lineNum - 1]) {
120
+ lines[lineNum - 1] = "// " + lines[lineNum - 1];
121
+ modified = true;
122
+ }
123
+ }
124
+ });
125
+ if (modified) {
126
+ const retriedSource = lines.join('\n');
127
+ (0, fs_1.writeFileSync)(tempFile, retriedSource);
128
+ result = (0, child_process_1.spawnSync)('go', ['run', tempFile], { encoding: 'utf-8', timeout });
129
+ }
130
+ }
131
+ if (result.error && result.error.code === 'ETIMEDOUT') {
132
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
133
+ }
134
+ if (result.status === 0) {
135
+ success = true;
136
+ }
137
+ else {
138
+ stack = result.stderr || "Go execution failed with non-zero exit code";
139
+ // Debug output for shared state issues
140
+ if (isSharedSandbox) {
141
+ stack += `\n\nGenerated Source:\n${finalSource}`;
142
+ }
143
+ }
144
+ return { success, stack, output: result.stdout };
145
+ }
146
+ catch (e) {
147
+ stack = e.message || "Failed to execute go run";
148
+ }
149
+ finally {
150
+ try {
151
+ (0, fs_1.unlinkSync)(tempFile);
152
+ }
153
+ catch {
154
+ // Ignore cleanup error
155
+ }
156
+ }
157
+ return { success, stack };
158
+ };
159
+ exports.goHandler = goHandler;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.javaHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ const javaHandler = (code, _snippet, config, _sandbox, _isSharedSandbox) => {
9
+ let success = false;
10
+ let stack = "";
11
+ // Java execution logic
12
+ // Auto-wrap in class Main and main method if not present
13
+ let javaCode = code;
14
+ let className = "Main";
15
+ // Simple heuristic to detect if class is provided or just snippet
16
+ if (!javaCode.includes("class ")) {
17
+ javaCode = `public class ${className} {
18
+ public static void main(String[] args) {
19
+ ${javaCode}
20
+ }
21
+ }`;
22
+ }
23
+ else {
24
+ // Try to extract class name if provided
25
+ const classMatch = javaCode.match(/class\s+(\w+)/);
26
+ if (classMatch) {
27
+ className = classMatch[1];
28
+ }
29
+ else {
30
+ // Fallback or error? For now assume user knows what they are doing if they write "class"
31
+ // but maybe we should ensure file name matches public class
32
+ }
33
+ }
34
+ const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
35
+ // Create a unique directory for this execution to avoid class name collisions
36
+ // if running parallel or multiple Main classes
37
+ const tempDir = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_java_${uniqueId}`);
38
+ const timeout = config.timeout || 30000;
39
+ // We need to make the directory
40
+ try {
41
+ if (!(0, fs_1.existsSync)(tempDir)) {
42
+ (0, fs_1.mkdirSync)(tempDir);
43
+ }
44
+ const tempSourceFile = (0, path_1.join)(tempDir, `${className}.java`);
45
+ (0, fs_1.writeFileSync)(tempSourceFile, javaCode);
46
+ // Compile with javac
47
+ const compileResult = (0, child_process_1.spawnSync)('javac', [tempSourceFile], { encoding: 'utf-8', cwd: tempDir, timeout });
48
+ if (compileResult.status !== 0) {
49
+ stack = compileResult.stderr || "Java compilation failed";
50
+ }
51
+ else {
52
+ // Run
53
+ const runResult = (0, child_process_1.spawnSync)('java', ['-cp', tempDir, className], { encoding: 'utf-8', cwd: tempDir, timeout });
54
+ if (runResult.error && runResult.error.code === 'ETIMEDOUT') {
55
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
56
+ }
57
+ if (runResult.status === 0) {
58
+ success = true;
59
+ }
60
+ else {
61
+ stack = runResult.stderr || "Java execution failed with non-zero exit code";
62
+ }
63
+ return { success, stack, output: runResult.stdout };
64
+ }
65
+ }
66
+ catch (e) {
67
+ stack = e.message || "Failed to execute javac or java";
68
+ }
69
+ finally {
70
+ try {
71
+ // Cleanup: remove file and directory
72
+ // This is a bit manual, but fs.rmSync is available in node 14+
73
+ if (fs_1.rmSync) {
74
+ (0, fs_1.rmSync)(tempDir, { recursive: true, force: true });
75
+ }
76
+ else {
77
+ // Fallback for older nodes if necessary, but we are on node 22 in CI
78
+ if ((0, fs_1.existsSync)((0, path_1.join)(tempDir, `${className}.java`)))
79
+ (0, fs_1.unlinkSync)((0, path_1.join)(tempDir, `${className}.java`));
80
+ if ((0, fs_1.existsSync)((0, path_1.join)(tempDir, `${className}.class`)))
81
+ (0, fs_1.unlinkSync)((0, path_1.join)(tempDir, `${className}.class`));
82
+ if ((0, fs_1.existsSync)(tempDir))
83
+ (0, fs_1.rmdirSync)(tempDir);
84
+ }
85
+ }
86
+ catch {
87
+ // Ignore cleanup error
88
+ }
89
+ }
90
+ return { success, stack };
91
+ };
92
+ exports.javaHandler = javaHandler;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.javascriptHandler = void 0;
4
+ const vm_1 = require("vm");
5
+ const esbuild_1 = require("esbuild");
6
+ const javascriptHandler = (code, _snippet, config, sandbox, _isSharedSandbox) => {
7
+ let success = false;
8
+ let stack = "";
9
+ let output = "";
10
+ // Capture console.log
11
+ const originalLog = sandbox.console.log;
12
+ sandbox.console.log = (...args) => {
13
+ output += args.map(String).join(' ') + '\n';
14
+ if (originalLog)
15
+ originalLog(...args);
16
+ };
17
+ try {
18
+ const result = (0, esbuild_1.transformSync)(code, {
19
+ loader: 'ts',
20
+ format: 'cjs',
21
+ target: 'node12'
22
+ });
23
+ const compiledCode = result.code || "";
24
+ const timeout = config.timeout || 30000;
25
+ (0, vm_1.runInNewContext)(compiledCode, sandbox, { timeout });
26
+ success = true;
27
+ }
28
+ catch (e) {
29
+ if (e.code === 'ERR_SCRIPT_EXECUTION_TIMEOUT') {
30
+ stack = `Execution timed out after ${config.timeout || 30000}ms`;
31
+ }
32
+ else {
33
+ stack = e.stack || "";
34
+ }
35
+ }
36
+ finally {
37
+ // Restore console.log? Not strictly necessary as sandbox is recreated or dedicated
38
+ // But if shared sandbox, we might want to keep accumulating output?
39
+ // No, output capture is per-snippet usually.
40
+ // But if shared sandbox is reused, `output` variable here is local.
41
+ // We override sandbox.console.log every time.
42
+ // Ideally we should restore it to avoid nesting if we re-use the sandbox object in a way that stacks?
43
+ // But `makeTestSandbox` creates a fresh object or we reuse the same one.
44
+ // If we reuse, `sandbox.console.log` is overwritten.
45
+ // We should probably save the original log from the *very first* time?
46
+ // Actually, `makeTestSandbox` sets `console.log: () => null` or `console`.
47
+ // So we are wrapping that.
48
+ }
49
+ return { success, stack, output: output.trimEnd() }; // Trim trailing newline for easier comparison
50
+ };
51
+ exports.javascriptHandler = javascriptHandler;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pascalHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ const pascalHandler = (code, _snippet, config, _sandbox, _isSharedSandbox) => {
9
+ let success = false;
10
+ let stack = "";
11
+ // Pascal execution logic
12
+ // Auto-wrap in program block if not present
13
+ let pascalCode = code;
14
+ let programName = "TestProgram";
15
+ // Simple heuristic to detect if program is provided
16
+ if (!pascalCode.toLowerCase().includes("program ")) {
17
+ pascalCode = `program ${programName};
18
+ begin
19
+ ${pascalCode}
20
+ end.`;
21
+ }
22
+ else {
23
+ // Try to extract program name if provided
24
+ const match = pascalCode.match(/program\s+(\w+);/i);
25
+ if (match) {
26
+ programName = match[1];
27
+ }
28
+ }
29
+ const uniqueId = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
30
+ const tempDir = (0, path_1.join)((0, os_1.tmpdir)(), `doccident_pascal_${uniqueId}`);
31
+ const timeout = config.timeout || 30000;
32
+ try {
33
+ if (!(0, fs_1.existsSync)(tempDir)) {
34
+ (0, fs_1.mkdirSync)(tempDir);
35
+ }
36
+ const tempSourceFile = (0, path_1.join)(tempDir, `${programName}.pas`);
37
+ const tempExeFile = (0, path_1.join)(tempDir, programName); // fpc creates executable with program name by default (or we specify -o)
38
+ (0, fs_1.writeFileSync)(tempSourceFile, pascalCode);
39
+ // Compile with fpc
40
+ // -o specifies output file name
41
+ const compileResult = (0, child_process_1.spawnSync)('fpc', [`-o${tempExeFile}`, tempSourceFile], { encoding: 'utf-8', cwd: tempDir, timeout });
42
+ if (compileResult.status !== 0) {
43
+ // Filter out the banner to just show the error if possible, or show all stderr/stdout
44
+ // fpc outputs errors to stdout often
45
+ stack = compileResult.stdout + "\n" + compileResult.stderr || "Pascal compilation failed";
46
+ }
47
+ else {
48
+ // Run
49
+ const runResult = (0, child_process_1.spawnSync)(tempExeFile, [], { encoding: 'utf-8', cwd: tempDir, timeout });
50
+ if (runResult.error && runResult.error.code === 'ETIMEDOUT') {
51
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
52
+ }
53
+ if (runResult.status === 0) {
54
+ success = true;
55
+ }
56
+ else {
57
+ stack = runResult.stderr || "Pascal execution failed with non-zero exit code";
58
+ }
59
+ return { success, stack, output: runResult.stdout };
60
+ }
61
+ }
62
+ catch (e) {
63
+ stack = e.message || "Failed to execute fpc";
64
+ }
65
+ finally {
66
+ try {
67
+ if (fs_1.rmSync) {
68
+ (0, fs_1.rmSync)(tempDir, { recursive: true, force: true });
69
+ }
70
+ else {
71
+ // Cleanup fallback
72
+ if ((0, fs_1.existsSync)((0, path_1.join)(tempDir, `${programName}.pas`)))
73
+ (0, fs_1.unlinkSync)((0, path_1.join)(tempDir, `${programName}.pas`));
74
+ if ((0, fs_1.existsSync)((0, path_1.join)(tempDir, `${programName}.o`)))
75
+ (0, fs_1.unlinkSync)((0, path_1.join)(tempDir, `${programName}.o`));
76
+ if ((0, fs_1.existsSync)((0, path_1.join)(tempDir, programName)))
77
+ (0, fs_1.unlinkSync)((0, path_1.join)(tempDir, programName));
78
+ if ((0, fs_1.existsSync)(tempDir))
79
+ (0, fs_1.rmdirSync)(tempDir);
80
+ }
81
+ }
82
+ catch {
83
+ // Ignore cleanup error
84
+ }
85
+ }
86
+ return { success, stack };
87
+ };
88
+ exports.pascalHandler = pascalHandler;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.perlHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const perlHandler = (code, _snippet, config, sandbox, isSharedSandbox) => {
6
+ let success = false;
7
+ let stack = "";
8
+ const context = sandbox;
9
+ // If sharing code, we need to accumulate previous perl snippets
10
+ if (isSharedSandbox) {
11
+ if (!context._perlContext) {
12
+ context._perlContext = "";
13
+ }
14
+ context._perlContext += code + "\n";
15
+ code = context._perlContext;
16
+ }
17
+ try {
18
+ const timeout = config.timeout || 30000;
19
+ const result = (0, child_process_1.spawnSync)('perl', [], { input: code, encoding: 'utf-8', timeout });
20
+ if (result.error && result.error.code === 'ETIMEDOUT') {
21
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
22
+ }
23
+ if (result.status === 0) {
24
+ success = true;
25
+ }
26
+ else {
27
+ stack = result.stderr || "Perl execution failed with non-zero exit code";
28
+ }
29
+ return { success, stack, output: result.stdout };
30
+ }
31
+ catch (e) {
32
+ stack = e.message || "Failed to spawn perl";
33
+ }
34
+ return { success, stack };
35
+ };
36
+ exports.perlHandler = perlHandler;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pythonHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const pythonHandler = (code, snippet, config, sandbox, isSharedSandbox) => {
6
+ let success = false;
7
+ let stack = "";
8
+ const context = sandbox;
9
+ // If sharing code, we need to accumulate previous python snippets
10
+ if (isSharedSandbox) {
11
+ if (!context._pythonContext) {
12
+ context._pythonContext = "";
13
+ }
14
+ context._pythonContext += code + "\n";
15
+ code = context._pythonContext;
16
+ }
17
+ try {
18
+ const args = snippet.args || [];
19
+ const env = snippet.env ? { ...process.env, ...snippet.env } : undefined;
20
+ const timeout = config.timeout || 30000;
21
+ // For python, args usually go to the script or interpreter?
22
+ // If we want to pass args to the script, we might need to invoke differently if using stdin.
23
+ // `python3 - arg1 arg2` reads from stdin.
24
+ // Let's prepend '-' to args if not empty, so python knows to read script from stdin before args.
25
+ // But spawnSync args array includes 'python3' arguments.
26
+ // If user supplies `-v`, it should be `python3 -v`.
27
+ // If user supplies script args, they come after.
28
+ // This is tricky. Let's assume user provides INTERPRETER args for now, as typical.
29
+ // Or if they start with `-`, they are interpreter args.
30
+ const spawnArgs = [...args];
31
+ const result = (0, child_process_1.spawnSync)('python3', spawnArgs, { input: code, encoding: 'utf-8', env, timeout });
32
+ if (result.error && result.error.code === 'ETIMEDOUT') {
33
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
34
+ }
35
+ if (result.status === 0) {
36
+ success = true;
37
+ }
38
+ else {
39
+ stack = result.stderr || "Python execution failed with non-zero exit code";
40
+ }
41
+ return { success, stack, output: result.stdout };
42
+ }
43
+ catch (e) {
44
+ stack = e.message || "Failed to spawn python3";
45
+ return { success, stack };
46
+ }
47
+ };
48
+ exports.pythonHandler = pythonHandler;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rHandler = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const rHandler = (code, _snippet, config, sandbox, isSharedSandbox) => {
6
+ let success = false;
7
+ let stack = "";
8
+ const context = sandbox;
9
+ // If sharing code, we need to accumulate previous R snippets
10
+ if (isSharedSandbox) {
11
+ if (!context._rContext) {
12
+ context._rContext = "";
13
+ }
14
+ context._rContext += code + "\n";
15
+ code = context._rContext;
16
+ }
17
+ try {
18
+ // Rscript - runs R code from stdin
19
+ const timeout = config.timeout || 30000;
20
+ const result = (0, child_process_1.spawnSync)('Rscript', ['-'], { input: code, encoding: 'utf-8', timeout });
21
+ if (result.error && result.error.code === 'ETIMEDOUT') {
22
+ return { success: false, stack: `Execution timed out after ${timeout}ms` };
23
+ }
24
+ if (result.status === 0) {
25
+ success = true;
26
+ }
27
+ else {
28
+ stack = result.stderr || "R execution failed with non-zero exit code";
29
+ }
30
+ return { success, stack, output: result.stdout };
31
+ }
32
+ catch (e) {
33
+ stack = e.message || "Failed to spawn Rscript";
34
+ return { success, stack };
35
+ }
36
+ };
37
+ exports.rHandler = rHandler;