@kokorolx/ai-sandbox-wrapper 2.2.0 → 2.3.0-beta

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 (3) hide show
  1. package/README.md +94 -679
  2. package/bin/ai-run +166 -15
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,612 +1,136 @@
1
1
  # 🔒 AI Sandbox Wrapper
2
2
 
3
- **Isolate AI coding agents from your host system. Protect your data.**
3
+ **Run OpenCode and other AI coding agents in secure Docker containers.**
4
4
 
5
- AI coding tools like Claude, Gemini, and Aider have full access to your filesystem, environment variables, and terminal. This project sandboxes them in Docker containers with **strict security restrictions**.
5
+ Protect your SSH keys, API tokens, and system files while using AI tools that need filesystem access.
6
6
 
7
- **What this does:** Runs AI tools in secure containers that can only access specific project folders, protecting your SSH keys, API tokens, and other sensitive data.
7
+ *Last updated: February 6, 2026*
8
8
 
9
- **What you get:** Peace of mind using AI coding tools without risking your personal and system data.
9
+ ## New in v2.3.0-beta: Web Mode & Port Exposure
10
10
 
11
- *Last updated: Tuesday, February 3, 2026*
11
+ - **Web Auto-Detection**: `opencode web` automatically exposes port 4096 and injects `--hostname 0.0.0.0`
12
+ - **`--expose` Flag**: New way to expose ports (replaces deprecated `PORT` env var)
13
+ - **Port Conflict Detection**: Fails fast if port is already in use
12
14
 
13
- ## ✨ New in v2.2.0: Clipboard Fixes & Screenshot Detection
14
-
15
- The **v2.2.0 release** solves the "air-gap" problem for text copying and streamlines screenshot workflows.
16
-
17
- - ✅ **OSC 52 Clipboard Support**: Copy text from inside Linux containers directly to your macOS clipboard (works over SSH too!).
18
- - ✅ **Auto-Detect Screenshot Folder**: Automatically finds where your Mac saves screenshots and offers to whitelist it. No more permission errors when dragging images into AI tools.
19
- - ✅ **Seamless Drag & Drop**: Just drag screenshots into the terminal window.
20
-
21
- ## ✨ New in v2.1.0: Stability & Native Persistence
22
-
23
- The **v2.1.0 release** focuses on architectural stability and a more intuitive persistence model.
24
-
25
- - ✅ **Stable Node 22 LTS**: Switched to a robust Node 22 base image for maximum compatibility and performance.
26
- - ✅ **Direct Mount Persistence**: Changes made *inside* the container (logins, settings, sessions) now save directly to your host's native folders.
27
- - ✅ **Cache Isolation**: Heavy caches (`node_modules`, `.npm`, `.cache`) are isolated using anonymous volumes to prevent "cache poisoning" and runtime conflicts.
28
-
29
- ### Native Config Mapping
30
- Your tool configurations are now directly linked from your Mac/PC:
31
- - Host: `~/.config/opencode` ↔ Container: `/home/agent/.config/opencode`
32
- - Host: `~/.local/share/opencode` ↔ Container: `/home/agent/.local/share/opencode`
33
-
34
- ---
35
-
36
- ## ⚠️ Breaking Change: v2.0.0 - Config Directory Reorganization
37
-
38
- **Version 2.0.0** reorganized the directory structure to a tool-centric layout and introduced a unified `config.json`.
39
-
40
- ## 🛡️ Why Use This?
41
-
42
- Without sandbox:
43
- - AI agents can read your SSH keys, API tokens, browser data
44
- - Can execute arbitrary code with your user permissions
45
- - Can access files outside your project
46
-
47
- With AI Sandbox:
48
- - ✅ AI only sees whitelisted workspace folders
49
- - ✅ No access to host environment variables (API keys hidden)
50
- - ✅ Read-only filesystem (except workspace)
51
- - ✅ No network access to host services
52
- - ✅ Runs as non-root user in container
53
- - ✅ CAP_DROP=ALL (no elevated privileges)
54
-
55
- ## 🚀 Step-by-Step Installation
56
-
57
- ### Step 1: Prerequisites
58
- Ensure you have Docker installed and running:
59
- - **macOS:** [Install Docker Desktop](https://www.docker.com/products/docker-desktop) and start it
60
- - **Linux:** Install Docker Engine with `curl -fsSL https://get.docker.com | sh`
61
- - **Windows:** Use WSL2 with Docker Desktop
62
-
63
- Verify Docker is working:
64
15
  ```bash
65
- docker --version
66
- docker ps # Should not show errors
67
- ```
68
-
69
- ### Step 2: Run Setup
16
+ # Web mode - automatic port exposure
17
+ opencode web
70
18
 
71
- **Option A: Using npx (Recommended)**
72
- ```bash
73
- npx @kokorolx/ai-sandbox-wrapper setup
74
- ```
19
+ # Custom port
20
+ opencode web --port 8080
75
21
 
76
- **Option B: Clone and run manually**
77
- ```bash
78
- git clone https://github.com/kokorolx/ai-sandbox-wrapper.git
79
- cd ai-sandbox-wrapper
80
- ./setup.sh
22
+ # Expose additional ports
23
+ opencode --expose 3000,5555 web
81
24
  ```
82
25
 
83
- **Fresh build (no Docker cache):**
84
- ```bash
85
- npx @kokorolx/ai-sandbox-wrapper setup --no-cache
86
- # or
87
- ./setup.sh --no-cache
88
- ```
26
+ ## 🛡️ Why Use This?
89
27
 
90
- ### Step 3: Follow the Interactive Prompts
91
- 1. **Whitelist workspaces (Optional)** - Enter directories AI tools can access, or just hit **Enter** to whitelist on-demand later.
92
- 2. **Select tools** - Use arrow keys to move, space to select, Enter to confirm
93
- 3. **Choose image source** - Select registry (faster) or build locally
28
+ | Without Sandbox | With AI Sandbox |
29
+ |-----------------|-----------------|
30
+ | AI reads SSH keys, API tokens | Only whitelisted folders visible |
31
+ | Full filesystem access | Read-only except workspace |
32
+ | Host environment exposed | ✅ API keys passed explicitly |
33
+ | Runs with your permissions | ✅ Non-root, CAP_DROP=ALL |
94
34
 
95
- ### Step 4: Complete Setup
96
- ```bash
97
- # Reload your shell to update PATH
98
- source ~/.zshrc
35
+ ## 🚀 Quick Start
99
36
 
100
- # Add your API keys (only if using tools that require them)
101
- nano ~/.ai-sandbox/env # Add ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.
102
- ```
37
+ **Prerequisites:** Docker Desktop (macOS/Windows) or Docker Engine (Linux)
103
38
 
104
- ### Step 5: Run Your First Tool
105
39
  ```bash
106
- # Navigate to a project directory that's in your whitelisted workspaces
107
- cd ~/projects/my-project
108
-
109
- # Run a tool (the example below assumes you selected Claude during setup)
110
- claude --version # or: ai-run claude --version
111
- ```
112
-
113
- ## 📋 What You Need
114
-
115
- **Required:**
116
- - **Docker** - Docker Desktop (macOS/Windows) or Docker Engine (Linux)
117
- - **Git** - For cloning the repository
118
- - **Bash** - For running the setup script
119
-
120
- **Optional (for specific tools):**
121
- - **Python 3** - For tools like Aider
122
- - **SSH keys** - For Git access in containers
123
-
124
- ## ✅ After Installation
40
+ # Install
41
+ npx @kokorolx/ai-sandbox-wrapper setup
125
42
 
126
- ### Verify Everything Works
127
- ```bash
128
- # Reload your shell to get the new commands
43
+ # Reload shell
129
44
  source ~/.zshrc
130
45
 
131
- # Check if the main command works
132
- ai-run --help
133
-
134
- # Test a tool you installed (replace 'claude' with your chosen tool)
135
- claude --version
136
- ```
137
-
138
- ### Add More Projects Later (Optional)
139
- If you want to give AI access to more project directories later:
140
- ```bash
141
- # Add a new workspace
142
- echo '/path/to/new/project' >> ~/.ai-sandbox/workspaces
143
-
144
- # View current allowed directories
145
- cat ~/.ai-sandbox/workspaces
146
- ```
147
-
148
- ### Configure API Keys (If Needed)
149
- Some tools require API keys to work properly:
150
- ```bash
151
- nano ~/.ai-sandbox/env
152
- ```
153
- Then add your keys in the format: `KEY_NAME=your_actual_key_here`
154
- Examples:
155
- - `ANTHROPIC_API_KEY=your_key_here` (for Claude)
156
- - `OPENAI_API_KEY=your_key_here` (for OpenAI tools)
157
-
158
- ## 🐳 Using Pre-Built Images
159
-
160
- **Skip the build process!** Pull pre-built images directly from GitLab Container Registry:
161
-
162
- ```bash
163
- # Pull a specific tool image
164
- docker pull registry.gitlab.com/kokorolee/ai-sandbox-wrapper/ai-claude:latest
165
- docker pull registry.gitlab.com/kokorolee/ai-sandbox-wrapper/ai-gemini:latest
166
- docker pull registry.gitlab.com/kokorolee/ai-sandbox-wrapper/ai-aider:latest
167
-
168
- # Or let setup.sh pull them automatically
169
- ./setup.sh # Select tools, images will be pulled if available
170
- ```
171
-
172
- **Available pre-built images:**
173
- - `ai-base:latest` - Base image with Node.js 22 LTS runtime
174
- - `ai-amp:latest` - Sourcegraph Amp
175
- - `ai-claude:latest` - Claude Code CLI
176
- - `ai-droid:latest` - Factory CLI
177
- - `ai-gemini:latest` - Google Gemini CLI
178
- - `ai-kilo:latest` - Kilo Code (500+ models)
179
- - `ai-codex:latest` - OpenAI Codex
180
- - `ai-aider:latest` - AI pair programmer
181
- - `ai-opencode:latest` - Open-source AI coding
182
- - `ai-qwen:latest` - Alibaba Qwen (1M context)
183
- - `ai-qoder:latest` - Qoder AI assistant
184
- - `ai-auggie:latest` - Augment Auggie
185
- - `ai-codebuddy:latest` - Tencent CodeBuddy
186
- - `ai-jules:latest` - Google Jules
187
- - `ai-shai:latest` - OVHcloud SHAI
188
-
189
- **Benefits:**
190
- - ⚡ **Faster setup** - No build time (seconds vs minutes)
191
- - ✅ **CI-tested** - All images verified in GitLab CI
192
- - 🔄 **Auto-updated** - Latest versions on every push to beta branch
193
-
194
- ## 📦 Supported Tools
195
-
196
- ### CLI Tools (Terminal-based)
197
-
198
- | Tool | Status | Install Type | Description |
199
- |------|--------|--------------|-------------|
200
- | **claude** | ✅ | Native binary | Anthropic Claude Code |
201
- | **opencode** | ✅ | Native Go | Open-source AI coding |
202
- | **gemini** | ✅ | npm/Node | Google Gemini CLI (free tier) |
203
- | **aider** | ✅ | Python | AI pair programmer (Git-native) |
204
- | **kilo** | ✅ | npm/Node | Kilo Code (500+ models) |
205
- | **codex** | ✅ | npm/Node | OpenAI Codex agent |
206
- | **amp** | ✅ | npm/Node | Sourcegraph Amp |
207
- | **qwen** | ✅ | npm/Node | Alibaba Qwen CLI (1M context) |
208
- | **droid** | ✅ | Custom | Factory CLI |
209
-
210
- > **Note:** GUI tools (VSCode, codeserver) have been removed in v2.0.1. Use your native IDE with AI tools running in the sandbox.
211
-
212
- ## ⚠️ Known Issues
213
-
214
- ### Native Tool Config Compatibility
215
-
216
- In v2.1.0+, tool configurations are **directly bind-mounted** from your host. This ensures 100% compatibility with your native tool settings and authentications.
217
-
218
- 1. **Host Config**: `~/.config/<tool>/` or `~/.<tool>/`
219
- 2. **Container Mount**: `/home/agent/.config/<tool>` (Automatic)
220
-
221
- **Currently Supported for Direct Mount:**
222
- - ✅ `claude`
223
- - ✅ `opencode`
224
- - ✅ `amp`
225
- - ✅ `gemini`
226
- - ✅ `aider`
227
- - ... and all other supported tools.
228
-
229
- Please [open an issue](https://github.com/kokorolx/ai-sandbox-wrapper/issues) if you encounter problems with specific tools.
230
-
231
- ## 🖥️ Platform Support
232
-
233
- | Platform | Status |
234
- |----------|--------|
235
- | macOS (Intel) | ✅ |
236
- | macOS (Apple Silicon) | ✅ |
237
- | Linux (x64) | ✅ |
238
- | Linux (ARM64) | ✅ |
239
- | Windows (Docker Desktop + WSL2) | ✅ |
240
-
241
- ## 📁 Directory Structure
242
-
243
- AI Sandbox Wrapper creates and manages a single consolidated directory in your home folder:
244
-
245
- | Directory | Purpose | Contents |
246
- |-----------|---------|----------|
247
- | `~/bin/` | Executables | `ai-run` wrapper and symlinks to tool scripts |
248
- | `~/.ai-sandbox/` | All config | Consolidated configuration directory (see structure below) |
249
- | `~/.ai-images/` | Local images | Locally built Docker images (if not using registry) |
250
-
251
- ### Sandbox Structure
252
-
253
- ```
254
- ~/.ai-sandbox/
255
- ├── config.json # Unified config (workspaces, git, networks)
256
- ├── tools/ # Isolated sandbox environments
257
- │ └── <tool>/
258
- │ └── home/ # Sandbox home directory (excludes native configs)
259
- ├── shared/ # Shared assets
260
- │ └── git/ # Shared git config and keys
261
- └── env # API keys (format: KEY=value)
46
+ # Run OpenCode
47
+ opencode
262
48
  ```
263
49
 
264
- **Note:** Tools also bind-mount your **native** `~/.config/<tool>` directories for persistence.
265
-
266
- ### Key Files
267
-
268
- | File | Purpose |
269
- |------|---------|
270
- | `~/.ai-sandbox/config.json` | Unified config (workspaces, git access, networks) |
271
- | `~/.ai-sandbox/env` | API keys (format: `KEY=value`, one per line) |
272
- | `~/.ai-sandbox/workspaces` | Legacy workspace file (fallback) |
273
- | `~/.ai-sandbox/git-allowed` | Legacy git-allowed file (fallback) |
50
+ During setup: select **opencode**, choose registry images (faster), whitelist your project directories.
274
51
 
275
52
  ## ⚙️ Configuration
276
53
 
277
- ### Tool-Specific Configuration
278
-
279
- Each tool has its own persistent home directory inside `~/.ai-sandbox/tools/<tool>/home/`.
280
-
281
- ```bash
282
- # View configuration paths for a specific tool (Recommended)
283
- npx @kokorolx/ai-sandbox-wrapper config tool claude
284
-
285
- # View configuration content
286
- npx @kokorolx/ai-sandbox-wrapper config tool claude --show
287
- ```
288
-
289
54
  ### API Keys
290
55
  ```bash
291
- # Edit environment file
292
56
  nano ~/.ai-sandbox/env
293
57
  ```
294
-
295
- ### Workspace Management
296
- ```bash
297
- # CLI commands (recommended)
298
- npx @kokorolx/ai-sandbox-wrapper workspace list
299
- npx @kokorolx/ai-sandbox-wrapper workspace add ~/projects/my-new-app
300
- npx @kokorolx/ai-sandbox-wrapper workspace remove ~/old-project
301
-
302
- # Interactive menu
303
- npx @kokorolx/ai-sandbox-wrapper update
304
-
305
- # Legacy (still works)
306
- echo '/path/to/project' >> ~/.ai-sandbox/workspaces
307
- cat ~/.ai-sandbox/workspaces
308
- ```
309
-
310
- ### Git Access Management
311
- ```bash
312
- # CLI commands
313
- npx @kokorolx/ai-sandbox-wrapper git status
314
- npx @kokorolx/ai-sandbox-wrapper git enable ~/projects/myrepo
315
- npx @kokorolx/ai-sandbox-wrapper git disable ~/projects/myrepo
316
-
317
- # Interactive menu
318
- npx @kokorolx/ai-sandbox-wrapper update
319
- ```
320
-
321
- ### Network Configuration
322
-
323
- AI containers can join Docker networks to communicate with other services (databases, APIs, MetaMCP).
324
-
325
- #### Runtime Selection (Recommended)
326
-
327
- ```bash
328
- # Interactive network selection
329
- ai-run opencode -n
330
-
331
- # Direct network specification
332
- ai-run opencode -n metamcp_metamcp-network
333
- ai-run opencode -n network1,network2,network3
334
- ```
335
-
336
- #### Saved Configuration
337
-
338
- Network selections are saved to `~/.ai-sandbox/config.json`:
339
- - **Per-workspace**: Saved for specific project directories
340
- - **Global**: Default for all workspaces
341
-
342
- ```bash
343
- # CLI commands
344
- npx @kokorolx/ai-sandbox-wrapper network list
345
- npx @kokorolx/ai-sandbox-wrapper network add mynetwork --global
346
- npx @kokorolx/ai-sandbox-wrapper network add dev-network --workspace ~/projects/myapp
347
- npx @kokorolx/ai-sandbox-wrapper network remove mynetwork --global
348
-
349
- # View current config
350
- npx @kokorolx/ai-sandbox-wrapper config show
351
- npx @kokorolx/ai-sandbox-wrapper config show --json
352
-
353
- # Example config.json structure (v2)
354
- {
355
- "version": 2,
356
- "workspaces": ["/Users/you/projects/my-app"],
357
- "git": {
358
- "allowedWorkspaces": ["/Users/you/projects/my-repo"],
359
- "keySelections": {}
360
- },
361
- "networks": {
362
- "global": ["shared-services"],
363
- "workspaces": {
364
- "/Users/you/projects/my-app": ["my-app_default", "redis_network"]
365
- }
366
- }
367
- }
368
58
  ```
369
-
370
- #### Without `-n` Flag
371
-
372
- When running without the flag, saved networks are used silently:
373
- - Workspace-specific config takes priority
374
- - Falls back to global config
375
- - Non-existent networks are skipped silently
376
-
377
- ### Environment Variables
378
-
379
- All environment variables are configured in `~/.ai-sandbox/env` or passed at runtime:
380
-
381
- #### Image Source
382
- Choose between locally built images or pre-built GitLab registry images:
383
-
384
- ```bash
385
- # Add to ~/.ai-sandbox/env
386
-
387
- # Use locally built images (default)
388
- AI_IMAGE_SOURCE=local
389
-
390
- # Use pre-built images from GitLab registry
391
- AI_IMAGE_SOURCE=registry
59
+ ANTHROPIC_API_KEY=sk-ant-...
60
+ OPENAI_API_KEY=sk-...
392
61
  ```
393
62
 
394
- Or run with environment variable:
63
+ ### Workspaces
395
64
  ```bash
396
- AI_IMAGE_SOURCE=registry ai-run claude
65
+ npx @kokorolx/ai-sandbox-wrapper workspace add ~/projects/my-app
66
+ # Or: echo '/path/to/project' >> ~/.ai-sandbox/workspaces
397
67
  ```
398
68
 
399
- #### Platform Selection
400
- For ARM64 Macs or other platforms, specify the container platform:
69
+ ### Port Exposure
401
70
 
402
71
  ```bash
403
- # Run with specific platform (linux/arm64, linux/amd64)
404
- AI_RUN_PLATFORM=linux/arm64 ai-run claude
405
- ```
406
-
407
- #### Docker Connection
408
- For remote Docker hosts or non-default configurations:
72
+ # New --expose flag (recommended)
73
+ opencode --expose 3000
74
+ opencode -e 3000,5555,5556
409
75
 
410
- ```bash
411
- # Use a different Docker socket
412
- export DOCKER_HOST=unix:///var/run/docker.sock
76
+ # Expose to network
77
+ PORT_BIND=all opencode --expose 3000
413
78
 
414
- # Or TCP connection
415
- export DOCKER_HOST=tcp://localhost:2375
79
+ # Legacy (deprecated)
80
+ PORT=3000 opencode
416
81
  ```
417
82
 
418
- #### Port Exposure
419
- Expose container ports to the host for web development, APIs, and dev servers:
420
-
83
+ **Web Mode Auto-Detection:**
421
84
  ```bash
422
- # Expose a single port (localhost only - secure default)
423
- PORT=3000 ai-run opencode
424
-
425
- # Expose multiple ports
426
- PORT=3000,5555,5556,5557 ai-run opencode
427
-
428
- # Expose to network (use with caution)
429
- PORT=3000 PORT_BIND=all ai-run opencode
85
+ opencode web # Auto-exposes 4096
86
+ opencode web --port 8080 # Auto-exposes 8080
87
+ opencode --expose 3000 web # Exposes both 3000 and 4096
430
88
  ```
431
89
 
432
- | Variable | Values | Default | Description |
433
- |----------|--------|---------|-------------|
434
- | `PORT` | Comma-separated ports | (none) | Ports to expose (e.g., `3000,5555`) |
435
- | `PORT_BIND` | `localhost`, `all` | `localhost` | Bind to localhost only or all interfaces |
436
-
437
- **Security Notes:**
438
- - Default binding is `127.0.0.1` (localhost only) - only accessible from your machine
439
- - Using `PORT_BIND=all` exposes ports to your network - a warning is displayed
440
- - Invalid port numbers (outside 1-65535) are skipped with a warning
441
-
442
- **Example: Rails Development**
443
- ```bash
444
- # Start container with Rails default port exposed
445
- PORT=3000 ai-run opencode --shell
446
-
447
- # Inside container, start Rails server
448
- rails server -b 0.0.0.0
449
-
450
- # Access from host browser at http://localhost:3000
90
+ Output:
451
91
  ```
452
-
453
- #### API Keys
454
- Configure in `~/.ai-sandbox/env`:
455
-
456
- ```bash
457
- # Required for Claude tools
458
- ANTHROPIC_API_KEY=sk-ant-api03-...
459
-
460
- # Required for OpenAI-based tools
461
- OPENAI_API_KEY=sk-...
462
-
463
- # Optional for Gemini CLI
464
- GOOGLE_API_KEY=AIza...
465
-
466
- # Optional: disable specific keys
467
- # ANTHROPIC_API_KEY=
468
- # OPENAI_API_KEY=
469
-
470
- ### Per-Project Config
471
-
472
- Each tool supports project-specific config files that override global settings. These files are located in your workspace and are accessible to the tool:
473
-
474
- | Tool | Project Config | Native Global Config |
475
- |------|----------------|----------------------|
476
- | Claude | `.claude.json` | `~/.config/claude/` |
477
- | Gemini | `.gemini.json` | `~/.config/gemini/` |
478
- | Aider | `.aider.conf` | `~/.config/aider/` |
479
- | Opencode | `.opencode.json` | `~/.config/opencode/` |
480
- | Amp | `.amp.json` | `~/.config/amp/` |
481
-
482
- **Persistence:** Since v2.1.0, changes to global settings *inside* the container are automatically saved back to your **Native Global Config** on the host.
483
-
484
- **Priority:** Project config > Native Global config > Container defaults
485
-
486
- ```bash
487
- # Example: Project-specific Claude config
488
- cat > .claude.json << 'EOF'
489
- {
490
- "model": "sonnet-4-20250514",
491
- "max_output_tokens": 8192,
492
- "temperature": 0.7
493
- }
494
- EOF
92
+ 🌐 Detected web command. Auto-exposing port 4096.
93
+ 🔌 Port mappings: 4096
94
+ 🌐 Web UI available at http://localhost:4096
495
95
  ```
496
96
 
497
- ### Tool-Specific Config Locations
498
-
499
- All tool configs are consolidated under `~/.ai-sandbox/home/{tool}/`:
500
-
97
+ **Port Conflict Detection:**
501
98
  ```
502
- ~/.ai-sandbox/home/{tool}/
503
- ├── .config/ # Tool configuration
504
- │ └── {tool}/ # Per-tool config directory
505
- ├── .local/share/ # Tool data (cache, sessions)
506
- ├── .cache/ # Runtime cache
507
- └── .claude/ # Claude-specific (for claude tool)
99
+ ❌ ERROR: Port 3000 is already in use by node (PID: 12345)
508
100
  ```
509
101
 
510
- Each tool's config is mounted to `/home/agent/` inside the container.
511
-
512
- ### Additional Tools (Container-Only)
513
-
514
- During setup, you can optionally install additional tools into the base Docker image. Tools are organized into two categories:
515
-
516
- #### AI Enhancement Tools
517
-
518
- | Tool | Description | Size Impact |
519
- |------|-------------|-------------|
520
- | spec-kit | Spec-driven development toolkit | ~50MB |
521
- | ux-ui-promax | UI/UX design intelligence tool | ~30MB |
522
- | openspec | OpenSpec - spec-driven development | ~20MB |
523
- | playwright | Browser automation with Chromium/Firefox/WebKit | ~500MB |
524
-
525
- **Playwright** is useful when AI tools need to:
526
- - Run browser-based tests
527
- - Scrape web content
528
- - Verify UI changes
529
- - Automate browser workflows
530
-
531
- #### Language Runtimes
532
-
533
- | Runtime | Description | Size Impact |
534
- |---------|-------------|-------------|
535
- | ruby | Ruby 3.3.0 + Rails 8.0.2 (via rbenv) | ~500MB |
536
-
537
- **Ruby/Rails** is useful when:
538
- - Developing Ruby on Rails applications
539
- - Running Rails generators and migrations
540
- - Using Bundler for dependency management
541
- - Building Ruby-based APIs and web apps
542
-
543
- #### Always Installed
544
-
545
- - `typescript` + `typescript-language-server` - Required for AI coding assistants with LSP integration
546
-
547
- #### Manual Installation
102
+ ### Network Access
548
103
 
549
104
  ```bash
550
- # Manual build with Playwright (if not selected during setup)
551
- INSTALL_PLAYWRIGHT=1 bash lib/install-base.sh
552
-
553
- # Manual build with Ruby/Rails (if not selected during setup)
554
- INSTALL_RUBY=1 bash lib/install-base.sh
555
-
556
- # Verify Playwright in container
557
- docker run --rm ai-base:latest npx playwright --version
558
-
559
- # Verify Ruby/Rails in container
560
- docker run --rm ai-base:latest ruby --version
561
- docker run --rm ai-base:latest rails --version
562
-
563
- # Verify TypeScript LSP
564
- docker run --rm ai-base:latest tsc --version
105
+ # Join Docker networks (for databases, APIs, MetaMCP)
106
+ opencode -n mynetwork
107
+ opencode -n network1,network2
565
108
  ```
566
109
 
567
- ### Git Workflow
568
- AI tools work **inside** containers without Git credentials by default (secure).
569
-
570
- **Option 1: Secure (Default) - Review & Commit from Host**
571
- ```bash
572
- # 1. AI tool makes changes
573
- ai-run claude # Edits files in your workspace
574
-
575
- # 2. Review changes on host
576
- git diff
577
-
578
- # 3. Commit from host (you have full control)
579
- git add .
580
- git commit -m "feat: changes suggested by AI"
581
- git push
582
- ```
110
+ ### Git Access
583
111
 
584
- **Option 2: Enable Git Access (Interactive Prompt)**
585
- When you run an AI tool, you'll be prompted:
112
+ Git credentials are **not** shared by default. When you run a tool, you'll be prompted:
586
113
  ```
587
114
  🔐 Git Access Control
588
- Allow AI tool to access Git credentials for this workspace?
589
-
590
- 1) Yes, allow once (this session only)
591
- 2) Yes, always allow for this workspace
115
+ 1) Yes, allow once
116
+ 2) Yes, always allow for this workspace
592
117
  3) No, keep Git disabled (secure default)
593
118
  ```
594
119
 
595
- **Managing Git access:**
596
- ```bash
597
- # View allowed workspaces
598
- cat ~/.ai-sandbox/git-allowed
120
+ ## 📁 Directory Structure
599
121
 
600
- # Remove a workspace from allowed list
601
- nano ~/.ai-sandbox/git-allowed # Delete the line
122
+ ```
123
+ ~/.ai-sandbox/
124
+ ├── config.json # Workspaces, git, networks
125
+ ├── env # API keys
126
+ ├── tools/ # Per-tool sandbox homes
127
+ │ └── opencode/home/
128
+ └── shared/git/ # Shared git credentials
602
129
  ```
603
130
 
604
- **Why this is secure:**
605
- - Opt-in per workspace (not global)
606
- - Granular control: Only selected keys and their matching Host configs are shared
607
- - ✅ SSH keys mounted read-only
608
- - ✅ You control which projects get Git access
609
- - ✅ Easy to revoke access anytime
131
+ Native configs are bind-mounted:
132
+ - `~/.config/opencode` `/home/agent/.config/opencode`
133
+ - `~/.local/share/opencode` `/home/agent/.local/share/opencode`
610
134
 
611
135
  ## 🔐 Security Model
612
136
 
@@ -623,159 +147,50 @@ nano ~/.ai-sandbox/git-allowed # Delete the line
623
147
  ┌─────────────────────────────────────────────────┐
624
148
  │ AI SANDBOX CONTAINER │
625
149
  │ ✅ /workspace (whitelisted folders only) │
626
- │ ✅ Passed API keys (explicit, for API calls)
627
- │ ✅ Git config (for commits)
150
+ │ ✅ Passed API keys (explicit)
151
+ │ ✅ Git config (opt-in per workspace)
628
152
  │ ❌ Everything else │
629
153
  └─────────────────────────────────────────────────┘
630
154
  ```
631
155
 
632
- ## ❓ Troubleshooting
633
-
634
- ### Common Issues
635
-
636
- **Docker not found**
637
- - Make sure Docker Desktop is installed and running
638
- - Check with: `docker --version` and `docker ps`
639
-
640
- **"command not found: ai-run"**
641
- - Reload your shell: `source ~/.zshrc`
642
- - Verify setup completed: check if `~/bin/ai-run` exists
643
-
644
- **"Workspaces not configured"** (Legacy)
645
- - Note: This error is resolved in v2.1.0+.
646
- - Run setup again: `./setup.sh` or simply run an AI tool in your project folder to trigger interactive whitelisting.
647
-
648
- **"BunInstallFailedError"** (Resolved in v2.1.0)
649
- - This was caused by stale caches. We now use **Cache Isolation** via anonymous volumes. If you still see this, run `./setup.sh --no-cache` to force a clean build.
650
-
651
- **Tool doesn't start**
652
- - Check if you selected the tool during setup
653
- - Look for the Docker image: `docker images | grep ai-`
654
-
655
- **"Outside whitelisted workspace" error**
656
- - Add your current directory: `echo "$(pwd)" >> ~/.ai-sandbox/workspaces`
657
- - Or navigate to a directory you whitelisted during setup
658
-
659
- **API key errors**
660
- - Check your keys in: `cat ~/.ai-sandbox/env`
661
- - Make sure keys are in format: `KEY_NAME=actual_key_value`
662
-
663
- ### Getting Help
664
-
665
- If you're still having issues:
666
- 1. Check that Docker is running
667
- 2. Re-run `./setup.sh` to reinstall
668
- 3. Look at the configuration files in `~/.ai-sandbox/`:
669
- - `~/.ai-sandbox/workspaces` - should contain your project directories
670
- - `~/.ai-sandbox/env` - should contain your API keys (if needed)
671
- 4. View Docker images: `docker images` to see if tools built successfully
672
-
673
156
  ## 📚 Quick Reference
674
157
 
675
- ### Main Commands
676
- - `ai-run <tool>` - Run any tool in sandbox (e.g., `ai-run claude`)
677
- - `ai-run <tool> --shell` - Start interactive shell mode (see [Shell Mode Guide](SHELL-MODE-USAGE.md))
678
- - `<tool>` - Shortcut for tools you installed (e.g., `claude`, `aider`)
679
-
680
- ### Execution Modes
681
-
682
- **Direct Mode (Default):**
683
- ```bash
684
- ai-run opencode
685
- # Tool runs directly, exits on Ctrl+C
686
- ```
687
-
688
- **Shell Mode (Interactive):**
689
- ```bash
690
- ai-run opencode --shell # or -s
691
- # Starts bash shell, run tool manually
692
- # Ctrl+C stops tool only, not container
693
- # Perfect for development and debugging
694
- ```
695
-
696
- See [SHELL-MODE-USAGE.md](SHELL-MODE-USAGE.md) for detailed examples and use cases.
697
-
698
- ### Configuration Files
699
- - `~/.ai-sandbox/env` - Store API keys here
700
- - `~/.ai-sandbox/workspaces` - Whitelisted project directories
701
- - `~/.ai-sandbox/cache/` - Tool cache (persistent)
702
- - `~/.ai-sandbox/home/` - Tool configurations (persistent)
703
-
704
- ### Common Tasks
705
158
  ```bash
706
- # Add a new project directory to AI access
707
- echo '/path/to/my/new/project' >> ~/.ai-sandbox/workspaces
708
-
709
- # Check what tools are installed
710
- ls ~/bin/
711
-
712
- # Reload shell after setup
713
- source ~/.zshrc
714
-
715
- # Update to latest version
716
- npx @kokorolx/ai-sandbox-wrapper@latest setup
717
-
718
- # Clean up caches and configs
719
- npx @kokorolx/ai-sandbox-wrapper clean
720
- ```
159
+ # Run OpenCode
160
+ opencode # Direct mode
161
+ opencode --shell # Interactive shell
162
+ opencode web # Web UI mode
721
163
 
722
- ### Cleanup Command
164
+ # Port exposure
165
+ opencode --expose 3000 # Expose port
166
+ opencode -e 3000,4000 # Multiple ports
723
167
 
724
- The `clean` command provides an interactive way to remove AI Sandbox directories:
168
+ # Network
169
+ opencode -n mynetwork # Join Docker network
725
170
 
726
- ```bash
171
+ # Management
172
+ npx @kokorolx/ai-sandbox-wrapper workspace list
727
173
  npx @kokorolx/ai-sandbox-wrapper clean
728
174
  ```
729
175
 
730
- **Features:**
731
- - Two-level menu: First select category, then specific tools/items
732
- - Shows directory sizes before deletion
733
- - Groups items by risk level (🟢 Safe, 🟡 Medium, 🔴 Critical)
734
- - Requires typing "yes" to confirm deletion
735
-
736
- **Categories:**
737
- | Category | Contents | Risk |
738
- |----------|----------|------|
739
- | Tool caches | `~/.ai-sandbox/cache/{tool}/` | 🟢 Safe to delete |
740
- | Tool configs | `~/.ai-sandbox/home/{tool}/` | 🟡 Loses settings |
741
- | Global config | `~/.ai-sandbox/workspaces`, `~/.ai-sandbox/env`, etc. | 🟡🔴 Mixed |
742
- | Everything | `~/.ai-sandbox/` | 🔴 Full reset |
743
-
744
- **Example:**
745
- ```
746
- 🧹 AI Sandbox Cleanup
747
-
748
- What would you like to clean?
749
- 1. Tool caches (~/.ai-sandbox/cache/) - Safe to delete
750
- 2. Tool configs (~/.ai-sandbox/home/) - Loses settings
751
- 3. Global config files - Loses preferences
752
- 4. Everything (~/.ai-sandbox/) - Full reset
753
-
754
- Enter selection (or 'q' to quit): 1
755
-
756
- 📁 Tool Caches (~/.ai-sandbox/cache/)
757
-
758
- Select tools to clear:
759
- 1. claude/ (45.2 MB)
760
- 2. opencode/ (120.5 MB)
761
-
762
- Enter selection (comma-separated, 'all', or 'b' to go back): 1
763
-
764
- You are about to delete:
765
- - ~/.ai-sandbox/cache/claude/ (45.2 MB)
176
+ ## ❓ Troubleshooting
766
177
 
767
- Total: 45.2 MB
178
+ | Issue | Solution |
179
+ |-------|----------|
180
+ | `command not found: opencode` | Run `source ~/.zshrc` |
181
+ | `Outside whitelisted workspace` | `echo "$(pwd)" >> ~/.ai-sandbox/workspaces` |
182
+ | Port already in use | Stop the process or use different port |
183
+ | Docker not found | Install and start Docker Desktop |
768
184
 
769
- Type 'yes' to confirm: yes
185
+ ## 📦 Other Tools
770
186
 
771
- Deleted ~/.ai-sandbox/cache/claude/
187
+ This sandbox also supports **Claude, Gemini, Aider, Kilo, Codex, Amp, Qwen**, and more.
772
188
 
773
- Deleted 1 items, freed 45.2 MB
774
- ```
189
+ See [TOOLS.md](TOOLS.md) for the full list and tool-specific configuration.
775
190
 
776
191
  ## 🤝 Contributing
777
192
 
778
- See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
193
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
779
194
 
780
195
  ## 📝 License
781
196
 
package/bin/ai-run CHANGED
@@ -8,6 +8,7 @@ shift
8
8
  SHELL_MODE=false
9
9
  NETWORK_FLAG=false
10
10
  NETWORK_ARG=""
11
+ EXPOSE_ARG=""
11
12
  TOOL_ARGS=()
12
13
 
13
14
  while [[ $# -gt 0 ]]; do
@@ -25,6 +26,13 @@ while [[ $# -gt 0 ]]; do
25
26
  shift
26
27
  fi
27
28
  ;;
29
+ --expose|-e)
30
+ shift
31
+ if [[ $# -gt 0 && ! "$1" =~ ^- ]]; then
32
+ EXPOSE_ARG="$1"
33
+ shift
34
+ fi
35
+ ;;
28
36
  *)
29
37
  TOOL_ARGS+=("$1")
30
38
  shift
@@ -118,7 +126,7 @@ migrate_to_v2() {
118
126
  [[ -d "$SANDBOX_DIR/cache" ]] && needs_migration=true
119
127
  [[ -d "$SANDBOX_DIR/git-keys" ]] && needs_migration=true
120
128
 
121
- [[ "$needs_migration" == "false" ]] && { touch "$V2_MARKER"; return 0; }
129
+ [[ "$needs_migration" == "false" ]] && { mkdir -p "$SANDBOX_DIR" && touch "$V2_MARKER"; return 0; }
122
130
 
123
131
  echo "🔄 Migrating to v2 folder structure..."
124
132
  mkdir -p "$SANDBOX_DIR/tools" "$SANDBOX_DIR/shared/git"
@@ -1213,31 +1221,172 @@ if [[ -n "$TTY_FLAGS" ]]; then
1213
1221
  CONTAINER_NAME="--name $(generate_container_name)"
1214
1222
  fi
1215
1223
 
1216
- # Port exposure configuration
1217
- PORT_MAPPINGS=""
1218
- if [[ -n "${PORT:-}" ]]; then
1219
- PORT_BIND="${PORT_BIND:-localhost}"
1220
- BIND_ADDR="127.0.0.1"
1224
+ # ============================================================================
1225
+ # WEB COMMAND DETECTION AND PORT EXPOSURE
1226
+ # ============================================================================
1221
1227
 
1222
- if [[ "$PORT_BIND" == "all" ]]; then
1223
- BIND_ADDR="0.0.0.0"
1224
- echo "⚠️ WARNING: Ports will be accessible from network (PORT_BIND=all)"
1228
+ # Detect if running opencode web command
1229
+ detect_opencode_web() {
1230
+ [[ "$TOOL" == "opencode" ]] || return 1
1231
+ for arg in "${TOOL_ARGS[@]}"; do
1232
+ [[ "$arg" == "web" ]] && return 0
1233
+ done
1234
+ return 1
1235
+ }
1236
+
1237
+ # Parse --port value from TOOL_ARGS (supports --port N and --port=N)
1238
+ parse_port_from_args() {
1239
+ local i=0
1240
+ while [[ $i -lt ${#TOOL_ARGS[@]} ]]; do
1241
+ local arg="${TOOL_ARGS[$i]}"
1242
+ if [[ "$arg" == "--port" ]]; then
1243
+ ((i++))
1244
+ if [[ $i -lt ${#TOOL_ARGS[@]} ]]; then
1245
+ echo "${TOOL_ARGS[$i]}"
1246
+ return 0
1247
+ fi
1248
+ elif [[ "$arg" =~ ^--port=(.+)$ ]]; then
1249
+ echo "${BASH_REMATCH[1]}"
1250
+ return 0
1251
+ fi
1252
+ ((i++))
1253
+ done
1254
+ return 1
1255
+ }
1256
+
1257
+ # Check if --hostname is already in TOOL_ARGS
1258
+ has_hostname_arg() {
1259
+ for arg in "${TOOL_ARGS[@]}"; do
1260
+ [[ "$arg" == "--hostname" || "$arg" =~ ^--hostname= ]] && return 0
1261
+ done
1262
+ return 1
1263
+ }
1264
+
1265
+ # Check if port is in use (lsof with netstat fallback)
1266
+ check_port_in_use() {
1267
+ local port="$1"
1268
+ if command -v lsof &>/dev/null; then
1269
+ lsof -i ":$port" &>/dev/null && return 0
1270
+ elif command -v netstat &>/dev/null; then
1271
+ netstat -tuln 2>/dev/null | grep -q ":$port " && return 0
1272
+ else
1273
+ return 2
1274
+ fi
1275
+
1276
+ docker ps --format "{{.Ports}}" 2>/dev/null | grep -q ":$port->" && return 0
1277
+ return 1
1278
+ }
1279
+
1280
+ # Get process info for port
1281
+ get_port_process_info() {
1282
+ local port="$1"
1283
+ if command -v lsof &>/dev/null; then
1284
+ lsof -i ":$port" -sTCP:LISTEN 2>/dev/null | awk 'NR==2 {print $1 " (PID: " $2 ")"}'
1285
+ elif command -v netstat &>/dev/null; then
1286
+ echo "unknown process"
1287
+ else
1288
+ echo "unknown"
1225
1289
  fi
1290
+ }
1226
1291
 
1292
+ # Initialize port list (bash 3.x compatible - no associative arrays)
1293
+ EXPOSE_PORTS_LIST=""
1294
+ WEB_PORT=""
1295
+
1296
+ # Helper: add port to list if not already present
1297
+ add_port_to_list() {
1298
+ local port="$1"
1299
+ local source="$2"
1300
+ if [[ ! " $EXPOSE_PORTS_LIST " =~ " $port " ]]; then
1301
+ EXPOSE_PORTS_LIST="$EXPOSE_PORTS_LIST $port"
1302
+ if [[ "${AI_RUN_DEBUG:-}" == "1" ]]; then
1303
+ echo "🔧 Debug: Added port $port from $source"
1304
+ fi
1305
+ fi
1306
+ }
1307
+
1308
+ # Parse --expose flag
1309
+ if [[ -n "$EXPOSE_ARG" ]]; then
1310
+ IFS=',' read -ra EXPOSE_PORTS <<< "$EXPOSE_ARG"
1311
+ for port in "${EXPOSE_PORTS[@]}"; do
1312
+ port=$(echo "$port" | tr -d ' ')
1313
+ if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then
1314
+ add_port_to_list "$port" "--expose"
1315
+ else
1316
+ echo "⚠️ WARNING: Invalid port number in --expose: $port (skipped)"
1317
+ fi
1318
+ done
1319
+ fi
1320
+
1321
+ # Web command detection and auto-exposure
1322
+ WEB_DETECTED=false
1323
+ if detect_opencode_web; then
1324
+ WEB_DETECTED=true
1325
+ WEB_PORT=$(parse_port_from_args)
1326
+ if [[ -z "$WEB_PORT" ]]; then
1327
+ WEB_PORT=4096
1328
+ fi
1329
+
1330
+ add_port_to_list "$WEB_PORT" "auto-detected"
1331
+ echo "🌐 Detected web command. Auto-exposing port $WEB_PORT."
1332
+
1333
+ if ! has_hostname_arg; then
1334
+ TOOL_ARGS+=("--hostname" "0.0.0.0")
1335
+ fi
1336
+ fi
1337
+
1338
+ # Handle legacy PORT environment variable
1339
+ if [[ -n "${PORT:-}" ]]; then
1340
+ echo "⚠️ WARNING: PORT environment variable is deprecated. Use --expose flag instead."
1227
1341
  IFS=',' read -ra PORTS <<< "$PORT"
1228
1342
  for port in "${PORTS[@]}"; do
1229
- # Trim whitespace
1230
1343
  port=$(echo "$port" | tr -d ' ')
1231
- # Validate port number (1-65535)
1232
1344
  if [[ "$port" =~ ^[0-9]+$ ]] && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then
1233
- PORT_MAPPINGS="$PORT_MAPPINGS -p $BIND_ADDR:$port:$port"
1345
+ add_port_to_list "$port" "PORT env"
1234
1346
  else
1235
- echo "⚠️ WARNING: Invalid port number: $port (skipped)"
1347
+ echo "⚠️ WARNING: Invalid port number in PORT: $port (skipped)"
1348
+ fi
1349
+ done
1350
+ fi
1351
+
1352
+ # Trim leading space from port list
1353
+ EXPOSE_PORTS_LIST=$(echo "$EXPOSE_PORTS_LIST" | sed 's/^ //')
1354
+
1355
+ # Port conflict detection
1356
+ PORT_CHECK_AVAILABLE=true
1357
+ if ! command -v lsof &>/dev/null && ! command -v netstat &>/dev/null; then
1358
+ echo "⚠️ WARNING: Cannot check port availability (lsof/netstat not found)"
1359
+ PORT_CHECK_AVAILABLE=false
1360
+ fi
1361
+
1362
+ if [[ "$PORT_CHECK_AVAILABLE" == "true" && -n "$EXPOSE_PORTS_LIST" ]]; then
1363
+ for port in $EXPOSE_PORTS_LIST; do
1364
+ if check_port_in_use "$port"; then
1365
+ PROCESS_INFO=$(get_port_process_info "$port")
1366
+ echo "❌ ERROR: Port $port is already in use by $PROCESS_INFO"
1367
+ exit 1
1236
1368
  fi
1237
1369
  done
1370
+ fi
1371
+
1372
+ # Build PORT_MAPPINGS from EXPOSE_PORTS_LIST
1373
+ if [[ -n "$EXPOSE_PORTS_LIST" ]]; then
1374
+ PORT_BIND="${PORT_BIND:-localhost}"
1375
+ BIND_ADDR="127.0.0.1"
1376
+
1377
+ if [[ "$PORT_BIND" == "all" ]]; then
1378
+ BIND_ADDR="0.0.0.0"
1379
+ echo "⚠️ WARNING: Ports will be accessible from network (PORT_BIND=all)"
1380
+ fi
1381
+
1382
+ for port in $EXPOSE_PORTS_LIST; do
1383
+ PORT_MAPPINGS="$PORT_MAPPINGS -p $BIND_ADDR:$port:$port"
1384
+ done
1238
1385
 
1239
- if [[ -n "$PORT_MAPPINGS" ]]; then
1240
- echo "🔌 Port mappings: ${PORT//,/ }"
1386
+ echo "🔌 Port mappings: $EXPOSE_PORTS_LIST"
1387
+
1388
+ if [[ "$WEB_DETECTED" == "true" ]]; then
1389
+ echo "🌐 Web UI available at http://localhost:$WEB_PORT"
1241
1390
  fi
1242
1391
  fi
1243
1392
 
@@ -1251,6 +1400,8 @@ if [[ "${AI_RUN_DEBUG:-}" == "1" ]]; then
1251
1400
  echo "🔧 Debug: PORT='${PORT:-}'"
1252
1401
  echo "🔧 Debug: PORT_BIND='${PORT_BIND:-localhost}'"
1253
1402
  echo "🔧 Debug: PORT_MAPPINGS='$PORT_MAPPINGS'"
1403
+ echo "🔧 Debug: WEB_DETECTED='$WEB_DETECTED'"
1404
+ echo "🔧 Debug: EXPOSE_PORTS_LIST='$EXPOSE_PORTS_LIST'"
1254
1405
  fi
1255
1406
 
1256
1407
  # Prepare command based on mode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kokorolx/ai-sandbox-wrapper",
3
- "version": "2.2.0",
3
+ "version": "2.3.0-beta",
4
4
  "description": "Docker-based security sandbox for AI coding agents. Isolate Claude, Gemini, Aider, and other AI tools from your host system.",
5
5
  "keywords": [
6
6
  "ai",