@kokorolx/ai-sandbox-wrapper 2.1.0 → 2.2.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
@@ -10,6 +10,14 @@ AI coding tools like Claude, Gemini, and Aider have full access to your filesyst
10
10
 
11
11
  *Last updated: Tuesday, February 3, 2026*
12
12
 
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
+
13
21
  ## ✨ New in v2.1.0: Stability & Native Persistence
14
22
 
15
23
  The **v2.1.0 release** focuses on architectural stability and a more intuitive persistence model.
package/bin/ai-run CHANGED
@@ -334,6 +334,52 @@ fi
334
334
  # Set AI_IMAGE_SOURCE=registry in ~/.ai-env to use pre-built images
335
335
  AI_IMAGE_SOURCE="${AI_IMAGE_SOURCE:-local}"
336
336
 
337
+ # ============================================================================
338
+ # SCREENSHOT DIRECTORY DETECTION (macOS Only)
339
+ # ============================================================================
340
+ if [[ "$(uname)" == "Darwin" ]] && [[ -t 0 ]]; then
341
+ # 1. Detect location (default to Desktop if key missing)
342
+ SCREENSHOT_DIR=$(defaults read com.apple.screencapture location 2>/dev/null || echo "$HOME/Desktop")
343
+ # Expand tilde if present
344
+ SCREENSHOT_DIR="${SCREENSHOT_DIR/#\~/$HOME}"
345
+
346
+ # 2. Check if valid directory
347
+ if [[ -d "$SCREENSHOT_DIR" ]]; then
348
+
349
+ # 3. Check if ALREADY whitelisted (exact match or parent)
350
+ IS_WHITELISTED=false
351
+ while IFS= read -r ws; do
352
+ # Check if screenshot dir IS a workspace, or IS INSIDE a workspace
353
+ if [[ "$SCREENSHOT_DIR" == "$ws" ]] || [[ "$SCREENSHOT_DIR" == "$ws"/* ]]; then
354
+ IS_WHITELISTED=true
355
+ break
356
+ fi
357
+ done < <(read_workspaces)
358
+
359
+ # 4. Prompt if not whitelisted
360
+ if [[ "$IS_WHITELISTED" == "false" ]]; then
361
+ echo ""
362
+ echo "📸 Screenshot Directory Detected"
363
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
364
+ echo "Location: $SCREENSHOT_DIR"
365
+ echo "Status: Not whitelisted"
366
+ echo ""
367
+ echo "Whitelisting this folder allows you to drag & drop screenshots into AI tools."
368
+ echo ""
369
+ # Use /dev/tty to ensure we read from user even if stdin is redirected
370
+ read -p "Whitelist screenshots folder? [y/N]: " CONFIRM_SS < /dev/tty
371
+
372
+ if [[ "$CONFIRM_SS" =~ ^[Yy]$ ]]; then
373
+ add_workspace "$SCREENSHOT_DIR"
374
+ echo "✅ Added to whitelist."
375
+ else
376
+ echo "❌ Skipped."
377
+ fi
378
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
379
+ fi
380
+ fi
381
+ fi
382
+
337
383
  if [[ "$AI_IMAGE_SOURCE" == "registry" ]]; then
338
384
  IMAGE="registry.gitlab.com/kokorolee/ai-sandbox-wrapper/ai-${TOOL}:latest"
339
385
  else
@@ -1067,6 +1113,58 @@ else
1067
1113
  fi
1068
1114
  fi
1069
1115
 
1116
+ # ============================================================================
1117
+ # DISPLAY & CLIPBOARD CONFIGURATION
1118
+ # ============================================================================
1119
+ detect_display_config() {
1120
+ local detected_flags=""
1121
+ local has_display=false
1122
+
1123
+ # 1. X11 Detection
1124
+ if [[ -n "$DISPLAY" ]]; then
1125
+ has_display=true
1126
+ detected_flags="$detected_flags -e DISPLAY=$DISPLAY"
1127
+
1128
+ # Mount X11 socket (common on Linux/macOS with XQuartz)
1129
+ if [[ -d "/tmp/.X11-unix" ]]; then
1130
+ detected_flags="$detected_flags -v /tmp/.X11-unix:/tmp/.X11-unix:rw"
1131
+ fi
1132
+
1133
+ # Handle XAuthority for authentication
1134
+ if [[ -f "$HOME/.Xauthority" ]]; then
1135
+ # Mount read-only for security
1136
+ # Mount to /tmp/.Xauthority to avoid conflict with /home/agent bind mount
1137
+ detected_flags="$detected_flags -e XAUTHORITY=/tmp/.Xauthority -v $HOME/.Xauthority:/tmp/.Xauthority:ro"
1138
+ fi
1139
+
1140
+ # Since we have X11, prefer it over Wayland to avoid clipboard issues in mixed environments
1141
+ # (Many Go apps like atotto/clipboard work better with xclip/X11 than wl-copy/Wayland in Docker)
1142
+ echo "$detected_flags"
1143
+ return
1144
+ fi
1145
+
1146
+ # 2. Wayland Detection
1147
+ if [[ -n "$WAYLAND_DISPLAY" ]]; then
1148
+ has_display=true
1149
+ detected_flags="$detected_flags -e WAYLAND_DISPLAY=$WAYLAND_DISPLAY"
1150
+
1151
+ # Handle XDG_RUNTIME_DIR (needed for Wayland sockets)
1152
+ if [[ -n "$XDG_RUNTIME_DIR" ]]; then
1153
+ # Map host runtime dir to container's /run/user/1001 (agent UID)
1154
+ # ensuring the container can access the socket
1155
+ local container_runtime_dir="/run/user/1001"
1156
+ detected_flags="$detected_flags -e XDG_RUNTIME_DIR=$container_runtime_dir -v $XDG_RUNTIME_DIR:$container_runtime_dir:rw"
1157
+ fi
1158
+ fi
1159
+
1160
+ # Debug log if no display detected (only if debug enabled)
1161
+ if [[ "$has_display" == "false" && "${AI_RUN_DEBUG:-}" == "1" ]]; then
1162
+ echo "🔧 Debug: No display server detected (DISPLAY/WAYLAND_DISPLAY unset). Clipboard integration disabled." >&2
1163
+ fi
1164
+
1165
+ echo "$detected_flags"
1166
+ }
1167
+
1070
1168
  # Generate container name based on tool and folder
1071
1169
  # Format: {tool}-{sanitized_folder_name}-{random_suffix}
1072
1170
  generate_container_name() {
@@ -1208,6 +1306,9 @@ if [[ "$TOOL" == "opencode" ]]; then
1208
1306
  CACHE_MOUNTS="-v /home/agent/.npm -v /home/agent/.cache -v /home/agent/.opencode/node_modules"
1209
1307
  fi
1210
1308
 
1309
+ # Detect display configuration (clipboard integration)
1310
+ DISPLAY_FLAGS=$(detect_display_config)
1311
+
1211
1312
  docker run $CONTAINER_NAME --rm $TTY_FLAGS \
1212
1313
  --init \
1213
1314
  --platform "$PLATFORM" \
@@ -1218,6 +1319,7 @@ docker run $CONTAINER_NAME --rm $TTY_FLAGS \
1218
1319
  $GIT_MOUNTS \
1219
1320
  $NETWORK_OPTIONS \
1220
1321
  $CACHE_MOUNTS \
1322
+ $DISPLAY_FLAGS \
1221
1323
  $HOST_ACCESS_ARGS \
1222
1324
  $PORT_MAPPINGS \
1223
1325
  -v "$HOME_DIR":/home/agent \
@@ -0,0 +1,17 @@
1
+ FROM ai-base:latest
2
+
3
+ # Switch to root only for installing bun globally (needed for the system)
4
+ USER root
5
+ RUN npm install -g bun
6
+ USER agent
7
+
8
+ # Install Amp into user directory
9
+ RUN mkdir -p /home/agent/lib/amp && \
10
+ cd /home/agent/lib/amp && \
11
+ bun init -y && \
12
+ bun add @sourcegraph/amp
13
+
14
+ # Add the node_modules .bin to PATH
15
+ ENV PATH="/home/agent/lib/amp/node_modules/.bin:${PATH}"
16
+
17
+ ENTRYPOINT ["amp"]
@@ -0,0 +1,47 @@
1
+ FROM node:22-bookworm-slim
2
+
3
+ ARG AGENT_UID=1001
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
8
+
9
+ # Install pnpm globally using npm (not bun, for stability)
10
+ RUN npm install -g pnpm
11
+
12
+ # Install TypeScript and LSP tools using npm
13
+ RUN npm install -g typescript typescript-language-server
14
+
15
+ # Verify installations
16
+ RUN node --version && npm --version && pnpm --version && tsc --version
17
+
18
+ # Install additional tools (if selected)
19
+ RUN PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install specify-cli --pip-args="git+https://github.com/github/spec-kit.git" && \
20
+ chmod +x /usr/local/bin/specify && \
21
+ ln -sf /usr/local/bin/specify /usr/local/bin/specify-cli
22
+ RUN mkdir -p /usr/local/lib/uipro-cli && \
23
+ cd /usr/local/lib/uipro-cli && \
24
+ npm init -y && \
25
+ npm install uipro-cli && \
26
+ ln -sf /usr/local/lib/uipro-cli/node_modules/.bin/uipro /usr/local/bin/uipro && \
27
+ ln -sf /usr/local/bin/uipro /usr/local/bin/uipro-cli && \
28
+ chmod -R 755 /usr/local/lib/uipro-cli && \
29
+ chmod +x /usr/local/bin/uipro
30
+ RUN mkdir -p /usr/local/lib/openspec && \
31
+ cd /usr/local/lib/openspec && \
32
+ npm init -y && \
33
+ npm install @fission-ai/openspec && \
34
+ ln -sf /usr/local/lib/openspec/node_modules/.bin/openspec /usr/local/bin/openspec && \
35
+ chmod -R 755 /usr/local/lib/openspec && \
36
+ chmod +x /usr/local/bin/openspec
37
+
38
+ # Create workspace
39
+ WORKDIR /workspace
40
+
41
+ # Non-root user for security
42
+ # Non-root user for security (match host UID)
43
+ RUN useradd -m -u ${AGENT_UID} -d /home/agent agent && \
44
+ 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
46
+ USER agent
47
+ ENV HOME=/home/agent
@@ -0,0 +1,10 @@
1
+ FROM ai-base:latest
2
+
3
+ USER root
4
+ # Install OpenCode using official native installer
5
+ RUN curl -fsSL https://opencode.ai/install | bash && \
6
+ mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \
7
+ rm -rf /home/agent/.opencode
8
+
9
+ USER agent
10
+ ENTRYPOINT ["opencode"]
@@ -14,14 +14,21 @@ mkdir -p "$HOME/.ai-sandbox/tools/$TOOL/home"
14
14
  # Create Dockerfile (extends base image for faster builds)
15
15
  cat <<'EOF' > "dockerfiles/$TOOL/Dockerfile"
16
16
  FROM ai-base:latest
17
+
18
+ # Switch to root only for installing bun globally (needed for the system)
17
19
  USER root
18
- # Install Amp globally into a persistent directory (not shadowed by home)
19
- RUN mkdir -p /usr/local/lib/amp && \
20
- cd /usr/local/lib/amp && \
21
- bun init -y && \
22
- bun add @sourcegraph/amp && \
23
- ln -s /usr/local/lib/amp/node_modules/.bin/amp /usr/local/bin/amp
20
+ RUN npm install -g bun
24
21
  USER agent
22
+
23
+ # Install Amp into user directory
24
+ RUN mkdir -p /home/agent/lib/amp && \
25
+ cd /home/agent/lib/amp && \
26
+ bun init -y && \
27
+ bun add @sourcegraph/amp
28
+
29
+ # Add the node_modules .bin to PATH
30
+ ENV PATH="/home/agent/lib/amp/node_modules/.bin:${PATH}"
31
+
25
32
  ENTRYPOINT ["amp"]
26
33
  EOF
27
34
 
@@ -126,6 +126,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
126
126
  libopenblas-dev \
127
127
  pipx \
128
128
  unzip \
129
+ xclip \
130
+ wl-clipboard \
129
131
  && curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh \
130
132
  && rm -rf /var/lib/apt/lists/* \
131
133
  && pipx ensurepath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kokorolx/ai-sandbox-wrapper",
3
- "version": "2.1.0",
3
+ "version": "2.2.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",