sandboxbox 2.2.7 → 2.2.9

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 CHANGED
@@ -5,10 +5,11 @@ Portable containerized environments using Podman with automatic WSL management a
5
5
 
6
6
  ## Core Components
7
7
 
8
- ### CLI (cli.js)
9
- - Commands: build, run, shell, claude, version
10
- - Auto-detects and starts Podman machine
11
- - Shell execution: `shell: process.platform === 'win32'`
8
+ ### CLI Architecture
9
+ - **Entry**: cli.js (main entry point)
10
+ - **Commands**: utils/commands/container.js (build, run, shell), utils/commands/claude.js (claude), utils/commands/index.js (version + exports)
11
+ - **Pattern**: Modular command structure, each file <100 lines
12
+ - **Shell execution**: `shell: process.platform === 'win32'` for all execSync calls
12
13
 
13
14
  ### Podman Downloader (scripts/download-podman.js)
14
15
  - Cross-platform binary downloads from GitHub releases
@@ -18,7 +19,6 @@ Portable containerized environments using Podman with automatic WSL management a
18
19
  - Auto-detects existing installations
19
20
  - Auto-triggers on first use if Podman not found
20
21
  - Verifies binary existence post-download
21
- - Auto-initializes Podman machine on Windows after download
22
22
 
23
23
  ### Container Images
24
24
  - **sandboxbox:latest**: Full development environment
@@ -55,36 +55,22 @@ if (process.platform === 'win32') {
55
55
  }
56
56
  ```
57
57
 
58
- ### Auto Podman Machine Start (Rootless Mode)
59
- ```javascript
60
- // Initialize with explicit rootless mode for portability
61
- if (process.platform === 'win32' && isBundled) {
62
- try {
63
- execSync(`"${podmanPath}" info`, { stdio: 'pipe' });
64
- } catch (infoError) {
65
- if (infoError.message.includes('Cannot connect to Podman')) {
66
- // Auto-initialize with rootless mode if machine doesn't exist
67
- execSync(`"${podmanPath}" machine init --rootful=false`, { stdio: 'inherit' });
68
- execSync(`"${podmanPath}" machine start`, { stdio: 'inherit' });
69
- }
70
- }
71
- }
72
- ```
73
-
74
- ### Rootless vs Rootful Mode
75
- - **Rootless (default)**: Runs without administrator privileges, portable across systems
76
- - **Configuration**: All machines initialized with `--rootful=false` flag
77
- - **Benefits**: No elevated permissions required, better security, true portability
78
-
79
- ### Portable Podman Architecture
80
- - **Direct Podman Execution**: Uses bundled Podman binary without complex machine management
81
- - **Rootless Operation**: Always runs in rootless mode for portability (--rootful=false)
82
- - **Self-Contained**: All dependencies included in the package
83
- - **Simple Configuration**: Minimal backend setup only when needed
84
- - **Auto-Download**: Downloads platform-specific binaries automatically
58
+ ### Automatic Backend Setup
59
+ **Implementation**: `ensureBackend(podmanPath)` in utils/podman.js
60
+ - Linux: Returns immediately (native execution, no backend needed)
61
+ - Windows/macOS: Checks `podman info` connectivity
62
+ - Auto-initializes on first run: `podman machine init --rootful=false` (Windows) or `podman machine init` (macOS)
63
+ - Auto-starts machine: `podman machine start`
64
+ - Shows progress: "Initializing Podman backend (first run, takes 2-3 minutes)"
65
+ - Detects existing machines via `podman machine list --format json`
66
+ - Called before all container operations (build, run, shell, claude)
67
+
68
+ ### Portable Architecture
69
+ - **Binary Auto-Download**: Platform-specific Podman binary (amd64/arm64) from GitHub releases
70
+ - **Rootless Mode**: Windows uses `--rootful=false` for portability
71
+ - **Backend Automation**: Fully automatic backend initialization on first container operation
85
72
  - **NPX Compatible**: Works via npx without global installation
86
- - **Architecture Support**: Auto-detects and downloads correct binary (amd64 or arm64)
87
- - **Cross-Platform**: Windows, macOS, Linux - all with amd64/arm64 support
73
+ - **Cross-Platform**: Windows (amd64/arm64), macOS (amd64/arm64), Linux (amd64/arm64)
88
74
 
89
75
  ## Isolation Architecture
90
76
 
package/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * SandboxBox CLI - Portable Container Runner with Podman
@@ -8,7 +8,7 @@
8
8
  import { resolve } from 'path';
9
9
  import { color } from './utils/colors.js';
10
10
  import { showBanner, showHelp } from './utils/ui.js';
11
- import { buildCommand, runCommand, shellCommand, claudeCommand, versionCommand } from './utils/commands.js';
11
+ import { buildCommand, runCommand, shellCommand, claudeCommand, versionCommand } from './utils/commands/index.js';
12
12
 
13
13
  async function main() {
14
14
  const args = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "2.2.7",
3
+ "version": "2.2.9",
4
4
  "description": "Portable container runner with Podman - Claude Code & Playwright support. Works on Windows, macOS, and Linux.",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -0,0 +1,90 @@
1
+ import { existsSync, writeFileSync } from 'fs';
2
+ import { execSync } from 'child_process';
3
+ import { resolve, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { color } from '../colors.js';
6
+ import { checkPodman, ensureBackend, getPodmanPath } from '../podman.js';
7
+ import { buildClaudeContainerCommand, createClaudeDockerfile } from '../claude-workspace.js';
8
+ import { createIsolatedEnvironment, setupCleanupHandlers, buildContainerMounts } from '../isolation.js';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ export function claudeCommand(projectDir, command = 'claude') {
14
+ if (!existsSync(projectDir)) {
15
+ console.log(color('red', `❌ Project directory not found: ${projectDir}`));
16
+ return false;
17
+ }
18
+
19
+ if (!existsSync(resolve(projectDir, '.git'))) {
20
+ console.log(color('red', `❌ Not a git repository: ${projectDir}`));
21
+ console.log(color('yellow', 'Please run this command in a git repository directory'));
22
+ return false;
23
+ }
24
+
25
+ const podmanPath = getPodmanPath();
26
+ try {
27
+ execSync(`"${podmanPath}" image inspect sandboxbox-local:latest`, {
28
+ stdio: 'pipe',
29
+ shell: process.platform === 'win32'
30
+ });
31
+ } catch {
32
+ console.log(color('yellow', '📦 Building Claude Code container...'));
33
+ if (!buildClaudeContainer()) {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ console.log(color('blue', '🚀 Starting Claude Code in isolated environment...'));
39
+ console.log(color('yellow', `Project: ${projectDir}`));
40
+ console.log(color('yellow', `Command: ${command}`));
41
+ console.log(color('cyan', '📦 Note: Changes will be isolated and will NOT affect the original repository\n'));
42
+
43
+ const buildPodman = checkPodman();
44
+ if (!buildPodman) return false;
45
+ if (!ensureBackend(buildPodman)) return false;
46
+
47
+ try {
48
+ const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
49
+ setupCleanupHandlers(cleanup);
50
+ const mounts = buildContainerMounts(tempProjectDir, projectDir);
51
+ const containerCommand = buildClaudeContainerCommand(tempProjectDir, buildPodman, command, mounts);
52
+
53
+ execSync(containerCommand, {
54
+ stdio: 'inherit',
55
+ shell: process.platform === 'win32'
56
+ });
57
+
58
+ cleanup();
59
+ console.log(color('green', '\n✅ Claude Code session completed! (Isolated - no host changes)'));
60
+ return true;
61
+ } catch (error) {
62
+ console.log(color('red', `\n❌ Claude Code failed: ${error.message}`));
63
+ return false;
64
+ }
65
+ }
66
+
67
+ function buildClaudeContainer() {
68
+ const dockerfilePath = resolve(__dirname, '..', '..', 'Dockerfile.claude');
69
+ const dockerfileContent = createClaudeDockerfile();
70
+
71
+ writeFileSync(dockerfilePath, dockerfileContent);
72
+ console.log(color('blue', '🏗️ Building Claude Code container...'));
73
+
74
+ const podmanPath = checkPodman();
75
+ if (!podmanPath) return false;
76
+ if (!ensureBackend(podmanPath)) return false;
77
+
78
+ try {
79
+ execSync(`"${podmanPath}" build -f "${dockerfilePath}" -t sandboxbox-local:latest .`, {
80
+ stdio: 'inherit',
81
+ cwd: resolve(__dirname, '..', '..'),
82
+ shell: process.platform === 'win32'
83
+ });
84
+ console.log(color('green', '\n✅ Claude Code container built successfully!'));
85
+ return true;
86
+ } catch (error) {
87
+ console.log(color('red', `\n❌ Build failed: ${error.message}`));
88
+ return false;
89
+ }
90
+ }
@@ -0,0 +1,99 @@
1
+ import { existsSync } from 'fs';
2
+ import { execSync } from 'child_process';
3
+ import { dirname } from 'path';
4
+ import { color } from '../colors.js';
5
+ import { checkPodman, ensureBackend } from '../podman.js';
6
+ import { createIsolatedEnvironment, setupCleanupHandlers, buildContainerMounts } from '../isolation.js';
7
+
8
+ export function buildCommand(dockerfilePath) {
9
+ if (!existsSync(dockerfilePath)) {
10
+ console.log(color('red', `❌ Dockerfile not found: ${dockerfilePath}`));
11
+ return false;
12
+ }
13
+
14
+ console.log(color('blue', '🏗️ Building container...'));
15
+ console.log(color('yellow', `Dockerfile: ${dockerfilePath}\n`));
16
+
17
+ const podmanPath = checkPodman();
18
+ if (!podmanPath) return false;
19
+ if (!ensureBackend(podmanPath)) return false;
20
+
21
+ try {
22
+ execSync(`"${podmanPath}" build -f "${dockerfilePath}" -t sandboxbox:latest .`, {
23
+ stdio: 'inherit',
24
+ cwd: dirname(dockerfilePath),
25
+ shell: process.platform === 'win32'
26
+ });
27
+ console.log(color('green', '\n✅ Container built successfully!'));
28
+ return true;
29
+ } catch (error) {
30
+ console.log(color('red', `\n❌ Build failed: ${error.message}`));
31
+ return false;
32
+ }
33
+ }
34
+
35
+ export function runCommand(projectDir, cmd = 'bash') {
36
+ if (!existsSync(projectDir)) {
37
+ console.log(color('red', `❌ Project directory not found: ${projectDir}`));
38
+ return false;
39
+ }
40
+
41
+ console.log(color('blue', '🚀 Running project in isolated container...'));
42
+ console.log(color('yellow', `Project: ${projectDir}`));
43
+ console.log(color('yellow', `Command: ${cmd}\n`));
44
+ console.log(color('cyan', '📦 Note: Changes will NOT affect host files (isolated environment)'));
45
+
46
+ const podmanPath = checkPodman();
47
+ if (!podmanPath) return false;
48
+ if (!ensureBackend(podmanPath)) return false;
49
+
50
+ try {
51
+ const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
52
+ setupCleanupHandlers(cleanup);
53
+ const mounts = buildContainerMounts(tempProjectDir, projectDir);
54
+
55
+ execSync(`"${podmanPath}" run --rm -it ${mounts.join(' ')} -w /workspace sandboxbox:latest ${cmd}`, {
56
+ stdio: 'inherit',
57
+ shell: process.platform === 'win32'
58
+ });
59
+
60
+ cleanup();
61
+ console.log(color('green', '\n✅ Container execution completed! (Isolated - no host changes)'));
62
+ return true;
63
+ } catch (error) {
64
+ console.log(color('red', `\n❌ Run failed: ${error.message}`));
65
+ return false;
66
+ }
67
+ }
68
+
69
+ export function shellCommand(projectDir) {
70
+ if (!existsSync(projectDir)) {
71
+ console.log(color('red', `❌ Project directory not found: ${projectDir}`));
72
+ return false;
73
+ }
74
+
75
+ console.log(color('blue', '🐚 Starting interactive shell in isolated container...'));
76
+ console.log(color('yellow', `Project: ${projectDir}\n`));
77
+ console.log(color('cyan', '📦 Note: Changes will NOT affect host files (isolated environment)'));
78
+
79
+ const podmanPath = checkPodman();
80
+ if (!podmanPath) return false;
81
+ if (!ensureBackend(podmanPath)) return false;
82
+
83
+ try {
84
+ const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
85
+ setupCleanupHandlers(cleanup);
86
+ const mounts = buildContainerMounts(tempProjectDir, projectDir);
87
+
88
+ execSync(`"${podmanPath}" run --rm -it ${mounts.join(' ')} -w /workspace sandboxbox:latest /bin/bash`, {
89
+ stdio: 'inherit',
90
+ shell: process.platform === 'win32'
91
+ });
92
+
93
+ cleanup();
94
+ return true;
95
+ } catch (error) {
96
+ console.log(color('red', `\n❌ Shell failed: ${error.message}`));
97
+ return false;
98
+ }
99
+ }
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from 'fs';
2
+ import { resolve, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { color } from '../colors.js';
5
+ import { checkPodman } from '../podman.js';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ export { buildCommand, runCommand, shellCommand } from './container.js';
11
+ export { claudeCommand } from './claude.js';
12
+
13
+ export function versionCommand() {
14
+ try {
15
+ const packageJson = JSON.parse(readFileSync(resolve(__dirname, '..', '..', 'package.json'), 'utf-8'));
16
+ console.log(color('green', `SandboxBox v${packageJson.version}`));
17
+ console.log(color('cyan', 'Portable containers with Claude Code integration'));
18
+ if (checkPodman()) {
19
+ console.log('');
20
+ }
21
+ return true;
22
+ } catch (error) {
23
+ console.log(color('red', '❌ Could not read version'));
24
+ return false;
25
+ }
26
+ }
package/utils/podman.js CHANGED
@@ -27,37 +27,37 @@ export function getPodmanPath() {
27
27
  }
28
28
 
29
29
  export function ensureBackend(podmanPath) {
30
- if (process.platform !== 'win32') return;
30
+ if (process.platform === 'linux') return true;
31
31
 
32
- const execOptions = {
33
- encoding: 'utf-8',
34
- stdio: 'pipe',
35
- shell: true
36
- };
32
+ const execOptions = { encoding: 'utf-8', stdio: 'pipe', shell: true };
37
33
 
38
34
  try {
39
35
  execSync(`"${podmanPath}" info`, execOptions);
36
+ return true;
40
37
  } catch (infoError) {
41
- if (infoError.message.includes('Cannot connect to Podman')) {
42
- console.log('\n🔧 Starting Podman backend (first run may take a few minutes)...');
43
- try {
44
- execSync(`"${podmanPath}" machine start`, {
45
- stdio: 'inherit',
46
- shell: true
47
- });
48
- } catch (startError) {
49
- if (startError.message.includes('does not exist') || startError.message.includes('not found')) {
50
- console.log('🔧 Creating Podman machine (rootless mode)...');
51
- execSync(`"${podmanPath}" machine init --rootful=false`, {
52
- stdio: 'inherit',
53
- shell: true
54
- });
55
- execSync(`"${podmanPath}" machine start`, {
56
- stdio: 'inherit',
57
- shell: true
58
- });
59
- }
38
+ if (!infoError.message.includes('Cannot connect to Podman')) throw infoError;
39
+
40
+ console.log(color('yellow', '\n🔧 Initializing Podman backend (first run, takes 2-3 minutes)...'));
41
+
42
+ try {
43
+ const machineListOutput = execSync(`"${podmanPath}" machine list --format json`, execOptions);
44
+ const machines = JSON.parse(machineListOutput || '[]');
45
+
46
+ if (machines.length === 0) {
47
+ console.log(color('cyan', ' Creating Podman machine...'));
48
+ const initCmd = process.platform === 'win32'
49
+ ? `"${podmanPath}" machine init --rootful=false`
50
+ : `"${podmanPath}" machine init`;
51
+ execSync(initCmd, { stdio: 'inherit', shell: true });
60
52
  }
53
+
54
+ console.log(color('cyan', ' Starting Podman machine...'));
55
+ execSync(`"${podmanPath}" machine start`, { stdio: 'inherit', shell: true });
56
+ console.log(color('green', '✅ Podman backend ready\n'));
57
+ return true;
58
+ } catch (backendError) {
59
+ console.log(color('red', `\n❌ Backend setup failed: ${backendError.message}`));
60
+ return false;
61
61
  }
62
62
  }
63
63
  }
package/utils/commands.js DELETED
@@ -1,203 +0,0 @@
1
- import { readFileSync, existsSync, writeFileSync } from 'fs';
2
- import { execSync } from 'child_process';
3
- import { resolve, dirname } from 'path';
4
- import { fileURLToPath } from 'url';
5
- import { color } from './colors.js';
6
- import { checkPodman, getPodmanPath, ensureBackend } from './podman.js';
7
- import { buildClaudeContainerCommand, createClaudeDockerfile } from './claude-workspace.js';
8
- import { createIsolatedEnvironment, setupCleanupHandlers, buildContainerMounts } from './isolation.js';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- export function buildCommand(dockerfilePath) {
14
- if (!existsSync(dockerfilePath)) {
15
- console.log(color('red', `❌ Dockerfile not found: ${dockerfilePath}`));
16
- return false;
17
- }
18
-
19
- console.log(color('blue', '🏗️ Building container...'));
20
- console.log(color('yellow', `Dockerfile: ${dockerfilePath}\n`));
21
-
22
- const podmanPath = checkPodman();
23
- if (!podmanPath) return false;
24
-
25
- ensureBackend(podmanPath);
26
-
27
- try {
28
- execSync(`"${podmanPath}" build -f "${dockerfilePath}" -t sandboxbox:latest .`, {
29
- stdio: 'inherit',
30
- cwd: dirname(dockerfilePath),
31
- shell: process.platform === 'win32'
32
- });
33
- console.log(color('green', '\n✅ Container built successfully!'));
34
- return true;
35
- } catch (error) {
36
- console.log(color('red', `\n❌ Build failed: ${error.message}`));
37
- return false;
38
- }
39
- }
40
-
41
- export function runCommand(projectDir, cmd = 'bash') {
42
- if (!existsSync(projectDir)) {
43
- console.log(color('red', `❌ Project directory not found: ${projectDir}`));
44
- return false;
45
- }
46
-
47
- console.log(color('blue', '🚀 Running project in isolated container...'));
48
- console.log(color('yellow', `Project: ${projectDir}`));
49
- console.log(color('yellow', `Command: ${cmd}\n`));
50
- console.log(color('cyan', '📦 Note: Changes will NOT affect host files (isolated environment)'));
51
-
52
- const podmanPath = checkPodman();
53
- if (!podmanPath) return false;
54
-
55
- ensureBackend(podmanPath);
56
-
57
- try {
58
- const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
59
- setupCleanupHandlers(cleanup);
60
- const mounts = buildContainerMounts(tempProjectDir, projectDir);
61
-
62
- execSync(`"${podmanPath}" run --rm -it ${mounts.join(' ')} -w /workspace sandboxbox:latest ${cmd}`, {
63
- stdio: 'inherit',
64
- shell: process.platform === 'win32'
65
- });
66
-
67
- cleanup();
68
- console.log(color('green', '\n✅ Container execution completed! (Isolated - no host changes)'));
69
- return true;
70
- } catch (error) {
71
- console.log(color('red', `\n❌ Run failed: ${error.message}`));
72
- return false;
73
- }
74
- }
75
-
76
- export function shellCommand(projectDir) {
77
- if (!existsSync(projectDir)) {
78
- console.log(color('red', `❌ Project directory not found: ${projectDir}`));
79
- return false;
80
- }
81
-
82
- console.log(color('blue', '🐚 Starting interactive shell in isolated container...'));
83
- console.log(color('yellow', `Project: ${projectDir}\n`));
84
- console.log(color('cyan', '📦 Note: Changes will NOT affect host files (isolated environment)'));
85
-
86
- const podmanPath = checkPodman();
87
- if (!podmanPath) return false;
88
-
89
- ensureBackend(podmanPath);
90
-
91
- try {
92
- const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
93
- setupCleanupHandlers(cleanup);
94
- const mounts = buildContainerMounts(tempProjectDir, projectDir);
95
-
96
- execSync(`"${podmanPath}" run --rm -it ${mounts.join(' ')} -w /workspace sandboxbox:latest /bin/bash`, {
97
- stdio: 'inherit',
98
- shell: process.platform === 'win32'
99
- });
100
-
101
- cleanup();
102
- return true;
103
- } catch (error) {
104
- console.log(color('red', `\n❌ Shell failed: ${error.message}`));
105
- return false;
106
- }
107
- }
108
-
109
- export function claudeCommand(projectDir, command = 'claude') {
110
- if (!existsSync(projectDir)) {
111
- console.log(color('red', `❌ Project directory not found: ${projectDir}`));
112
- return false;
113
- }
114
-
115
- if (!existsSync(resolve(projectDir, '.git'))) {
116
- console.log(color('red', `❌ Not a git repository: ${projectDir}`));
117
- console.log(color('yellow', 'Please run this command in a git repository directory'));
118
- return false;
119
- }
120
-
121
- const podmanPath = getPodmanPath();
122
- try {
123
- execSync(`"${podmanPath}" image inspect sandboxbox-local:latest`, {
124
- stdio: 'pipe',
125
- shell: process.platform === 'win32'
126
- });
127
- } catch {
128
- console.log(color('yellow', '📦 Building Claude Code container...'));
129
- if (!buildClaudeContainer()) {
130
- return false;
131
- }
132
- }
133
-
134
- console.log(color('blue', '🚀 Starting Claude Code in isolated environment...'));
135
- console.log(color('yellow', `Project: ${projectDir}`));
136
- console.log(color('yellow', `Command: ${command}`));
137
- console.log(color('cyan', '📦 Note: Changes will be isolated and will NOT affect the original repository\n'));
138
-
139
- const buildPodman = checkPodman();
140
- if (!buildPodman) return false;
141
-
142
- ensureBackend(buildPodman);
143
-
144
- try {
145
- const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
146
- setupCleanupHandlers(cleanup);
147
- const mounts = buildContainerMounts(tempProjectDir, projectDir);
148
- const containerCommand = buildClaudeContainerCommand(tempProjectDir, buildPodman, command, mounts);
149
-
150
- execSync(containerCommand, {
151
- stdio: 'inherit',
152
- shell: process.platform === 'win32'
153
- });
154
-
155
- cleanup();
156
- console.log(color('green', '\n✅ Claude Code session completed! (Isolated - no host changes)'));
157
- return true;
158
- } catch (error) {
159
- console.log(color('red', `\n❌ Claude Code failed: ${error.message}`));
160
- return false;
161
- }
162
- }
163
-
164
- export function versionCommand() {
165
- try {
166
- const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8'));
167
- console.log(color('green', `SandboxBox v${packageJson.version}`));
168
- console.log(color('cyan', 'Portable containers with Claude Code integration'));
169
- if (checkPodman()) {
170
- console.log('');
171
- }
172
- return true;
173
- } catch (error) {
174
- console.log(color('red', '❌ Could not read version'));
175
- return false;
176
- }
177
- }
178
-
179
- function buildClaudeContainer() {
180
- const dockerfilePath = resolve(__dirname, '../Dockerfile.claude');
181
- const dockerfileContent = createClaudeDockerfile();
182
-
183
- writeFileSync(dockerfilePath, dockerfileContent);
184
- console.log(color('blue', '🏗️ Building Claude Code container...'));
185
-
186
- const podmanPath = checkPodman();
187
- if (!podmanPath) return false;
188
-
189
- ensureBackend(podmanPath);
190
-
191
- try {
192
- execSync(`"${podmanPath}" build -f "${dockerfilePath}" -t sandboxbox-local:latest .`, {
193
- stdio: 'inherit',
194
- cwd: dirname(__dirname),
195
- shell: process.platform === 'win32'
196
- });
197
- console.log(color('green', '\n✅ Claude Code container built successfully!'));
198
- return true;
199
- } catch (error) {
200
- console.log(color('red', `\n❌ Build failed: ${error.message}`));
201
- return false;
202
- }
203
- }