feat(sandbox): podman backend + goose AI harness + noVNC GUI sandbox
Add Podman as a rootless/daemonless sandbox backend alongside Docker, Multipass and Local, and wire Goose in as the default agentic harness for the granted `!task` path (bridge execs `<engine> exec <name> goose run` and streams output to chat; auto-degrades to the simple one-shot injector when goose is absent). Add an optional GUI sandbox track (XFCE + TigerVNC + websockify/noVNC on :6080) summoned via `/sbx <engine> gui`, plus container-side provisioning in sandbox-bootstrap.sh and a host-side ensure-podman.sh prereq helper. Refresh the in-app command help to the backend-led `/sbx <engine> [gui]` grammar and minor ui tweaks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,18 @@
|
||||
#
|
||||
# The baseline is untouched: ./bootstrap.sh alone never installs or enables AI.
|
||||
#
|
||||
# It also installs Goose (block/goose) by default — the agentic harness the /ai
|
||||
# agent uses for the sandbox `!task` path — and writes a host Goose config that
|
||||
# points it at the local Ollama. Skip it with --no-goose (the agent still works:
|
||||
# the bridge falls back to its built-in one-shot injector).
|
||||
#
|
||||
# usage:
|
||||
# ./bootstrap-ai.sh # baseline setup + Ollama + default model
|
||||
# ./bootstrap-ai.sh # baseline setup + Ollama + default model + Goose
|
||||
# ./bootstrap-ai.sh --release # ...and build the client in release mode
|
||||
# ./bootstrap-ai.sh --check # report only; install/pull nothing
|
||||
# ./bootstrap-ai.sh --yes # don't prompt before installing Ollama / pulling the model
|
||||
# ./bootstrap-ai.sh --ai-only # only the AI layer; skip the baseline ./bootstrap.sh
|
||||
# ./bootstrap-ai.sh --no-goose # skip the Goose harness install (one-shot injector only)
|
||||
# ./bootstrap-ai.sh -h | --help # this help
|
||||
#
|
||||
# environment:
|
||||
@@ -25,19 +31,22 @@ ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
MODEL="${HH_AI_MODEL:-qwen2.5:3b}"
|
||||
OLLAMA_HOST="${OLLAMA_HOST:-http://localhost:11434}"
|
||||
INSTALLER_URL="https://ollama.com/install.sh"
|
||||
GOOSE_INSTALLER_URL="https://github.com/block/goose/releases/download/stable/download_cli.sh"
|
||||
|
||||
RELEASE_ARGS=()
|
||||
CHECK_ONLY=0
|
||||
ASSUME_YES=0
|
||||
AI_ONLY=0
|
||||
DO_GOOSE=1
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--release) RELEASE_ARGS+=(--release) ;;
|
||||
--check) CHECK_ONLY=1 ;;
|
||||
--yes|-y) ASSUME_YES=1 ;;
|
||||
--ai-only) AI_ONLY=1 ;;
|
||||
--release) RELEASE_ARGS+=(--release) ;;
|
||||
--check) CHECK_ONLY=1 ;;
|
||||
--yes|-y) ASSUME_YES=1 ;;
|
||||
--ai-only) AI_ONLY=1 ;;
|
||||
--no-goose) DO_GOOSE=0 ;;
|
||||
-h|--help|-help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "✖ unknown arg: $arg (try --release / --check / --yes / --ai-only / --help)" >&2; exit 2 ;;
|
||||
*) echo "✖ unknown arg: $arg (try --release / --check / --yes / --ai-only / --no-goose / --help)" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -65,6 +74,14 @@ if have ollama; then echo " ✓ ollama ($(ollama --version 2>&1 | head -1))"
|
||||
else echo " · ollama not installed"; fi
|
||||
if ollama_up; then echo " ✓ ollama daemon reachable at $OLLAMA_HOST"
|
||||
else echo " · ollama daemon not reachable at $OLLAMA_HOST"; fi
|
||||
# Goose may install to ~/.local/bin, which isn't always on PATH in this shell.
|
||||
goose_bin() { command -v goose 2>/dev/null || { [[ -x "$HOME/.local/bin/goose" ]] && echo "$HOME/.local/bin/goose"; }; }
|
||||
if [[ $DO_GOOSE -eq 1 ]]; then
|
||||
if [[ -n "$(goose_bin)" ]]; then echo " ✓ goose ($("$(goose_bin)" --version 2>&1 | head -1))"
|
||||
else echo " · goose not installed (will install — the agent's default !task harness)"; fi
|
||||
else
|
||||
echo " · goose skipped (--no-goose; agent uses its one-shot injector)"
|
||||
fi
|
||||
|
||||
if [[ $CHECK_ONLY -eq 1 ]]; then
|
||||
echo "--check: no changes made"
|
||||
@@ -126,6 +143,56 @@ else
|
||||
echo " ✓ model '$MODEL' ready"
|
||||
fi
|
||||
|
||||
# 5. Goose harness (default on; --no-goose skips). Goose is the agentic harness
|
||||
# the /ai agent runs for the sandbox `!task` path. It ships as a release binary
|
||||
# (not apt/pip), so we use its official installer with CONFIGURE=false to skip
|
||||
# the interactive setup — we write a minimal host config ourselves instead.
|
||||
# Failure here is non-fatal: the bridge falls back to its built-in one-shot
|
||||
# injector, so the agent still works without Goose.
|
||||
if [[ $DO_GOOSE -eq 1 ]]; then
|
||||
echo
|
||||
echo "── Goose harness ──"
|
||||
if [[ -z "$(goose_bin)" ]]; then
|
||||
if [[ "$(uname -s)" != "Linux" && "$(uname -s)" != "Darwin" ]]; then
|
||||
echo " ✖ automatic Goose install supports Linux/macOS only — see https://block.github.io/goose/ ; the agent will use its one-shot injector." >&2
|
||||
else
|
||||
echo " Goose is not installed. The official installer will run:"
|
||||
echo " curl -fsSL $GOOSE_INSTALLER_URL | CONFIGURE=false bash"
|
||||
proceed=1
|
||||
if [[ $ASSUME_YES -ne 1 && -t 0 ]]; then
|
||||
read -r -p " install Goose now? [Y/n] " ans
|
||||
[[ -z "$ans" || "$ans" == [yY]* ]] || proceed=0
|
||||
fi
|
||||
if [[ $proceed -eq 1 ]]; then
|
||||
if curl -fsSL "$GOOSE_INSTALLER_URL" | CONFIGURE=false bash; then
|
||||
echo " ✓ goose installed ($([ -n "$(goose_bin)" ] && "$(goose_bin)" --version 2>&1 | head -1))"
|
||||
else
|
||||
echo " ⚠ Goose install failed — the agent will fall back to its one-shot injector" >&2
|
||||
fi
|
||||
else
|
||||
echo " · skipped Goose install — the agent will use its one-shot injector"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# Write a minimal host Goose config pointing at the local Ollama. Goose reads
|
||||
# ~/.config/goose/config.yaml; we only set it if absent so we never clobber a
|
||||
# config the user has tuned themselves.
|
||||
GOOSE_CFG="${XDG_CONFIG_HOME:-$HOME/.config}/goose/config.yaml"
|
||||
if [[ -f "$GOOSE_CFG" ]]; then
|
||||
echo " ✓ host Goose config already exists ($GOOSE_CFG) — leaving it untouched"
|
||||
else
|
||||
mkdir -p "$(dirname "$GOOSE_CFG")"
|
||||
cat > "$GOOSE_CFG" <<EOF
|
||||
# Written by hh bootstrap-ai.sh — local-first Goose defaults (host).
|
||||
GOOSE_PROVIDER: ollama
|
||||
GOOSE_MODEL: $MODEL
|
||||
OLLAMA_HOST: $OLLAMA_HOST
|
||||
EOF
|
||||
echo " ✓ wrote host Goose config → $GOOSE_CFG (ollama/$MODEL)"
|
||||
fi
|
||||
echo " ⓘ in-sandbox Goose (containers/VMs) is installed separately by scripts/sandbox-bootstrap.sh"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "AI ready. start a local agent against a running room with:"
|
||||
echo " .venv/bin/python -m cmd_chat.agent <host> <port> \\"
|
||||
|
||||
Reference in New Issue
Block a user