@strands-agents/sdk 1.3.0 → 1.4.0
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/README.md +13 -13
- package/dist/src/__fixtures__/test-sandbox.node.d.ts +15 -0
- package/dist/src/__fixtures__/test-sandbox.node.d.ts.map +1 -0
- package/dist/src/__fixtures__/test-sandbox.node.js +22 -0
- package/dist/src/__fixtures__/test-sandbox.node.js.map +1 -0
- package/dist/src/__tests__/mcp.test.js +14 -14
- package/dist/src/__tests__/mcp.test.js.map +1 -1
- package/dist/src/agent/__tests__/agent.test.js +195 -0
- package/dist/src/agent/__tests__/agent.test.js.map +1 -1
- package/dist/src/agent/__tests__/tool-caller.test.d.ts +2 -0
- package/dist/src/agent/__tests__/tool-caller.test.d.ts.map +1 -0
- package/dist/src/agent/__tests__/tool-caller.test.js +459 -0
- package/dist/src/agent/__tests__/tool-caller.test.js.map +1 -0
- package/dist/src/agent/agent.d.ts +62 -2
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +122 -66
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/agent/tool-caller.d.ts +149 -0
- package/dist/src/agent/tool-caller.d.ts.map +1 -0
- package/dist/src/agent/tool-caller.js +198 -0
- package/dist/src/agent/tool-caller.js.map +1 -0
- package/dist/src/errors.d.ts +17 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +21 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/interventions/handler.d.ts +1 -2
- package/dist/src/interventions/handler.d.ts.map +1 -1
- package/dist/src/interventions/registry.d.ts +2 -0
- package/dist/src/interventions/registry.d.ts.map +1 -1
- package/dist/src/interventions/registry.js +4 -0
- package/dist/src/interventions/registry.js.map +1 -1
- package/dist/src/mcp.d.ts +20 -15
- package/dist/src/mcp.d.ts.map +1 -1
- package/dist/src/mcp.js +15 -8
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/models/__tests__/anthropic.test.js +21 -6
- package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
- package/dist/src/models/__tests__/bedrock.test.js +142 -0
- package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
- package/dist/src/models/anthropic.d.ts.map +1 -1
- package/dist/src/models/anthropic.js +5 -2
- package/dist/src/models/anthropic.js.map +1 -1
- package/dist/src/models/bedrock.d.ts +26 -1
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +22 -4
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/openai/__tests__/chat.test.js +2 -10
- package/dist/src/models/openai/__tests__/chat.test.js.map +1 -1
- package/dist/src/models/openai/__tests__/errors.test.d.ts +2 -0
- package/dist/src/models/openai/__tests__/errors.test.d.ts.map +1 -0
- package/dist/src/models/openai/__tests__/errors.test.js +30 -0
- package/dist/src/models/openai/__tests__/errors.test.js.map +1 -0
- package/dist/src/models/openai/__tests__/responses.test.js +0 -19
- package/dist/src/models/openai/__tests__/responses.test.js.map +1 -1
- package/dist/src/models/openai/errors.d.ts.map +1 -1
- package/dist/src/models/openai/errors.js +5 -3
- package/dist/src/models/openai/errors.js.map +1 -1
- package/dist/src/multiagent/__tests__/nodes.test.js +50 -0
- package/dist/src/multiagent/__tests__/nodes.test.js.map +1 -1
- package/dist/src/multiagent/nodes.d.ts +23 -2
- package/dist/src/multiagent/nodes.d.ts.map +1 -1
- package/dist/src/multiagent/nodes.js +18 -4
- package/dist/src/multiagent/nodes.js.map +1 -1
- package/dist/src/registry/__tests__/tool-registry.test.js +50 -1
- package/dist/src/registry/__tests__/tool-registry.test.js.map +1 -1
- package/dist/src/registry/tool-registry.d.ts +13 -0
- package/dist/src/registry/tool-registry.d.ts.map +1 -1
- package/dist/src/registry/tool-registry.js +35 -1
- package/dist/src/registry/tool-registry.js.map +1 -1
- package/dist/src/sandbox/__tests__/posix-shell.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/posix-shell.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/posix-shell.test.node.js +252 -0
- package/dist/src/sandbox/__tests__/posix-shell.test.node.js.map +1 -0
- package/dist/src/sandbox/base.d.ts +138 -0
- package/dist/src/sandbox/base.d.ts.map +1 -0
- package/dist/src/sandbox/base.js +84 -0
- package/dist/src/sandbox/base.js.map +1 -0
- package/dist/src/sandbox/constants.d.ts +7 -0
- package/dist/src/sandbox/constants.d.ts.map +1 -0
- package/dist/src/sandbox/constants.js +7 -0
- package/dist/src/sandbox/constants.js.map +1 -0
- package/dist/src/sandbox/posix-shell.d.ts +32 -0
- package/dist/src/sandbox/posix-shell.d.ts.map +1 -0
- package/dist/src/sandbox/posix-shell.js +78 -0
- package/dist/src/sandbox/posix-shell.js.map +1 -0
- package/dist/src/sandbox/stream-process.d.ts +32 -0
- package/dist/src/sandbox/stream-process.d.ts.map +1 -0
- package/dist/src/sandbox/stream-process.js +160 -0
- package/dist/src/sandbox/stream-process.js.map +1 -0
- package/dist/src/sandbox/types.d.ts +57 -0
- package/dist/src/sandbox/types.d.ts.map +1 -0
- package/dist/src/sandbox/types.js +8 -0
- package/dist/src/sandbox/types.js.map +1 -0
- package/dist/src/telemetry/__tests__/meter.test.js +11 -0
- package/dist/src/telemetry/__tests__/meter.test.js.map +1 -1
- package/dist/src/telemetry/meter.d.ts +10 -6
- package/dist/src/telemetry/meter.d.ts.map +1 -1
- package/dist/src/telemetry/meter.js +16 -3
- package/dist/src/telemetry/meter.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/__tests__/messages.test.js +28 -0
- package/dist/src/types/__tests__/messages.test.js.map +1 -1
- package/dist/src/types/agent.d.ts +51 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/lifecycle-observer.d.ts +18 -0
- package/dist/src/types/lifecycle-observer.d.ts.map +1 -0
- package/dist/src/types/lifecycle-observer.js +2 -0
- package/dist/src/types/lifecycle-observer.js.map +1 -0
- package/dist/src/types/messages.d.ts +18 -2
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js +9 -0
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/utils/shell-quote.d.ts +12 -0
- package/dist/src/utils/shell-quote.d.ts.map +1 -0
- package/dist/src/utils/shell-quote.js +14 -0
- package/dist/src/utils/shell-quote.js.map +1 -0
- package/dist/src/vended-interventions/hitl/__tests__/hitl.test.d.ts +2 -0
- package/dist/src/vended-interventions/hitl/__tests__/hitl.test.d.ts.map +1 -0
- package/dist/src/vended-interventions/hitl/__tests__/hitl.test.js +358 -0
- package/dist/src/vended-interventions/hitl/__tests__/hitl.test.js.map +1 -0
- package/dist/src/vended-interventions/hitl/hitl.d.ts +115 -0
- package/dist/src/vended-interventions/hitl/hitl.d.ts.map +1 -0
- package/dist/src/vended-interventions/hitl/hitl.js +138 -0
- package/dist/src/vended-interventions/hitl/hitl.js.map +1 -0
- package/dist/src/vended-interventions/hitl/index.d.ts +24 -0
- package/dist/src/vended-interventions/hitl/index.d.ts.map +1 -0
- package/dist/src/vended-interventions/hitl/index.js +23 -0
- package/dist/src/vended-interventions/hitl/index.js.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/handler.test.d.ts +2 -0
- package/dist/src/vended-interventions/steering/__tests__/handler.test.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/handler.test.js +163 -0
- package/dist/src/vended-interventions/steering/__tests__/handler.test.js.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/llm.test.d.ts +2 -0
- package/dist/src/vended-interventions/steering/__tests__/llm.test.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/llm.test.js +60 -0
- package/dist/src/vended-interventions/steering/__tests__/llm.test.js.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.d.ts +2 -0
- package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.js +94 -0
- package/dist/src/vended-interventions/steering/__tests__/tool-ledger.test.js.map +1 -0
- package/dist/src/vended-interventions/steering/handlers/handler.d.ts +64 -0
- package/dist/src/vended-interventions/steering/handlers/handler.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/handlers/handler.js +71 -0
- package/dist/src/vended-interventions/steering/handlers/handler.js.map +1 -0
- package/dist/src/vended-interventions/steering/handlers/llm.d.ts +72 -0
- package/dist/src/vended-interventions/steering/handlers/llm.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/handlers/llm.js +177 -0
- package/dist/src/vended-interventions/steering/handlers/llm.js.map +1 -0
- package/dist/src/vended-interventions/steering/index.d.ts +31 -0
- package/dist/src/vended-interventions/steering/index.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/index.js +32 -0
- package/dist/src/vended-interventions/steering/index.js.map +1 -0
- package/dist/src/vended-interventions/steering/providers/context-provider.d.ts +55 -0
- package/dist/src/vended-interventions/steering/providers/context-provider.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/providers/context-provider.js +8 -0
- package/dist/src/vended-interventions/steering/providers/context-provider.js.map +1 -0
- package/dist/src/vended-interventions/steering/providers/tool-ledger.d.ts +49 -0
- package/dist/src/vended-interventions/steering/providers/tool-ledger.d.ts.map +1 -0
- package/dist/src/vended-interventions/steering/providers/tool-ledger.js +75 -0
- package/dist/src/vended-interventions/steering/providers/tool-ledger.js.map +1 -0
- package/dist/src/vended-plugins/index.d.ts +11 -0
- package/dist/src/vended-plugins/index.d.ts.map +1 -0
- package/dist/src/vended-plugins/index.js +11 -0
- package/dist/src/vended-plugins/index.js.map +1 -0
- package/dist/src/vended-tools/index.d.ts +17 -0
- package/dist/src/vended-tools/index.d.ts.map +1 -0
- package/dist/src/vended-tools/index.js +17 -0
- package/dist/src/vended-tools/index.js.map +1 -0
- package/package.json +31 -15
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { TestSandbox } from '../../__fixtures__/test-sandbox.node.js';
|
|
4
|
+
import { streamProcess } from '../stream-process.js';
|
|
5
|
+
const TEST_DIR = '/tmp/strands-test-shell-sandbox';
|
|
6
|
+
describe.skipIf(process.platform === 'win32')('PosixShellSandbox', () => {
|
|
7
|
+
let sandbox;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
10
|
+
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
11
|
+
sandbox = new TestSandbox(TEST_DIR);
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
15
|
+
});
|
|
16
|
+
describe('execute (via shell commands)', () => {
|
|
17
|
+
it('runs a command', async () => {
|
|
18
|
+
const result = await sandbox.execute('echo hello');
|
|
19
|
+
expect(result.exitCode).toBe(0);
|
|
20
|
+
expect(result.stdout).toBe('hello\n');
|
|
21
|
+
});
|
|
22
|
+
it('runs in workingDir', async () => {
|
|
23
|
+
const result = await sandbox.execute('pwd');
|
|
24
|
+
expect(result.stdout.trim()).toContain('strands-test-shell-sandbox');
|
|
25
|
+
});
|
|
26
|
+
it('respects cwd option', async () => {
|
|
27
|
+
const result = await sandbox.execute('pwd', { cwd: '/tmp' });
|
|
28
|
+
expect(result.stdout.trim()).toMatch(/\/tmp$/);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('executeCode (via shell quoting)', () => {
|
|
32
|
+
it('runs python code through shell', async () => {
|
|
33
|
+
const result = await sandbox.executeCode('print(2 + 2)', 'python3');
|
|
34
|
+
expect(result.exitCode).toBe(0);
|
|
35
|
+
expect(result.stdout).toBe('4\n');
|
|
36
|
+
});
|
|
37
|
+
it('handles code with special characters', async () => {
|
|
38
|
+
const result = await sandbox.executeCode('print(\'hello "world"\')', 'python3');
|
|
39
|
+
expect(result.stdout).toBe('hello "world"\n');
|
|
40
|
+
});
|
|
41
|
+
it('handles code with single quotes', async () => {
|
|
42
|
+
const result = await sandbox.executeCode('print("it\'s working")', 'python3');
|
|
43
|
+
expect(result.stdout).toBe("it's working\n");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('language validation', () => {
|
|
47
|
+
it('rejects path traversal', async () => {
|
|
48
|
+
await expect(sandbox.executeCode('x', '../../../bin/sh')).rejects.toThrow('invalid characters');
|
|
49
|
+
});
|
|
50
|
+
it('rejects shell metacharacters', async () => {
|
|
51
|
+
await expect(sandbox.executeCode('x', 'python;rm -rf /')).rejects.toThrow('invalid characters');
|
|
52
|
+
});
|
|
53
|
+
it('rejects spaces', async () => {
|
|
54
|
+
await expect(sandbox.executeCode('x', 'python -c')).rejects.toThrow('invalid characters');
|
|
55
|
+
});
|
|
56
|
+
it('allows valid interpreters', async () => {
|
|
57
|
+
const result = await sandbox.executeCode('print("safe")', 'python3');
|
|
58
|
+
expect(result.exitCode).toBe(0);
|
|
59
|
+
});
|
|
60
|
+
it('allows dots and hyphens', async () => {
|
|
61
|
+
const result = await sandbox.executeCode('x', 'fake-lang.99');
|
|
62
|
+
expect(result.exitCode).toBe(127);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('read/write (via base64 encoding over shell)', () => {
|
|
66
|
+
it('text file roundtrip', async () => {
|
|
67
|
+
await sandbox.writeText('test.txt', 'hello shell');
|
|
68
|
+
const text = await sandbox.readText('test.txt');
|
|
69
|
+
expect(text).toBe('hello shell');
|
|
70
|
+
});
|
|
71
|
+
it('binary file roundtrip', async () => {
|
|
72
|
+
const bytes = new Uint8Array([0, 1, 2, 127, 128, 254, 255]);
|
|
73
|
+
await sandbox.writeFile('binary.bin', bytes);
|
|
74
|
+
const read = await sandbox.readFile('binary.bin');
|
|
75
|
+
expect(Array.from(read)).toStrictEqual(Array.from(bytes));
|
|
76
|
+
});
|
|
77
|
+
it('all 256 byte values roundtrip', async () => {
|
|
78
|
+
const bytes = new Uint8Array(256);
|
|
79
|
+
for (let i = 0; i < 256; i++)
|
|
80
|
+
bytes[i] = i;
|
|
81
|
+
await sandbox.writeFile('all-bytes.bin', bytes);
|
|
82
|
+
const read = await sandbox.readFile('all-bytes.bin');
|
|
83
|
+
expect(Array.from(read)).toStrictEqual(Array.from(bytes));
|
|
84
|
+
});
|
|
85
|
+
it('creates parent directories', async () => {
|
|
86
|
+
await sandbox.writeText('deep/nested/file.txt', 'deep');
|
|
87
|
+
const text = await sandbox.readText('deep/nested/file.txt');
|
|
88
|
+
expect(text).toBe('deep');
|
|
89
|
+
});
|
|
90
|
+
it('handles unicode content', async () => {
|
|
91
|
+
const content = '日本語 🚀 émojis';
|
|
92
|
+
await sandbox.writeText('unicode.txt', content);
|
|
93
|
+
const text = await sandbox.readText('unicode.txt');
|
|
94
|
+
expect(text).toBe(content);
|
|
95
|
+
});
|
|
96
|
+
it('handles shell metacharacters in content', async () => {
|
|
97
|
+
const content = '$(rm -rf /) `whoami` && || $HOME';
|
|
98
|
+
await sandbox.writeText('meta.txt', content);
|
|
99
|
+
const text = await sandbox.readText('meta.txt');
|
|
100
|
+
expect(text).toBe(content);
|
|
101
|
+
});
|
|
102
|
+
it('throws on nonexistent file', async () => {
|
|
103
|
+
await expect(sandbox.readFile('nope.txt')).rejects.toThrow();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('remove', () => {
|
|
107
|
+
it('removes a file', async () => {
|
|
108
|
+
await sandbox.writeText('delete-me.txt', 'bye');
|
|
109
|
+
await sandbox.removeFile('delete-me.txt');
|
|
110
|
+
await expect(sandbox.readFile('delete-me.txt')).rejects.toThrow();
|
|
111
|
+
});
|
|
112
|
+
it('throws on nonexistent file', async () => {
|
|
113
|
+
await expect(sandbox.removeFile('nope.txt')).rejects.toThrow();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('list (via ls -1ap parsing)', () => {
|
|
117
|
+
it('lists directory contents', async () => {
|
|
118
|
+
await sandbox.writeText('a.txt', 'a');
|
|
119
|
+
await sandbox.writeText('b.txt', 'b');
|
|
120
|
+
const files = await sandbox.listFiles('.');
|
|
121
|
+
const names = files.map((f) => f.name);
|
|
122
|
+
expect(names).toContain('a.txt');
|
|
123
|
+
expect(names).toContain('b.txt');
|
|
124
|
+
});
|
|
125
|
+
it('identifies directories', async () => {
|
|
126
|
+
await sandbox.execute('mkdir -p subdir');
|
|
127
|
+
const files = await sandbox.listFiles('.');
|
|
128
|
+
const subdir = files.find((f) => f.name === 'subdir');
|
|
129
|
+
expect(subdir?.isDir).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
it('excludes . and .. entries', async () => {
|
|
132
|
+
await sandbox.writeText('file.txt', '');
|
|
133
|
+
const files = await sandbox.listFiles('.');
|
|
134
|
+
const names = files.map((f) => f.name);
|
|
135
|
+
expect(names).not.toContain('.');
|
|
136
|
+
expect(names).not.toContain('..');
|
|
137
|
+
});
|
|
138
|
+
it('throws on nonexistent directory', async () => {
|
|
139
|
+
await expect(sandbox.listFiles('/tmp/nonexistent-dir-xyz')).rejects.toThrow();
|
|
140
|
+
});
|
|
141
|
+
it('throws when path is a file, not a directory', async () => {
|
|
142
|
+
await sandbox.writeText('not-a-dir.txt', 'hello');
|
|
143
|
+
await expect(sandbox.listFiles('not-a-dir.txt')).rejects.toThrow();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe('shellQuote', () => {
|
|
147
|
+
it('handles paths with spaces', async () => {
|
|
148
|
+
await sandbox.execute('mkdir -p "with spaces"');
|
|
149
|
+
await sandbox.writeText('with spaces/file.txt', 'spaced');
|
|
150
|
+
const text = await sandbox.readText('with spaces/file.txt');
|
|
151
|
+
expect(text).toBe('spaced');
|
|
152
|
+
});
|
|
153
|
+
it('handles paths with single quotes', async () => {
|
|
154
|
+
await sandbox.execute('mkdir -p "it\'s"');
|
|
155
|
+
await sandbox.writeText("it's/file.txt", 'quoted');
|
|
156
|
+
const text = await sandbox.readText("it's/file.txt");
|
|
157
|
+
expect(text).toBe('quoted');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('timeout', () => {
|
|
161
|
+
it('kills process on timeout', async () => {
|
|
162
|
+
const start = Date.now();
|
|
163
|
+
await expect(sandbox.execute('sleep 60', { timeout: 0.2 })).rejects.toThrow('timed out');
|
|
164
|
+
const elapsed = Date.now() - start;
|
|
165
|
+
expect(elapsed).toBeLessThan(2000);
|
|
166
|
+
});
|
|
167
|
+
it('does not timeout fast commands', async () => {
|
|
168
|
+
const result = await sandbox.execute('echo fast', { timeout: 5 });
|
|
169
|
+
expect(result.exitCode).toBe(0);
|
|
170
|
+
expect(result.stdout).toBe('fast\n');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('abort signal', () => {
|
|
174
|
+
it('kills process when signal is aborted', async () => {
|
|
175
|
+
const controller = new AbortController();
|
|
176
|
+
const promise = sandbox.execute('sleep 60', { signal: controller.signal });
|
|
177
|
+
setTimeout(() => controller.abort(), 100);
|
|
178
|
+
await expect(promise).rejects.toThrow('aborted');
|
|
179
|
+
});
|
|
180
|
+
it('rejects immediately if signal is already aborted', async () => {
|
|
181
|
+
const controller = new AbortController();
|
|
182
|
+
controller.abort();
|
|
183
|
+
await expect(sandbox.execute('sleep 60', { signal: controller.signal })).rejects.toThrow('aborted');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('concurrent execution', () => {
|
|
187
|
+
it('handles multiple concurrent commands', async () => {
|
|
188
|
+
const results = await Promise.all([
|
|
189
|
+
sandbox.execute('echo one'),
|
|
190
|
+
sandbox.execute('echo two'),
|
|
191
|
+
sandbox.execute('echo three'),
|
|
192
|
+
]);
|
|
193
|
+
expect(results.map((r) => r.stdout.trim()).sort()).toStrictEqual(['one', 'three', 'two']);
|
|
194
|
+
});
|
|
195
|
+
it('handles concurrent file writes to different files', async () => {
|
|
196
|
+
await Promise.all([
|
|
197
|
+
sandbox.writeText('a.txt', 'aaa'),
|
|
198
|
+
sandbox.writeText('b.txt', 'bbb'),
|
|
199
|
+
sandbox.writeText('c.txt', 'ccc'),
|
|
200
|
+
]);
|
|
201
|
+
const [a, b, c] = await Promise.all([
|
|
202
|
+
sandbox.readText('a.txt'),
|
|
203
|
+
sandbox.readText('b.txt'),
|
|
204
|
+
sandbox.readText('c.txt'),
|
|
205
|
+
]);
|
|
206
|
+
expect(a).toBe('aaa');
|
|
207
|
+
expect(b).toBe('bbb');
|
|
208
|
+
expect(c).toBe('ccc');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
describe('streaming', () => {
|
|
212
|
+
it('yields StreamChunks then ExecutionResult', async () => {
|
|
213
|
+
const chunks = [];
|
|
214
|
+
for await (const chunk of sandbox.executeStreaming('echo hello')) {
|
|
215
|
+
chunks.push(chunk);
|
|
216
|
+
}
|
|
217
|
+
const streamChunks = chunks.filter((c) => c.type === 'streamChunk');
|
|
218
|
+
const results = chunks.filter((c) => c.type === 'executionResult');
|
|
219
|
+
expect(streamChunks.length).toBeGreaterThan(0);
|
|
220
|
+
expect(results).toHaveLength(1);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('streamProcess edge cases', () => {
|
|
224
|
+
it('returns exit code 127 when command is not found', async () => {
|
|
225
|
+
const result = await sandbox.execute('nonexistent_binary_xyz_12345');
|
|
226
|
+
expect(result.exitCode).toBe(127);
|
|
227
|
+
expect(result.stderr).toContain('not found');
|
|
228
|
+
});
|
|
229
|
+
it('maps signal termination to 128 + signal number', async () => {
|
|
230
|
+
// sh -c 'kill -9 $$' sends SIGKILL to itself → exit code 128 + 9 = 137
|
|
231
|
+
const result = await sandbox.execute("sh -c 'kill -9 $$'");
|
|
232
|
+
expect(result.exitCode).toBe(137);
|
|
233
|
+
});
|
|
234
|
+
it('returns enoentMessage when spawned binary does not exist', async () => {
|
|
235
|
+
const chunks = [];
|
|
236
|
+
for await (const chunk of streamProcess('nonexistent_binary_xyz_12345', [], {
|
|
237
|
+
enoentMessage: 'binary not found',
|
|
238
|
+
})) {
|
|
239
|
+
chunks.push(chunk);
|
|
240
|
+
}
|
|
241
|
+
const result = chunks.find((c) => c.type === 'executionResult');
|
|
242
|
+
expect(result).toStrictEqual({
|
|
243
|
+
type: 'executionResult',
|
|
244
|
+
exitCode: 127,
|
|
245
|
+
stdout: '',
|
|
246
|
+
stderr: 'binary not found',
|
|
247
|
+
outputFiles: [],
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
//# sourceMappingURL=posix-shell.test.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posix-shell.test.node.js","sourceRoot":"","sources":["../../../../src/sandbox/__tests__/posix-shell.test.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base sandbox interface.
|
|
3
|
+
*
|
|
4
|
+
* Defines the abstract {@link Sandbox} class that all sandbox implementations
|
|
5
|
+
* must extend. The class provides six abstract operations (command execution,
|
|
6
|
+
* code execution, and file I/O) and convenience wrappers for common patterns.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExecutionResult, FileInfo, StreamChunk } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Options for command and code execution.
|
|
11
|
+
*/
|
|
12
|
+
export interface ExecuteOptions {
|
|
13
|
+
/** Maximum execution time in seconds. `undefined` means no timeout. */
|
|
14
|
+
timeout?: number | undefined;
|
|
15
|
+
/** Working directory for execution. `undefined` means use the sandbox default. */
|
|
16
|
+
cwd?: string | undefined;
|
|
17
|
+
/** Abort signal to cancel execution. The process is killed when the signal fires. */
|
|
18
|
+
signal?: AbortSignal | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Abstract execution environment.
|
|
22
|
+
*
|
|
23
|
+
* A Sandbox provides the runtime context where tools execute code,
|
|
24
|
+
* run commands, and interact with a filesystem. Multiple tools share
|
|
25
|
+
* the same Sandbox instance, giving them a common working directory
|
|
26
|
+
* and filesystem.
|
|
27
|
+
*
|
|
28
|
+
* Streaming methods (`executeStreaming`, `executeCodeStreaming`) are the abstract primitives.
|
|
29
|
+
* Non-streaming convenience methods (`execute`, `executeCode`) consume
|
|
30
|
+
* the stream and return the final result.
|
|
31
|
+
*/
|
|
32
|
+
export declare abstract class Sandbox {
|
|
33
|
+
/**
|
|
34
|
+
* Execute a shell command, streaming output.
|
|
35
|
+
*
|
|
36
|
+
* Yields {@link StreamChunk} objects for stdout and stderr as output
|
|
37
|
+
* arrives. The final yield is an {@link ExecutionResult} with the
|
|
38
|
+
* exit code and complete output.
|
|
39
|
+
*
|
|
40
|
+
* @param command - The shell command to execute.
|
|
41
|
+
* @param options - Execution options (timeout, cwd).
|
|
42
|
+
* @returns Async iterable yielding StreamChunks followed by a final ExecutionResult.
|
|
43
|
+
*/
|
|
44
|
+
abstract executeStreaming(command: string, options?: ExecuteOptions): AsyncIterable<StreamChunk | ExecutionResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Execute source code via a language interpreter, streaming output.
|
|
47
|
+
*
|
|
48
|
+
* @param code - The source code to execute.
|
|
49
|
+
* @param language - The interpreter to use (e.g., `"python3"`, `"node"`).
|
|
50
|
+
* @param options - Execution options (timeout, cwd).
|
|
51
|
+
* @returns Async iterable yielding StreamChunks followed by a final ExecutionResult.
|
|
52
|
+
*/
|
|
53
|
+
abstract executeCodeStreaming(code: string, language: string, options?: ExecuteOptions): AsyncIterable<StreamChunk | ExecutionResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Read a file from the sandbox filesystem as raw bytes.
|
|
56
|
+
*
|
|
57
|
+
* Returns `Uint8Array` to support both text and binary files.
|
|
58
|
+
* Use {@link readText} for a convenience wrapper that decodes to a string.
|
|
59
|
+
*
|
|
60
|
+
* @param path - Path to the file to read.
|
|
61
|
+
* @returns The file contents as raw bytes.
|
|
62
|
+
* @throws Error if the file does not exist.
|
|
63
|
+
*/
|
|
64
|
+
abstract readFile(path: string): Promise<Uint8Array>;
|
|
65
|
+
/**
|
|
66
|
+
* Write raw bytes to a file in the sandbox filesystem.
|
|
67
|
+
*
|
|
68
|
+
* Implementations should create parent directories if they do not exist.
|
|
69
|
+
* Use {@link writeText} for a convenience wrapper that encodes a string.
|
|
70
|
+
*
|
|
71
|
+
* @param path - Path to the file to write.
|
|
72
|
+
* @param content - The content to write.
|
|
73
|
+
*/
|
|
74
|
+
abstract writeFile(path: string, content: Uint8Array): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Remove a file from the sandbox filesystem.
|
|
77
|
+
*
|
|
78
|
+
* @param path - Path to the file to remove.
|
|
79
|
+
* @throws Error if the file does not exist.
|
|
80
|
+
*/
|
|
81
|
+
abstract removeFile(path: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* List files in a sandbox directory.
|
|
84
|
+
*
|
|
85
|
+
* Returns {@link FileInfo} entries with name, isDir, and size metadata.
|
|
86
|
+
* Fields `isDir` and `size` may be `undefined` if the backend cannot
|
|
87
|
+
* determine them.
|
|
88
|
+
*
|
|
89
|
+
* @param path - Path to the directory to list.
|
|
90
|
+
* @returns Array of FileInfo entries for the directory contents.
|
|
91
|
+
* @throws Error if the directory does not exist.
|
|
92
|
+
*/
|
|
93
|
+
abstract listFiles(path: string): Promise<FileInfo[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Execute a shell command and return the result.
|
|
96
|
+
*
|
|
97
|
+
* Consumes {@link executeStreaming} and returns the final {@link ExecutionResult}.
|
|
98
|
+
* Use `executeStreaming` when you need to process output as it arrives.
|
|
99
|
+
*
|
|
100
|
+
* @param command - The shell command to execute.
|
|
101
|
+
* @param options - Execution options (timeout, cwd).
|
|
102
|
+
* @returns The execution result with exit code and output.
|
|
103
|
+
*/
|
|
104
|
+
execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Execute source code and return the result.
|
|
107
|
+
*
|
|
108
|
+
* Consumes {@link executeCodeStreaming} and returns the final {@link ExecutionResult}.
|
|
109
|
+
* Use `executeCodeStreaming` when you need to process output as it arrives.
|
|
110
|
+
*
|
|
111
|
+
* @param code - The source code to execute.
|
|
112
|
+
* @param language - The interpreter to use.
|
|
113
|
+
* @param options - Execution options (timeout, cwd).
|
|
114
|
+
* @returns The execution result with exit code and output.
|
|
115
|
+
*/
|
|
116
|
+
executeCode(code: string, language: string, options?: ExecuteOptions): Promise<ExecutionResult>;
|
|
117
|
+
/**
|
|
118
|
+
* Read a text file from the sandbox filesystem.
|
|
119
|
+
*
|
|
120
|
+
* Convenience wrapper over {@link readFile} that decodes bytes as UTF-8.
|
|
121
|
+
* For other encodings, call `readFile` and decode manually.
|
|
122
|
+
*
|
|
123
|
+
* @param path - Path to the file to read.
|
|
124
|
+
* @returns The file contents decoded as a UTF-8 string.
|
|
125
|
+
*/
|
|
126
|
+
readText(path: string): Promise<string>;
|
|
127
|
+
/**
|
|
128
|
+
* Write a text file to the sandbox filesystem.
|
|
129
|
+
*
|
|
130
|
+
* Convenience wrapper over {@link writeFile} that encodes a string as UTF-8.
|
|
131
|
+
* For other encodings, encode manually and call `writeFile`.
|
|
132
|
+
*
|
|
133
|
+
* @param path - Path to the file to write.
|
|
134
|
+
* @param content - The text content to write.
|
|
135
|
+
*/
|
|
136
|
+
writeText(path: string, content: string): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/sandbox/base.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,kFAAkF;IAClF,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,qFAAqF;IACrF,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CACjC;AAED;;;;;;;;;;;GAWG;AACH,8BAAsB,OAAO;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,WAAW,GAAG,eAAe,CAAC;IAElH;;;;;;;OAOG;IACH,QAAQ,CAAC,oBAAoB,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,aAAa,CAAC,WAAW,GAAG,eAAe,CAAC;IAE/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAEpD;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAEpE;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEhD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAIrD;;;;;;;;;OASG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IASlF;;;;;;;;;;OAUG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IASrG;;;;;;;;OAQG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C;;;;;;;;OAQG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG9D"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base sandbox interface.
|
|
3
|
+
*
|
|
4
|
+
* Defines the abstract {@link Sandbox} class that all sandbox implementations
|
|
5
|
+
* must extend. The class provides six abstract operations (command execution,
|
|
6
|
+
* code execution, and file I/O) and convenience wrappers for common patterns.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Abstract execution environment.
|
|
10
|
+
*
|
|
11
|
+
* A Sandbox provides the runtime context where tools execute code,
|
|
12
|
+
* run commands, and interact with a filesystem. Multiple tools share
|
|
13
|
+
* the same Sandbox instance, giving them a common working directory
|
|
14
|
+
* and filesystem.
|
|
15
|
+
*
|
|
16
|
+
* Streaming methods (`executeStreaming`, `executeCodeStreaming`) are the abstract primitives.
|
|
17
|
+
* Non-streaming convenience methods (`execute`, `executeCode`) consume
|
|
18
|
+
* the stream and return the final result.
|
|
19
|
+
*/
|
|
20
|
+
export class Sandbox {
|
|
21
|
+
// ---- Non-streaming convenience methods ----
|
|
22
|
+
/**
|
|
23
|
+
* Execute a shell command and return the result.
|
|
24
|
+
*
|
|
25
|
+
* Consumes {@link executeStreaming} and returns the final {@link ExecutionResult}.
|
|
26
|
+
* Use `executeStreaming` when you need to process output as it arrives.
|
|
27
|
+
*
|
|
28
|
+
* @param command - The shell command to execute.
|
|
29
|
+
* @param options - Execution options (timeout, cwd).
|
|
30
|
+
* @returns The execution result with exit code and output.
|
|
31
|
+
*/
|
|
32
|
+
async execute(command, options) {
|
|
33
|
+
for await (const chunk of this.executeStreaming(command, options)) {
|
|
34
|
+
if (chunk.type === 'executionResult') {
|
|
35
|
+
return chunk;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw new Error('executeStreaming() did not yield an ExecutionResult');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Execute source code and return the result.
|
|
42
|
+
*
|
|
43
|
+
* Consumes {@link executeCodeStreaming} and returns the final {@link ExecutionResult}.
|
|
44
|
+
* Use `executeCodeStreaming` when you need to process output as it arrives.
|
|
45
|
+
*
|
|
46
|
+
* @param code - The source code to execute.
|
|
47
|
+
* @param language - The interpreter to use.
|
|
48
|
+
* @param options - Execution options (timeout, cwd).
|
|
49
|
+
* @returns The execution result with exit code and output.
|
|
50
|
+
*/
|
|
51
|
+
async executeCode(code, language, options) {
|
|
52
|
+
for await (const chunk of this.executeCodeStreaming(code, language, options)) {
|
|
53
|
+
if (chunk.type === 'executionResult') {
|
|
54
|
+
return chunk;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw new Error('executeCodeStreaming() did not yield an ExecutionResult');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read a text file from the sandbox filesystem.
|
|
61
|
+
*
|
|
62
|
+
* Convenience wrapper over {@link readFile} that decodes bytes as UTF-8.
|
|
63
|
+
* For other encodings, call `readFile` and decode manually.
|
|
64
|
+
*
|
|
65
|
+
* @param path - Path to the file to read.
|
|
66
|
+
* @returns The file contents decoded as a UTF-8 string.
|
|
67
|
+
*/
|
|
68
|
+
async readText(path) {
|
|
69
|
+
return new TextDecoder().decode(await this.readFile(path));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Write a text file to the sandbox filesystem.
|
|
73
|
+
*
|
|
74
|
+
* Convenience wrapper over {@link writeFile} that encodes a string as UTF-8.
|
|
75
|
+
* For other encodings, encode manually and call `writeFile`.
|
|
76
|
+
*
|
|
77
|
+
* @param path - Path to the file to write.
|
|
78
|
+
* @param content - The text content to write.
|
|
79
|
+
*/
|
|
80
|
+
async writeText(path, content) {
|
|
81
|
+
await this.writeFile(path, new TextEncoder().encode(content));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/sandbox/base.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH;;;;;;;;;;;GAWG;AACH,MAAM,OAAgB,OAAO;IAwE3B,8CAA8C;IAE9C;;;;;;;;;OASG;IACH,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,OAAwB;QACrD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YAClE,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBACrC,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAA;IACxE,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,WAAW,CAAC,IAAY,EAAE,QAAgB,EAAE,OAAwB;QACxE,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;YAC7E,IAAI,KAAK,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBACrC,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5D,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAAe;QAC3C,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;IAC/D,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regex pattern for validating language/interpreter names.
|
|
3
|
+
* Allows alphanumeric characters, dots, hyphens, and underscores.
|
|
4
|
+
* Rejects path separators, spaces, and shell metacharacters to prevent injection.
|
|
5
|
+
*/
|
|
6
|
+
export declare const LANGUAGE_PATTERN: RegExp;
|
|
7
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/sandbox/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAsB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regex pattern for validating language/interpreter names.
|
|
3
|
+
* Allows alphanumeric characters, dots, hyphens, and underscores.
|
|
4
|
+
* Rejects path separators, spaces, and shell metacharacters to prevent injection.
|
|
5
|
+
*/
|
|
6
|
+
export const LANGUAGE_PATTERN = /^[a-zA-Z0-9._-]+$/;
|
|
7
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/sandbox/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell sandbox with default implementations for file and code operations.
|
|
3
|
+
*
|
|
4
|
+
* Subclasses only need to implement {@link PosixShellSandbox.executeStreaming} —
|
|
5
|
+
* all other operations are implemented by running shell commands through it.
|
|
6
|
+
* Use this for remote environments where only shell access is available
|
|
7
|
+
* (Docker containers, SSH connections, cloud runtimes).
|
|
8
|
+
*/
|
|
9
|
+
import { Sandbox } from './base.js';
|
|
10
|
+
import type { ExecuteOptions } from './base.js';
|
|
11
|
+
import type { ExecutionResult, FileInfo, StreamChunk } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Abstract sandbox that provides shell-based defaults for file and code operations.
|
|
14
|
+
* Assumes a POSIX-compatible shell (sh/bash) on the target.
|
|
15
|
+
*
|
|
16
|
+
* Subclasses only need to implement {@link executeStreaming}. The remaining
|
|
17
|
+
* operations — `executeCodeStreaming`, `readFile`, `writeFile`, `removeFile`,
|
|
18
|
+
* and `listFiles` — are implemented via shell commands piped through
|
|
19
|
+
* `executeStreaming`.
|
|
20
|
+
*
|
|
21
|
+
* Subclasses may override any method with a native implementation for
|
|
22
|
+
* better performance or to handle edge cases (e.g., binary-safe file
|
|
23
|
+
* transfer via Docker stdin pipes, or native API calls for cloud backends).
|
|
24
|
+
*/
|
|
25
|
+
export declare abstract class PosixShellSandbox extends Sandbox {
|
|
26
|
+
executeCodeStreaming(code: string, language: string, options?: ExecuteOptions): AsyncGenerator<StreamChunk | ExecutionResult, void, undefined>;
|
|
27
|
+
readFile(path: string): Promise<Uint8Array>;
|
|
28
|
+
writeFile(path: string, content: Uint8Array): Promise<void>;
|
|
29
|
+
removeFile(path: string): Promise<void>;
|
|
30
|
+
listFiles(path: string): Promise<FileInfo[]>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=posix-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posix-shell.d.ts","sourceRoot":"","sources":["../../../src/sandbox/posix-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAGxE;;;;;;;;;;;;GAYG;AACH,8BAAsB,iBAAkB,SAAQ,OAAO;IAC9C,oBAAoB,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,cAAc,CAAC,WAAW,GAAG,eAAe,EAAE,IAAI,EAAE,SAAS,CAAC;IAS3D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQ3C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAqBnD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell sandbox with default implementations for file and code operations.
|
|
3
|
+
*
|
|
4
|
+
* Subclasses only need to implement {@link PosixShellSandbox.executeStreaming} —
|
|
5
|
+
* all other operations are implemented by running shell commands through it.
|
|
6
|
+
* Use this for remote environments where only shell access is available
|
|
7
|
+
* (Docker containers, SSH connections, cloud runtimes).
|
|
8
|
+
*/
|
|
9
|
+
import { Sandbox } from './base.js';
|
|
10
|
+
import { LANGUAGE_PATTERN } from './constants.js';
|
|
11
|
+
import { shellQuote } from '../utils/shell-quote.js';
|
|
12
|
+
/**
|
|
13
|
+
* Abstract sandbox that provides shell-based defaults for file and code operations.
|
|
14
|
+
* Assumes a POSIX-compatible shell (sh/bash) on the target.
|
|
15
|
+
*
|
|
16
|
+
* Subclasses only need to implement {@link executeStreaming}. The remaining
|
|
17
|
+
* operations — `executeCodeStreaming`, `readFile`, `writeFile`, `removeFile`,
|
|
18
|
+
* and `listFiles` — are implemented via shell commands piped through
|
|
19
|
+
* `executeStreaming`.
|
|
20
|
+
*
|
|
21
|
+
* Subclasses may override any method with a native implementation for
|
|
22
|
+
* better performance or to handle edge cases (e.g., binary-safe file
|
|
23
|
+
* transfer via Docker stdin pipes, or native API calls for cloud backends).
|
|
24
|
+
*/
|
|
25
|
+
export class PosixShellSandbox extends Sandbox {
|
|
26
|
+
async *executeCodeStreaming(code, language, options) {
|
|
27
|
+
if (!LANGUAGE_PATTERN.test(language)) {
|
|
28
|
+
throw new Error(`language parameter contains invalid characters: ${language}`);
|
|
29
|
+
}
|
|
30
|
+
const encoded = btoa(Array.from(new TextEncoder().encode(code), (b) => String.fromCharCode(b)).join(''));
|
|
31
|
+
const eof = `STRANDS_EOF_${crypto.randomUUID().slice(0, 16)}`;
|
|
32
|
+
yield* this.executeStreaming(`base64 -d << '${eof}' | ${language}\n${encoded}\n${eof}`, options);
|
|
33
|
+
}
|
|
34
|
+
async readFile(path) {
|
|
35
|
+
const result = await this.execute(`base64 < ${shellQuote(path)}`);
|
|
36
|
+
if (result.exitCode !== 0) {
|
|
37
|
+
throw new Error(result.stderr || `Failed to read file: ${path}`);
|
|
38
|
+
}
|
|
39
|
+
return Uint8Array.from(atob(result.stdout.replace(/\s/g, '')), (c) => c.charCodeAt(0));
|
|
40
|
+
}
|
|
41
|
+
async writeFile(path, content) {
|
|
42
|
+
const encoded = btoa(Array.from(content, (b) => String.fromCharCode(b)).join(''));
|
|
43
|
+
const quoted = shellQuote(path);
|
|
44
|
+
const eof = `STRANDS_EOF_${crypto.randomUUID().slice(0, 16)}`;
|
|
45
|
+
const cmd = `mkdir -p "$(dirname ${quoted})" && base64 -d << '${eof}' > ${quoted}\n${encoded}\n${eof}`;
|
|
46
|
+
const result = await this.execute(cmd);
|
|
47
|
+
if (result.exitCode !== 0) {
|
|
48
|
+
throw new Error(result.stderr || `Failed to write file: ${path}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async removeFile(path) {
|
|
52
|
+
const result = await this.execute(`rm ${shellQuote(path)}`);
|
|
53
|
+
if (result.exitCode !== 0) {
|
|
54
|
+
throw new Error(result.stderr || `Failed to remove file: ${path}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async listFiles(path) {
|
|
58
|
+
const quoted = shellQuote(path);
|
|
59
|
+
const result = await this.execute(`test -d ${quoted} || exit 1; env QUOTING_STYLE=literal ls -1ap ${quoted}`);
|
|
60
|
+
if (result.exitCode !== 0) {
|
|
61
|
+
throw new Error(result.stderr || `Failed to list directory: ${path}`);
|
|
62
|
+
}
|
|
63
|
+
const entries = [];
|
|
64
|
+
for (const raw of result.stdout.split('\n')) {
|
|
65
|
+
const line = raw.replace(/\r$/, '');
|
|
66
|
+
if (!line || line === './' || line === '../') {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const isDir = line.endsWith('/');
|
|
70
|
+
const name = isDir ? line.slice(0, -1) : line;
|
|
71
|
+
if (name) {
|
|
72
|
+
entries.push({ name, isDir });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return entries;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=posix-shell.js.map
|