sandboxbox 2.0.4 ā 2.0.6
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/0.60 +0 -0
- package/Dockerfile +94 -94
- package/README.md +242 -242
- package/cli.js +341 -277
- package/npx-test/package.json +1 -0
- package/package.json +38 -38
- package/scripts/download-podman.js +237 -148
- package/test/Dockerfile +19 -0
- package/test/index.js +16 -0
- package/test/package.json +13 -0
- package/bin/.gitkeep +0 -1
package/cli.js
CHANGED
@@ -1,278 +1,342 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
|
3
|
-
/**
|
4
|
-
* SandboxBox CLI - Portable Container Runner with Podman
|
5
|
-
*
|
6
|
-
* Cross-platform container runner using Podman
|
7
|
-
* Works on Windows, macOS, and Linux
|
8
|
-
*
|
9
|
-
* Simple usage:
|
10
|
-
* npx sandboxbox build # Build container from Dockerfile
|
11
|
-
* npx sandboxbox run <project> # Run project in container
|
12
|
-
* npx sandboxbox shell <project> # Interactive shell
|
13
|
-
*/
|
14
|
-
|
15
|
-
import { readFileSync, existsSync } from 'fs';
|
16
|
-
import { execSync } from 'child_process';
|
17
|
-
import { fileURLToPath } from 'url';
|
18
|
-
import { dirname, resolve } from 'path';
|
19
|
-
|
20
|
-
const __filename = fileURLToPath(import.meta.url);
|
21
|
-
const __dirname = dirname(__filename);
|
22
|
-
|
23
|
-
// Colors for output
|
24
|
-
const colors = {
|
25
|
-
red: '\x1b[31m',
|
26
|
-
green: '\x1b[32m',
|
27
|
-
yellow: '\x1b[33m',
|
28
|
-
blue: '\x1b[34m',
|
29
|
-
magenta: '\x1b[35m',
|
30
|
-
cyan: '\x1b[36m',
|
31
|
-
white: '\x1b[37m',
|
32
|
-
reset: '\x1b[0m'
|
33
|
-
};
|
34
|
-
|
35
|
-
function color(colorName, text) {
|
36
|
-
return `${colors[colorName]}${text}${colors.reset}`;
|
37
|
-
}
|
38
|
-
|
39
|
-
function showBanner() {
|
40
|
-
console.log(color('cyan', 'š¦ SandboxBox - Portable Container Runner'));
|
41
|
-
console.log(color('cyan', 'āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
42
|
-
console.log('');
|
43
|
-
}
|
44
|
-
|
45
|
-
function showHelp() {
|
46
|
-
console.log(color('yellow', 'Usage:'));
|
47
|
-
console.log(' npx sandboxbox <command> [options]');
|
48
|
-
console.log('');
|
49
|
-
console.log(color('yellow', 'Commands:'));
|
50
|
-
console.log(' build [dockerfile] Build container from Dockerfile (default: ./Dockerfile)');
|
51
|
-
console.log(' run <project-dir> [cmd] Run project in container');
|
52
|
-
console.log(' shell <project-dir> Start interactive shell in container');
|
53
|
-
console.log(' version Show version information');
|
54
|
-
console.log('');
|
55
|
-
console.log(color('yellow', 'Examples:'));
|
56
|
-
console.log(' npx sandboxbox build');
|
57
|
-
console.log(' npx sandboxbox build ./Dockerfile.custom');
|
58
|
-
console.log(' npx sandboxbox run ./my-project');
|
59
|
-
console.log(' npx sandboxbox run ./my-project "npm test"');
|
60
|
-
console.log(' npx sandboxbox shell ./my-project');
|
61
|
-
console.log('');
|
62
|
-
console.log(color('yellow', 'Requirements:'));
|
63
|
-
console.log(' - Podman (https://podman.io/getting-started/installation)');
|
64
|
-
console.log(' - Works on Windows, macOS, and Linux!');
|
65
|
-
console.log('');
|
66
|
-
console.log(color('magenta', 'š Fast startup ⢠True isolation ⢠Cross-platform'));
|
67
|
-
}
|
68
|
-
|
69
|
-
function getPodmanPath() {
|
70
|
-
// Check for bundled podman first
|
71
|
-
const platform = process.platform;
|
72
|
-
const arch = process.arch === 'arm64' ? 'arm64' : 'amd64';
|
73
|
-
let bundledPodman;
|
74
|
-
|
75
|
-
if (platform === 'win32') {
|
76
|
-
bundledPodman = resolve(__dirname, 'bin', 'podman.exe');
|
77
|
-
} else if (platform === 'darwin') {
|
78
|
-
bundledPodman = resolve(__dirname, 'bin', 'podman');
|
79
|
-
} else {
|
80
|
-
bundledPodman = resolve(__dirname, 'bin', `podman-remote-static-linux_${arch}`);
|
81
|
-
}
|
82
|
-
|
83
|
-
if (existsSync(bundledPodman)) {
|
84
|
-
return bundledPodman;
|
85
|
-
}
|
86
|
-
// Fall back to system podman
|
87
|
-
return 'podman';
|
88
|
-
}
|
89
|
-
|
90
|
-
function checkPodman() {
|
91
|
-
const podmanPath = getPodmanPath();
|
92
|
-
const isBundled = podmanPath.includes('bin');
|
93
|
-
|
94
|
-
try {
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
}
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
console.log(color('
|
177
|
-
console.log(color('
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
}
|
226
|
-
|
227
|
-
const
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
}
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
process.exit(1);
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
});
|
2
|
+
|
3
|
+
/**
|
4
|
+
* SandboxBox CLI - Portable Container Runner with Podman
|
5
|
+
*
|
6
|
+
* Cross-platform container runner using Podman
|
7
|
+
* Works on Windows, macOS, and Linux
|
8
|
+
*
|
9
|
+
* Simple usage:
|
10
|
+
* npx sandboxbox build # Build container from Dockerfile
|
11
|
+
* npx sandboxbox run <project> # Run project in container
|
12
|
+
* npx sandboxbox shell <project> # Interactive shell
|
13
|
+
*/
|
14
|
+
|
15
|
+
import { readFileSync, existsSync } from 'fs';
|
16
|
+
import { execSync } from 'child_process';
|
17
|
+
import { fileURLToPath } from 'url';
|
18
|
+
import { dirname, resolve } from 'path';
|
19
|
+
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
21
|
+
const __dirname = dirname(__filename);
|
22
|
+
|
23
|
+
// Colors for output
|
24
|
+
const colors = {
|
25
|
+
red: '\x1b[31m',
|
26
|
+
green: '\x1b[32m',
|
27
|
+
yellow: '\x1b[33m',
|
28
|
+
blue: '\x1b[34m',
|
29
|
+
magenta: '\x1b[35m',
|
30
|
+
cyan: '\x1b[36m',
|
31
|
+
white: '\x1b[37m',
|
32
|
+
reset: '\x1b[0m'
|
33
|
+
};
|
34
|
+
|
35
|
+
function color(colorName, text) {
|
36
|
+
return `${colors[colorName]}${text}${colors.reset}`;
|
37
|
+
}
|
38
|
+
|
39
|
+
function showBanner() {
|
40
|
+
console.log(color('cyan', 'š¦ SandboxBox - Portable Container Runner'));
|
41
|
+
console.log(color('cyan', 'āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
42
|
+
console.log('');
|
43
|
+
}
|
44
|
+
|
45
|
+
function showHelp() {
|
46
|
+
console.log(color('yellow', 'Usage:'));
|
47
|
+
console.log(' npx sandboxbox <command> [options]');
|
48
|
+
console.log('');
|
49
|
+
console.log(color('yellow', 'Commands:'));
|
50
|
+
console.log(' build [dockerfile] Build container from Dockerfile (default: ./Dockerfile)');
|
51
|
+
console.log(' run <project-dir> [cmd] Run project in container');
|
52
|
+
console.log(' shell <project-dir> Start interactive shell in container');
|
53
|
+
console.log(' version Show version information');
|
54
|
+
console.log('');
|
55
|
+
console.log(color('yellow', 'Examples:'));
|
56
|
+
console.log(' npx sandboxbox build');
|
57
|
+
console.log(' npx sandboxbox build ./Dockerfile.custom');
|
58
|
+
console.log(' npx sandboxbox run ./my-project');
|
59
|
+
console.log(' npx sandboxbox run ./my-project "npm test"');
|
60
|
+
console.log(' npx sandboxbox shell ./my-project');
|
61
|
+
console.log('');
|
62
|
+
console.log(color('yellow', 'Requirements:'));
|
63
|
+
console.log(' - Podman (https://podman.io/getting-started/installation)');
|
64
|
+
console.log(' - Works on Windows, macOS, and Linux!');
|
65
|
+
console.log('');
|
66
|
+
console.log(color('magenta', 'š Fast startup ⢠True isolation ⢠Cross-platform'));
|
67
|
+
}
|
68
|
+
|
69
|
+
function getPodmanPath() {
|
70
|
+
// Check for bundled podman first
|
71
|
+
const platform = process.platform;
|
72
|
+
const arch = process.arch === 'arm64' ? 'arm64' : 'amd64';
|
73
|
+
let bundledPodman;
|
74
|
+
|
75
|
+
if (platform === 'win32') {
|
76
|
+
bundledPodman = resolve(__dirname, 'bin', 'podman.exe');
|
77
|
+
} else if (platform === 'darwin') {
|
78
|
+
bundledPodman = resolve(__dirname, 'bin', 'podman');
|
79
|
+
} else {
|
80
|
+
bundledPodman = resolve(__dirname, 'bin', `podman-remote-static-linux_${arch}`);
|
81
|
+
}
|
82
|
+
|
83
|
+
if (existsSync(bundledPodman)) {
|
84
|
+
return bundledPodman;
|
85
|
+
}
|
86
|
+
// Fall back to system podman
|
87
|
+
return 'podman';
|
88
|
+
}
|
89
|
+
|
90
|
+
function checkPodman() {
|
91
|
+
const podmanPath = getPodmanPath();
|
92
|
+
const isBundled = podmanPath.includes('bin');
|
93
|
+
|
94
|
+
try {
|
95
|
+
// For Windows bundled binary, ensure proper path handling
|
96
|
+
const execOptions = {
|
97
|
+
encoding: 'utf-8',
|
98
|
+
stdio: 'pipe',
|
99
|
+
shell: process.platform === 'win32' // Use shell on Windows for better compatibility
|
100
|
+
};
|
101
|
+
|
102
|
+
const version = execSync(`"${podmanPath}" --version`, execOptions).trim();
|
103
|
+
console.log(color('green', `ā
${version}${isBundled ? ' (bundled)' : ''}`));
|
104
|
+
|
105
|
+
// Check if Podman machine is running (Windows only)
|
106
|
+
if (process.platform === 'win32' && isBundled) {
|
107
|
+
try {
|
108
|
+
execSync(`"${podmanPath}" info`, { ...execOptions, stdio: 'pipe' });
|
109
|
+
} catch (infoError) {
|
110
|
+
if (infoError.message.includes('Cannot connect to Podman')) {
|
111
|
+
console.log(color('yellow', '\nš§ Podman machine not running, auto-initializing...'));
|
112
|
+
|
113
|
+
try {
|
114
|
+
// Try to start existing machine first
|
115
|
+
try {
|
116
|
+
execSync(`"${podmanPath}" machine start`, {
|
117
|
+
stdio: 'inherit',
|
118
|
+
cwd: __dirname,
|
119
|
+
shell: process.platform === 'win32'
|
120
|
+
});
|
121
|
+
console.log(color('green', '\nā
Podman machine started successfully in rootless mode!'));
|
122
|
+
} catch (startError) {
|
123
|
+
if (startError.message.includes('not found') || startError.message.includes('does not exist')) {
|
124
|
+
// Machine doesn't exist, initialize it
|
125
|
+
execSync(`"${podmanPath}" machine init`, {
|
126
|
+
stdio: 'inherit',
|
127
|
+
cwd: __dirname,
|
128
|
+
shell: process.platform === 'win32'
|
129
|
+
});
|
130
|
+
|
131
|
+
// Start the newly initialized machine
|
132
|
+
execSync(`"${podmanPath}" machine start`, {
|
133
|
+
stdio: 'inherit',
|
134
|
+
cwd: __dirname,
|
135
|
+
shell: process.platform === 'win32'
|
136
|
+
});
|
137
|
+
|
138
|
+
console.log(color('green', '\nā
Podman machine initialized and started successfully in rootless mode!'));
|
139
|
+
} else {
|
140
|
+
throw startError;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
} catch (machineError) {
|
144
|
+
console.log(color('red', `\nā Failed to initialize Podman machine: ${machineError.message}`));
|
145
|
+
console.log(color('yellow', '\nš” Please run manually:'));
|
146
|
+
console.log(' podman machine init && podman machine start');
|
147
|
+
return null;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
return podmanPath;
|
154
|
+
} catch (error) {
|
155
|
+
// If no bundled Podman and system Podman not found, try to download
|
156
|
+
if (!isBundled) {
|
157
|
+
console.log(color('red', 'ā Podman not found'));
|
158
|
+
console.log(color('yellow', '\nš¦ Auto-downloading Podman...'));
|
159
|
+
|
160
|
+
try {
|
161
|
+
// Run the download script directly
|
162
|
+
const scriptPath = resolve(__dirname, 'scripts', 'download-podman.js');
|
163
|
+
execSync(`node "${scriptPath}"`, { stdio: 'inherit', cwd: __dirname, shell: process.platform === 'win32' });
|
164
|
+
|
165
|
+
// Try again with downloaded Podman
|
166
|
+
const newPodmanPath = getPodmanPath();
|
167
|
+
const execOptions = {
|
168
|
+
encoding: 'utf-8',
|
169
|
+
stdio: 'pipe',
|
170
|
+
shell: process.platform === 'win32'
|
171
|
+
};
|
172
|
+
const version = execSync(`"${newPodmanPath}" --version`, execOptions).trim();
|
173
|
+
console.log(color('green', `\nā
${version} (auto-downloaded)`));
|
174
|
+
return newPodmanPath;
|
175
|
+
} catch (downloadError) {
|
176
|
+
console.log(color('red', `\nā Auto-download failed: ${downloadError.message}`));
|
177
|
+
console.log(color('yellow', '\nš” Please install Podman manually:'));
|
178
|
+
}
|
179
|
+
} else {
|
180
|
+
console.log(color('red', 'ā Podman not found'));
|
181
|
+
console.log(color('yellow', '\nš” Please install Podman manually:'));
|
182
|
+
}
|
183
|
+
|
184
|
+
console.log('');
|
185
|
+
if (process.platform === 'win32') {
|
186
|
+
console.log(color('cyan', ' Windows:'));
|
187
|
+
console.log(' winget install RedHat.Podman');
|
188
|
+
} else if (process.platform === 'darwin') {
|
189
|
+
console.log(color('cyan', ' macOS:'));
|
190
|
+
console.log(' brew install podman');
|
191
|
+
console.log(' podman machine init && podman machine start');
|
192
|
+
} else {
|
193
|
+
console.log(color('cyan', ' Linux:'));
|
194
|
+
console.log(' sudo apt-get install podman # Ubuntu/Debian');
|
195
|
+
console.log(' sudo dnf install podman # Fedora');
|
196
|
+
}
|
197
|
+
console.log('');
|
198
|
+
return null;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
async function main() {
|
203
|
+
const args = process.argv.slice(2);
|
204
|
+
|
205
|
+
showBanner();
|
206
|
+
|
207
|
+
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
208
|
+
showHelp();
|
209
|
+
process.exit(0);
|
210
|
+
}
|
211
|
+
|
212
|
+
const command = args[0].toLowerCase();
|
213
|
+
const commandArgs = args.slice(1);
|
214
|
+
|
215
|
+
switch (command) {
|
216
|
+
case 'build':
|
217
|
+
const dockerfilePath = commandArgs[0] || './Dockerfile';
|
218
|
+
|
219
|
+
if (!existsSync(dockerfilePath)) {
|
220
|
+
console.log(color('red', `ā Dockerfile not found: ${dockerfilePath}`));
|
221
|
+
process.exit(1);
|
222
|
+
}
|
223
|
+
|
224
|
+
console.log(color('blue', 'šļø Building container...'));
|
225
|
+
console.log(color('yellow', `Dockerfile: ${dockerfilePath}\n`));
|
226
|
+
|
227
|
+
const buildPodman = checkPodman();
|
228
|
+
if (!buildPodman) process.exit(1);
|
229
|
+
|
230
|
+
try {
|
231
|
+
console.log('');
|
232
|
+
execSync(`"${buildPodman}" build -f "${dockerfilePath}" -t sandboxbox:latest .`, {
|
233
|
+
stdio: 'inherit',
|
234
|
+
cwd: __dirname,
|
235
|
+
shell: process.platform === 'win32'
|
236
|
+
});
|
237
|
+
console.log('');
|
238
|
+
console.log(color('green', 'ā
Container built successfully!'));
|
239
|
+
console.log(color('cyan', '\nš” Next steps:'));
|
240
|
+
console.log(' npx sandboxbox run ./my-project');
|
241
|
+
} catch (error) {
|
242
|
+
console.log(color('red', `\nā Build failed: ${error.message}`));
|
243
|
+
process.exit(1);
|
244
|
+
}
|
245
|
+
break;
|
246
|
+
|
247
|
+
case 'run':
|
248
|
+
if (commandArgs.length === 0) {
|
249
|
+
console.log(color('red', 'ā Please specify a project directory'));
|
250
|
+
console.log(color('yellow', 'Usage: npx sandboxbox run <project-dir> [command]'));
|
251
|
+
process.exit(1);
|
252
|
+
}
|
253
|
+
|
254
|
+
const projectDir = resolve(commandArgs[0]);
|
255
|
+
const cmd = commandArgs[1] || 'bash';
|
256
|
+
|
257
|
+
if (!existsSync(projectDir)) {
|
258
|
+
console.log(color('red', `ā Project directory not found: ${projectDir}`));
|
259
|
+
process.exit(1);
|
260
|
+
}
|
261
|
+
|
262
|
+
console.log(color('blue', 'š Running project in container...'));
|
263
|
+
console.log(color('yellow', `Project: ${projectDir}`));
|
264
|
+
console.log(color('yellow', `Command: ${cmd}\n`));
|
265
|
+
|
266
|
+
const runPodman = checkPodman();
|
267
|
+
if (!runPodman) process.exit(1);
|
268
|
+
|
269
|
+
try {
|
270
|
+
console.log('');
|
271
|
+
execSync(`"${runPodman}" run --rm -it -v "${projectDir}:/workspace" -w /workspace sandboxbox:latest ${cmd}`, {
|
272
|
+
stdio: 'inherit',
|
273
|
+
shell: process.platform === 'win32'
|
274
|
+
});
|
275
|
+
console.log('');
|
276
|
+
console.log(color('green', 'ā
Container execution completed!'));
|
277
|
+
} catch (error) {
|
278
|
+
console.log(color('red', `\nā Run failed: ${error.message}`));
|
279
|
+
process.exit(1);
|
280
|
+
}
|
281
|
+
break;
|
282
|
+
|
283
|
+
case 'shell':
|
284
|
+
if (commandArgs.length === 0) {
|
285
|
+
console.log(color('red', 'ā Please specify a project directory'));
|
286
|
+
console.log(color('yellow', 'Usage: npx sandboxbox shell <project-dir>'));
|
287
|
+
process.exit(1);
|
288
|
+
}
|
289
|
+
|
290
|
+
const shellProjectDir = resolve(commandArgs[0]);
|
291
|
+
|
292
|
+
if (!existsSync(shellProjectDir)) {
|
293
|
+
console.log(color('red', `ā Project directory not found: ${shellProjectDir}`));
|
294
|
+
process.exit(1);
|
295
|
+
}
|
296
|
+
|
297
|
+
console.log(color('blue', 'š Starting interactive shell...'));
|
298
|
+
console.log(color('yellow', `Project: ${shellProjectDir}\n`));
|
299
|
+
|
300
|
+
const shellPodman = checkPodman();
|
301
|
+
if (!shellPodman) process.exit(1);
|
302
|
+
|
303
|
+
try {
|
304
|
+
console.log('');
|
305
|
+
execSync(`"${shellPodman}" run --rm -it -v "${shellProjectDir}:/workspace" -w /workspace sandboxbox:latest /bin/bash`, {
|
306
|
+
stdio: 'inherit',
|
307
|
+
shell: process.platform === 'win32'
|
308
|
+
});
|
309
|
+
} catch (error) {
|
310
|
+
console.log(color('red', `\nā Shell failed: ${error.message}`));
|
311
|
+
process.exit(1);
|
312
|
+
}
|
313
|
+
break;
|
314
|
+
|
315
|
+
case 'version':
|
316
|
+
try {
|
317
|
+
const packageJson = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf-8'));
|
318
|
+
console.log(color('green', `SandboxBox v${packageJson.version}`));
|
319
|
+
console.log(color('cyan', 'Portable containers with Claude Code & Playwright'));
|
320
|
+
if (checkPodman()) {
|
321
|
+
console.log('');
|
322
|
+
}
|
323
|
+
} catch (error) {
|
324
|
+
console.log(color('red', 'ā Could not read version'));
|
325
|
+
}
|
326
|
+
break;
|
327
|
+
|
328
|
+
default:
|
329
|
+
console.log(color('red', `ā Unknown command: ${command}`));
|
330
|
+
console.log(color('yellow', 'Use --help for usage information'));
|
331
|
+
process.exit(1);
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
// Run if called directly
|
336
|
+
main().catch(error => {
|
337
|
+
console.error(color('red', 'ā SandboxBox failed:'));
|
338
|
+
console.error(color('red', error.message));
|
339
|
+
console.error('');
|
340
|
+
console.error(color('yellow', 'š” Try: npx sandboxbox --help'));
|
341
|
+
process.exit(1);
|
342
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name": "test", "scripts": {"test": "echo Hello"}}
|