sandboxbox 2.0.7 ā 2.0.8
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/CLAUDE.md +68 -1
- package/Dockerfile.simple +18 -0
- package/cli.js +101 -7
- package/file.txt +1 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
@@ -132,7 +132,74 @@ exec claude # Changes save directly to local repo
|
|
132
132
|
### Path resolution issues
|
133
133
|
**Solution**: Use explicit REPO_PATH environment variable
|
134
134
|
|
135
|
+
## Command Isolation Principles
|
136
|
+
|
137
|
+
### Critical Architecture Distinction
|
138
|
+
- **`run` command**: Creates isolated temporary environment - changes DO NOT affect host
|
139
|
+
- **`claude` command**: Mounts local repository directly - changes DO affect host
|
140
|
+
- **`shell` command**: Creates isolated temporary environment - changes DO NOT affect host
|
141
|
+
|
142
|
+
### Isolation Implementation (run/shell commands)
|
143
|
+
```javascript
|
144
|
+
// Creates temporary directory with copied project
|
145
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'sandboxbox-'));
|
146
|
+
const tempProjectDir = join(tempDir, projectName);
|
147
|
+
|
148
|
+
// Cross-platform file copying with hidden files (.git, etc.)
|
149
|
+
if (process.platform === 'win32') {
|
150
|
+
execSync(`powershell -Command "Copy-Item -Path '${projectDir}\\*' -Destination '${tempProjectDir}' -Recurse -Force"`, {
|
151
|
+
stdio: 'pipe',
|
152
|
+
shell: true
|
153
|
+
});
|
154
|
+
// Copy hidden files separately
|
155
|
+
execSync(`powershell -Command "Get-ChildItem -Path '${projectDir}' -Force -Name | Where-Object { $_ -like '.*' } | ForEach-Object { Copy-Item -Path (Join-Path '${projectDir}' $_) -Destination '${tempProjectDir}' -Recurse -Force }"`, {
|
156
|
+
stdio: 'pipe',
|
157
|
+
shell: true
|
158
|
+
});
|
159
|
+
} else {
|
160
|
+
execSync(`cp -r "${projectDir}"/.* "${tempProjectDir}/" 2>/dev/null || true`, {
|
161
|
+
stdio: 'pipe',
|
162
|
+
shell: true
|
163
|
+
});
|
164
|
+
execSync(`cp -r "${projectDir}"/* "${tempProjectDir}/"`, {
|
165
|
+
stdio: 'pipe',
|
166
|
+
shell: true
|
167
|
+
});
|
168
|
+
}
|
169
|
+
|
170
|
+
// Automatic cleanup on exit
|
171
|
+
const cleanup = () => {
|
172
|
+
try {
|
173
|
+
rmSync(tempDir, { recursive: true, force: true });
|
174
|
+
} catch (cleanupError) {
|
175
|
+
// Ignore cleanup errors
|
176
|
+
}
|
177
|
+
};
|
178
|
+
|
179
|
+
process.on('exit', cleanup);
|
180
|
+
process.on('SIGINT', () => { cleanup(); process.exit(130); });
|
181
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(143); });
|
182
|
+
```
|
183
|
+
|
184
|
+
### Container Naming and Cleanup
|
185
|
+
- Use random short names: `sandboxbox-run-${Math.random().toString(36).substr(2, 9)}`
|
186
|
+
- Force cleanup: `podman rm -f container-name`
|
187
|
+
- Automatic cleanup handlers for all exit scenarios
|
188
|
+
- Cross-platform signal handling (SIGINT, SIGTERM)
|
189
|
+
|
190
|
+
### Cross-Platform Path Handling
|
191
|
+
```javascript
|
192
|
+
// Normalize Windows paths for podman cp command
|
193
|
+
const normalizedProjectDir = projectDir.replace(/\\/g, '/');
|
194
|
+
```
|
195
|
+
|
135
196
|
## Version Management
|
136
197
|
- Publish new version when fixing critical Windows issues
|
137
198
|
- Clear npm cache: `npm cache clean --force`
|
138
|
-
- Use specific version: `npx sandboxbox@latest`
|
199
|
+
- Use specific version: `npx sandboxbox@latest`
|
200
|
+
|
201
|
+
## File Cleanup Requirements
|
202
|
+
- All temporary containers auto-cleanup on exit
|
203
|
+
- All temporary directories auto-cleanup on exit
|
204
|
+
- Error handling for cleanup failures (ignore errors)
|
205
|
+
- Signal handlers ensure cleanup on interrupts
|
@@ -0,0 +1,18 @@
|
|
1
|
+
FROM node:20
|
2
|
+
|
3
|
+
# Install basic development tools
|
4
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
5
|
+
git \
|
6
|
+
bash \
|
7
|
+
curl \
|
8
|
+
nano \
|
9
|
+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
10
|
+
|
11
|
+
# Create workspace directory
|
12
|
+
WORKDIR /workspace
|
13
|
+
|
14
|
+
# Set up non-root user
|
15
|
+
USER node
|
16
|
+
|
17
|
+
# Install Claude Code
|
18
|
+
RUN npm install -g @anthropic-ai/claude-code@latest
|
package/cli.js
CHANGED
@@ -7,10 +7,11 @@
|
|
7
7
|
* Works on Windows, macOS, and Linux
|
8
8
|
*/
|
9
9
|
|
10
|
-
import { readFileSync, existsSync, writeFileSync } from 'fs';
|
10
|
+
import { readFileSync, existsSync, writeFileSync, mkdtempSync, rmSync } from 'fs';
|
11
11
|
import { execSync } from 'child_process';
|
12
|
-
import { resolve, dirname } from 'path';
|
12
|
+
import { resolve, dirname, join } from 'path';
|
13
13
|
import { fileURLToPath } from 'url';
|
14
|
+
import { tmpdir } from 'os';
|
14
15
|
|
15
16
|
import { color } from './utils/colors.js';
|
16
17
|
import { checkPodman, getPodmanPath } from './utils/podman.js';
|
@@ -161,19 +162,74 @@ async function main() {
|
|
161
162
|
process.exit(1);
|
162
163
|
}
|
163
164
|
|
164
|
-
console.log(color('blue', 'š Running project in container...'));
|
165
|
+
console.log(color('blue', 'š Running project in isolated container...'));
|
165
166
|
console.log(color('yellow', `Project: ${projectDir}`));
|
166
167
|
console.log(color('yellow', `Command: ${cmd}\n`));
|
168
|
+
console.log(color('cyan', 'š¦ Note: Changes will NOT affect host files (isolated environment)'));
|
167
169
|
|
168
170
|
const runPodman = checkPodman();
|
169
171
|
if (!runPodman) process.exit(1);
|
170
172
|
|
171
173
|
try {
|
172
|
-
|
174
|
+
// Create a temporary directory for isolation
|
175
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'sandboxbox-'));
|
176
|
+
const projectName = projectDir.split(/[\\\/]/).pop() || 'project';
|
177
|
+
const tempProjectDir = join(tempDir, projectName);
|
178
|
+
|
179
|
+
// Copy project to temporary directory (creates isolation)
|
180
|
+
// First create the directory
|
181
|
+
execSync(`mkdir -p "${tempProjectDir}"`, {
|
182
|
+
stdio: 'pipe',
|
183
|
+
shell: true
|
184
|
+
});
|
185
|
+
|
186
|
+
if (process.platform === 'win32') {
|
187
|
+
// Windows approach - include hidden files like .git
|
188
|
+
execSync(`powershell -Command "Copy-Item -Path '${projectDir}\\*' -Destination '${tempProjectDir}' -Recurse -Force -Exclude 'node_modules'"`, {
|
189
|
+
stdio: 'pipe',
|
190
|
+
shell: true
|
191
|
+
});
|
192
|
+
// Also copy hidden files separately
|
193
|
+
execSync(`powershell -Command "Get-ChildItem -Path '${projectDir}' -Force -Name | Where-Object { $_ -like '.*' } | ForEach-Object { Copy-Item -Path (Join-Path '${projectDir}' $_) -Destination '${tempProjectDir}' -Recurse -Force }"`, {
|
194
|
+
stdio: 'pipe',
|
195
|
+
shell: true
|
196
|
+
});
|
197
|
+
} else {
|
198
|
+
// Unix approach - include hidden files
|
199
|
+
execSync(`cp -r "${projectDir}"/.* "${tempProjectDir}/" 2>/dev/null || true`, {
|
200
|
+
stdio: 'pipe',
|
201
|
+
shell: true
|
202
|
+
});
|
203
|
+
execSync(`cp -r "${projectDir}"/* "${tempProjectDir}/"`, {
|
204
|
+
stdio: 'pipe',
|
205
|
+
shell: true
|
206
|
+
});
|
207
|
+
}
|
208
|
+
|
209
|
+
// Ensure cleanup on exit
|
210
|
+
const cleanup = () => {
|
211
|
+
try {
|
212
|
+
rmSync(tempDir, { recursive: true, force: true });
|
213
|
+
} catch (cleanupError) {
|
214
|
+
// Ignore cleanup errors
|
215
|
+
}
|
216
|
+
};
|
217
|
+
|
218
|
+
// Set up cleanup handlers
|
219
|
+
process.on('exit', cleanup);
|
220
|
+
process.on('SIGINT', () => { cleanup(); process.exit(130); });
|
221
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(143); });
|
222
|
+
|
223
|
+
// Run the command in isolated container with temporary directory
|
224
|
+
execSync(`"${runPodman}" run --rm -it -v "${tempProjectDir}:/workspace:rw" -w /workspace sandboxbox:latest ${cmd}`, {
|
173
225
|
stdio: 'inherit',
|
174
226
|
shell: process.platform === 'win32'
|
175
227
|
});
|
176
|
-
|
228
|
+
|
229
|
+
// Clean up the temporary directory
|
230
|
+
cleanup();
|
231
|
+
|
232
|
+
console.log(color('green', '\nā
Container execution completed! (Isolated - no host changes)'));
|
177
233
|
} catch (error) {
|
178
234
|
console.log(color('red', `\nā Run failed: ${error.message}`));
|
179
235
|
process.exit(1);
|
@@ -194,17 +250,55 @@ async function main() {
|
|
194
250
|
process.exit(1);
|
195
251
|
}
|
196
252
|
|
197
|
-
console.log(color('blue', 'š Starting interactive shell...'));
|
253
|
+
console.log(color('blue', 'š Starting interactive shell in isolated container...'));
|
198
254
|
console.log(color('yellow', `Project: ${shellProjectDir}\n`));
|
255
|
+
console.log(color('cyan', 'š¦ Note: Changes will NOT affect host files (isolated environment)'));
|
199
256
|
|
200
257
|
const shellPodman = checkPodman();
|
201
258
|
if (!shellPodman) process.exit(1);
|
202
259
|
|
203
260
|
try {
|
204
|
-
|
261
|
+
// Create a temporary container with copied project (isolated environment)
|
262
|
+
const tempShellContainerName = `sandboxbox-shell-${Math.random().toString(36).substr(2, 9)}`;
|
263
|
+
|
264
|
+
// Ensure cleanup on exit
|
265
|
+
const cleanup = () => {
|
266
|
+
try {
|
267
|
+
execSync(`"${shellPodman}" rm -f "${tempShellContainerName}"`, {
|
268
|
+
stdio: 'pipe',
|
269
|
+
shell: process.platform === 'win32'
|
270
|
+
});
|
271
|
+
} catch (cleanupError) {
|
272
|
+
// Ignore cleanup errors
|
273
|
+
}
|
274
|
+
};
|
275
|
+
|
276
|
+
// Set up cleanup handlers
|
277
|
+
process.on('exit', cleanup);
|
278
|
+
process.on('SIGINT', () => { cleanup(); process.exit(130); });
|
279
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(143); });
|
280
|
+
|
281
|
+
// Copy project into container (isolated)
|
282
|
+
execSync(`"${shellPodman}" create --name "${tempShellContainerName}" -w /workspace -it sandboxbox:latest /bin/bash`, {
|
283
|
+
stdio: 'pipe',
|
284
|
+
shell: process.platform === 'win32'
|
285
|
+
});
|
286
|
+
|
287
|
+
// Copy project files into isolated container - use proper path handling
|
288
|
+
const normalizedShellProjectDir = shellProjectDir.replace(/\\/g, '/');
|
289
|
+
execSync(`"${shellPodman}" cp "${normalizedShellProjectDir}" "${tempShellContainerName}:/workspace"`, {
|
290
|
+
stdio: 'pipe',
|
291
|
+
shell: process.platform === 'win32'
|
292
|
+
});
|
293
|
+
|
294
|
+
// Start interactive shell in the isolated container
|
295
|
+
execSync(`"${shellPodman}" start -i "${tempShellContainerName}"`, {
|
205
296
|
stdio: 'inherit',
|
206
297
|
shell: process.platform === 'win32'
|
207
298
|
});
|
299
|
+
|
300
|
+
// Clean up the temporary container
|
301
|
+
cleanup();
|
208
302
|
} catch (error) {
|
209
303
|
console.log(color('red', `\nā Shell failed: ${error.message}`));
|
210
304
|
process.exit(1);
|
package/file.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
'modified in container'
|
package/package.json
CHANGED