Close the last onboarding gap: one shareable App Lab app a student imports and Runs, no adb / no host install. - package-onboard-app.sh: assemble a self-contained bundle — ZeroClaw binary (matrix_text + i2c_scan), single-agent config, skills, responder sketch, and the BAKED cloud token. Ships without .secret_key (each board mints its own) or a team Telegram token; dist/ is gitignored. - onboard-app/config.toml: the canonical packaged config (proven anthropic.max single 'default' agent, matrix + i2c_scan allowlisted, Telegram-ready, secrets stripped). - ONBOARDING.md: the full flow — instructor packages once, student imports + Runs, then the wizard. Notes APESS_URL (mDNS/per-team) + LAN reachability. Validated on-hardware: a freshly-imported bundle mints its key, boots the cloud agent, and runs the matrix + i2c_scan prompts in-container. Co-Authored-By: Claude Opus 4.8 <[email protected]>
97 lines
4.4 KiB
Bash
Executable File
97 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# package-onboard-app.sh — assemble a SELF-CONTAINED, distributable App Lab app
|
|
# ("APESS Onboard") that a student imports and clicks Run. Everything is baked in:
|
|
# the ZeroClaw binary, the single-agent config, the cloud token, the skills, and
|
|
# the resident responder sketch. No adb, no host install, no per-board setup.
|
|
#
|
|
# The instructor runs this ONCE to produce the bundle, then shares it via the App
|
|
# Lab UI (share → QR). Students scan the QR to import, open the app, click Run:
|
|
# the node comes up in one container, flashes the responder, and self-registers to
|
|
# the team's APESS laptop.
|
|
#
|
|
# Usage:
|
|
# export ANTHROPIC_OAUTH_TOKEN=sk-ant-oat01-… # baked into the app
|
|
# ./deploy/uno-q/package-onboard-app.sh
|
|
#
|
|
# Env:
|
|
# ANTHROPIC_OAUTH_TOKEN (required) cloud Max token, baked into .zeroclaw/oauth_token
|
|
# ZEROCLAW_BIN aarch64 binary (default: the built release-fast one)
|
|
# APESS_URL where the board self-registers (default: mDNS apess-api.local)
|
|
# FLEET_SECRET shared fleet secret (default: apess2026)
|
|
# OUT output bundle dir (default: deploy/uno-q/dist/apess-onboard)
|
|
set -euo pipefail
|
|
HERE="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO="$(cd "$HERE/../.." && pwd)"
|
|
NODE_SRC="${NODE_SRC:-$HOME/projects/zeroclaw/firmware/zeroclaw-node}"
|
|
ZEROCLAW_BIN="${ZEROCLAW_BIN:-$HOME/projects/zeroclaw/target/aarch64-unknown-linux-gnu/release-fast/zeroclaw}"
|
|
APESS_URL="${APESS_URL:-http://apess-api.local:3000}"
|
|
FLEET_SECRET="${FLEET_SECRET:-apess2026}"
|
|
OUT="${OUT:-$HERE/dist/apess-onboard}"
|
|
ok(){ printf ' \033[32m✓\033[0m %s\n' "$*"; }
|
|
bad(){ printf ' \033[31m✗\033[0m %s\n' "$*"; exit 1; }
|
|
|
|
[ -n "${ANTHROPIC_OAUTH_TOKEN:-}" ] || bad "ANTHROPIC_OAUTH_TOKEN not set (it gets baked into the app)"
|
|
[ -f "$ZEROCLAW_BIN" ] || bad "binary not found: $ZEROCLAW_BIN (build it first)"
|
|
[ -f "$NODE_SRC/app.yaml" ] || bad "node app source not found: $NODE_SRC"
|
|
[ -f "$HERE/onboard-app/config.toml" ] || bad "canonical config missing: onboard-app/config.toml"
|
|
|
|
echo "→ assembling the bundle at $OUT"
|
|
rm -rf "$OUT"
|
|
mkdir -p "$OUT/bin" "$OUT/.zeroclaw/shared"
|
|
|
|
# App Lab app scaffold (manifest + entrypoint + resident sketch)
|
|
cp "$NODE_SRC/app.yaml" "$OUT/app.yaml"
|
|
cp -r "$NODE_SRC/python" "$OUT/python"
|
|
cp -r "$NODE_SRC/sketch" "$OUT/sketch"
|
|
ok "app.yaml + python + sketch (responder w/ i2c_scan)"
|
|
|
|
# The ZeroClaw binary (matrix_text + i2c_scan + the works)
|
|
install -m755 "$ZEROCLAW_BIN" "$OUT/bin/zeroclaw"
|
|
ok "binary ($(du -h "$OUT/bin/zeroclaw" | cut -f1))"
|
|
|
|
# Single-agent config (proven: anthropic.max, matrix + i2c_scan allowlisted,
|
|
# telegram-ready, secrets stripped so a fresh board mints its own .secret_key)
|
|
cp "$HERE/onboard-app/config.toml" "$OUT/.zeroclaw/config.toml"
|
|
ok "config (single 'default' agent, matrix + i2c_scan)"
|
|
|
|
# Skills — the resident copy the daemon seeds each agent's workspace from
|
|
cp -r "$HERE/skills" "$OUT/.zeroclaw/shared/skills"
|
|
ok "skills ($(ls "$HERE/skills" | wc -l | tr -d ' ') bundles)"
|
|
|
|
# BAKED cloud token (per the workshop decision) — the instructor's Max token,
|
|
# shared across the fleet. Kept in the app bundle only, never in the repo.
|
|
printf '%s' "$ANTHROPIC_OAUTH_TOKEN" > "$OUT/.zeroclaw/oauth_token"
|
|
chmod 600 "$OUT/.zeroclaw/oauth_token"
|
|
ok "cloud token baked in (.zeroclaw/oauth_token)"
|
|
|
|
# Self-register inputs. KIT_ID + CLAIM_CODE are per-board; the packaged defaults
|
|
# are placeholders the app regenerates a code from if unset. APESS_URL points the
|
|
# board at the team's laptop stack (default: mDNS name the deploy/lan box advertises).
|
|
cat > "$OUT/.zeroclaw/apess-node.env" <<EOF
|
|
KIT_ID=
|
|
CLAIM_CODE=
|
|
FLEET_SECRET=$FLEET_SECRET
|
|
APESS_URL=$APESS_URL
|
|
GATEWAY_PORT=8080
|
|
EOF
|
|
ok "apess-node.env (APESS_URL=$APESS_URL)"
|
|
|
|
# Optional embedded ZeroClaw dashboard (served at :8080/). Carried if present.
|
|
if [ -d "$HOME/projects/zeroclaw/web-dist" ]; then
|
|
cp -r "$HOME/projects/zeroclaw/web-dist" "$OUT/web-dist"; ok "web dashboard"
|
|
else
|
|
echo " (no web-dist — the node dashboard link will 404; students use the APESS wizard)"
|
|
fi
|
|
|
|
echo
|
|
ok "bundle ready: $OUT"
|
|
cat <<EOF
|
|
|
|
Distribute it:
|
|
1. Import onto a board (instructor test):
|
|
arduino-app-cli app new --from-app "$OUT"
|
|
2. Or share to students: open the app in App Lab → Share → QR. Students scan to
|
|
import, then Run. Set APESS_URL per team if not using mDNS
|
|
(edit .zeroclaw/apess-node.env, or point apess-api.local at the laptop).
|
|
EOF
|