@kokorolx/ai-sandbox-wrapper 2.4.0 → 2.6.0

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/README.md CHANGED
@@ -4,9 +4,36 @@
4
4
 
5
5
  Protect your SSH keys, API tokens, and system files while using AI tools that need filesystem access.
6
6
 
7
- *Last updated: February 6, 2026*
7
+ *Last updated: February 9, 2026*
8
8
 
9
- ## ✨ New in v2.3.0-beta: Web Mode & Port Exposure
9
+ ---
10
+
11
+ ## 📑 Table of Contents
12
+
13
+ - [What's New](#-whats-new)
14
+ - [Why Use This?](#ī¸-why-use-this)
15
+ - [Quick Start](#-quick-start)
16
+ - [Configuration](#ī¸-configuration)
17
+ - [API Keys](#api-keys)
18
+ - [Workspaces](#workspaces)
19
+ - [Port Exposure](#port-exposure)
20
+ - [Server Authentication](#server-authentication)
21
+ - [Network Access](#network-access)
22
+ - [Git Access](#git-access)
23
+ - [Clipboard](#clipboard)
24
+ - [Directory Structure](#-directory-structure)
25
+ - [Security Model](#-security-model)
26
+ - [Quick Reference](#-quick-reference)
27
+ - [Troubleshooting](#-troubleshooting)
28
+ - [Other Tools](#-other-tools)
29
+ - [Contributing](#-contributing)
30
+ - [License](#-license)
31
+
32
+ ---
33
+
34
+ ## ✨ What's New
35
+
36
+ ### v2.3.0-beta: Web Mode & Port Exposure
10
37
 
11
38
  - **Web Auto-Detection**: `opencode web` automatically exposes port 4096 and injects `--hostname 0.0.0.0`
12
39
  - **`--expose` Flag**: New way to expose ports (replaces deprecated `PORT` env var)
@@ -23,6 +50,8 @@ opencode web --port 8080
23
50
  opencode --expose 3000,5555 web
24
51
  ```
25
52
 
53
+ ---
54
+
26
55
  ## đŸ›Ąī¸ Why Use This?
27
56
 
28
57
  | Without Sandbox | With AI Sandbox |
@@ -32,6 +61,8 @@ opencode --expose 3000,5555 web
32
61
  | Host environment exposed | ✅ API keys passed explicitly |
33
62
  | Runs with your permissions | ✅ Non-root, CAP_DROP=ALL |
34
63
 
64
+ ---
65
+
35
66
  ## 🚀 Quick Start
36
67
 
37
68
  **Prerequisites:** Docker Desktop (macOS/Windows) or Docker Engine (Linux)
@@ -49,9 +80,12 @@ opencode
49
80
 
50
81
  During setup: select **opencode**, choose registry images (faster), whitelist your project directories.
51
82
 
83
+ ---
84
+
52
85
  ## âš™ī¸ Configuration
53
86
 
54
87
  ### API Keys
88
+
55
89
  ```bash
56
90
  nano ~/.ai-sandbox/env
57
91
  ```
@@ -61,6 +95,7 @@ OPENAI_API_KEY=sk-...
61
95
  ```
62
96
 
63
97
  ### Workspaces
98
+
64
99
  ```bash
65
100
  npx @kokorolx/ai-sandbox-wrapper workspace add ~/projects/my-app
66
101
  # Or: echo '/path/to/project' >> ~/.ai-sandbox/workspaces
@@ -94,7 +129,7 @@ Output:
94
129
  🌐 Web UI available at http://localhost:4096
95
130
  ```
96
131
 
97
- ### Server Authentication (OpenCode web/serve)
132
+ ### Server Authentication
98
133
 
99
134
  Control authentication for OpenCode web server:
100
135
 
@@ -141,6 +176,65 @@ Git credentials are **not** shared by default. When you run a tool, you'll be pr
141
176
  3) No, keep Git disabled (secure default)
142
177
  ```
143
178
 
179
+ ### Clipboard
180
+
181
+ Clipboard access in containers requires a terminal that supports **OSC52** protocol.
182
+
183
+ **Supported terminals:** iTerm2, Warp, Kitty, Alacritty, WezTerm, Windows Terminal, Ghostty
184
+
185
+ **Not supported:** GNOME Terminal, VS Code Terminal, Tilix, Terminator
186
+
187
+ Test if your terminal supports clipboard:
188
+ ```bash
189
+ printf "\033]52;c;$(printf "test" | base64)\a"
190
+ # Press Cmd+V / Ctrl+V - if you see "test", it works
191
+ ```
192
+
193
+ 📖 **Full details:** [CLIPBOARD_SUPPORT.md](CLIPBOARD_SUPPORT.md)
194
+
195
+ ### MCP Tools (Browser Automation)
196
+
197
+ During setup, you can optionally install MCP servers for AI agent browser automation:
198
+
199
+ | Tool | Maintainer | Features | Size |
200
+ |------|------------|----------|------|
201
+ | **Chrome DevTools MCP** | Google | Performance profiling, Core Web Vitals, detailed console/network inspection | ~400MB |
202
+ | **Playwright MCP** | Microsoft | Multi-browser (Chromium), TypeScript code generation, vision mode | ~300MB |
203
+
204
+ After installation, configure your MCP client (e.g., OpenCode) to use them:
205
+
206
+ **`~/.config/opencode/opencode.json`:**
207
+ ```json
208
+ {
209
+ "mcp": {
210
+ "chrome-devtools": {
211
+ "type": "local",
212
+ "command": [
213
+ "chrome-devtools-mcp",
214
+ "--headless",
215
+ "--isolated",
216
+ "--executablePath", "/opt/chromium",
217
+ "--chromeArg=--no-sandbox",
218
+ "--chromeArg=--disable-setuid-sandbox"
219
+ ]
220
+ },
221
+ "playwright": {
222
+ "type": "local",
223
+ "command": [
224
+ "npx", "@playwright/mcp@latest",
225
+ "--headless",
226
+ "--browser", "chromium",
227
+ "--no-sandbox"
228
+ ]
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ > **Note:** The `--no-sandbox` flags are required when running in Docker containers. This is safe because the container itself provides isolation.
235
+
236
+ ---
237
+
144
238
  ## 📁 Directory Structure
145
239
 
146
240
  ```
@@ -156,6 +250,8 @@ Native configs are bind-mounted:
156
250
  - `~/.config/opencode` ↔ `/home/agent/.config/opencode`
157
251
  - `~/.local/share/opencode` ↔ `/home/agent/.local/share/opencode`
158
252
 
253
+ ---
254
+
159
255
  ## 🔐 Security Model
160
256
 
161
257
  ```
@@ -177,6 +273,8 @@ Native configs are bind-mounted:
177
273
  └─────────────────────────────────────────────────┘
178
274
  ```
179
275
 
276
+ ---
277
+
180
278
  ## 📚 Quick Reference
181
279
 
182
280
  ```bash
@@ -197,6 +295,8 @@ npx @kokorolx/ai-sandbox-wrapper workspace list
197
295
  npx @kokorolx/ai-sandbox-wrapper clean
198
296
  ```
199
297
 
298
+ ---
299
+
200
300
  ## ❓ Troubleshooting
201
301
 
202
302
  | Issue | Solution |
@@ -205,6 +305,9 @@ npx @kokorolx/ai-sandbox-wrapper clean
205
305
  | `Outside whitelisted workspace` | `echo "$(pwd)" >> ~/.ai-sandbox/workspaces` |
206
306
  | Port already in use | Stop the process or use different port |
207
307
  | Docker not found | Install and start Docker Desktop |
308
+ | Clipboard not working | Use OSC52-compatible terminal. See [CLIPBOARD_SUPPORT.md](CLIPBOARD_SUPPORT.md) |
309
+
310
+ ---
208
311
 
209
312
  ## đŸ“Ļ Other Tools
210
313
 
@@ -212,10 +315,14 @@ This sandbox also supports **Claude, Gemini, Aider, Kilo, Codex, Amp, Qwen**, an
212
315
 
213
316
  See [TOOLS.md](TOOLS.md) for the full list and tool-specific configuration.
214
317
 
318
+ ---
319
+
215
320
  ## 🤝 Contributing
216
321
 
217
322
  See [CONTRIBUTING.md](CONTRIBUTING.md).
218
323
 
324
+ ---
325
+
219
326
  ## 📝 License
220
327
 
221
328
  MIT
package/bin/ai-run CHANGED
@@ -16,6 +16,7 @@ Options:
16
16
  --password-env <VAR> Read OpenCode server password from environment variable
17
17
  --allow-unsecured Allow OpenCode server to run without password (suppresses warning)
18
18
  -h, --help Show this help message
19
+ --help-env Show environment variables reference
19
20
 
20
21
  OpenCode Server Authentication (web/serve mode only):
21
22
  When running 'opencode web' or 'opencode serve', you can control authentication:
@@ -44,11 +45,85 @@ EOF
44
45
  exit 0
45
46
  }
46
47
 
48
+ show_help_env() {
49
+ cat << 'EOF'
50
+ Environment Variables Reference
51
+ ===============================
52
+
53
+ Runtime Environment Variables (inline with ai-run):
54
+ ---------------------------------------------------
55
+ AI_IMAGE_SOURCE=registry Use pre-built images from GitLab registry instead of local
56
+ Example: AI_IMAGE_SOURCE=registry ai-run opencode
57
+
58
+ AI_RUN_DEBUG=1 Enable debug output (shows Docker command details)
59
+ Example: AI_RUN_DEBUG=1 ai-run opencode
60
+
61
+ AI_RUN_PLATFORM=linux/amd64 Force specific platform (useful for cross-arch)
62
+ Example: AI_RUN_PLATFORM=linux/amd64 ai-run opencode
63
+
64
+ PORT_BIND=all Bind exposed ports to all interfaces (0.0.0.0) instead of localhost
65
+ âš ī¸ Security risk - use only when needed
66
+ Example: PORT_BIND=all ai-run opencode web -e 4096
67
+
68
+ PORT=3000,4000 (Deprecated) Expose ports - use --expose flag instead
69
+ Example: PORT=3000 ai-run opencode
70
+
71
+ Build Environment Variables (inline with setup.sh or install scripts):
72
+ ----------------------------------------------------------------------
73
+ DOCKER_NO_CACHE=1 Force rebuild without Docker cache
74
+ Example: DOCKER_NO_CACHE=1 bash setup.sh
75
+
76
+ OPENCODE_VERSION=1.1.52 Install specific OpenCode version instead of latest
77
+ Example: OPENCODE_VERSION=1.1.52 bash lib/install-opencode.sh
78
+
79
+ INSTALL_CHROME_DEVTOOLS_MCP=1 Install Chrome DevTools MCP in base image
80
+ INSTALL_PLAYWRIGHT_MCP=1 Install Playwright MCP in base image
81
+ INSTALL_PLAYWRIGHT=1 Install Playwright browser automation
82
+ INSTALL_RUBY=1 Install Ruby 3.3.0 + Rails 8.0.2
83
+ INSTALL_SPEC_KIT=1 Install spec-kit (specify CLI)
84
+ INSTALL_UX_UI_PROMAX=1 Install uipro CLI
85
+ INSTALL_OPENSPEC=1 Install OpenSpec CLI
86
+
87
+ Container Environment Variables (passed to container via ~/.ai-sandbox/env):
88
+ -----------------------------------------------------------------------------
89
+ ANTHROPIC_API_KEY Anthropic API key for Claude
90
+ OPENAI_API_KEY OpenAI API key
91
+ OPENCODE_SERVER_PASSWORD Password for OpenCode web server
92
+ OPENCODE_SERVER_USERNAME Username for OpenCode web server (default: opencode)
93
+ GITHUB_TOKEN GitHub token for gh CLI authentication
94
+ GH_TOKEN Alternative GitHub token variable
95
+
96
+ Configuration Files:
97
+ --------------------
98
+ ~/.ai-sandbox/config.json Main configuration (workspaces, git, networks, MCP)
99
+ ~/.ai-sandbox/env API keys and secrets (KEY=value format)
100
+ ~/.ai-sandbox/workspaces Legacy workspace list (one path per line)
101
+
102
+ Examples:
103
+ # Debug mode with registry images
104
+ AI_RUN_DEBUG=1 AI_IMAGE_SOURCE=registry ai-run opencode
105
+
106
+ # Rebuild everything from scratch
107
+ DOCKER_NO_CACHE=1 bash setup.sh --no-cache
108
+
109
+ # Install specific OpenCode version
110
+ OPENCODE_VERSION=1.1.52 bash lib/install-opencode.sh
111
+
112
+ # Expose port to network (not just localhost)
113
+ PORT_BIND=all ai-run opencode web -e 4096
114
+ EOF
115
+ exit 0
116
+ }
117
+
47
118
  # Check for help flag before anything else
48
119
  if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
49
120
  show_help
50
121
  fi
51
122
 
123
+ if [[ "${1:-}" == "--help-env" ]]; then
124
+ show_help_env
125
+ fi
126
+
52
127
  TOOL="$1"
53
128
  shift 2>/dev/null || { echo "❌ ERROR: No tool specified. Use 'ai-run --help' for usage."; exit 1; }
54
129
 
@@ -1398,6 +1473,273 @@ if is_opencode_web_mode; then
1398
1473
  resolve_opencode_password
1399
1474
  fi
1400
1475
 
1476
+ # ============================================================================
1477
+ # MCP AUTO-CONFIGURATION FOR OPENCODE
1478
+ # ============================================================================
1479
+
1480
+ # Check if MCP tool is installed (from config.json, set during setup.sh)
1481
+ is_mcp_installed() {
1482
+ local mcp_tool="$1"
1483
+ if has_jq && [[ -f "$AI_SANDBOX_CONFIG" ]]; then
1484
+ jq -e --arg tool "$mcp_tool" '.mcp.installed | index($tool) != null' "$AI_SANDBOX_CONFIG" &>/dev/null
1485
+ else
1486
+ return 1
1487
+ fi
1488
+ }
1489
+
1490
+ # Check if MCP is already configured in OpenCode config
1491
+ is_mcp_configured() {
1492
+ local mcp_name="$1"
1493
+ local config_file="$HOME/.config/opencode/opencode.json"
1494
+
1495
+ if [[ ! -f "$config_file" ]]; then
1496
+ return 1
1497
+ fi
1498
+
1499
+ if has_jq; then
1500
+ jq -e --arg name "$mcp_name" '.mcp[$name] // empty' "$config_file" &>/dev/null
1501
+ else
1502
+ grep -q "\"$mcp_name\"" "$config_file" 2>/dev/null
1503
+ fi
1504
+ }
1505
+
1506
+ # Add MCP configuration to OpenCode config
1507
+ add_mcp_config() {
1508
+ local mcp_name="$1"
1509
+ local mcp_command="$2"
1510
+ local force="${3:-false}"
1511
+ local config_file="$HOME/.config/opencode/opencode.json"
1512
+
1513
+ # Check if already configured and warn user
1514
+ if [[ "$force" != "true" ]] && is_mcp_configured "$mcp_name"; then
1515
+ echo ""
1516
+ echo " âš ī¸ WARNING: '$mcp_name' is already configured!"
1517
+ echo " Reconfiguring will overwrite your existing settings."
1518
+ echo " Any custom credentials or options will be lost."
1519
+ read -p " Are you sure you want to overwrite? [y/N]: " overwrite_choice
1520
+ if [[ ! "$overwrite_choice" =~ ^[Yy]$ ]]; then
1521
+ echo " â­ī¸ Kept existing configuration"
1522
+ return 1
1523
+ fi
1524
+ fi
1525
+
1526
+ mkdir -p "$(dirname "$config_file")"
1527
+
1528
+ if [[ ! -f "$config_file" ]]; then
1529
+ # Create new config with MCP
1530
+ echo "{\"mcp\": {\"$mcp_name\": {\"type\": \"local\", \"command\": $mcp_command}}}" > "$config_file"
1531
+ elif has_jq; then
1532
+ # Add MCP to existing config
1533
+ jq --arg name "$mcp_name" --argjson cmd "$mcp_command" \
1534
+ '.mcp = (.mcp // {}) | .mcp[$name] = {"type": "local", "command": $cmd}' \
1535
+ "$config_file" > "$config_file.tmp" && mv "$config_file.tmp" "$config_file"
1536
+ else
1537
+ echo "âš ī¸ jq not found. Please manually add MCP configuration to $config_file"
1538
+ return 1
1539
+ fi
1540
+ chmod 600 "$config_file"
1541
+ }
1542
+
1543
+ # Mark MCP as skipped for this workspace (don't ask again)
1544
+ mark_mcp_skipped() {
1545
+ local skip_file="$SANDBOX_DIR/.mcp-skip-$WORKSPACE_MD5"
1546
+ date -Iseconds > "$skip_file" 2>/dev/null || date > "$skip_file"
1547
+ }
1548
+
1549
+ # Check if MCP prompt was skipped for this workspace
1550
+ is_mcp_skipped() {
1551
+ local skip_file="$SANDBOX_DIR/.mcp-skip-$WORKSPACE_MD5"
1552
+ [[ -f "$skip_file" ]]
1553
+ }
1554
+
1555
+ # Configure MCP tools for OpenCode
1556
+ configure_opencode_mcp() {
1557
+ # Only run for opencode tool in interactive mode
1558
+ [[ "$TOOL" != "opencode" ]] && return 0
1559
+ [[ ! -t 0 ]] && return 0
1560
+
1561
+ local config_file="$HOME/.config/opencode/opencode.json"
1562
+
1563
+ # Generate workspace hash for skip tracking
1564
+ WORKSPACE_MD5=$(echo "$CURRENT_DIR" | md5sum | cut -c1-8)
1565
+
1566
+ # Check if already skipped for this workspace
1567
+ if is_mcp_skipped; then
1568
+ return 0
1569
+ fi
1570
+
1571
+ # Detect installed MCP tools (from config.json, set during setup.sh)
1572
+ local chrome_installed=false
1573
+ local playwright_installed=false
1574
+ local chrome_configured=false
1575
+ local playwright_configured=false
1576
+
1577
+ if is_mcp_installed "chrome-devtools"; then
1578
+ chrome_installed=true
1579
+ is_mcp_configured "chrome-devtools" && chrome_configured=true
1580
+ fi
1581
+
1582
+ if is_mcp_installed "playwright"; then
1583
+ playwright_installed=true
1584
+ is_mcp_configured "playwright" && playwright_configured=true
1585
+ fi
1586
+
1587
+ # If no MCP tools installed in image, return
1588
+ if [[ "$chrome_installed" == "false" && "$playwright_installed" == "false" ]]; then
1589
+ return 0
1590
+ fi
1591
+
1592
+ # If all installed tools are already configured, return silently
1593
+ local all_configured=true
1594
+ [[ "$chrome_installed" == "true" && "$chrome_configured" == "false" ]] && all_configured=false
1595
+ [[ "$playwright_installed" == "true" && "$playwright_configured" == "false" ]] && all_configured=false
1596
+
1597
+ if [[ "$all_configured" == "true" ]]; then
1598
+ return 0
1599
+ fi
1600
+
1601
+ # Build lists of configured and unconfigured tools
1602
+ local unconfigured=()
1603
+ local configured=()
1604
+ [[ "$chrome_installed" == "true" && "$chrome_configured" == "false" ]] && unconfigured+=("chrome-devtools")
1605
+ [[ "$chrome_installed" == "true" && "$chrome_configured" == "true" ]] && configured+=("chrome-devtools")
1606
+ [[ "$playwright_installed" == "true" && "$playwright_configured" == "false" ]] && unconfigured+=("playwright")
1607
+ [[ "$playwright_installed" == "true" && "$playwright_configured" == "true" ]] && configured+=("playwright")
1608
+
1609
+ # Show prompt
1610
+ echo ""
1611
+ echo "🔌 MCP Tools Detected"
1612
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1613
+
1614
+ # Show already configured tools
1615
+ if [[ ${#configured[@]} -gt 0 ]]; then
1616
+ echo "Already configured:"
1617
+ for tool in "${configured[@]}"; do
1618
+ case "$tool" in
1619
+ chrome-devtools)
1620
+ echo " ✓ Chrome DevTools MCP"
1621
+ ;;
1622
+ playwright)
1623
+ echo " ✓ Playwright MCP"
1624
+ ;;
1625
+ esac
1626
+ done
1627
+ echo ""
1628
+ fi
1629
+
1630
+ # Show unconfigured tools
1631
+ if [[ ${#unconfigured[@]} -gt 0 ]]; then
1632
+ echo "Not yet configured:"
1633
+ for tool in "${unconfigured[@]}"; do
1634
+ case "$tool" in
1635
+ chrome-devtools)
1636
+ echo " â€ĸ Chrome DevTools MCP - browser automation + performance profiling"
1637
+ ;;
1638
+ playwright)
1639
+ echo " â€ĸ Playwright MCP - multi-browser automation"
1640
+ ;;
1641
+ esac
1642
+ done
1643
+ echo ""
1644
+ fi
1645
+
1646
+ echo "Configure MCP tools in OpenCode?"
1647
+ echo " 1) Yes, configure all detected tools"
1648
+ echo " 2) Yes, let me choose which ones"
1649
+ echo " 3) No, skip (I'll configure manually)"
1650
+ echo " 4) No, don't ask again for this workspace"
1651
+ echo ""
1652
+ read -p "Choice [1-4]: " mcp_choice
1653
+
1654
+ local configured_any=false
1655
+
1656
+ case "$mcp_choice" in
1657
+ 1)
1658
+ # Configure all (both unconfigured and offer to reconfigure configured ones)
1659
+ local all_tools=()
1660
+ [[ "$chrome_installed" == "true" ]] && all_tools+=("chrome-devtools")
1661
+ [[ "$playwright_installed" == "true" ]] && all_tools+=("playwright")
1662
+
1663
+ for tool in "${all_tools[@]}"; do
1664
+ case "$tool" in
1665
+ chrome-devtools)
1666
+ if add_mcp_config "chrome-devtools" '["chrome-devtools-mcp", "--headless", "--isolated", "--executablePath", "/opt/chromium"]'; then
1667
+ echo " ✓ Configured Chrome DevTools MCP"
1668
+ configured_any=true
1669
+ fi
1670
+ ;;
1671
+ playwright)
1672
+ if add_mcp_config "playwright" '["npx", "@playwright/mcp@latest", "--headless", "--browser", "chromium"]'; then
1673
+ echo " ✓ Configured Playwright MCP"
1674
+ configured_any=true
1675
+ fi
1676
+ ;;
1677
+ esac
1678
+ done
1679
+ ;;
1680
+ 2)
1681
+ # Let user choose from all installed tools
1682
+ local all_tools=()
1683
+ [[ "$chrome_installed" == "true" ]] && all_tools+=("chrome-devtools")
1684
+ [[ "$playwright_installed" == "true" ]] && all_tools+=("playwright")
1685
+
1686
+ for tool in "${all_tools[@]}"; do
1687
+ local tool_desc=""
1688
+ local status_hint=""
1689
+ case "$tool" in
1690
+ chrome-devtools)
1691
+ tool_desc="Chrome DevTools MCP (browser automation + DevTools)"
1692
+ is_mcp_configured "chrome-devtools" && status_hint=" [already configured]"
1693
+ ;;
1694
+ playwright)
1695
+ tool_desc="Playwright MCP (multi-browser automation)"
1696
+ is_mcp_configured "playwright" && status_hint=" [already configured]"
1697
+ ;;
1698
+ esac
1699
+ read -p " Configure $tool_desc$status_hint? [y/N]: " tool_choice
1700
+ if [[ "$tool_choice" =~ ^[Yy]$ ]]; then
1701
+ case "$tool" in
1702
+ chrome-devtools)
1703
+ if add_mcp_config "chrome-devtools" '["chrome-devtools-mcp", "--headless", "--isolated", "--executablePath", "/opt/chromium"]'; then
1704
+ echo " ✓ Configured"
1705
+ configured_any=true
1706
+ fi
1707
+ ;;
1708
+ playwright)
1709
+ if add_mcp_config "playwright" '["npx", "@playwright/mcp@latest", "--headless", "--browser", "chromium"]'; then
1710
+ echo " ✓ Configured"
1711
+ configured_any=true
1712
+ fi
1713
+ ;;
1714
+ esac
1715
+ else
1716
+ echo " â­ī¸ Skipped"
1717
+ fi
1718
+ done
1719
+ ;;
1720
+ 4)
1721
+ mark_mcp_skipped
1722
+ echo "â„šī¸ Won't ask again for this workspace"
1723
+ ;;
1724
+ *)
1725
+ echo "â„šī¸ Skipped."
1726
+ ;;
1727
+ esac
1728
+
1729
+ # Show config file path for easy editing
1730
+ echo ""
1731
+ if [[ "$configured_any" == "true" ]]; then
1732
+ echo "✅ MCP configuration saved!"
1733
+ fi
1734
+ echo "📄 Config file: $config_file"
1735
+ echo " Edit this file to customize MCP settings or add credentials."
1736
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
1737
+ echo ""
1738
+ }
1739
+
1740
+ # Run MCP configuration check for opencode
1741
+ configure_opencode_mcp
1742
+
1401
1743
  # ============================================================================
1402
1744
  # WEB COMMAND DETECTION AND PORT EXPOSURE
1403
1745
  # ============================================================================
@@ -2,9 +2,9 @@ FROM node:22-bookworm-slim
2
2
 
3
3
  ARG AGENT_UID=1001
4
4
 
5
- # Install common dependencies
6
- # Note: python3-venv is needed for many tools, unzip for some installers
7
- RUN apt-get update && apt-get install -y --no-install-recommends git curl ssh ca-certificates jq python3 python3-pip python3-venv python3-dev python3-setuptools build-essential libopenblas-dev pipx unzip xclip wl-clipboard && curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && rm -rf /var/lib/apt/lists/* && pipx ensurepath
5
+ RUN apt-get update && apt-get install -y --no-install-recommends git curl ssh ca-certificates jq python3 python3-pip python3-venv python3-dev python3-setuptools build-essential libopenblas-dev pipx unzip xclip wl-clipboard ripgrep && curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh && rm -rf /var/lib/apt/lists/* && pipx ensurepath
6
+
7
+ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && apt-get update && apt-get install -y gh && rm -rf /var/lib/apt/lists/*
8
8
 
9
9
  # Install pnpm globally using npm (not bun, for stability)
10
10
  RUN npm install -g pnpm
@@ -34,14 +34,80 @@ RUN mkdir -p /usr/local/lib/openspec && \
34
34
  ln -sf /usr/local/lib/openspec/node_modules/.bin/openspec /usr/local/bin/openspec && \
35
35
  chmod -R 755 /usr/local/lib/openspec && \
36
36
  chmod +x /usr/local/bin/openspec
37
+ # Install Playwright system dependencies
38
+ RUN apt-get update && apt-get install -y --no-install-recommends \
39
+ libglib2.0-0 \
40
+ libnspr4 \
41
+ libnss3 \
42
+ libdbus-1-3 \
43
+ libatk1.0-0 \
44
+ libatk-bridge2.0-0 \
45
+ libcups2 \
46
+ libxcb1 \
47
+ libxkbcommon0 \
48
+ libatspi2.0-0 \
49
+ libx11-6 \
50
+ libxcomposite1 \
51
+ libxdamage1 \
52
+ libxext6 \
53
+ libxfixes3 \
54
+ libxrandr2 \
55
+ libgbm1 \
56
+ libcairo2 \
57
+ libpango-1.0-0 \
58
+ libasound2 \
59
+ && rm -rf /var/lib/apt/lists/*
60
+ # Install Playwright and browsers via npm
61
+ RUN npm install -g playwright && npx playwright install
62
+ RUN apt-get update && apt-get install -y --no-install-recommends \
63
+ libglib2.0-0 \
64
+ libnspr4 \
65
+ libnss3 \
66
+ libdbus-1-3 \
67
+ libatk1.0-0 \
68
+ libatk-bridge2.0-0 \
69
+ libcups2 \
70
+ libxcb1 \
71
+ libxkbcommon0 \
72
+ libatspi2.0-0 \
73
+ libx11-6 \
74
+ libxcomposite1 \
75
+ libxdamage1 \
76
+ libxext6 \
77
+ libxfixes3 \
78
+ libxrandr2 \
79
+ libgbm1 \
80
+ libdrm2 \
81
+ libcairo2 \
82
+ libpango-1.0-0 \
83
+ libasound2 \
84
+ fonts-liberation \
85
+ libappindicator3-1 \
86
+ libu2f-udev \
87
+ libvulkan1 \
88
+ libxshmfence1 \
89
+ xdg-utils \
90
+ wget \
91
+ && rm -rf /var/lib/apt/lists/*
92
+ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
93
+ RUN mkdir -p /opt/playwright-browsers && \
94
+ npm install -g @playwright/mcp@latest && \
95
+ npx playwright-core install --no-shell chromium && \
96
+ npx playwright-core install-deps chromium && \
97
+ chmod -R 777 /opt/playwright-browsers && \
98
+ ln -sf $(ls -d /opt/playwright-browsers/chromium-*/chrome-linux/chrome | head -1) /opt/chromium
99
+ ENV CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS=1
100
+ RUN npm install -g chrome-devtools-mcp@latest && \
101
+ touch /opt/.mcp-chrome-devtools-installed
102
+ RUN touch /opt/.mcp-playwright-installed
37
103
 
38
104
  # Create workspace
39
105
  WORKDIR /workspace
40
106
 
41
- # Non-root user for security
42
107
  # Non-root user for security (match host UID)
43
108
  RUN useradd -m -u ${AGENT_UID} -d /home/agent agent && \
44
109
  mkdir -p /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config && \
45
- chown -R agent:agent /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config /workspace
110
+ chown -R agent:agent /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config /workspace && \
111
+ ([ -d /opt/playwright-browsers ] && chown -R agent:agent /opt/playwright-browsers || true)
46
112
  USER agent
47
113
  ENV HOME=/home/agent
@@ -1,7 +1,6 @@
1
1
  FROM ai-base:latest
2
2
 
3
3
  USER root
4
- # Install OpenCode using official native installer
5
4
  RUN curl -fsSL https://opencode.ai/install | bash && \
6
5
  mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \
7
6
  rm -rf /home/agent/.opencode
@@ -104,13 +104,72 @@ RUN gem install rails -v 8.0.2 && gem install bundler && rbenv rehash
104
104
  '
105
105
  fi
106
106
 
107
+ # MCP Tools for AI agent browser automation
108
+ # Both tools share Playwright's Chromium (native ARM64/x86_64, avoids Puppeteer arch issues)
109
+ MCP_BROWSER_INSTALLED=false
110
+
111
+ if [[ "${INSTALL_CHROME_DEVTOOLS_MCP:-0}" -eq 1 ]] || [[ "${INSTALL_PLAYWRIGHT_MCP:-0}" -eq 1 ]]; then
112
+ MCP_BROWSER_INSTALLED=true
113
+ echo "đŸ“Ļ Installing shared Chromium browser for MCP tools"
114
+ ADDITIONAL_TOOLS_INSTALL+='RUN apt-get update && apt-get install -y --no-install-recommends \
115
+ libglib2.0-0 \
116
+ libnspr4 \
117
+ libnss3 \
118
+ libdbus-1-3 \
119
+ libatk1.0-0 \
120
+ libatk-bridge2.0-0 \
121
+ libcups2 \
122
+ libxcb1 \
123
+ libxkbcommon0 \
124
+ libatspi2.0-0 \
125
+ libx11-6 \
126
+ libxcomposite1 \
127
+ libxdamage1 \
128
+ libxext6 \
129
+ libxfixes3 \
130
+ libxrandr2 \
131
+ libgbm1 \
132
+ libdrm2 \
133
+ libcairo2 \
134
+ libpango-1.0-0 \
135
+ libasound2 \
136
+ fonts-liberation \
137
+ libappindicator3-1 \
138
+ libu2f-udev \
139
+ libvulkan1 \
140
+ libxshmfence1 \
141
+ xdg-utils \
142
+ wget \
143
+ && rm -rf /var/lib/apt/lists/*
144
+ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
145
+ RUN mkdir -p /opt/playwright-browsers && \
146
+ npm install -g @playwright/mcp@latest && \
147
+ npx playwright-core install --no-shell chromium && \
148
+ npx playwright-core install-deps chromium && \
149
+ chmod -R 777 /opt/playwright-browsers && \
150
+ ln -sf $(ls -d /opt/playwright-browsers/chromium-*/chrome-linux/chrome | head -1) /opt/chromium
151
+ '
152
+ fi
153
+
154
+ if [[ "${INSTALL_CHROME_DEVTOOLS_MCP:-0}" -eq 1 ]]; then
155
+ echo "đŸ“Ļ Chrome DevTools MCP will be installed in base image"
156
+ ADDITIONAL_TOOLS_INSTALL+='ENV CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS=1
157
+ RUN npm install -g chrome-devtools-mcp@latest && \
158
+ touch /opt/.mcp-chrome-devtools-installed
159
+ '
160
+ fi
161
+
162
+ if [[ "${INSTALL_PLAYWRIGHT_MCP:-0}" -eq 1 ]]; then
163
+ echo "đŸ“Ļ Playwright MCP will be installed in base image"
164
+ ADDITIONAL_TOOLS_INSTALL+='RUN touch /opt/.mcp-playwright-installed
165
+ '
166
+ fi
167
+
107
168
  cat > "dockerfiles/base/Dockerfile" <<EOF
108
169
  FROM node:22-bookworm-slim
109
170
 
110
171
  ARG AGENT_UID=1001
111
172
 
112
- # Install common dependencies
113
- # Note: python3-venv is needed for many tools, unzip for some installers
114
173
  RUN apt-get update && apt-get install -y --no-install-recommends \
115
174
  git \
116
175
  curl \
@@ -128,10 +187,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
128
187
  unzip \
129
188
  xclip \
130
189
  wl-clipboard \
190
+ ripgrep \
131
191
  && curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh \
132
192
  && rm -rf /var/lib/apt/lists/* \
133
193
  && pipx ensurepath
134
194
 
195
+ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
196
+ && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
197
+ && echo "deb [arch=\$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
198
+ && apt-get update \
199
+ && apt-get install -y gh \
200
+ && rm -rf /var/lib/apt/lists/*
201
+
135
202
  # Install pnpm globally using npm (not bun, for stability)
136
203
  RUN npm install -g pnpm
137
204
 
@@ -146,11 +213,11 @@ ${ADDITIONAL_TOOLS_INSTALL}
146
213
  # Create workspace
147
214
  WORKDIR /workspace
148
215
 
149
- # Non-root user for security
150
216
  # Non-root user for security (match host UID)
151
217
  RUN useradd -m -u \${AGENT_UID} -d /home/agent agent && \\
152
218
  mkdir -p /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config && \\
153
- chown -R agent:agent /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config /workspace
219
+ chown -R agent:agent /home/agent/.cache /home/agent/.npm /home/agent/.opencode /home/agent/.config /workspace && \\
220
+ ([ -d /opt/playwright-browsers ] && chown -R agent:agent /opt/playwright-browsers || true)
154
221
  USER agent
155
222
  ENV HOME=/home/agent
156
223
  EOF
@@ -1,22 +1,36 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # OpenCode installer: Open-source AI coding tool (Native Go Binary)
5
4
  TOOL="opencode"
5
+ OPENCODE_VERSION="${OPENCODE_VERSION:-}"
6
6
 
7
- echo "Installing $TOOL (OpenCode AI - Native Go Binary)..."
7
+ if [[ -n "$OPENCODE_VERSION" ]]; then
8
+ echo "Installing $TOOL v$OPENCODE_VERSION (OpenCode AI - Native Go Binary)..."
9
+ else
10
+ echo "Installing $TOOL (OpenCode AI - Native Go Binary, latest)..."
11
+ fi
8
12
 
9
- # Create directories
10
13
  mkdir -p "dockerfiles/$TOOL"
11
14
  mkdir -p "$HOME/.ai-sandbox/tools/$TOOL/home/.cache"
12
15
  mkdir -p "$HOME/.ai-sandbox/tools/$TOOL/home"
13
16
 
14
- # Create Dockerfile using official native installer (Go binary)
15
- cat <<'EOF' > "dockerfiles/$TOOL/Dockerfile"
17
+ if [[ -n "$OPENCODE_VERSION" ]]; then
18
+ cat > "dockerfiles/$TOOL/Dockerfile" <<EOF
19
+ FROM ai-base:latest
20
+
21
+ USER root
22
+ RUN curl -fsSL https://opencode.ai/install | bash -s -- --version $OPENCODE_VERSION && \\
23
+ mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \\
24
+ rm -rf /home/agent/.opencode
25
+
26
+ USER agent
27
+ ENTRYPOINT ["opencode"]
28
+ EOF
29
+ else
30
+ cat <<'EOF' > "dockerfiles/$TOOL/Dockerfile"
16
31
  FROM ai-base:latest
17
32
 
18
33
  USER root
19
- # Install OpenCode using official native installer
20
34
  RUN curl -fsSL https://opencode.ai/install | bash && \
21
35
  mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \
22
36
  rm -rf /home/agent/.opencode
@@ -24,6 +38,7 @@ RUN curl -fsSL https://opencode.ai/install | bash && \
24
38
  USER agent
25
39
  ENTRYPOINT ["opencode"]
26
40
  EOF
41
+ fi
27
42
 
28
43
  # Build image
29
44
  echo "Building Docker image for $TOOL (native binary)..."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kokorolx/ai-sandbox-wrapper",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
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",
package/setup.sh CHANGED
@@ -321,8 +321,21 @@ if [[ ${#CONTAINERIZED_TOOLS[@]} -gt 0 ]]; then
321
321
  echo "Language runtimes selected: ${LANGUAGE_RUNTIMES[*]}"
322
322
  fi
323
323
 
324
- # Combine both categories for processing
325
- ADDITIONAL_TOOLS=("${AI_ENHANCEMENT_TOOLS[@]}" "${LANGUAGE_RUNTIMES[@]}")
324
+ echo ""
325
+
326
+ # Category 3: MCP Tools (Browser automation for AI agents)
327
+ MCP_OPTIONS="chrome-devtools-mcp,playwright-mcp"
328
+ MCP_DESCS="Google Chrome DevTools MCP - performance profiling + debugging (~400MB),Microsoft Playwright MCP - multi-browser automation (~300MB)"
329
+
330
+ multi_select "Select MCP Tools for AI Agent Browser Automation" "$MCP_OPTIONS" "$MCP_DESCS"
331
+ MCP_TOOLS=("${SELECTED_ITEMS[@]}")
332
+
333
+ if [[ ${#MCP_TOOLS[@]} -gt 0 ]]; then
334
+ echo "MCP tools selected: ${MCP_TOOLS[*]}"
335
+ fi
336
+
337
+ # Combine all categories for processing
338
+ ADDITIONAL_TOOLS=("${AI_ENHANCEMENT_TOOLS[@]}" "${LANGUAGE_RUNTIMES[@]}" "${MCP_TOOLS[@]}")
326
339
  else
327
340
  ADDITIONAL_TOOLS=()
328
341
  echo "â„šī¸ No containerized AI tools selected. Skipping additional tools."
@@ -361,6 +374,8 @@ if [[ $NEEDS_BASE_IMAGE -eq 1 ]]; then
361
374
  INSTALL_OPENSPEC=0
362
375
  INSTALL_PLAYWRIGHT=0
363
376
  INSTALL_RUBY=0
377
+ INSTALL_CHROME_DEVTOOLS_MCP=0
378
+ INSTALL_PLAYWRIGHT_MCP=0
364
379
 
365
380
  for addon in "${ADDITIONAL_TOOLS[@]}"; do
366
381
  case "$addon" in
@@ -379,11 +394,32 @@ if [[ $NEEDS_BASE_IMAGE -eq 1 ]]; then
379
394
  ruby)
380
395
  INSTALL_RUBY=1
381
396
  ;;
397
+ chrome-devtools-mcp)
398
+ INSTALL_CHROME_DEVTOOLS_MCP=1
399
+ ;;
400
+ playwright-mcp)
401
+ INSTALL_PLAYWRIGHT_MCP=1
402
+ ;;
382
403
  esac
383
404
  done
384
405
 
385
- export INSTALL_SPEC_KIT INSTALL_UX_UI_PROMAX INSTALL_OPENSPEC INSTALL_PLAYWRIGHT INSTALL_RUBY
406
+ export INSTALL_SPEC_KIT INSTALL_UX_UI_PROMAX INSTALL_OPENSPEC INSTALL_PLAYWRIGHT INSTALL_RUBY INSTALL_CHROME_DEVTOOLS_MCP INSTALL_PLAYWRIGHT_MCP
386
407
  bash "$SCRIPT_DIR/lib/install-base.sh"
408
+
409
+ # Save MCP selections to ~/.ai-sandbox/config.json for ai-run auto-configuration
410
+ SANDBOX_CONFIG="$HOME/.ai-sandbox/config.json"
411
+ mkdir -p "$HOME/.ai-sandbox"
412
+ if command -v jq &>/dev/null; then
413
+ if [[ ! -f "$SANDBOX_CONFIG" ]]; then
414
+ echo '{"version":2,"workspaces":[],"git":{"allowedWorkspaces":[],"keySelections":{}},"networks":{"global":[],"workspaces":{}},"mcp":{"installed":[]}}' > "$SANDBOX_CONFIG"
415
+ fi
416
+ MCP_INSTALLED='[]'
417
+ [[ "$INSTALL_CHROME_DEVTOOLS_MCP" -eq 1 ]] && MCP_INSTALLED=$(echo "$MCP_INSTALLED" | jq '. + ["chrome-devtools"]')
418
+ [[ "$INSTALL_PLAYWRIGHT_MCP" -eq 1 ]] && MCP_INSTALLED=$(echo "$MCP_INSTALLED" | jq '. + ["playwright"]')
419
+ jq --argjson mcp "$MCP_INSTALLED" '.mcp.installed = $mcp' "$SANDBOX_CONFIG" > "$SANDBOX_CONFIG.tmp" && mv "$SANDBOX_CONFIG.tmp" "$SANDBOX_CONFIG"
420
+ chmod 600 "$SANDBOX_CONFIG"
421
+ echo "✅ MCP tool selections saved to config"
422
+ fi
387
423
  fi
388
424
 
389
425
  # Install selected tools
@@ -483,6 +519,12 @@ if [[ ${#ADDITIONAL_TOOLS[@]} -gt 0 ]]; then
483
519
  openspec)
484
520
  echo " openspec - OpenSpec CLI for spec-driven development"
485
521
  ;;
522
+ chrome-devtools-mcp)
523
+ echo " chrome-devtools-mcp - Google Chrome DevTools MCP server"
524
+ ;;
525
+ playwright-mcp)
526
+ echo " @playwright/mcp - Microsoft Playwright MCP server"
527
+ ;;
486
528
  esac
487
529
  done
488
530
  fi