sandboxbox 3.0.3 → 3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "3.0.3",
3
+ "version": "3.0.5",
4
4
  "description": "Lightweight process containment sandbox for CLI tools - Playwright, Claude Code, and more. Pure Node.js, no dependencies.",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -15,43 +15,6 @@ const ALLOWED_TOOLS = [
15
15
  'mcp__vexify__search_code'
16
16
  ];
17
17
 
18
- function handleStreamingOutput(data) {
19
- const lines = data.toString().split('\n').filter(line => line.trim());
20
-
21
- for (const line of lines) {
22
- const event = JSON.parse(line);
23
-
24
- if (event.type === 'system' && event.subtype === 'init') {
25
- if (!claudeStarted) {
26
- const claudeCreateTime = Date.now() - claudeStartTime;
27
- console.log(color('green', `✅ Claude Code started in ${claudeCreateTime}ms`));
28
- claudeStarted = true;
29
- }
30
- console.log(color('green', `✅ Session started (${event.session_id.substring(0, 8)}...)`));
31
- console.log(color('cyan', `📦 Model: ${event.model}`));
32
- console.log(color('cyan', `🔧 Tools: ${event.tools.length} available\n`));
33
- } else if (event.type === 'assistant' && event.message) {
34
- const content = event.message.content;
35
- if (Array.isArray(content)) {
36
- for (const block of content) {
37
- if (block.type === 'text') {
38
- process.stdout.write(block.text);
39
- } else if (block.type === 'tool_use') {
40
- console.log(color('cyan', `\n🔧 Using tool: ${block.name}`));
41
- }
42
- }
43
- }
44
- } else if (event.type === 'result') {
45
- const usage = event.usage || {};
46
- const cost = event.total_cost_usd || 0;
47
- console.log(color('green', `\n\n✅ Completed in ${event.duration_ms}ms`));
48
- console.log(color('yellow', `💰 Cost: $${cost.toFixed(4)}`));
49
- if (usage.input_tokens) {
50
- console.log(color('cyan', `📊 Tokens: ${usage.input_tokens} in, ${usage.output_tokens} out`));
51
- }
52
- }
53
- }
54
- }
55
18
 
56
19
  export async function claudeCommand(projectDir, prompt) {
57
20
  if (!existsSync(projectDir)) {
@@ -102,16 +65,58 @@ export async function claudeCommand(projectDir, prompt) {
102
65
  const claudeStartTime = Date.now();
103
66
  console.log(color('cyan', '⏱️ Stage 3: Starting Claude Code...'));
104
67
 
105
- const proc = spawn('claude', claudeArgs, {
106
- cwd: join(sandboxDir, 'workspace'),
68
+ const proc = spawn('sh', ['-c', `cd "${join(sandboxDir, 'workspace')}" && claude ${claudeArgs.join(' ')}`], {
107
69
  env: env, // Use the environment directly without modification
108
70
  stdio: ['pipe', 'pipe', 'pipe'],
109
- shell: true, // Use shell to ensure environment variables are properly expanded
71
+ shell: false, // Don't use nested shell
110
72
  detached: false
111
73
  });
112
74
 
113
75
  let claudeStarted = false;
114
76
 
77
+ function handleStreamingOutput(data) {
78
+ const lines = data.toString().split('\n').filter(line => line.trim());
79
+
80
+ for (const line of lines) {
81
+ try {
82
+ const event = JSON.parse(line);
83
+
84
+ if (event.type === 'system' && event.subtype === 'init') {
85
+ if (!claudeStarted) {
86
+ const claudeCreateTime = Date.now() - claudeStartTime;
87
+ console.log(color('green', `✅ Claude Code started in ${claudeCreateTime}ms`));
88
+ claudeStarted = true;
89
+ }
90
+ console.log(color('green', `✅ Session started (${event.session_id.substring(0, 8)}...)`));
91
+ console.log(color('cyan', `📦 Model: ${event.model}`));
92
+ console.log(color('cyan', `🔧 Tools: ${event.tools.length} available\n`));
93
+ } else if (event.type === 'assistant' && event.message) {
94
+ const content = event.message.content;
95
+ if (Array.isArray(content)) {
96
+ for (const block of content) {
97
+ if (block.type === 'text') {
98
+ process.stdout.write(block.text);
99
+ } else if (block.type === 'tool_use') {
100
+ console.log(color('cyan', `\n🔧 Using tool: ${block.name}`));
101
+ }
102
+ }
103
+ }
104
+ } else if (event.type === 'result') {
105
+ const usage = event.usage || {};
106
+ const cost = event.total_cost_usd || 0;
107
+ console.log(color('green', `\n\n✅ Completed in ${event.duration_ms}ms`));
108
+ console.log(color('yellow', `💰 Cost: $${cost.toFixed(4)}`));
109
+ if (usage.input_tokens) {
110
+ console.log(color('cyan', `📊 Tokens: ${usage.input_tokens} in, ${usage.output_tokens} out`));
111
+ }
112
+ }
113
+ } catch (jsonError) {
114
+ // Skip malformed JSON lines - might be incomplete chunks
115
+ // Silently continue to avoid breaking the stream
116
+ }
117
+ }
118
+ }
119
+
115
120
  // Add error handling
116
121
  proc.on('error', (error) => {
117
122
  console.log(color('red', `🔍 Debug: Process error: ${error.message}`));
@@ -129,12 +134,17 @@ export async function claudeCommand(projectDir, prompt) {
129
134
  proc.stdout.on('data', (data) => {
130
135
  stdoutOutput += data.toString();
131
136
 
132
- // Check for errors in JSON output
137
+ // Check for errors in JSON output with error handling
133
138
  const lines = data.toString().split('\n').filter(l => l.trim());
134
139
  for (const line of lines) {
135
- const event = JSON.parse(line);
136
- if (event.type === 'result' && event.is_error) {
137
- lastError = event.result;
140
+ try {
141
+ const event = JSON.parse(line);
142
+ if (event.type === 'result' && event.is_error) {
143
+ lastError = event.result;
144
+ }
145
+ } catch (jsonError) {
146
+ // Ignore JSON parsing errors - might be incomplete chunks
147
+ console.error('JSON parse error:', jsonError.message);
138
148
  }
139
149
  }
140
150