@kokorolx/ai-sandbox-wrapper 3.2.0 → 3.3.0-beta.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/bin/ai-run CHANGED
@@ -783,6 +783,83 @@ if [[ -d "$HOST_SKILLS_DIR" ]]; then
783
783
  SHARED_CACHE_MOUNTS="$SHARED_CACHE_MOUNTS -v $HOST_SKILLS_DIR:/home/agent/.config/opencode/skills:ro"
784
784
  fi
785
785
 
786
+ # Host Chrome for Playwright MCP (via CDP - Chrome DevTools Protocol)
787
+ # NOTE: macOS Chrome binary (Mach-O) cannot run inside a Linux container.
788
+ # Instead, we launch Chrome on the host with --remote-debugging-port and
789
+ # connect from the container via CDP. Each container gets its own port and
790
+ # its own MCP entry; entries are sweep-cleaned on every start.
791
+ HOST_CHROME_CDP=false
792
+ HOST_CHROME_CDP_PORT=19222
793
+ PLAYWRIGHT_MCP_NAME=""
794
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
795
+ # shellcheck source=lib/playwright-mcp-config.sh
796
+ [[ -f "$SCRIPT_DIR/lib/playwright-mcp-config.sh" ]] && source "$SCRIPT_DIR/lib/playwright-mcp-config.sh"
797
+
798
+ if [[ "$TOOL" == "opencode" ]] && command -v jq &>/dev/null && [[ -f "$AI_SANDBOX_CONFIG" ]] && declare -f pmcp::sanitize_name >/dev/null; then
799
+ PLAYWRIGHT_HOST_CHROME=$(jq -r '.mcp.chromePath // empty' "$AI_SANDBOX_CONFIG" 2>/dev/null)
800
+ if [[ -n "$PLAYWRIGHT_HOST_CHROME" ]] && [[ -f "$PLAYWRIGHT_HOST_CHROME" ]]; then
801
+ HOST_CHROME_CDP=true
802
+ echo "🌐 Host Chrome CDP mode: $PLAYWRIGHT_HOST_CHROME"
803
+
804
+ # CONTAINER_NAME has the form "--name foo" or is empty. Extract the value
805
+ # for hashing only — the MCP key uses just the port (containers that
806
+ # collide on a port intentionally share the same Chrome / MCP entry).
807
+ CONTAINER_NAME_VALUE="${CONTAINER_NAME#--name }"
808
+ [[ "$CONTAINER_NAME_VALUE" == "$CONTAINER_NAME" ]] && CONTAINER_NAME_VALUE="anon-$$"
809
+
810
+ # Deterministic port per container name
811
+ CONTAINER_HASH=$(echo "$CONTAINER_NAME_VALUE" | md5sum | cut -c1-4)
812
+ HOST_CHROME_CDP_PORT=$((19222 + 0x$CONTAINER_HASH % 100))
813
+ PLAYWRIGHT_MCP_NAME="playwright_port_${HOST_CHROME_CDP_PORT}"
814
+
815
+ # Reuse-if-alive: probe before launching
816
+ if pmcp::probe_chrome "$HOST_CHROME_CDP_PORT"; then
817
+ echo " ✅ Chrome already running on port $HOST_CHROME_CDP_PORT (reusing)"
818
+ else
819
+ echo " 🚀 Launching Chrome with remote debugging on port $HOST_CHROME_CDP_PORT..."
820
+ mkdir -p "$SANDBOX_DIR/chrome-profile-$HOST_CHROME_CDP_PORT"
821
+ "$PLAYWRIGHT_HOST_CHROME" \
822
+ --remote-debugging-port="$HOST_CHROME_CDP_PORT" \
823
+ --user-data-dir="$SANDBOX_DIR/chrome-profile-$HOST_CHROME_CDP_PORT" \
824
+ --no-first-run \
825
+ --no-default-browser-check \
826
+ &>/dev/null &
827
+ CHROME_PID=$!
828
+ for i in {1..20}; do
829
+ if pmcp::probe_chrome "$HOST_CHROME_CDP_PORT"; then
830
+ echo " ✅ Chrome ready (PID: $CHROME_PID, port: $HOST_CHROME_CDP_PORT)"
831
+ echo " 👀 You can watch the browser window to see what the AI is doing"
832
+ break
833
+ fi
834
+ sleep 0.25
835
+ done
836
+ if ! pmcp::probe_chrome "$HOST_CHROME_CDP_PORT"; then
837
+ echo " ⚠️ Chrome failed to start. Falling back to container Chromium."
838
+ HOST_CHROME_CDP=false
839
+ kill "$CHROME_PID" 2>/dev/null || true
840
+ PLAYWRIGHT_MCP_NAME=""
841
+ fi
842
+ fi
843
+
844
+ # Locked sweep+append on the shared OpenCode config
845
+ if [[ "$HOST_CHROME_CDP" == "true" ]]; then
846
+ OPENCODE_CONFIG_FILE="$HOME/.config/opencode/opencode.json"
847
+ LOCK_FILE="$HOME/.config/opencode/.playwright.lock"
848
+ mkdir -p "$(dirname "$OPENCODE_CONFIG_FILE")"
849
+ [[ -f "$OPENCODE_CONFIG_FILE" ]] || echo '{}' > "$OPENCODE_CONFIG_FILE"
850
+ pmcp::with_lock "$LOCK_FILE" pmcp::sweep_and_append "$OPENCODE_CONFIG_FILE" "$PLAYWRIGHT_MCP_NAME" "$HOST_CHROME_CDP_PORT"
851
+ rc=$?
852
+ if [[ "$rc" == "99" ]]; then
853
+ echo " ⚠️ Could not acquire MCP config lock within 5s; skipping registration."
854
+ PLAYWRIGHT_MCP_NAME=""
855
+ elif [[ "$rc" != "0" ]]; then
856
+ echo " ⚠️ MCP config update failed (rc=$rc); skipping registration."
857
+ PLAYWRIGHT_MCP_NAME=""
858
+ fi
859
+ fi
860
+ fi
861
+ fi
862
+
786
863
  # Nano-brain mount: writable so container can modify config, write memory, logs, etc.
787
864
  NANO_BRAIN_MOUNT=""
788
865
  if [[ -d "$HOME/.nano-brain" ]]; then
@@ -1921,6 +1998,12 @@ configure_opencode_mcp() {
1921
1998
  is_mcp_configured "playwright" && playwright_configured=true
1922
1999
  fi
1923
2000
 
2001
+ # Get host Chrome path if using playwright-host
2002
+ local PLAYWRIGHT_HOST_CHROME=""
2003
+ if command -v jq &>/dev/null && [[ -f "$AI_SANDBOX_CONFIG" ]]; then
2004
+ PLAYWRIGHT_HOST_CHROME=$(jq -r '.mcp.chromePath // empty' "$AI_SANDBOX_CONFIG" 2>/dev/null)
2005
+ fi
2006
+
1924
2007
  # If no MCP tools installed in image, return
1925
2008
  if [[ "$chrome_installed" == "false" && "$playwright_installed" == "false" ]]; then
1926
2009
  return 0
@@ -1957,7 +2040,11 @@ configure_opencode_mcp() {
1957
2040
  echo " ✓ Chrome DevTools MCP"
1958
2041
  ;;
1959
2042
  playwright)
1960
- echo " Playwright MCP"
2043
+ if [[ -n "$PLAYWRIGHT_HOST_CHROME" ]] && [[ -f "$PLAYWRIGHT_HOST_CHROME" ]]; then
2044
+ echo " ✓ Playwright MCP (host Chrome)"
2045
+ else
2046
+ echo " ✓ Playwright MCP"
2047
+ fi
1961
2048
  ;;
1962
2049
  esac
1963
2050
  done
@@ -1973,7 +2060,11 @@ configure_opencode_mcp() {
1973
2060
  echo " • Chrome DevTools MCP - browser automation + performance profiling"
1974
2061
  ;;
1975
2062
  playwright)
1976
- echo " Playwright MCP - multi-browser automation"
2063
+ if [[ -n "$PLAYWRIGHT_HOST_CHROME" ]] && [[ -f "$PLAYWRIGHT_HOST_CHROME" ]]; then
2064
+ echo " • Playwright MCP (host Chrome) - use your installed Chrome browser"
2065
+ else
2066
+ echo " • Playwright MCP - multi-browser automation"
2067
+ fi
1977
2068
  ;;
1978
2069
  esac
1979
2070
  done
@@ -2006,9 +2097,16 @@ configure_opencode_mcp() {
2006
2097
  fi
2007
2098
  ;;
2008
2099
  playwright)
2009
- if add_mcp_config "playwright" '["playwright-mcp", "--headless", "--browser", "chromium"]'; then
2010
- echo " Configured Playwright MCP"
2100
+ # Check if using host Chrome via CDP
2101
+ if [[ -n "$PLAYWRIGHT_HOST_CHROME" ]] && [[ -f "$PLAYWRIGHT_HOST_CHROME" ]]; then
2102
+ echo " ℹ️ Playwright MCP entry will be registered per-container at runtime (host Chrome mode)."
2011
2103
  configured_any=true
2104
+ else
2105
+ # Use container Chromium
2106
+ if add_mcp_config "playwright" '["playwright-mcp", "--headless", "--browser", "chromium"]'; then
2107
+ echo " ✓ Configured Playwright MCP"
2108
+ configured_any=true
2109
+ fi
2012
2110
  fi
2013
2111
  ;;
2014
2112
  esac
@@ -2042,9 +2140,16 @@ configure_opencode_mcp() {
2042
2140
  fi
2043
2141
  ;;
2044
2142
  playwright)
2045
- if add_mcp_config "playwright" '["playwright-mcp", "--headless", "--browser", "chromium"]'; then
2046
- echo " Configured"
2143
+ # Check if using host Chrome via CDP
2144
+ if [[ -n "$PLAYWRIGHT_HOST_CHROME" ]] && [[ -f "$PLAYWRIGHT_HOST_CHROME" ]]; then
2145
+ echo " ℹ️ Playwright MCP entry will be registered per-container at runtime (host Chrome mode)."
2047
2146
  configured_any=true
2147
+ else
2148
+ # Use container Chromium
2149
+ if add_mcp_config "playwright" '["playwright-mcp", "--headless", "--browser", "chromium"]'; then
2150
+ echo " ✓ Configured"
2151
+ configured_any=true
2152
+ fi
2048
2153
  fi
2049
2154
  ;;
2050
2155
  esac
@@ -2581,27 +2686,38 @@ EOF
2581
2686
  up --remove-orphans
2582
2687
  fi
2583
2688
 
2584
- docker run $CONTAINER_NAME --rm $TTY_FLAGS \
2585
- --init \
2586
- --platform "$PLATFORM" \
2587
- $ENTRYPOINT_OVERRIDE \
2588
- $VOLUME_MOUNTS \
2589
- $CONFIG_MOUNT \
2590
- $TOOL_CONFIG_MOUNTS \
2591
- $RG_COMPAT_MOUNT \
2592
- $GIT_MOUNTS \
2593
- $SSH_AGENT_ENV \
2594
- $NETWORK_OPTIONS \
2595
- $DISPLAY_FLAGS \
2596
- $HOST_ACCESS_ARGS \
2597
- $PORT_MAPPINGS \
2598
- $OPENCODE_PASSWORD_ENV \
2599
- -v "$HOME_DIR":/home/agent \
2600
- $SHARED_CACHE_MOUNTS \
2601
- $NANO_BRAIN_MOUNT \
2602
- -w "$CURRENT_DIR" \
2603
- --env-file "$ENV_FILE" \
2604
- -e TERM="$TERM" \
2605
- -e COLORTERM="$COLORTERM" \
2606
- $TERMINAL_SIZE \
2607
- "$IMAGE" "${DOCKER_COMMAND[@]}"
2689
+ # Build docker run arguments as an array (handles paths with spaces correctly)
2690
+ DOCKER_ARGS=()
2691
+ DOCKER_ARGS+=($CONTAINER_NAME --rm $TTY_FLAGS)
2692
+ DOCKER_ARGS+=(--init)
2693
+ DOCKER_ARGS+=(--platform "$PLATFORM")
2694
+ DOCKER_ARGS+=($ENTRYPOINT_OVERRIDE)
2695
+ DOCKER_ARGS+=($VOLUME_MOUNTS)
2696
+ DOCKER_ARGS+=($CONFIG_MOUNT)
2697
+ DOCKER_ARGS+=($TOOL_CONFIG_MOUNTS)
2698
+ DOCKER_ARGS+=($RG_COMPAT_MOUNT)
2699
+ DOCKER_ARGS+=($GIT_MOUNTS)
2700
+ DOCKER_ARGS+=($SSH_AGENT_ENV)
2701
+ DOCKER_ARGS+=($NETWORK_OPTIONS)
2702
+ DOCKER_ARGS+=($DISPLAY_FLAGS)
2703
+ DOCKER_ARGS+=($HOST_ACCESS_ARGS)
2704
+ DOCKER_ARGS+=($PORT_MAPPINGS)
2705
+ DOCKER_ARGS+=($OPENCODE_PASSWORD_ENV)
2706
+ DOCKER_ARGS+=(-v "$HOME_DIR":/home/agent)
2707
+ DOCKER_ARGS+=($SHARED_CACHE_MOUNTS)
2708
+ DOCKER_ARGS+=($NANO_BRAIN_MOUNT)
2709
+ DOCKER_ARGS+=(-w "$CURRENT_DIR")
2710
+ DOCKER_ARGS+=(--env-file "$ENV_FILE")
2711
+ DOCKER_ARGS+=(-e TERM="$TERM")
2712
+ DOCKER_ARGS+=(-e COLORTERM="$COLORTERM")
2713
+ if [[ -n "${PLAYWRIGHT_MCP_NAME:-}" ]]; then
2714
+ DOCKER_ARGS+=(-e "PLAYWRIGHT_MCP_NAME=$PLAYWRIGHT_MCP_NAME")
2715
+ DOCKER_ARGS+=(-e "PLAYWRIGHT_PORT=$HOST_CHROME_CDP_PORT")
2716
+ fi
2717
+ DOCKER_ARGS+=($TERMINAL_SIZE)
2718
+
2719
+ DOCKER_ARGS+=("$IMAGE")
2720
+ DOCKER_ARGS+=("${DOCKER_COMMAND[@]}")
2721
+
2722
+ # Execute docker run with proper argument handling
2723
+ docker run "${DOCKER_ARGS[@]}"
@@ -170,13 +170,25 @@ if [[ "${INSTALL_CHROME_DEVTOOLS_MCP:-0}" -eq 1 ]] || [[ "${INSTALL_PLAYWRIGHT_M
170
170
  wget \
171
171
  && rm -rf /var/lib/apt/lists/*
172
172
  ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
173
- RUN mkdir -p /opt/playwright-browsers && \
173
+ '
174
+
175
+ # Only install Chromium if not using host Chrome
176
+ if [[ "${INSTALL_PLAYWRIGHT_HOST:-0}" -eq 1 ]]; then
177
+ echo " 📦 Using host Chrome - skipping Chromium installation"
178
+ ADDITIONAL_TOOLS_INSTALL+='RUN mkdir -p /opt/playwright-browsers && \
179
+ npm install -g @playwright/mcp@latest && \
180
+ touch /opt/.mcp-playwright-installed
181
+ '
182
+ else
183
+ echo " 📦 Installing Chromium browser for MCP tools"
184
+ ADDITIONAL_TOOLS_INSTALL+='RUN mkdir -p /opt/playwright-browsers && \
174
185
  npm install -g @playwright/mcp@latest && \
175
186
  npx playwright-core install --no-shell chromium && \
176
187
  npx playwright-core install-deps chromium && \
177
188
  chmod -R 777 /opt/playwright-browsers && \
178
189
  ln -sf $(ls -d /opt/playwright-browsers/chromium-*/chrome-linux/chrome | sort -V | tail -1) /opt/chromium
179
190
  '
191
+ fi
180
192
  fi
181
193
 
182
194
  if [[ "${INSTALL_CHROME_DEVTOOLS_MCP:-0}" -eq 1 ]]; then
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env bash
2
+ # Helpers for managing per-container Playwright MCP entries in the shared
3
+ # OpenCode config (~/.config/opencode/opencode.json). All functions are pure
4
+ # except where noted. Callers are responsible for holding the flock around
5
+ # pmcp::sweep_and_append.
6
+
7
+ # Replace any character outside [A-Za-z0-9_-] with underscore. Empty input
8
+ # becomes "unnamed". Used to keep MCP keys jq-safe.
9
+ pmcp::sanitize_name() {
10
+ local input="${1:-}"
11
+ if [[ -z "$input" ]]; then
12
+ echo "unnamed"
13
+ return
14
+ fi
15
+ printf '%s' "$input" | tr -c 'A-Za-z0-9_-' '_'
16
+ }
17
+
18
+ # Probe a port for a valid Chrome CDP endpoint. Returns 0 if /json/version
19
+ # responds with JSON containing a "Browser" field within the timeout.
20
+ # Args: $1 = port
21
+ pmcp::probe_chrome() {
22
+ local port="$1"
23
+ local body
24
+ body=$(curl -fsS --max-time 0.5 "http://localhost:$port/json/version" 2>/dev/null) || return 1
25
+ [[ "$body" == *'"Browser"'* ]] || return 1
26
+ return 0
27
+ }
28
+
29
+ # Host address from container (Docker Desktop on Mac).
30
+ PMCP_DOCKER_HOST_IP="${PMCP_DOCKER_HOST_IP:-192.168.65.254}"
31
+
32
+ # Sweep dead playwright_* entries and append a new one. MUST be called inside
33
+ # a flock by the caller. Does not acquire the lock itself, by design — locking
34
+ # happens around a larger critical section in the caller.
35
+ # Args: $1 = config file path, $2 = full MCP key (e.g. playwright_foo_19223), $3 = port
36
+ pmcp::sweep_and_append() {
37
+ local cfg="$1" name="$2" port="$3"
38
+
39
+ if [[ ! -f "$cfg" ]]; then
40
+ echo " ⚠️ pmcp: config file not found: $cfg" >&2
41
+ return 1
42
+ fi
43
+
44
+ # Collect dead keys
45
+ local keys dead_keys=()
46
+ keys=$(jq -r '(.mcp // {}) | keys[] | select(startswith("playwright_"))' "$cfg" 2>/dev/null || true)
47
+ while IFS= read -r key; do
48
+ [[ -z "$key" ]] && continue
49
+ local cmd_url
50
+ cmd_url=$(jq -r --arg k "$key" '.mcp[$k].command[]? | select(startswith("http://"))' "$cfg" 2>/dev/null | head -1)
51
+ [[ -z "$cmd_url" ]] && continue
52
+ local entry_port="${cmd_url##*:}"
53
+ if ! pmcp::probe_chrome "$entry_port"; then
54
+ dead_keys+=("$key")
55
+ fi
56
+ done <<< "$keys"
57
+
58
+ # Build --arg flags for each dead key, then run a single jq invocation
59
+ # that deletes them all and appends the new entry.
60
+ local tmp="$cfg.tmp.$$"
61
+ local args=()
62
+ local i=0
63
+ for k in "${dead_keys[@]+"${dead_keys[@]}"}"; do
64
+ args+=(--arg "k$i" "$k")
65
+ i=$((i + 1))
66
+ done
67
+ jq "${args[@]+"${args[@]}"}" --arg name "$name" --arg host "$PMCP_DOCKER_HOST_IP" --arg port "$port" \
68
+ '
69
+ def setup($args; $name; $host; $port):
70
+ .mcp = (.mcp // {})
71
+ | reduce ($args[]) as $k (.; del(.mcp[$k]))
72
+ | .mcp[$name] = {"type":"local","command":["playwright-mcp","--cdp-endpoint","http://" + $host + ":" + $port]};
73
+ setup([$ARGS.named | to_entries[] | select(.key|startswith("k")) | .value]; $name; $host; $port)
74
+ ' "$cfg" > "$tmp"
75
+
76
+ mv "$tmp" "$cfg"
77
+ chmod 600 "$cfg"
78
+
79
+ if (( ${#dead_keys[@]} > 0 )); then
80
+ echo " 🧹 pmcp: removed ${#dead_keys[@]} stale entr$([ ${#dead_keys[@]} -eq 1 ] && echo y || echo ies): ${dead_keys[*]}"
81
+ fi
82
+ echo " ➕ pmcp: registered $name → http://$PMCP_DOCKER_HOST_IP:$port"
83
+ }
84
+
85
+ # Run a command while holding an exclusive lock on $1. Uses flock(1) if available,
86
+ # else falls back to a mkdir-based mutex (portable across macOS where flock is
87
+ # not built-in). Times out after 5 seconds; on timeout, returns 99 without
88
+ # running the command. Returns the command's exit status otherwise.
89
+ # Args: $1 = lockfile path, $2... = command + args
90
+ pmcp::with_lock() {
91
+ local lockfile="$1"; shift
92
+ local timeout=5
93
+
94
+ if command -v flock >/dev/null 2>&1; then
95
+ (
96
+ flock -w "$timeout" 9 || exit 99
97
+ "$@"
98
+ ) 9>"$lockfile"
99
+ return $?
100
+ fi
101
+
102
+ # mkdir-based fallback. mkdir is atomic on POSIX filesystems.
103
+ local mutex="${lockfile}.d"
104
+ local waited=0
105
+ while ! mkdir "$mutex" 2>/dev/null; do
106
+ if (( waited >= timeout * 10 )); then
107
+ return 99
108
+ fi
109
+ sleep 0.1
110
+ waited=$((waited + 1))
111
+ done
112
+ trap "rmdir '$mutex' 2>/dev/null || true" EXIT
113
+ "$@"
114
+ local rc=$?
115
+ rmdir "$mutex" 2>/dev/null || true
116
+ trap - EXIT
117
+ return $rc
118
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kokorolx/ai-sandbox-wrapper",
3
- "version": "3.2.0",
3
+ "version": "3.3.0-beta.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",
@@ -1,103 +0,0 @@
1
- ---
2
- name: rtk
3
- description: "Token optimizer for AI coding agents. Wraps common CLI commands with rtk to reduce LLM token consumption by 60-90%."
4
- compatibility: "OpenCode with RTK binary installed"
5
- metadata:
6
- author: Sisyphus
7
- version: "1.0.0"
8
- ---
9
-
10
- # RTK — Rust Token Killer
11
-
12
- **Purpose**: Reduce token consumption by 60-90% on shell commands. RTK filters and compresses command output before it reaches your context.
13
-
14
- ## When This Skill Activates
15
-
16
- This skill is loaded automatically. Once active, **always** prefix supported commands with `rtk`.
17
-
18
- ## Command Mappings (MANDATORY)
19
-
20
- When running shell commands via Bash tool, use `rtk` prefix for these commands:
21
-
22
- | Instead of | Use | Savings |
23
- |-----------|-----|---------|
24
- | `git status` | `rtk git status` | ~80% |
25
- | `git diff` | `rtk git diff` | ~75% |
26
- | `git log` | `rtk git log` | ~80% |
27
- | `git add/commit/push/pull` | `rtk git add/commit/push/pull` | ~90% |
28
- | `ls` / `ls -la` | `rtk ls` | ~80% |
29
- | `cat file` | `rtk read file` | ~70% |
30
- | `grep pattern .` | `rtk grep pattern .` | ~80% |
31
- | `rg pattern` | `rtk grep pattern .` | ~80% |
32
- | `npm test` / `cargo test` / `pytest` | `rtk test <cmd>` | ~90% |
33
- | `npm run build` / `cargo build` | `rtk err <cmd>` | ~80% |
34
- | `gh pr list/view` | `rtk gh pr list/view` | ~70% |
35
- | `docker ps` | `rtk docker ps` | ~80% |
36
- | `eslint` / `tsc` | `rtk lint` / `rtk tsc` | ~80% |
37
-
38
- ## Searching Inside `node_modules` / Ignored Directories
39
-
40
- By default, `rtk grep` respects `.gitignore` rules — meaning `node_modules`, `.nuxt`, `dist`, etc. are **excluded**. This is the right behavior 99% of the time.
41
-
42
- When you **need** to search inside ignored directories (debugging a library, checking an API signature, tracing a dependency bug):
43
-
44
- ```bash
45
- # Search all files including node_modules (--no-ignore bypasses .gitignore)
46
- rtk grep "defineStore" . --no-ignore
47
-
48
- # Search a specific package only (combine --no-ignore with --glob)
49
- rtk grep "defineStore" . --no-ignore --glob 'node_modules/pinia/**'
50
- ```
51
-
52
- **What does NOT work:**
53
- - `rtk grep "pattern" node_modules/pinia/` — still excluded even with direct path
54
- - `rtk grep "pattern" . --glob 'node_modules/**'` — glob alone doesn't override .gitignore
55
-
56
- **Key flag: `--no-ignore`** — this is the ONLY way to search ignored directories with rtk grep.
57
-
58
- ### Other useful `rtk grep` flags
59
-
60
- ```bash
61
- rtk grep "pattern" . -t ts # Filter by file type (ts, py, rust, etc.)
62
- rtk grep "pattern" . -m 100 # Increase max results (default: 50)
63
- rtk grep "pattern" . -u # Ultra-compact mode (even fewer tokens)
64
- rtk grep "pattern" . -l 120 # Max line length before truncation (default: 80)
65
- ```
66
-
67
- ## Commands to NOT Wrap
68
-
69
- Do NOT prefix these with `rtk` (unsupported or counterproductive):
70
-
71
- - `npx`, `npm install`, `pip install` (package managers)
72
- - `node`, `python3`, `ruby` (interpreters)
73
- - `nano-brain`, `openspec`, `opencode` (custom tools)
74
- - Heredocs (`<<EOF`)
75
- - Piped commands (`cmd1 | cmd2`) — wrap only the first command if applicable
76
- - Commands already prefixed with `rtk`
77
-
78
- ## How RTK Works
79
-
80
- ```
81
- Without RTK: git status → 50 lines raw output → 2,000 tokens
82
- With RTK: rtk git status → "3 modified, 1 untracked ✓" → 200 tokens
83
- ```
84
-
85
- RTK runs the real command, then filters/compresses the output. The agent sees a compact summary instead of verbose raw output.
86
-
87
- ## Detection
88
-
89
- Before using RTK commands, verify it's installed:
90
- ```bash
91
- rtk --version
92
- ```
93
-
94
- If `rtk` is not found, skip this skill — run commands normally without the `rtk` prefix.
95
-
96
- ## Token Savings Reference
97
-
98
- Typical 30-min coding session:
99
- - Without RTK: ~150,000 tokens
100
- - With RTK: ~45,000 tokens
101
- - **Savings: ~70%**
102
-
103
- Biggest wins: test output (`rtk test` — 90%), git operations (`rtk git` — 80%), file reading (`rtk read` — 70%).
@@ -1,118 +0,0 @@
1
- ---
2
- name: rtk-setup
3
- description: "One-time setup + ongoing enforcement of RTK (Rust Token Killer) across sessions and subagents. Persists RTK instructions to AGENTS.md and propagates to delegated tasks."
4
- compatibility: "OpenCode with RTK binary installed"
5
- metadata:
6
- author: Sisyphus
7
- version: "1.0.0"
8
- ---
9
-
10
- # RTK Setup — Persistent RTK Enforcement
11
-
12
- This skill performs **setup** (persist RTK instructions) and **ongoing enforcement** (use rtk, propagate to subagents).
13
-
14
- ## Phase 1: Detection (ALWAYS run first)
15
-
16
- Run these checks before anything else:
17
-
18
- ```bash
19
- rtk --version
20
- ```
21
-
22
- - If `rtk` is NOT found → **STOP**. Tell the user: "RTK is not installed. Install it first: `cargo install --git https://github.com/rtk-ai/rtk --locked`". Do NOT proceed with setup.
23
- - If `rtk` IS found → continue.
24
-
25
- ### Check oh-my-opencode
26
-
27
- ```bash
28
- ls ~/.config/opencode/oh-my-opencode.json 2>/dev/null
29
- ```
30
-
31
- - If found → omo is installed. Note this for Phase 2.
32
- - If not found → skip omo-specific steps.
33
-
34
- ## Phase 2: Setup (persist to AGENTS.md)
35
-
36
- Check BOTH of these files for the RTK managed block:
37
-
38
- 1. **User-level**: `~/.config/opencode/AGENTS.md`
39
- 2. **Project-level**: `./AGENTS.md` (current workspace)
40
-
41
- For EACH file, check if `<!-- RTK:START -->` exists. If it does NOT exist, **append** the following managed block to the file (create the file if it doesn't exist). NEVER replace existing content — only append.
42
-
43
- ```markdown
44
- <!-- RTK:START -->
45
- <!-- Managed block - do not edit manually. Updated by: rtk-setup skill -->
46
-
47
- ## RTK Token Optimizer
48
-
49
- This project uses **RTK** (Rust Token Killer) to reduce LLM token consumption by 60-90%.
50
-
51
- ### Rules for ALL agents (including subagents)
52
-
53
- **ALWAYS** prefix these commands with `rtk`:
54
-
55
- | Command | Use instead |
56
- |---------|-------------|
57
- | `git status/diff/log/add/commit/push/pull` | `rtk git ...` |
58
- | `ls`, `ls -la` | `rtk ls` |
59
- | `cat file` | `rtk read file` |
60
- | `grep pattern .` / `rg pattern` | `rtk grep pattern .` |
61
- | `npm test` / `cargo test` / `pytest` | `rtk test <cmd>` |
62
- | `npm run build` / `cargo build` | `rtk err <cmd>` |
63
- | `gh pr list/view` | `rtk gh pr list/view` |
64
- | `docker ps` | `rtk docker ps` |
65
- | `eslint` / `tsc` | `rtk lint` / `rtk tsc` |
66
-
67
- **Do NOT** prefix: `npx`, `npm install`, `pip install`, `node`, `python3`, heredocs, piped commands.
68
-
69
- <!-- RTK:END -->
70
- ```
71
-
72
- ### If oh-my-opencode is installed
73
-
74
- After updating AGENTS.md files, check if the omo config at `~/.config/opencode/oh-my-opencode.json` has `prompt_append` fields on agents. If it does, inform the user:
75
-
76
- > "omo is installed. For maximum coverage, you can add RTK instructions to agent `prompt_append` fields in `oh-my-opencode.json`. This ensures subagents always use rtk even when AGENTS.md is not loaded. Want me to do this?"
77
-
78
- **Only modify `oh-my-opencode.json` if the user explicitly confirms.** If they confirm, append this line to the `prompt_append` of `sisyphus-junior` agent (the primary coder):
79
-
80
- ```
81
- \n\nRTK: ALWAYS prefix shell commands with `rtk` when available (git, ls, grep, test, build). Example: `rtk git status` not `git status`.
82
- ```
83
-
84
- Do NOT modify other agents' prompt_append unless asked.
85
-
86
- ## Phase 3: Ongoing Enforcement (EVERY time this skill is loaded)
87
-
88
- ### For the current agent
89
-
90
- From this point forward in this session, **you MUST**:
91
-
92
- 1. **Use `rtk` prefix** for all supported shell commands (see table above)
93
- 2. **Verify rtk is available** before first use: `rtk --version`
94
- 3. If rtk is not available in the current environment, fall back to normal commands silently
95
-
96
- ### For subagent delegation
97
-
98
- When delegating ANY task that involves shell commands (via `task()`, `delegate_task()`, or any delegation mechanism), **ALWAYS** add this to the `MUST DO` section of the delegation prompt:
99
-
100
- ```
101
- - Use `rtk` prefix for shell commands when available (git, ls, grep, test, build). Run `rtk --version` first to check. If not installed, use normal commands. Examples: `rtk git status`, `rtk ls`, `rtk grep pattern .`, `rtk test npm test`.
102
- ```
103
-
104
- This is NON-NEGOTIABLE. Subagents do not read AGENTS.md, so RTK instructions MUST be passed explicitly in every delegation prompt.
105
-
106
- ### Quick reference for subagent prompts
107
-
108
- Copy-paste this one-liner into MUST DO sections:
109
-
110
- > Use `rtk` prefix for all shell commands (git, ls, grep, test, build, docker). Example: `rtk git status` not `git status`. If `rtk` is not found, use normal commands.
111
-
112
- ## Summary
113
-
114
- | Phase | When | What |
115
- |-------|------|------|
116
- | Detection | Always first | Check rtk installed, check omo |
117
- | Setup | Once (idempotent) | Append RTK block to AGENTS.md (user + project) |
118
- | Enforcement | Every session | Use rtk yourself, propagate to all subagents |
@@ -1,9 +0,0 @@
1
- FROM ai-base:latest
2
-
3
- USER root
4
- RUN curl -fsSL https://opencode.ai/install | bash && \
5
- mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \
6
- rm -rf /home/agent/.opencode
7
-
8
- USER agent
9
- ENTRYPOINT ["opencode"]
@@ -1,103 +0,0 @@
1
- ---
2
- name: rtk
3
- description: "Token optimizer for AI coding agents. Wraps common CLI commands with rtk to reduce LLM token consumption by 60-90%."
4
- compatibility: "OpenCode with RTK binary installed"
5
- metadata:
6
- author: Sisyphus
7
- version: "1.0.0"
8
- ---
9
-
10
- # RTK — Rust Token Killer
11
-
12
- **Purpose**: Reduce token consumption by 60-90% on shell commands. RTK filters and compresses command output before it reaches your context.
13
-
14
- ## When This Skill Activates
15
-
16
- This skill is loaded automatically. Once active, **always** prefix supported commands with `rtk`.
17
-
18
- ## Command Mappings (MANDATORY)
19
-
20
- When running shell commands via Bash tool, use `rtk` prefix for these commands:
21
-
22
- | Instead of | Use | Savings |
23
- |-----------|-----|---------|
24
- | `git status` | `rtk git status` | ~80% |
25
- | `git diff` | `rtk git diff` | ~75% |
26
- | `git log` | `rtk git log` | ~80% |
27
- | `git add/commit/push/pull` | `rtk git add/commit/push/pull` | ~90% |
28
- | `ls` / `ls -la` | `rtk ls` | ~80% |
29
- | `cat file` | `rtk read file` | ~70% |
30
- | `grep pattern .` | `rtk grep pattern .` | ~80% |
31
- | `rg pattern` | `rtk grep pattern .` | ~80% |
32
- | `npm test` / `cargo test` / `pytest` | `rtk test <cmd>` | ~90% |
33
- | `npm run build` / `cargo build` | `rtk err <cmd>` | ~80% |
34
- | `gh pr list/view` | `rtk gh pr list/view` | ~70% |
35
- | `docker ps` | `rtk docker ps` | ~80% |
36
- | `eslint` / `tsc` | `rtk lint` / `rtk tsc` | ~80% |
37
-
38
- ## Searching Inside `node_modules` / Ignored Directories
39
-
40
- By default, `rtk grep` respects `.gitignore` rules — meaning `node_modules`, `.nuxt`, `dist`, etc. are **excluded**. This is the right behavior 99% of the time.
41
-
42
- When you **need** to search inside ignored directories (debugging a library, checking an API signature, tracing a dependency bug):
43
-
44
- ```bash
45
- # Search all files including node_modules (--no-ignore bypasses .gitignore)
46
- rtk grep "defineStore" . --no-ignore
47
-
48
- # Search a specific package only (combine --no-ignore with --glob)
49
- rtk grep "defineStore" . --no-ignore --glob 'node_modules/pinia/**'
50
- ```
51
-
52
- **What does NOT work:**
53
- - `rtk grep "pattern" node_modules/pinia/` — still excluded even with direct path
54
- - `rtk grep "pattern" . --glob 'node_modules/**'` — glob alone doesn't override .gitignore
55
-
56
- **Key flag: `--no-ignore`** — this is the ONLY way to search ignored directories with rtk grep.
57
-
58
- ### Other useful `rtk grep` flags
59
-
60
- ```bash
61
- rtk grep "pattern" . -t ts # Filter by file type (ts, py, rust, etc.)
62
- rtk grep "pattern" . -m 100 # Increase max results (default: 50)
63
- rtk grep "pattern" . -u # Ultra-compact mode (even fewer tokens)
64
- rtk grep "pattern" . -l 120 # Max line length before truncation (default: 80)
65
- ```
66
-
67
- ## Commands to NOT Wrap
68
-
69
- Do NOT prefix these with `rtk` (unsupported or counterproductive):
70
-
71
- - `npx`, `npm install`, `pip install` (package managers)
72
- - `node`, `python3`, `ruby` (interpreters)
73
- - `nano-brain`, `openspec`, `opencode` (custom tools)
74
- - Heredocs (`<<EOF`)
75
- - Piped commands (`cmd1 | cmd2`) — wrap only the first command if applicable
76
- - Commands already prefixed with `rtk`
77
-
78
- ## How RTK Works
79
-
80
- ```
81
- Without RTK: git status → 50 lines raw output → 2,000 tokens
82
- With RTK: rtk git status → "3 modified, 1 untracked ✓" → 200 tokens
83
- ```
84
-
85
- RTK runs the real command, then filters/compresses the output. The agent sees a compact summary instead of verbose raw output.
86
-
87
- ## Detection
88
-
89
- Before using RTK commands, verify it's installed:
90
- ```bash
91
- rtk --version
92
- ```
93
-
94
- If `rtk` is not found, skip this skill — run commands normally without the `rtk` prefix.
95
-
96
- ## Token Savings Reference
97
-
98
- Typical 30-min coding session:
99
- - Without RTK: ~150,000 tokens
100
- - With RTK: ~45,000 tokens
101
- - **Savings: ~70%**
102
-
103
- Biggest wins: test output (`rtk test` — 90%), git operations (`rtk git` — 80%), file reading (`rtk read` — 70%).
@@ -1,118 +0,0 @@
1
- ---
2
- name: rtk-setup
3
- description: "One-time setup + ongoing enforcement of RTK (Rust Token Killer) across sessions and subagents. Persists RTK instructions to AGENTS.md and propagates to delegated tasks."
4
- compatibility: "OpenCode with RTK binary installed"
5
- metadata:
6
- author: Sisyphus
7
- version: "1.0.0"
8
- ---
9
-
10
- # RTK Setup — Persistent RTK Enforcement
11
-
12
- This skill performs **setup** (persist RTK instructions) and **ongoing enforcement** (use rtk, propagate to subagents).
13
-
14
- ## Phase 1: Detection (ALWAYS run first)
15
-
16
- Run these checks before anything else:
17
-
18
- ```bash
19
- rtk --version
20
- ```
21
-
22
- - If `rtk` is NOT found → **STOP**. Tell the user: "RTK is not installed. Install it first: `cargo install --git https://github.com/rtk-ai/rtk --locked`". Do NOT proceed with setup.
23
- - If `rtk` IS found → continue.
24
-
25
- ### Check oh-my-opencode
26
-
27
- ```bash
28
- ls ~/.config/opencode/oh-my-opencode.json 2>/dev/null
29
- ```
30
-
31
- - If found → omo is installed. Note this for Phase 2.
32
- - If not found → skip omo-specific steps.
33
-
34
- ## Phase 2: Setup (persist to AGENTS.md)
35
-
36
- Check BOTH of these files for the RTK managed block:
37
-
38
- 1. **User-level**: `~/.config/opencode/AGENTS.md`
39
- 2. **Project-level**: `./AGENTS.md` (current workspace)
40
-
41
- For EACH file, check if `<!-- RTK:START -->` exists. If it does NOT exist, **append** the following managed block to the file (create the file if it doesn't exist). NEVER replace existing content — only append.
42
-
43
- ```markdown
44
- <!-- RTK:START -->
45
- <!-- Managed block - do not edit manually. Updated by: rtk-setup skill -->
46
-
47
- ## RTK Token Optimizer
48
-
49
- This project uses **RTK** (Rust Token Killer) to reduce LLM token consumption by 60-90%.
50
-
51
- ### Rules for ALL agents (including subagents)
52
-
53
- **ALWAYS** prefix these commands with `rtk`:
54
-
55
- | Command | Use instead |
56
- |---------|-------------|
57
- | `git status/diff/log/add/commit/push/pull` | `rtk git ...` |
58
- | `ls`, `ls -la` | `rtk ls` |
59
- | `cat file` | `rtk read file` |
60
- | `grep pattern .` / `rg pattern` | `rtk grep pattern .` |
61
- | `npm test` / `cargo test` / `pytest` | `rtk test <cmd>` |
62
- | `npm run build` / `cargo build` | `rtk err <cmd>` |
63
- | `gh pr list/view` | `rtk gh pr list/view` |
64
- | `docker ps` | `rtk docker ps` |
65
- | `eslint` / `tsc` | `rtk lint` / `rtk tsc` |
66
-
67
- **Do NOT** prefix: `npx`, `npm install`, `pip install`, `node`, `python3`, heredocs, piped commands.
68
-
69
- <!-- RTK:END -->
70
- ```
71
-
72
- ### If oh-my-opencode is installed
73
-
74
- After updating AGENTS.md files, check if the omo config at `~/.config/opencode/oh-my-opencode.json` has `prompt_append` fields on agents. If it does, inform the user:
75
-
76
- > "omo is installed. For maximum coverage, you can add RTK instructions to agent `prompt_append` fields in `oh-my-opencode.json`. This ensures subagents always use rtk even when AGENTS.md is not loaded. Want me to do this?"
77
-
78
- **Only modify `oh-my-opencode.json` if the user explicitly confirms.** If they confirm, append this line to the `prompt_append` of `sisyphus-junior` agent (the primary coder):
79
-
80
- ```
81
- \n\nRTK: ALWAYS prefix shell commands with `rtk` when available (git, ls, grep, test, build). Example: `rtk git status` not `git status`.
82
- ```
83
-
84
- Do NOT modify other agents' prompt_append unless asked.
85
-
86
- ## Phase 3: Ongoing Enforcement (EVERY time this skill is loaded)
87
-
88
- ### For the current agent
89
-
90
- From this point forward in this session, **you MUST**:
91
-
92
- 1. **Use `rtk` prefix** for all supported shell commands (see table above)
93
- 2. **Verify rtk is available** before first use: `rtk --version`
94
- 3. If rtk is not available in the current environment, fall back to normal commands silently
95
-
96
- ### For subagent delegation
97
-
98
- When delegating ANY task that involves shell commands (via `task()`, `delegate_task()`, or any delegation mechanism), **ALWAYS** add this to the `MUST DO` section of the delegation prompt:
99
-
100
- ```
101
- - Use `rtk` prefix for shell commands when available (git, ls, grep, test, build). Run `rtk --version` first to check. If not installed, use normal commands. Examples: `rtk git status`, `rtk ls`, `rtk grep pattern .`, `rtk test npm test`.
102
- ```
103
-
104
- This is NON-NEGOTIABLE. Subagents do not read AGENTS.md, so RTK instructions MUST be passed explicitly in every delegation prompt.
105
-
106
- ### Quick reference for subagent prompts
107
-
108
- Copy-paste this one-liner into MUST DO sections:
109
-
110
- > Use `rtk` prefix for all shell commands (git, ls, grep, test, build, docker). Example: `rtk git status` not `git status`. If `rtk` is not found, use normal commands.
111
-
112
- ## Summary
113
-
114
- | Phase | When | What |
115
- |-------|------|------|
116
- | Detection | Always first | Check rtk installed, check omo |
117
- | Setup | Once (idempotent) | Append RTK block to AGENTS.md (user + project) |
118
- | Enforcement | Every session | Use rtk yourself, propagate to all subagents |