feat: opencode/tinfoil backend support in all launchers
Adds LOOP_BACKEND=opencode|claude (+ LOOP_MODEL) to launch.sh and launch-upgrader.sh, enabling the loops/upgrader to run via opencode CLI against the tinfoil.sh API (deepseek-v4-pro etc.) instead of Claude. launch.sh: - LOOP_BACKEND (claude|opencode), LOOP_MODEL env vars - OPENCODE_BIN, OPENCODE_HOST (tailscale IP), OPENCODE_PORT (per-session) - start_agent: backend switch — claude path unchanged; opencode starts `opencode --hostname <ts-ip> --port <N> run <kickoff>` so the web UI is bound to the tailscale interface (tailnet-only observability) - preflight: validates the right binary per backend - heal_session / heal_orchestrator: extend active-work detection to opencode spinner chars + "Running tool" - help: shows both backend configs launch-upgrader.sh: - UPGRADER_BACKEND / UPGRADER_MODEL (LOOP_BACKEND/LOOP_MODEL override) - start: same backend switch as launch.sh - OPENCODE_PORT=4098 (separate from loops 4096/4097) configuration.nix: note opencode binary location + re-install command. Tinfoil config: ~/.config/opencode/opencode.jsonc — provider "tinfoil" with baseURL=https://api.tinfoil.sh/v1, apiKey=env:TINFOIL_API_KEY (key + TINFOIL_MODEL + TINFOIL_BASE_URL stored in .testenv). opencode v1.15.13 installed at /home/loops/.local/bin/opencode. Usage: LOOP_BACKEND=opencode LOOP_MODEL=tinfoil/deepseek-v4-pro \ RESUME_PHASE=1 cc-ci-plan/launch.sh start Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6910b197d0
commit
a87d42f491
@@ -27,22 +27,35 @@ set -euo pipefail
|
||||
|
||||
SESSION="${UPGRADER_SESSION:-cc-ci-upgrader}" # tmux session name == remote-control name
|
||||
WORKDIR="${UPGRADER_DIR:-/srv/cc-ci}" # cwd: where .claude/skills/ + .testenv live
|
||||
|
||||
# Backend selection — mirrors launch.sh. LOOP_BACKEND overrides for consistency.
|
||||
UPGRADER_BACKEND="${LOOP_BACKEND:-${UPGRADER_BACKEND:-claude}}" # "claude" or "opencode"
|
||||
# Model: LOOP_MODEL > UPGRADER_MODEL > backend default (sonnet for claude, provider/model for opencode).
|
||||
UPGRADER_MODEL="${LOOP_MODEL:-${UPGRADER_MODEL:-sonnet}}"
|
||||
|
||||
CLAUDE_BIN="${CLAUDE_BIN:-claude}"
|
||||
CLAUDE_FLAGS="${CLAUDE_FLAGS:---dangerously-skip-permissions}"
|
||||
UPGRADER_MODEL="${UPGRADER_MODEL:-sonnet}" # model for the upgrader agent (sonnet = default)
|
||||
REMOTE_CONTROL="${REMOTE_CONTROL:-1}" # 1 => --remote-control (viewable at claude.ai/code)
|
||||
OPENCODE_BIN="${OPENCODE_BIN:-/home/loops/.local/bin/opencode}"
|
||||
OPENCODE_HOST="${OPENCODE_HOST:-$(tailscale ip -4 2>/dev/null | head -1)}"
|
||||
OPENCODE_PORT="${OPENCODE_PORT:-4098}" # upgrader gets its own port offset
|
||||
REMOTE_CONTROL="${REMOTE_CONTROL:-1}" # 1 => --remote-control / opencode web
|
||||
LOG_DIR="${LOG_DIR:-/srv/cc-ci/.cc-ci-logs}"
|
||||
UPGRADER_ARGS="${UPGRADER_ARGS:-}"
|
||||
|
||||
log() { printf '[upgrader %(%H:%M:%S)T] %s\n' -1 "$*"; }
|
||||
die() { log "ERROR: $*"; exit 1; }
|
||||
session_alive() { tmux has-session -t "$SESSION" 2>/dev/null; }
|
||||
# "actively working" = the TUI shows the interrupt hint (a turn in flight). Absent => idle/finished/wedged.
|
||||
session_busy() { tmux capture-pane -pt "$SESSION" 2>/dev/null | grep -q 'esc to interrupt'; }
|
||||
# "actively working" = claude shows interrupt hint; opencode shows spinner/Running tool.
|
||||
session_busy() { tmux capture-pane -pt "$SESSION" 2>/dev/null | grep -qE 'esc to interrupt|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|⠇|⠏|Running tool'; }
|
||||
|
||||
preflight() {
|
||||
command -v tmux >/dev/null 2>&1 || die "missing dependency: tmux"
|
||||
command -v "$CLAUDE_BIN" >/dev/null 2>&1 || die "claude CLI not found (set CLAUDE_BIN)"
|
||||
case "$UPGRADER_BACKEND" in
|
||||
claude) command -v "$CLAUDE_BIN" >/dev/null 2>&1 || die "claude CLI not found (set CLAUDE_BIN)" ;;
|
||||
opencode) command -v "$OPENCODE_BIN" >/dev/null 2>&1 || die "opencode not found (set OPENCODE_BIN)"
|
||||
[[ -n "$OPENCODE_HOST" ]] || die "could not detect tailscale IP for OPENCODE_HOST" ;;
|
||||
*) die "unknown UPGRADER_BACKEND '$UPGRADER_BACKEND' — use 'claude' or 'opencode'" ;;
|
||||
esac
|
||||
[[ -d "$WORKDIR" ]] || die "workdir not found: $WORKDIR"
|
||||
[[ -d "$WORKDIR/.claude/skills/upgrade-all" ]] || die "upgrade-all skill not found under $WORKDIR/.claude/skills"
|
||||
mkdir -p "$LOG_DIR"
|
||||
@@ -88,12 +101,23 @@ start() {
|
||||
log "$SESSION exists but idle/stale (or fresh requested) — killing it first"
|
||||
tmux kill-session -t "$SESSION" 2>/dev/null || true; sleep 1
|
||||
fi
|
||||
local kf rc=""
|
||||
local kf
|
||||
kf="$(write_kickoff)"
|
||||
[[ "$REMOTE_CONTROL" == "1" ]] && rc="--remote-control '$SESSION'"
|
||||
log "starting $SESSION (cwd=$WORKDIR, rc=$REMOTE_CONTROL, model=$UPGRADER_MODEL, args='${UPGRADER_ARGS:-<none>}')"
|
||||
tmux new-session -d -s "$SESSION" -c "$WORKDIR" \
|
||||
"$CLAUDE_BIN $rc --model '$UPGRADER_MODEL' $CLAUDE_FLAGS \"\$(cat '$kf')\""
|
||||
log "starting $SESSION (backend=$UPGRADER_BACKEND, model=$UPGRADER_MODEL, args='${UPGRADER_ARGS:-<none>}')"
|
||||
case "$UPGRADER_BACKEND" in
|
||||
claude)
|
||||
local rc=""
|
||||
[[ "$REMOTE_CONTROL" == "1" ]] && rc="--remote-control '$SESSION'"
|
||||
tmux new-session -d -s "$SESSION" -c "$WORKDIR" \
|
||||
"$CLAUDE_BIN $rc --model '$UPGRADER_MODEL' $CLAUDE_FLAGS \"\$(cat '$kf')\""
|
||||
;;
|
||||
opencode)
|
||||
local web_url="http://${OPENCODE_HOST}:${OPENCODE_PORT}"
|
||||
tmux new-session -d -s "$SESSION" -c "$WORKDIR" \
|
||||
"set -a; . /srv/cc-ci/.testenv; set +a; $OPENCODE_BIN --model '$UPGRADER_MODEL' --hostname '$OPENCODE_HOST' --port '$OPENCODE_PORT' run \"\$(cat '$kf')\""
|
||||
log "$SESSION web UI: $web_url (tailnet only)"
|
||||
;;
|
||||
esac
|
||||
tmux pipe-pane -o -t "$SESSION" "cat >> '$LOG_DIR/$SESSION.log'"
|
||||
log "started. status: $0 status | attach: tmux attach -t $SESSION | log: $LOG_DIR/$SESSION.log"
|
||||
}
|
||||
@@ -118,7 +142,10 @@ cc-ci upgrader launcher — one-shot weekly recipe-upgrade job agent (remote-con
|
||||
$0 attach tmux attach to the session
|
||||
$0 stop kill the session
|
||||
|
||||
Env: SESSION=$SESSION WORKDIR=$WORKDIR REMOTE_CONTROL=$REMOTE_CONTROL UPGRADER_MODEL=$UPGRADER_MODEL UPGRADER_ARGS='${UPGRADER_ARGS:-<none>}'
|
||||
Env: UPGRADER_BACKEND=$UPGRADER_BACKEND UPGRADER_MODEL=$UPGRADER_MODEL UPGRADER_ARGS='${UPGRADER_ARGS:-<none>}'
|
||||
claude: CLAUDE_BIN=$CLAUDE_BIN REMOTE_CONTROL=$REMOTE_CONTROL
|
||||
opencode: OPENCODE_BIN=$OPENCODE_BIN web=http://${OPENCODE_HOST}:${OPENCODE_PORT} (tailnet only)
|
||||
(LOOP_BACKEND / LOOP_MODEL override UPGRADER_BACKEND / UPGRADER_MODEL for unified control)
|
||||
The agent runs /upgrade-all (DEFAULT mode) to completion, then STOPS and stays idle (viewable in the
|
||||
web UI). It does NOT self-terminate; the next weekly `start` clears the idle session and runs fresh.
|
||||
EOF
|
||||
|
||||
Reference in New Issue
Block a user