@kokorolx/ai-sandbox-wrapper 2.7.0 → 3.0.1

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.
@@ -0,0 +1,118 @@
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 |
package/lib/AGENTS.md CHANGED
@@ -49,6 +49,20 @@ lib/
49
49
  | CodeServer | `install-codeserver.sh` | VSCode browser |
50
50
  | VSCode | `install-vscode.sh` | Desktop X11 |
51
51
 
52
+ ## File Writing Rules (MANDATORY)
53
+
54
+ **NEVER write an entire file at once.** Always use chunk-by-chunk editing:
55
+
56
+ 1. **Use the Edit tool** (find-and-replace) for all file modifications — insert, update, or delete content in targeted chunks
57
+ 2. **Only use the Write tool** for brand-new files that don't exist yet, AND only if the file is small (< 50 lines)
58
+ 3. **For new large files (50+ lines):** Write a skeleton first (headers/structure only), then use Edit to fill in each section chunk by chunk
59
+ 4. **Why:** Writing entire files at once causes truncation, context window overflow, and silent data loss on large files
60
+
61
+ **Anti-patterns (NEVER do these):**
62
+ - `Write` tool to overwrite an existing file with full content
63
+ - `Write` tool to create a file with 100+ lines in one shot
64
+ - Regenerating an entire file to change a few lines
65
+
52
66
  ## Conventions
53
67
 
54
68
  - Scripts use `set -e` for fail-fast
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ TOOLS="${TOOLS:-}"
5
+ if [[ -z "$TOOLS" ]]; then
6
+ echo "❌ No tools selected. Set TOOLS=tool1,tool2,..."
7
+ exit 1
8
+ fi
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
+ cd "$PROJECT_DIR"
13
+
14
+ SANDBOX_DIR="dockerfiles/sandbox"
15
+ mkdir -p "$SANDBOX_DIR"
16
+
17
+ echo "🔄 Generating unified sandbox Dockerfile..."
18
+ echo " Tools: $TOOLS"
19
+
20
+ GENERATE_ONLY=1 INSTALL_RTK="${INSTALL_RTK:-0}" \
21
+ INSTALL_PLAYWRIGHT_MCP="${INSTALL_PLAYWRIGHT_MCP:-0}" \
22
+ INSTALL_CHROME_DEVTOOLS_MCP="${INSTALL_CHROME_DEVTOOLS_MCP:-0}" \
23
+ INSTALL_PLAYWRIGHT="${INSTALL_PLAYWRIGHT:-0}" \
24
+ INSTALL_RUBY="${INSTALL_RUBY:-0}" \
25
+ INSTALL_SPEC_KIT="${INSTALL_SPEC_KIT:-0}" \
26
+ INSTALL_UX_UI_PROMAX="${INSTALL_UX_UI_PROMAX:-0}" \
27
+ INSTALL_OPENSPEC="${INSTALL_OPENSPEC:-0}" \
28
+ bash "$SCRIPT_DIR/install-base.sh"
29
+
30
+ BASE_DOCKERFILE="dockerfiles/base/Dockerfile"
31
+ if [[ ! -f "$BASE_DOCKERFILE" ]]; then
32
+ echo "❌ Base Dockerfile not found at $BASE_DOCKERFILE"
33
+ exit 1
34
+ fi
35
+
36
+ BASE_CONTENT=$(cat "$BASE_DOCKERFILE")
37
+ BASE_PREAMBLE=$(echo "$BASE_CONTENT" | sed '/^USER agent$/,$d')
38
+
39
+ {
40
+ echo "$BASE_PREAMBLE"
41
+ echo ""
42
+
43
+ IFS=',' read -ra TOOL_ARRAY <<< "$TOOLS"
44
+ for tool in "${TOOL_ARRAY[@]}"; do
45
+ tool=$(echo "$tool" | tr -d ' ')
46
+ INSTALL_SCRIPT="$SCRIPT_DIR/install-${tool}.sh"
47
+
48
+ if [[ ! -f "$INSTALL_SCRIPT" ]]; then
49
+ echo "⚠️ Warning: No install script for '$tool', skipping" >&2
50
+ continue
51
+ fi
52
+
53
+ echo "# === $tool ==="
54
+ SNIPPET_MODE=1 source "$INSTALL_SCRIPT"
55
+ dockerfile_snippet
56
+ echo ""
57
+ done
58
+
59
+ echo "USER agent"
60
+ echo "ENV HOME=/home/agent"
61
+ echo "CMD [\"bash\"]"
62
+ } > "$SANDBOX_DIR/Dockerfile"
63
+
64
+ if [[ -d "dockerfiles/base/skills" ]]; then
65
+ cp -r "dockerfiles/base/skills" "$SANDBOX_DIR/"
66
+ fi
67
+
68
+ echo "✅ Dockerfile generated at $SANDBOX_DIR/Dockerfile"
69
+
70
+ echo "🔨 Building ai-sandbox:latest..."
71
+ HOST_UID=$(id -u)
72
+ docker build ${DOCKER_NO_CACHE:+--no-cache} \
73
+ --build-arg AGENT_UID="${HOST_UID}" \
74
+ -t "ai-sandbox:latest" "$SANDBOX_DIR"
75
+
76
+ echo "✅ ai-sandbox:latest built successfully"
77
+
78
+ SANDBOX_CONFIG="$HOME/.ai-sandbox/config.json"
79
+ if command -v jq &>/dev/null && [[ -f "$SANDBOX_CONFIG" ]]; then
80
+ TOOLS_JSON=$(echo "$TOOLS" | tr ',' '\n' | jq -R . | jq -s .)
81
+ jq --argjson tools "$TOOLS_JSON" '.tools.installed = $tools' "$SANDBOX_CONFIG" > "$SANDBOX_CONFIG.tmp" \
82
+ && mv "$SANDBOX_CONFIG.tmp" "$SANDBOX_CONFIG"
83
+ chmod 600 "$SANDBOX_CONFIG"
84
+ echo "✅ Saved tools list to $SANDBOX_CONFIG"
85
+ fi
86
+
87
+ echo ""
88
+ echo "🎉 Sandbox ready with tools: $TOOLS"
89
+ echo " Run: docker run --rm -it ai-sandbox:latest"
@@ -1,7 +1,17 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Aider installer: Python-based AI coding assistant
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER agent
7
+ RUN python3 -m pip install --break-system-packages aider-install && aider-install
8
+ SNIPPET
9
+ }
10
+
11
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
12
+ return 0 2>/dev/null || exit 0
13
+ fi
14
+
5
15
  TOOL="aider"
6
16
 
7
17
  echo "Installing $TOOL (Python-based AI pair programmer)..."
@@ -1,7 +1,21 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Amp installer: Sourcegraph's AI coding assistant
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/amp && \
8
+ cd /usr/local/lib/amp && \
9
+ bun init -y && \
10
+ bun add @sourcegraph/amp && \
11
+ ln -s /usr/local/lib/amp/node_modules/.bin/amp /usr/local/bin/amp
12
+ SNIPPET
13
+ }
14
+
15
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
16
+ return 0 2>/dev/null || exit 0
17
+ fi
18
+
5
19
  TOOL="amp"
6
20
 
7
21
  echo "Installing $TOOL (Sourcegraph Amp)..."
@@ -15,20 +29,14 @@ mkdir -p "$HOME/.ai-sandbox/tools/$TOOL/home"
15
29
  cat <<'EOF' > "dockerfiles/$TOOL/Dockerfile"
16
30
  FROM ai-base:latest
17
31
 
18
- # Switch to root only for installing bun globally (needed for the system)
19
32
  USER root
20
- RUN npm install -g bun
21
- USER agent
22
-
23
- # Install Amp into user directory
24
- RUN mkdir -p /home/agent/lib/amp && \
25
- cd /home/agent/lib/amp && \
33
+ RUN mkdir -p /usr/local/lib/amp && \
34
+ cd /usr/local/lib/amp && \
26
35
  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}"
36
+ bun add @sourcegraph/amp && \
37
+ ln -s /usr/local/lib/amp/node_modules/.bin/amp /usr/local/bin/amp
31
38
 
39
+ USER agent
32
40
  ENTRYPOINT ["amp"]
33
41
  EOF
34
42
 
@@ -1,7 +1,22 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Auggie CLI installer: Augment Code's AI assistant
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/auggie && \
8
+ cd /usr/local/lib/auggie && \
9
+ bun init -y && \
10
+ bun add @augmentcode/auggie && \
11
+ ln -s /usr/local/lib/auggie/node_modules/.bin/auggie /usr/local/bin/auggie
12
+ USER agent
13
+ SNIPPET
14
+ }
15
+
16
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
17
+ return 0 2>/dev/null || exit 0
18
+ fi
19
+
5
20
  TOOL="auggie"
6
21
 
7
22
  echo "Installing $TOOL (Augment Auggie CLI)..."
@@ -49,6 +49,22 @@ RUN cargo install --git https://github.com/rtk-ai/rtk --locked
49
49
  ADDITIONAL_TOOLS_INSTALL+='# Install RTK - token optimizer for AI coding agents (built from source)
50
50
  COPY --from=rtk-builder /usr/local/cargo/bin/rtk /usr/local/bin/rtk
51
51
  '
52
+ # Copy RTK OpenCode skills into build context so they can be COPY'd into the image
53
+ SCRIPT_BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
54
+ RTK_SKILLS_SRC="${SCRIPT_BASE_DIR}/../skills"
55
+ if [[ -d "$RTK_SKILLS_SRC/rtk" && -d "$RTK_SKILLS_SRC/rtk-setup" ]]; then
56
+ mkdir -p "dockerfiles/base/skills/rtk" "dockerfiles/base/skills/rtk-setup"
57
+ cp "$RTK_SKILLS_SRC/rtk/SKILL.md" "dockerfiles/base/skills/rtk/SKILL.md"
58
+ cp "$RTK_SKILLS_SRC/rtk-setup/SKILL.md" "dockerfiles/base/skills/rtk-setup/SKILL.md"
59
+ ADDITIONAL_TOOLS_INSTALL+='# Install RTK OpenCode skills (auto-discovered by OpenCode agents)
60
+ RUN mkdir -p /home/agent/.config/opencode/skills/rtk /home/agent/.config/opencode/skills/rtk-setup
61
+ COPY skills/rtk/SKILL.md /home/agent/.config/opencode/skills/rtk/SKILL.md
62
+ COPY skills/rtk-setup/SKILL.md /home/agent/.config/opencode/skills/rtk-setup/SKILL.md
63
+ '
64
+ echo " ✅ RTK OpenCode skills will be copied into container"
65
+ else
66
+ echo " ⚠️ RTK skills not found at $RTK_SKILLS_SRC — skipping skill installation"
67
+ fi
52
68
  fi
53
69
 
54
70
  if [[ "${INSTALL_PLAYWRIGHT:-0}" -eq 1 ]]; then
@@ -112,7 +128,7 @@ ENV PATH=$RBENV_ROOT/bin:$RBENV_ROOT/shims:$PATH
112
128
 
113
129
  RUN rbenv install 3.3.0 && rbenv global 3.3.0 && rbenv rehash
114
130
 
115
- RUN gem install rails -v 8.0.2 && gem install bundler && rbenv rehash
131
+ RUN gem install rails -v 8.0.2 && gem install bundler solargraph && rbenv rehash
116
132
  '
117
133
  fi
118
134
 
@@ -201,10 +217,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
201
217
  xclip \
202
218
  wl-clipboard \
203
219
  ripgrep \
220
+ tmux \
221
+ fd-find \
222
+ sqlite3 \
223
+ poppler-utils \
224
+ qpdf \
225
+ tesseract-ocr \
204
226
  && curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh \
205
227
  && rm -rf /var/lib/apt/lists/* \
206
228
  && pipx ensurepath
207
229
 
230
+ # Install Python PDF processing tools for PDF skill
231
+ RUN pip3 install --no-cache-dir --break-system-packages pypdf pdfplumber reportlab pytesseract pdf2image
232
+
208
233
  RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
209
234
  && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
210
235
  && 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 \
@@ -212,11 +237,14 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | d
212
237
  && apt-get install -y gh \
213
238
  && rm -rf /var/lib/apt/lists/*
214
239
 
240
+ # Install bun (used by most AI tool install scripts)
241
+ RUN npm install -g bun
242
+
215
243
  # Install pnpm globally using npm (not bun, for stability)
216
244
  RUN npm install -g pnpm
217
245
 
218
246
  # Install TypeScript and LSP tools using npm
219
- RUN npm install -g typescript typescript-language-server
247
+ RUN npm install -g typescript typescript-language-server pyright vscode-langservers-extracted
220
248
 
221
249
  # Verify installations
222
250
  RUN node --version && npm --version && pnpm --version && tsc --version
@@ -235,6 +263,12 @@ USER agent
235
263
  ENV HOME=/home/agent
236
264
  EOF
237
265
 
266
+ # GENERATE_ONLY mode: write Dockerfile but don't build
267
+ if [[ "${GENERATE_ONLY:-0}" -eq 1 ]]; then
268
+ echo "✅ Base Dockerfile generated at dockerfiles/base/Dockerfile"
269
+ exit 0
270
+ fi
271
+
238
272
  echo "Building base Docker image..."
239
273
  HOST_UID=$(id -u)
240
274
  docker build ${DOCKER_NO_CACHE:+--no-cache} \
@@ -1,7 +1,27 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Claude Code installer: Anthropic's AI coding agent (Native Binary)
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN apt-get update && apt-get install -y --no-install-recommends tmux && rm -rf /var/lib/apt/lists/*
8
+ RUN npm install -g @kaitranntt/ccs --ignore-scripts && \
9
+ mkdir -p /home/agent/.ccs && \
10
+ chown -R agent:agent /home/agent/.ccs && \
11
+ which ccs && ccs --version && \
12
+ sed -i 's/fs\.symlinkSync(sourcePath, targetPath, symlinkType)/fs\.symlinkSync(require("path").relative(require("path").dirname(targetPath), sourcePath), targetPath, symlinkType)/g' /usr/local/lib/node_modules/@kaitranntt/ccs/dist/utils/claude-symlink-manager.js
13
+ RUN export HOME=/root && curl -fsSL https://claude.ai/install.sh | bash && \
14
+ mkdir -p /usr/local/share && \
15
+ mv /root/.local/share/claude /usr/local/share/claude && \
16
+ ln -sf /usr/local/share/claude/versions/$(ls /usr/local/share/claude/versions | head -1) /usr/local/bin/claude
17
+ USER agent
18
+ SNIPPET
19
+ }
20
+
21
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
22
+ return 0 2>/dev/null || exit 0
23
+ fi
24
+
5
25
  TOOL="claude"
6
26
 
7
27
  echo "Installing $TOOL (Anthropic Claude Code - Native Binary)..."
@@ -24,12 +44,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends tmux && rm -rf
24
44
  RUN npm install -g @kaitranntt/ccs --ignore-scripts && \
25
45
  mkdir -p /home/agent/.ccs && \
26
46
  chown -R agent:agent /home/agent/.ccs && \
27
- which ccs && ccs --version
47
+ which ccs && ccs --version && \
48
+ sed -i 's/fs\.symlinkSync(sourcePath, targetPath, symlinkType)/fs\.symlinkSync(require("path").relative(require("path").dirname(targetPath), sourcePath), targetPath, symlinkType)/g' /usr/local/lib/node_modules/@kaitranntt/ccs/dist/utils/claude-symlink-manager.js
28
49
 
29
50
  # Install Claude Code using official native installer
30
- RUN curl -fsSL https://claude.ai/install.sh | bash && \
51
+ RUN export HOME=/root && curl -fsSL https://claude.ai/install.sh | bash && \
31
52
  mkdir -p /usr/local/share && \
32
- mv /home/agent/.local/share/claude /usr/local/share/claude && \
53
+ mv /root/.local/share/claude /usr/local/share/claude && \
33
54
  ln -sf /usr/local/share/claude/versions/$(ls /usr/local/share/claude/versions | head -1) /usr/local/bin/claude
34
55
 
35
56
  USER agent
@@ -1,7 +1,22 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # CodeBuddy CLI installer: Tencent's AI assistant
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/codebuddy && \
8
+ cd /usr/local/lib/codebuddy && \
9
+ bun init -y && \
10
+ bun add @tencent-ai/codebuddy-code && \
11
+ ln -s /usr/local/lib/codebuddy/node_modules/.bin/codebuddy /usr/local/bin/codebuddy
12
+ USER agent
13
+ SNIPPET
14
+ }
15
+
16
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
17
+ return 0 2>/dev/null || exit 0
18
+ fi
19
+
5
20
  TOOL="codebuddy"
6
21
 
7
22
  echo "Installing $TOOL (Tencent CodeBuddy CLI)..."
@@ -1,7 +1,22 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Codex CLI installer: OpenAI's terminal coding agent
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/codex && \
8
+ cd /usr/local/lib/codex && \
9
+ bun init -y && \
10
+ bun add @openai/codex && \
11
+ ln -s /usr/local/lib/codex/node_modules/.bin/codex /usr/local/bin/codex
12
+ USER agent
13
+ SNIPPET
14
+ }
15
+
16
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
17
+ return 0 2>/dev/null || exit 0
18
+ fi
19
+
5
20
  TOOL="codex"
6
21
 
7
22
  echo "Installing $TOOL (OpenAI Codex CLI)..."
@@ -1,6 +1,20 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /home/agent/.factory && chown -R agent:agent /home/agent/.factory && \
8
+ export HOME=/root && bash -c "curl -fsSL https://app.factory.ai/cli | sh" && \
9
+ mv /root/.local/bin/droid /usr/local/bin/droid
10
+ USER agent
11
+ SNIPPET
12
+ }
13
+
14
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
15
+ return 0 2>/dev/null || exit 0
16
+ fi
17
+
4
18
  echo "Installing droid (Factory CLI)..."
5
19
 
6
20
  # Create directories
@@ -12,10 +26,9 @@ mkdir -p "$HOME/.ai-sandbox/tools/droid/home"
12
26
  cat <<'EOF' > "dockerfiles/droid/Dockerfile"
13
27
  FROM ai-base:latest
14
28
  USER root
15
- RUN mkdir -p /home/agent/.factory && \
16
- bash -c "curl -fsSL https://app.factory.ai/cli | sh" && \
17
- mv /home/agent/.local/bin/droid /usr/local/bin/droid && \
18
- chown -R agent:agent /home/agent/.factory
29
+ RUN mkdir -p /home/agent/.factory && chown -R agent:agent /home/agent/.factory && \
30
+ export HOME=/root && bash -c "curl -fsSL https://app.factory.ai/cli | sh" && \
31
+ mv /root/.local/bin/droid /usr/local/bin/droid
19
32
  USER agent
20
33
  ENTRYPOINT ["bash", "-c", "exec droid \"$@\"", "--"]
21
34
  EOF
@@ -1,7 +1,22 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Gemini CLI installer: Google's AI coding agent
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/gemini && \
8
+ cd /usr/local/lib/gemini && \
9
+ bun init -y && \
10
+ bun add @google/gemini-cli && \
11
+ ln -s /usr/local/lib/gemini/node_modules/.bin/gemini /usr/local/bin/gemini
12
+ USER agent
13
+ SNIPPET
14
+ }
15
+
16
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
17
+ return 0 2>/dev/null || exit 0
18
+ fi
19
+
5
20
  TOOL="gemini"
6
21
 
7
22
  echo "Installing $TOOL (Google Gemini CLI)..."
@@ -1,7 +1,22 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Jules CLI installer: Google's AI coding assistant
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN mkdir -p /usr/local/lib/jules && \
8
+ cd /usr/local/lib/jules && \
9
+ bun init -y && \
10
+ bun add @google/jules && \
11
+ ln -s /usr/local/lib/jules/node_modules/.bin/jules /usr/local/bin/jules
12
+ USER agent
13
+ SNIPPET
14
+ }
15
+
16
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
17
+ return 0 2>/dev/null || exit 0
18
+ fi
19
+
5
20
  TOOL="jules"
6
21
 
7
22
  echo "Installing $TOOL (Google Jules CLI)..."
@@ -1,8 +1,18 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # Kilo Code installer: Multi-model AI coding agent
5
- # Note: Uses npm instead of bun due to cheerio dependency resolution issue
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN npm install -g @kilocode/cli
8
+ USER agent
9
+ SNIPPET
10
+ }
11
+
12
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
13
+ return 0 2>/dev/null || exit 0
14
+ fi
15
+
6
16
  TOOL="kilo"
7
17
 
8
18
  echo "Installing $TOOL (Kilo Code CLI)..."
@@ -1,7 +1,16 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
- # OpenClaw installer: Uses official Docker Compose setup
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ # openclaw uses docker-compose and is handled separately - no Dockerfile snippet
7
+ SNIPPET
8
+ }
9
+
10
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
11
+ return 0 2>/dev/null || exit 0
12
+ fi
13
+
5
14
  TOOL="openclaw"
6
15
 
7
16
  echo "🔄 Installing $TOOL (OpenClaw - Official Docker Compose)..."
@@ -1,6 +1,19 @@
1
1
  #!/usr/bin/env bash
2
2
  set -e
3
3
 
4
+ dockerfile_snippet() {
5
+ cat <<'SNIPPET'
6
+ USER root
7
+ RUN curl -fsSL https://opencode.ai/install | bash && \
8
+ mv /root/.opencode/bin/opencode /usr/local/bin/opencode && \
9
+ rm -rf /root/.opencode
10
+ SNIPPET
11
+ }
12
+
13
+ if [[ "${SNIPPET_MODE:-}" == "1" ]]; then
14
+ return 0 2>/dev/null || exit 0
15
+ fi
16
+
4
17
  TOOL="opencode"
5
18
  OPENCODE_VERSION="${OPENCODE_VERSION:-}"
6
19
 
@@ -20,8 +33,8 @@ FROM ai-base:latest
20
33
 
21
34
  USER root
22
35
  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
36
+ mv /root/.opencode/bin/opencode /usr/local/bin/opencode && \\
37
+ rm -rf /root/.opencode
25
38
 
26
39
  USER agent
27
40
  ENTRYPOINT ["opencode"]
@@ -32,8 +45,8 @@ FROM ai-base:latest
32
45
 
33
46
  USER root
34
47
  RUN curl -fsSL https://opencode.ai/install | bash && \
35
- mv /home/agent/.opencode/bin/opencode /usr/local/bin/opencode && \
36
- rm -rf /home/agent/.opencode
48
+ mv /root/.opencode/bin/opencode /usr/local/bin/opencode && \
49
+ rm -rf /root/.opencode
37
50
 
38
51
  USER agent
39
52
  ENTRYPOINT ["opencode"]