Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Options:
- `--proxy` - Proxy UI mode: `web` (default, mitmweb browser UI) or `tui` (mitmproxy console, use with `sandcat proxy` to attach)
- `--secret-provider` / `--sp` - Secret backend: `none` (default), `1password`, `protonpass` (skips prompt when set)
- `--1password` - Deprecated alias for `--secret-provider 1password`
- `--features` - Comma-separated optional non-provider features: `tui` (proxy console mode; prefer `--proxy tui`), `no-gitignore` (skip appending the `# Sandcat` block to the project's `.gitignore`; equivalent to `SANDCAT_GITIGNORE=false`), `no-rtk` (skip RTK installation; equivalent to `SANDCAT_RTK=false`), `strict-network` (project settings get network presets for the selected stacks instead of the allow-all-GET wildcard; equivalent to `SANDCAT_STRICT_NETWORK=true`)
- `--features` - Comma-separated optional non-provider features: `tui` (proxy console mode; prefer `--proxy tui`), `no-gitignore` (skip appending the `# Sandcat` block to the project's `.gitignore`; equivalent to `SANDCAT_GITIGNORE=false`), `strict-network` (project settings get network presets for the selected stacks instead of the allow-all-GET wildcard; equivalent to `SANDCAT_STRICT_NETWORK=true`)
- `--name` - Project name for Docker Compose (default: derived from directory name)
- `--path` - Project directory (default: current directory)

Expand Down
40 changes: 2 additions & 38 deletions cli/lib/agents.bash
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/usr/bin/env bash

# shellcheck source=./rtk.bash
source "${BASH_SOURCE[0]%/*}/rtk.bash"

# Returns supported agents as a space-separated list.
sct_available_agents() {
echo "claude cursor codex copilot"
Expand Down Expand Up @@ -371,7 +368,6 @@ EOF
return 0
;;
esac
sct_rtk_docker_install_block
}

# Returns Dockerfile config-home preparation block for selected agent.
Expand All @@ -397,11 +393,8 @@ EOF
;;
codex)
cat <<'EOF'
# Pre-create ~/.codex and ~/.codex-host so Docker bind-mounts don't
# create them as root-owned. The host AGENTS.md is bind-mounted into
# ~/.codex-host/ (not directly into ~/.codex/) so the user-init copy
# step can seed a writable ~/.codex/AGENTS.md that rtk can patch.
RUN mkdir -p /home/vscode/.codex /home/vscode/.codex-host
# Pre-create ~/.codex so Docker bind-mounts don't create it as root-owned.
RUN mkdir -p /home/vscode/.codex
RUN echo 'alias codex-yolo="codex --yolo"' >> /home/vscode/.bashrc
EOF
;;
Expand Down Expand Up @@ -509,34 +502,6 @@ if command -v codex >/dev/null 2>&1; then
codex --version >/dev/null 2>&1 \
|| echo "sandcat: codex --version failed (non-fatal)" >&2
fi

# Seed the writable ~/.codex/AGENTS.md from the host bind-mount so
# `rtk init --codex` can patch it. Sandcat mounts the host's
# ~/.codex/AGENTS.md read-only at ~/.codex-host/AGENTS.md (a separate
# path) precisely so this copy can happen without hitting EROFS.
# Copy is one-shot: only when ~/.codex/AGENTS.md does not exist yet
# (agent-home volume was fresh). Later host edits to AGENTS.md take
# effect after a `docker compose down -v` (or manual rm inside).
if [ -f "$HOME/.codex-host/AGENTS.md" ] && [ ! -e "$HOME/.codex/AGENTS.md" ]; then
mkdir -p "$HOME/.codex"
cp "$HOME/.codex-host/AGENTS.md" "$HOME/.codex/AGENTS.md"
elif [ ! -e "$HOME/.codex/AGENTS.md" ]; then
# No host AGENTS.md either — create empty one so rtk init has
# something to patch.
mkdir -p "$HOME/.codex"
: > "$HOME/.codex/AGENTS.md"
fi

# Auto-init rtk for codex: writes ~/.codex/RTK.md and appends an
# @RTK.md reference to ~/.codex/AGENTS.md. Idempotent — skipped once
# the reference is already present. stdin is closed so rtk's first-run
# prompts (telemetry consent) can't block container start.
if command -v rtk >/dev/null 2>&1 \
&& [ "${SANDCAT_RTK:-true}" != "false" ] \
&& ! grep -q '@RTK.md\|RTK\.md' "$HOME/.codex/AGENTS.md" 2>/dev/null; then
rtk init -g --codex </dev/null >/dev/null 2>&1 \
|| echo "sandcat: rtk init failed (non-fatal)" >&2
fi
EOF
;;
copilot)
Expand All @@ -555,5 +520,4 @@ EOF
return 0
;;
esac
sct_rtk_user_init_block "$agent"
}
2 changes: 1 addition & 1 deletion cli/lib/composefile.bash
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ add_codex_config_volumes() {
local active=${2:-true}

# shellcheck disable=SC2016
add_volume_entry "$compose_file" '${HOME}/.codex/AGENTS.md:/home/vscode/.codex-host/AGENTS.md:ro' "$active" 'Host Codex config (optional) — copied into writable ~/.codex/AGENTS.md by app-user-init.sh so rtk can patch it'
add_volume_entry "$compose_file" '${HOME}/.codex/AGENTS.md:/home/vscode/.codex/AGENTS.md:ro' "$active" 'Host Codex config (optional)'
# shellcheck disable=SC2016
add_volume_entry "$compose_file" '${HOME}/.codex/skills:/home/vscode/.codex/skills:ro' "$active"
# shellcheck disable=SC2016
Expand Down
99 changes: 0 additions & 99 deletions cli/lib/rtk.bash

This file was deleted.

13 changes: 1 addition & 12 deletions cli/libexec/init/init
Original file line number Diff line number Diff line change
Expand Up @@ -307,19 +307,16 @@ init() {
# tui → mitmproxy console instead of web UI
# no-shared-cache → disable shared JVM dependency cache volumes
# no-gitignore → skip appending the Sandcat block to .gitignore
# no-rtk → skip installing the rtk shell hook
# strict-network → project settings get stack network presets instead
# of the allow-all-GET wildcard (default deny beyond
# the presets and the user-settings layer)
local gitignore_enabled=${SANDCAT_GITIGNORE:-true}
local rtk_enabled=${SANDCAT_RTK:-true}
local strict_network=${SANDCAT_STRICT_NETWORK:-false}
if [[ "$features_provided" != "true" ]]; then
local available_features=(
"tui (mitmproxy console instead of web UI)"
"no-shared-cache (per-project dep cache instead of shared)"
"no-gitignore (do not append Sandcat block to .gitignore)"
"no-rtk (do not install rtk shell hook)"
"strict-network (stack presets instead of allow-all-GET wildcard)"
)
local selected_features
Expand All @@ -332,7 +329,6 @@ init() {
tui) proxy_mode="tui" ;;
no-shared-cache) export SANDCAT_MOUNT_SHARED_CACHE="false" ;;
no-gitignore) gitignore_enabled=false ;;
no-rtk) rtk_enabled=false ;;
strict-network) strict_network=true ;;
esac
done
Expand All @@ -345,13 +341,12 @@ init() {
tui) proxy_mode="tui" ;;
no-shared-cache) export SANDCAT_MOUNT_SHARED_CACHE="false" ;;
no-gitignore) gitignore_enabled=false ;;
no-rtk) rtk_enabled=false ;;
strict-network) strict_network=true ;;
1password)
echo "Use --secret-provider 1password instead of --features 1password" | error
return 1
;;
*) echo "Unknown feature: $f (expected: tui, no-shared-cache, no-gitignore, no-rtk, strict-network)" | error; return 1 ;;
*) echo "Unknown feature: $f (expected: tui, no-shared-cache, no-gitignore, strict-network)" | error; return 1 ;;
esac
done
fi
Expand Down Expand Up @@ -416,7 +411,6 @@ init() {
--proxy "$proxy_mode"
--secret-provider "$secret_provider"
)
export SANDCAT_RTK="$rtk_enabled"
devcontainer "${devcontainer_args[@]}"

local gitignore_status="skipped"
Expand Down Expand Up @@ -460,11 +454,6 @@ init() {
echo " User settings: ~/.config/sandcat/settings.json (git identity, API keys)" | info
echo " Devcontainer: .devcontainer/" | info
echo " Gitignore: $gitignore_status" | info
if [[ "$rtk_enabled" == "true" ]]; then
echo " RTK: installed (disable with --features no-rtk)" | info
else
echo " RTK: disabled" | info
fi
if [[ "$strict_network" == "true" ]]; then
local preset_summary="${stacks_resolved:-none}"
echo " Network: strict — stack presets: ${preset_summary// /, } (edit .sandcat/settings.json to allow more)" | info
Expand Down
94 changes: 5 additions & 89 deletions cli/test/agents/agents.bats
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ setup() {
}

@test "sct_agent_docker_install_block: codex installs codex to /usr/local/bin" {
unset SANDCAT_RTK
run sct_agent_docker_install_block codex
assert_output --partial "chatgpt.com/codex/install.sh"
assert_output --partial "CODEX_INSTALL_DIR=/usr/local/bin"
Expand All @@ -351,49 +350,11 @@ setup() {
refute_output --partial "ENV CODEX_INSTALL_DIR"
}

@test "sct_agent_docker_install_block: codex append rtk install when enabled" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_docker_install_block codex
assert_output --partial "chatgpt.com/codex/install.sh"
assert_output --partial "raw.githubusercontent.com/rtk-ai/rtk"
}

@test "sct_agent_docker_install_block: codex skips rtk when SANDCAT_RTK=false" {
source "$SCT_LIBDIR/rtk.bash"
SANDCAT_RTK=false run sct_agent_docker_install_block codex
assert_output --partial "chatgpt.com/codex/install.sh"
refute_output --partial "raw.githubusercontent.com/rtk-ai/rtk"
}

@test "sct_agent_docker_install_block: unknown returns empty" {
run sct_agent_docker_install_block unknown
assert_output ""
}

@test "sct_agent_docker_install_block: claude append rtk install when enabled" {
# shellcheck source=../../lib/rtk.bash
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_docker_install_block claude
assert_output --partial "claude.ai/install.sh"
assert_output --partial "raw.githubusercontent.com/rtk-ai/rtk"
}

@test "sct_agent_docker_install_block: claude skips rtk when SANDCAT_RTK=false" {
source "$SCT_LIBDIR/rtk.bash"
SANDCAT_RTK=false run sct_agent_docker_install_block claude
assert_output --partial "claude.ai/install.sh"
refute_output --partial "raw.githubusercontent.com/rtk-ai/rtk"
}

@test "sct_agent_docker_install_block: unknown returns empty even with rtk enabled" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_docker_install_block unknown
assert_output ""
}

# --------------------------------------------------- Dockerfile home prep

@test "sct_agent_docker_home_prep_block: claude pre-creates ~/.claude" {
Expand All @@ -406,10 +367,9 @@ setup() {
assert_output --partial "/home/vscode/.cursor"
}

@test "sct_agent_docker_home_prep_block: codex pre-creates ~/.codex, ~/.codex-host and codex-yolo alias" {
@test "sct_agent_docker_home_prep_block: codex pre-creates ~/.codex and codex-yolo alias" {
run sct_agent_docker_home_prep_block codex
assert_output --partial "/home/vscode/.codex"
assert_output --partial "/home/vscode/.codex-host"
assert_output --partial 'alias codex-yolo="codex --yolo"'
}

Expand All @@ -431,58 +391,14 @@ setup() {
assert_output --partial "Sandcat cursor.cli"
}

@test "sct_agent_user_init_block: unknown returns empty" {
run sct_agent_user_init_block unknown
assert_output ""
}

@test "sct_agent_user_init_block: claude appends rtk init when enabled" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_user_init_block claude
assert_output --partial "hasCompletedOnboarding"
assert_output --partial "rtk init -g"
}

@test "sct_agent_user_init_block: claude skips rtk when SANDCAT_RTK=false" {
source "$SCT_LIBDIR/rtk.bash"
SANDCAT_RTK=false run sct_agent_user_init_block claude
assert_output --partial "hasCompletedOnboarding"
refute_output --partial "rtk init"
}

@test "sct_agent_user_init_block: cursor appends rtk init when enabled" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_user_init_block cursor
assert_output --partial "cursor-cli-config.json"
assert_output --partial "rtk init -g --hook-only --auto-patch --agent cursor"
}

@test "sct_agent_user_init_block: cursor skips rtk when SANDCAT_RTK=false" {
source "$SCT_LIBDIR/rtk.bash"
SANDCAT_RTK=false run sct_agent_user_init_block cursor
assert_output --partial "cursor-cli-config.json"
refute_output --partial "rtk init"
}

@test "sct_agent_user_init_block: codex emits rtk init --codex + host AGENTS.md seed" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
@test "sct_agent_user_init_block: codex runs health check" {
run sct_agent_user_init_block codex
assert_output --partial "codex --version"
assert_output --partial "rtk init -g --codex </dev/null"
assert_output --partial ".codex-host/AGENTS.md"
assert_output --partial "@RTK.md"
assert_output --partial "non-fatal"
}

@test "sct_agent_user_init_block: codex has SANDCAT_RTK runtime guard" {
source "$SCT_LIBDIR/rtk.bash"
unset SANDCAT_RTK
run sct_agent_user_init_block codex
assert_output --partial 'SANDCAT_RTK:-true'
assert_output --partial '!= "false"'
@test "sct_agent_user_init_block: unknown returns empty" {
run sct_agent_user_init_block unknown
assert_output ""
}

# --------------------------------------------------- mitm streaming flags
Expand Down
Loading
Loading