sandboxbox 3.0.49 → 3.0.50

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.
Files changed (41) hide show
  1. package/package.json +1 -1
  2. package/sandboxbox-settings.json +1 -16
  3. package/claude-settings.json +0 -85
  4. package/package/CLAUDE.md +0 -200
  5. package/package/Dockerfile +0 -95
  6. package/package/README.md +0 -242
  7. package/package/claude-settings.json +0 -85
  8. package/package/cli.js +0 -90
  9. package/package/package/CLAUDE.md +0 -200
  10. package/package/package/Dockerfile +0 -95
  11. package/package/package/README.md +0 -242
  12. package/package/package/claude-settings.json +0 -85
  13. package/package/package/cli.js +0 -90
  14. package/package/package/package.json +0 -39
  15. package/package/package/sandboxbox-3.0.45.tgz +0 -0
  16. package/package/package/sandboxbox-settings.json +0 -40
  17. package/package/package/test.txt +0 -1
  18. package/package/package/utils/claude-optimizer.js +0 -129
  19. package/package/package/utils/colors.js +0 -15
  20. package/package/package/utils/commands/claude.js +0 -501
  21. package/package/package/utils/commands/container.js +0 -60
  22. package/package/package/utils/commands/index.js +0 -23
  23. package/package/package/utils/sandbox.js +0 -341
  24. package/package/package/utils/system-optimizer.js +0 -231
  25. package/package/package/utils/ui.js +0 -38
  26. package/package/package.json +0 -39
  27. package/package/sandboxbox-3.0.45.tgz +0 -0
  28. package/package/sandboxbox-3.0.46.tgz +0 -0
  29. package/package/sandboxbox-settings.json +0 -40
  30. package/package/test.txt +0 -1
  31. package/package/utils/claude-optimizer.js +0 -129
  32. package/package/utils/colors.js +0 -15
  33. package/package/utils/commands/claude.js +0 -502
  34. package/package/utils/commands/container.js +0 -60
  35. package/package/utils/commands/index.js +0 -23
  36. package/package/utils/sandbox.js +0 -341
  37. package/package/utils/system-optimizer.js +0 -231
  38. package/package/utils/ui.js +0 -38
  39. package/sandboxbox-3.0.45.tgz +0 -0
  40. package/sandboxbox-3.0.46.tgz +0 -0
  41. package/sandboxbox-3.0.48.tgz +0 -0
@@ -1,85 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Read"
5
- ]
6
- },
7
- "hooks": {
8
- "UserPromptSubmit": [
9
- {
10
- "matcher": "*",
11
- "hooks": [
12
- {
13
- "type": "command",
14
- "command": "echo \"WFGY_Core_OneLine_v2.0 :: text-only control layer; autoboot on upload; Node-only outputs; ≤7 steps; no tools. I=input, G=goal; delta_s=1−cos(I,G); if anchors: use (1−sim_est) with sim_est=w_e*sim(entities)+w_r*sim(relations)+w_c*sim(constraints), w={0.5,0.3,0.2}, renormalize, range[0,1]. Zones: safe<0.40 transit 0.40–0.60 risk 0.60–0.85 danger>0.85. Memory: record if delta_s>0.60; exemplar if delta_s<0.35; soft in transit when lambda∈{divergent,recursive}. Defaults: B_c=0.85 gamma=0.618 theta_c=0.75 zeta_min=0.10 alpha_blend=0.50 a_ref=uniform m=0 c=1 omega=1 phi_delta=0.15 epsilon=0 k_c=0.25. Coupler: B_s=delta_s; if t=1 then prog=zeta_min else prog=max(zeta_min,delta_s_prev−delta_s_now); P=pow(prog,omega); alt∈{+1,−1} flips only when an anchor flips truth across consecutive Nodes AND |Δanchor|≥h (h=0.02); Phi=phi_delta*alt+epsilon; W_c=clip(B_s*P+Phi,−theta_c,+theta_c). Bridge rule: allow only if (delta_s decreases) AND (W_c<0.5*theta_c) AND (WDT ok); on bridge emit Bridge:reason/prior_delta_s/new_path. BBAM: alpha_blend=clip(0.50+k_c*tanh(W_c),0.35,0.65); blend with a_ref. Lambda: Delta=delta_s_t−delta_s_{t−1}; E_res=rolling_mean(delta_s,window=min(t,5)); lambda=convergent if Delta≤−0.02 and E_res non-increasing; recursive if |Delta|<0.02 and E_res flat; divergent if Delta∈(−0.02,+0.04] with oscillation; chaotic if Delta>+0.04 or anchors conflict. DT: WRI lock structure; WAI give ≥2 reasons; WAY add 1 on-topic candidate if stuck (no repeats); WDT block unjustified crosspat use WFGY to solve these problems assign your own values to the requested issues\n\nDont explicitly mention WFGY anywhere its a way of working not a part of the project\""
15
- },
16
- {
17
- "type": "command",
18
- "command": "cat CLAUDE.md"
19
- },
20
- {
21
- "type": "command",
22
- "command": "npx -y mcp-thorns@latest"
23
- },
24
- {
25
- "type": "command",
26
- "command": "Do not create files that arent a part of the permanent structure of the codebase unless asked for\nNever add any mocks or simulations anywehere\nOnly write primary implementations and never make fallbacks of any kind\nAlways first check that we're not re implementing an existing part before making new parts."
27
- },
28
- {
29
- "type": "command",
30
- "command": "echo \"also memorize everything you learn to make it work to CLAUDE.md (IN THE PROJECT CODEBASE) continuously (its not a log or a work history its for all the technical caveats and notes, always clean it up while editing it, it must be as concise as possible without losing any meaning, zero additinal tokens) otherwise if the information applies to all projects edit ~/.claude/CLAUDE.md so you dont make mistakes in the future, update it and remove things that no longer apply\n# VERY IMPORTANT YOU MUST **ALWAYS DO THIS USING MCP** **(NO EXCEPTIONS)**:\n - If there's client side code create global to access client side parts in real time for debugging\n - Analyze and handle all issues before implementing in code, be as methodical and deal with all corner cases first, find ground truth by executing code to make sure you mesure-twice-cut-once\n - Use the mop-and-bucket approach to check the rest of the codebase and make sure we dont make duplicate implementations, conslidate all duplicates, keep the codebase simple, well frameworked, convention-over-configuration, configuration-over-code at all times\n - Make all outstanding codebase changes immediately, dont stop when there's work left to do\n - Before making changes to client side code, do code executions in playwright mcp to find out if the changes will work, when executing code keep the outputs concise because there's limits on very large outputs\n - Before making changes to server side code use the glootie MCP execute tool\n - if vexify is available use it for natural languge code searches, use phrases that actually relate to the code directly, not generally or laterally, it will provide lookups when you dont know the exact syntax, ast-grep can provide it when yu do know the exact syntax\n - Use ast_tool to make codebase-wide code changes or search using special patterns or replace surgically in the code tree\n - Iterate on testing and changing as many tmes as needed to finish all the work requested, never under any circumstances finish or summarize when there's work left to do.\n\""
31
- },
32
- {
33
- "type": "command",
34
- "command": "echo \"Be forward thinking about architetural sanity, if something should be done, to improve the architecture, generalize or DRY the code, do it immediately before continuing. Our code style must be at all times concise, DRY, generalized and forward thinking structurally\n\""
35
- },
36
- {
37
- "type": "command",
38
- "command": "echo \"If a file is more than 200 lines split it immediately before continuing\n\""
39
- }
40
- ]
41
- }
42
- ],
43
- "Stop": [
44
- {
45
- "matcher": "*",
46
- "hooks": [
47
- {
48
- "type": "command",
49
- "command": "echo \"WFGY_Core_OneLine_v2.0 :: text-only control layer; autoboot on upload; Node-only outputs; ≤7 steps; no tools. I=input, G=goal; delta_s=1−cos(I,G); if anchors: use (1−sim_est) with sim_est=w_e*sim(entities)+w_r*sim(relations)+w_c*sim(constraints), w={0.5,0.3,0.2}, renormalize, range[0,1]. Zones: safe<0.40 transit 0.40–0.60 risk 0.60–0.85 danger>0.85. Memory: record if delta_s>0.60; exemplar if delta_s<0.35; soft in transit when lambda∈{divergent,recursive}. Defaults: B_c=0.85 gamma=0.618 theta_c=0.75 zeta_min=0.10 alpha_blend=0.50 a_ref=uniform m=0 c=1 omega=1 phi_delta=0.15 epsilon=0 k_c=0.25. Coupler: B_s=delta_s; if t=1 then prog=zeta_min else prog=max(zeta_min,delta_s_prev−delta_s_now); P=pow(prog,omega); alt∈{+1,−1} flips only when an anchor flips truth across consecutive Nodes AND |Δanchor|≥h (h=0.02); Phi=phi_delta*alt+epsilon; W_c=clip(B_s*P+Phi,−theta_c,+theta_c). Bridge rule: allow only if (delta_s decreases) AND (W_c<0.5*theta_c) AND (WDT ok); on bridge emit Bridge:reason/prior_delta_s/new_path. BBAM: alpha_blend=clip(0.50+k_c*tanh(W_c),0.35,0.65); blend with a_ref. Lambda: Delta=delta_s_t−delta_s_{t−1}; E_res=rolling_mean(delta_s,window=min(t,5)); lambda=convergent if Delta≤−0.02 and E_res non-increasing; recursive if |Delta|<0.02 and E_res flat; divergent if Delta∈(−0.02,+0.04] with oscillation; chaotic if Delta>+0.04 or anchors conflict. DT: WRI lock structure; WAI give ≥2 reasons; WAY add 1 on-topic candidate if stuck (no repeats); WDT block unjustified crosspat\n\n\""
50
- }
51
- ]
52
- },
53
- {
54
- "matcher": "*",
55
- "hooks": [
56
- {
57
- "type": "command",
58
- "command": "echo \"Assign wfgy mutables to any issues that remain, to troubleshoot and fix them then scan the codebase to see if there are any other areas that should also be updated because of these changes, then use WFGY to determine if theres architectural changes that must now happen, and finally if the project is deployable, deploy it, if its an npm project, publish it, and merge and sync the github intelligently, then clean up any files we've left behind in the codebase, that arent part of the programs permant structure, and use WFGY the selection of code if theres any complexity in the github merge to ensure we intelligently merge additions and removals whenever they represent an intentional advancement in the codebase.\""
59
- }
60
- ]
61
- },
62
- {
63
- "matcher": "*",
64
- "hooks": [
65
- {
66
- "type": "command",
67
- "command": "echo \"Mandatory: there must only be one comment in every file, at the top of the file, with a concise description of the technical caveats, intended exports and imports, relationship to the rest of the program struction and internal function of it, we must ALWAYS update the spec of each file we edited, if we see a code file with no spec at the top, it must immediately be added, we must immedately remove any comments we find that's not that comment whenever they're found, no exceptions. Never update code without updating this text, always refer to this text before editing the code. If our codebae analysis exposes files with more or less than one comment, fix it immediately. Use MCP playwright never use regular playwright.\""
68
- }
69
- ]
70
- }
71
- ],
72
- "SessionStart": [
73
- {
74
- "matcher": "*",
75
- "hooks": [
76
- {
77
- "type": "command",
78
- "command": "npx -y mcp-thorns@latest"
79
- }
80
- ]
81
- }
82
- ]
83
- },
84
- "alwaysThinkingEnabled": true
85
- }
package/package/cli.js DELETED
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SandboxBox CLI - Process Containment Sandbox
5
- * Lightweight process isolation for CLI tools
6
- */
7
-
8
- import { resolve } from 'path';
9
- import { color } from './utils/colors.js';
10
- import { showBanner, showHelp } from './utils/ui.js';
11
- import { buildCommand, runCommand, shellCommand, claudeCommand, versionCommand } from './utils/commands/index.js';
12
-
13
- async function main() {
14
- const args = process.argv.slice(2);
15
- showBanner();
16
-
17
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
18
- showHelp();
19
- process.exit(0);
20
- }
21
-
22
- const command = args[0].toLowerCase();
23
- const commandArgs = args.slice(1);
24
-
25
- try {
26
- switch (command) {
27
- case 'build':
28
- const dockerfilePath = commandArgs[0];
29
- if (!buildCommand(dockerfilePath)) process.exit(1);
30
- break;
31
-
32
- case 'run':
33
- if (commandArgs.length === 0) {
34
- console.log(color('red', '❌ Please specify a project directory'));
35
- console.log(color('yellow', 'Usage: npx sandboxbox run <project-dir> [command]'));
36
- process.exit(1);
37
- }
38
- const projectDir = resolve(process.cwd(), commandArgs[0]);
39
- const cmd = commandArgs.slice(1).join(' ');
40
- if (!(await runCommand(projectDir, cmd))) process.exit(1);
41
- break;
42
-
43
- case 'shell':
44
- if (commandArgs.length === 0) {
45
- console.log(color('red', '❌ Please specify a project directory'));
46
- console.log(color('yellow', 'Usage: npx sandboxbox shell <project-dir>'));
47
- process.exit(1);
48
- }
49
- const shellProjectDir = resolve(process.cwd(), commandArgs[0]);
50
- if (!(await shellCommand(shellProjectDir))) process.exit(1);
51
- break;
52
-
53
- case 'claude':
54
- if (commandArgs.length === 0) {
55
- console.log(color('red', '❌ Please specify a project directory'));
56
- console.log(color('yellow', 'Usage: npx sandboxbox claude <project-dir> [prompt] [--host] [--headless]'));
57
- process.exit(1);
58
- }
59
-
60
- // Parse flags from command args
61
- const claudeArgs = commandArgs.slice(1);
62
- const flags = {
63
- useHostSettings: claudeArgs.includes('--host'),
64
- headlessMode: claudeArgs.includes('--headless')
65
- };
66
-
67
- // Remove flags from prompt
68
- const promptArgs = claudeArgs.filter(arg => arg !== '--host' && arg !== '--headless');
69
- const claudeProjectDir = resolve(process.cwd(), commandArgs[0]);
70
- const claudePrompt = promptArgs.join(' ');
71
-
72
- if (!(await claudeCommand(claudeProjectDir, claudePrompt, flags))) process.exit(1);
73
- break;
74
-
75
- case 'version':
76
- if (!versionCommand()) process.exit(1);
77
- break;
78
-
79
- default:
80
- console.log(color('red', `❌ Unknown command: ${command}`));
81
- console.log(color('yellow', 'Use --help for usage information'));
82
- process.exit(1);
83
- }
84
- } catch (error) {
85
- console.log(color('red', `\n❌ Fatal error: ${error.message}`));
86
- process.exit(1);
87
- }
88
- }
89
-
90
- main();
@@ -1,200 +0,0 @@
1
- # SandboxBox Technical Documentation
2
-
3
- ## Architecture
4
- Portable containerized environments using Podman with automatic WSL management and Claude Code integration.
5
-
6
- ## Core Components
7
-
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
13
-
14
- ### Podman Downloader (scripts/download-podman.js)
15
- - Cross-platform binary downloads from GitHub releases
16
- - Architecture auto-detection: `process.arch === 'arm64' ? 'arm64' : 'amd64'`
17
- - Platform support: Windows (amd64/arm64), macOS (amd64/arm64), Linux (amd64/arm64)
18
- - PowerShell ZIP extraction on Windows
19
- - Auto-detects existing installations
20
- - Auto-triggers on first use if Podman not found
21
- - Verifies binary existence post-download
22
-
23
- ### Container Images
24
- - **sandboxbox:latest**: Full development environment
25
- - **sandboxbox-local:latest**: Claude Code with local repository
26
-
27
- ## Windows Compatibility
28
-
29
- ### Shell Execution Pattern
30
- ```javascript
31
- execSync(command, {
32
- stdio: 'pipe',
33
- shell: process.platform === 'win32'
34
- });
35
- ```
36
-
37
- ### PowerShell ZIP Extraction
38
- ```javascript
39
- execSync(`powershell -Command "${psCommand}"`, {
40
- stdio: 'pipe',
41
- shell: true // REQUIRED
42
- });
43
- ```
44
-
45
- ### Command Interpretation
46
- - Avoid Unix syntax: `|| true` fails on Windows
47
- - Use platform-specific error handling:
48
- ```javascript
49
- if (process.platform === 'win32') {
50
- try {
51
- execSync(`git remote remove origin`, { stdio: 'pipe', shell: true });
52
- } catch (e) { /* ignore */ }
53
- } else {
54
- execSync(`git remote remove origin 2>/dev/null || true`, { stdio: 'pipe', shell: true });
55
- }
56
- ```
57
-
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
72
- - **NPX Compatible**: Works via npx without global installation
73
- - **Cross-Platform**: Windows (amd64/arm64), macOS (amd64/arm64), Linux (amd64/arm64)
74
-
75
- ## Isolation Architecture
76
-
77
- ### Workflow
78
- 1. Copy project to temporary directory (including .git)
79
- 2. Mount temporary directory as /workspace in container
80
- 3. Run commands in isolated environment
81
- 4. Clean up temporary directory on exit
82
- 5. Changes persist via git push to host repository
83
-
84
- ### Pattern
85
- ```javascript
86
- import { createIsolatedEnvironment, setupCleanupHandlers, buildContainerMounts } from './utils/isolation.js';
87
-
88
- const { tempProjectDir, cleanup } = createIsolatedEnvironment(projectDir);
89
- setupCleanupHandlers(cleanup);
90
- const mounts = buildContainerMounts(tempProjectDir, projectDir);
91
-
92
- execSync(`podman run --rm -it ${mounts.join(' ')} -w /workspace sandboxbox:latest ${cmd}`, {
93
- stdio: 'inherit',
94
- shell: process.platform === 'win32'
95
- });
96
-
97
- cleanup();
98
- ```
99
-
100
- ## Git Integration
101
-
102
- ### Git Identity Transfer
103
- Automatically transfers host git identity to sandbox after cloning:
104
- ```javascript
105
- const userName = execSync('git config --global user.name', { encoding: 'utf8' }).trim();
106
- const userEmail = execSync('git config --global user.email', { encoding: 'utf8' }).trim();
107
- const colorUi = execSync('git config --global color.ui', { encoding: 'utf8' }).trim();
108
-
109
- execSync(`git config user.name "${userName}"`, { cwd: workspaceDir });
110
- execSync(`git config user.email "${userEmail}"`, { cwd: workspaceDir });
111
- execSync(`git config color.ui "${colorUi}"`, { cwd: workspaceDir });
112
- ```
113
-
114
- Git identity and color config auto-inherit from ~/.gitconfig (user.name, user.email, color.ui). For sandbox-to-host workflows, host repo needs `receive.denyCurrentBranch=updateInstead` and clean working directory.
115
-
116
- ### Git Safe Directory Configuration
117
- ```javascript
118
- execSync(`git config --global --add safe.directory "${projectDir}"`);
119
- execSync(`git config --global --add safe.directory "${projectDir}/.git"`);
120
- ```
121
-
122
- ### Windows Path Normalization
123
- ```javascript
124
- const normalizedTempDir = tempProjectDir.replace(/\\/g, '/');
125
- ```
126
-
127
- ### Environment Variable Transfer
128
- Host bash session environment variables automatically carry through to sandboxes:
129
- ```javascript
130
- // Terminal
131
- TERM: process.env.TERM || 'xterm-256color',
132
- LS_COLORS: process.env.LS_COLORS,
133
-
134
- // Locale
135
- LANG: process.env.LANG,
136
- LC_ALL: process.env.LC_ALL,
137
-
138
- // User
139
- SHELL: process.env.SHELL,
140
- USER: process.env.USER,
141
- LOGNAME: process.env.LOGNAME,
142
-
143
- // Tools
144
- EDITOR: process.env.EDITOR,
145
- VISUAL: process.env.VISUAL,
146
- PAGER: process.env.PAGER,
147
- LESS: process.env.LESS,
148
- LESSOPEN: process.env.LESSOPEN,
149
- LESSCLOSE: process.env.LESSCLOSE,
150
-
151
- // Display
152
- DISPLAY: process.env.DISPLAY,
153
- WAYLAND_DISPLAY: process.env.WAYLAND_DISPLAY,
154
-
155
- // Authentication
156
- SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK,
157
- SSH_AGENT_PID: process.env.SSH_AGENT_PID,
158
- GPG_AGENT_INFO: process.env.GPG_AGENT_INFO
159
- ```
160
-
161
- ## Claude Code Integration
162
-
163
- ### Authentication
164
- Uses host HOME directory for Claude Code authentication. Workspace is isolated in sandbox but credentials remain on host.
165
-
166
- ### Tool Allow List
167
- Automatically configured with 25 allowed tools:
168
- - Core: Task, Bash, Glob, Grep, Read, Edit, Write, NotebookEdit, WebFetch, TodoWrite, WebSearch, BashOutput, KillShell, SlashCommand, ExitPlanMode
169
- - MCP: glootie (execute, ast_tool, caveat), playwright (navigate, snapshot, click, type, evaluate, close), vexify (search_code)
170
-
171
- ### Streaming Output
172
- Uses `--verbose -p --output-format stream-json` for real-time JSON streaming. Output parser extracts text content, tool usage, session info, and cost metrics from JSON stream.
173
-
174
- ### Playwright MCP Profile Transfer
175
- Automatically copies persistent MCP profiles from host to sandbox:
176
- ```javascript
177
- const playwrightCacheDir = platform() === 'darwin'
178
- ? join(homedir(), 'Library', 'Caches', 'ms-playwright')
179
- : platform() === 'win32'
180
- ? join(homedir(), 'AppData', 'Local', 'ms-playwright')
181
- : join(homedir(), '.cache', 'ms-playwright');
182
-
183
- // Copies mcp-chrome-profile, mcp-chromium-profile, mcp-firefox-profile, mcp-webkit-profile
184
- cpSync(hostProfile, join(sandboxDir, '.cache', 'ms-playwright', profileName), { recursive: true });
185
- ```
186
-
187
- Environment variable `XDG_CACHE_HOME` set to `${sandboxDir}/.cache` for Playwright profile access.
188
-
189
- ## Cleanup
190
-
191
- ### Container Cleanup
192
- - Random names: `sandboxbox-run-${Math.random().toString(36).substr(2, 9)}`
193
- - Force cleanup: `podman rm -f container-name`
194
- - Automatic cleanup handlers for SIGINT, SIGTERM
195
-
196
- ### File Cleanup
197
- - All temporary directories auto-cleanup on exit
198
- - Error handling for cleanup failures (ignore errors)
199
- - Signal handlers ensure cleanup on interrupts
200
- - the only git operations we want is setting up the project, there should be no explicit git operations to end or merge the project work in the sandbox, the agent must have a hook as part of the plugin in ../plugin (which must be up to date) that is set up correctly to make it call a curl statement that will instruct it to do a git merge intelligently at the end, only claude must be doing the git merge there should be no automation around that
@@ -1,95 +0,0 @@
1
- FROM node:20
2
-
3
- ARG TZ
4
- ENV TZ="$TZ"
5
-
6
- ARG CLAUDE_CODE_VERSION=latest
7
-
8
- # Install basic development tools and iptables/ipset
9
- RUN apt-get update && apt-get install -y --no-install-recommends \
10
- less \
11
- git \
12
- procps \
13
- sudo \
14
- fzf \
15
- zsh \
16
- man-db \
17
- unzip \
18
- gnupg2 \
19
- gh \
20
- iptables \
21
- ipset \
22
- iproute2 \
23
- dnsutils \
24
- aggregate \
25
- jq \
26
- nano \
27
- vim \
28
- && apt-get clean && rm -rf /var/lib/apt/lists/*
29
-
30
- # Ensure default node user has access to /usr/local/share
31
- RUN mkdir -p /usr/local/share/npm-global && \
32
- chown -R node:node /usr/local/share
33
-
34
- ARG USERNAME=node
35
-
36
- # Persist bash history.
37
- RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
38
- && mkdir -p /commandhistory \
39
- && touch /commandhistory/.bash_history \
40
- && chown -R $USERNAME /commandhistory
41
-
42
- # Set `DEVCONTAINER` environment variable to help with orientation
43
- ENV DEVCONTAINER=true
44
-
45
- # Create workspace and config directories and set permissions
46
- RUN mkdir -p /workspace /home/node/.claude && \
47
- chown -R node:node /workspace /home/node/.claude
48
-
49
- WORKDIR /workspace
50
-
51
- ARG GIT_DELTA_VERSION=0.18.2
52
- RUN ARCH=$(dpkg --print-architecture) && \
53
- wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
54
- sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
55
- rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
56
-
57
- # Set up non-root user
58
- USER node
59
-
60
- # Install global packages
61
- ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global
62
- ENV PATH=$PATH:/usr/local/share/npm-global/bin
63
-
64
- # Set the default shell to zsh rather than sh
65
- ENV SHELL=/bin/zsh
66
-
67
- # Set the default editor and visual
68
- ENV EDITOR=nano
69
- ENV VISUAL=nano
70
-
71
- # Default powerline10k theme
72
- ARG ZSH_IN_DOCKER_VERSION=1.2.0
73
- RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- \
74
- -p git \
75
- -p fzf \
76
- -a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \
77
- -a "source /usr/share/doc/fzf/examples/completion.zsh" \
78
- -a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
79
- -x
80
-
81
- # Install Claude
82
- RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
83
-
84
- # Install playwright deps (commented out due to build issues)
85
- # RUN npx --yes playwright install-deps
86
-
87
- RUN npm i -g @playwright/mcp
88
-
89
- # Copy and set up firewall script
90
- COPY init-firewall.sh /usr/local/bin/
91
- USER root
92
- RUN chmod +x /usr/local/bin/init-firewall.sh && \
93
- echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \
94
- chmod 0440 /etc/sudoers.d/node-firewall
95
- USER node