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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ jobs:

- name: Installer behaviour matrix
run: tests/installer-matrix.sh "$RC_BIN"

# Cheap and offline: builds the bundles and checks the docs inside them
# against the files shipped beside them. The real airgapped build (claw-ui
# fetch + bun) stays in drift.yml.
- name: Bundle/doc consistency
run: tests/bundle-consistency.sh "$RC_BIN"
3 changes: 3 additions & 0 deletions .github/workflows/drift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
- name: Installer behaviour matrix
run: tests/installer-matrix.sh "$RC_BIN"

- name: Bundle/doc consistency
run: tests/bundle-consistency.sh "$RC_BIN"

- name: Airgapped bundle (build, then install it offline)
run: tests/airgapped-bundle.sh "$RC_BIN"

Expand Down
28 changes: 20 additions & 8 deletions release/files/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,32 @@ This bundle contains everything to **operate a Hypervisor cluster from a prompt*

## 1. Set it up (once)

**One-liner (recommended):**
Use the installer that matches the bundle you have — **they are not interchangeable**. Check with
`ls setup*.sh`: the airgapped bundle ships `setup-airgapped.sh`, the online one does not.

**Airgapped bundle** (`rantai-copilot-airgapped-*`) — for a host with no internet. This is the only
installer that stages the prebuilt web console shipped inside the tarball. `setup.sh` does not, so
using it here leaves `copilot-web` trying to fetch claw-ui over a network you don't have:
```bash
curl -fsSL https://raw.githubusercontent.com/RantAI-dev/RantAI-Copilot/main/get.sh | bash
rantaiclaw setup # set your LLM provider + key (OpenRouter / Anthropic / MiniMax)
./setup-airgapped.sh
rantaiclaw setup provider # LLM provider + key — offline, needs no network
```

**Or from this bundle** (if you downloaded the tarball):
**Online bundle** (`rantai-copilot-*`) — for a host that can reach GitHub:
```bash
tar xzf rantai-copilot-*-x86_64-linux.tar.gz
cd rantai-copilot-*-x86_64-linux
./setup.sh
rantaiclaw setup # LLM provider + key (OpenRouter / Anthropic / MiniMax)
```
Either way: installs `rantaiclaw` to `~/.local/bin` and deploys the skills. Configure your LLM
afterward with `rantaiclaw setup` (both the one-liner and `setup.sh` leave this to you).

**No tarball yet?** On a connected machine:
```bash
curl -fsSL https://raw.githubusercontent.com/RantAI-dev/RantAI-Copilot/main/get.sh | bash
```

Either installer puts `rantaiclaw` in `~/.local/bin` and deploys the skills; both leave the LLM
config to you. **Updating an airgapped host — and rolling back if it goes wrong — is in
`README.md`, under *Install the agent → Airgapped mode*. Read it before you upgrade**: the config
migration is one-way, and those steps are what keep it reversible.

> Linux x86_64 only (the binary is static, runs on any modern distro). Other platforms: build
> from source — see the repo README.
Expand Down
79 changes: 79 additions & 0 deletions tests/bundle-consistency.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Do the documents we ship agree with the files we ship alongside them?
#
# Every defect this guards against was found the same way: by opening the tarball
# an operator would actually carry, not by reading the repo. A doc that names the
# wrong installer, or lags the repo by a release, is discovered on a host with no
# internet and no way to look anything up — so it gets checked here instead.
#
# Usage: tests/bundle-consistency.sh [path-to-rantaiclaw]
# Falls back to $RC_BIN, then to whatever `rantaiclaw` is on PATH.
# No network and no bun needed: the airgapped bundle is staged the way
# pack-airgapped.sh stages it, minus the claw-ui fetch (tests/airgapped-bundle.sh
# builds the real thing). The staging is pinned to pack-airgapped.sh below so this
# shortcut cannot silently drift away from what actually ships.
set -uo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/.." && pwd)"
RC="${1:-${RC_BIN:-$(command -v rantaiclaw 2>/dev/null || true)}}"
[ -x "$RC" ] || { echo "✗ need a rantaiclaw binary: tests/bundle-consistency.sh <path>"; exit 2; }
RC="$(cd "$(dirname "$RC")" && pwd)/$(basename "$RC")"

W="$(mktemp -d)"; trap 'rm -rf "$W"; rm -rf "$REPO/dist"' EXIT
PASS=0; FAIL=0
ck() { if eval "$2"; then printf ' PASS %s\n' "$1"; PASS=$((PASS+1)); else printf ' FAIL %s\n' "$1"; FAIL=$((FAIL+1)); fi; }
TAG=v0.0.0-test

bash "$REPO/release/build-bundle.sh" "$RC" "$TAG" >"$W/build.log" 2>&1 \
|| { echo " FAIL build-bundle.sh — see $W/build.log"; exit 1; }
tar xzf "$REPO/dist/rantai-copilot-$TAG-x86_64-linux.tar.gz" -C "$W"
ONLINE="$W/rantai-copilot-$TAG-x86_64-linux"

# Airgapped = the same base plus the offline installer (pack-airgapped.sh step 4).
AIR="$W/airgapped"; cp -r "$ONLINE" "$AIR"
install -m755 "$REPO/release/files/setup-airgapped.sh" "$AIR/setup-airgapped.sh"

echo "== the staging shortcut still matches pack-airgapped.sh =="
ck "pack-airgapped.sh installs setup-airgapped.sh" \
"grep -q 'install -m755 \"\$HERE/files/setup-airgapped.sh\" \"\$STAGE/setup-airgapped.sh\"' '$REPO/release/pack-airgapped.sh'"
ck "pack-airgapped.sh builds on the base bundle" \
"grep -q 'build-bundle.sh' '$REPO/release/pack-airgapped.sh'"

echo "== shipped docs match the repo (a bundle must never carry a stale copy) =="
ck "README.md is the repo's" "cmp -s '$ONLINE/README.md' '$REPO/README.md'"
ck "QUICKSTART.md is the repo's" "cmp -s '$ONLINE/QUICKSTART.md' '$REPO/release/files/QUICKSTART.md'"
ck "tutorials/ is the repo's" "diff -r -q '$ONLINE/tutorials' '$REPO/tutorials' >/dev/null"

echo "== entrypoints are present, executable, and parse =="
for f in setup.sh web-ui.sh copilot-uninstall; do
ck "online bundle ships $f (executable)" "[ -x '$ONLINE/$f' ]"
ck "online bundle $f parses" "bash -n '$ONLINE/$f' 2>/dev/null"
done
ck "airgapped bundle ships setup-airgapped.sh (executable)" "[ -x '$AIR/setup-airgapped.sh' ]"
ck "airgapped bundle setup-airgapped.sh parses" "bash -n '$AIR/setup-airgapped.sh' 2>/dev/null"
ck "online bundle does NOT ship setup-airgapped.sh" "[ ! -e '$ONLINE/setup-airgapped.sh' ]"
ck "no bundle ships install.sh (git-clone only)" "[ ! -e '$ONLINE/install.sh' ] && [ ! -e '$AIR/install.sh' ]"

echo "== docs route the operator to an installer that is actually in the box =="
# The airgapped installer is the only one that stages the prebuilt console, so a
# QUICKSTART that never names it sends an offline operator to `setup.sh` and a
# `copilot-web` that tries to reach the network.
ck "QUICKSTART names setup-airgapped.sh" "grep -q 'setup-airgapped.sh' '$AIR/QUICKSTART.md'"
ck "QUICKSTART names setup.sh" "grep -q 'setup.sh' '$ONLINE/QUICKSTART.md'"
ck "QUICKSTART points at the update/rollback docs" "grep -qi 'README.md' '$ONLINE/QUICKSTART.md'"
# `install.sh` exists only in a git checkout. Naming it in a shipped doc is fine —
# telling a bundle operator to run it is not, so every mention must say where it comes from.
for d in QUICKSTART.md README.md tutorials/hypervisor.md; do
ck "$d qualifies any install.sh mention" \
"! grep -q 'install\\.sh' '$ONLINE/$d' || grep -qiE 'clone|from source' '$ONLINE/$d'"
done

echo "== the offline console really is what setup-airgapped.sh stages =="
# setup.sh must not claim to handle the offline console; if it ever grows that,
# the QUICKSTART split above becomes wrong and should be revisited deliberately.
ck "setup.sh does not stage the prebuilt console" "! grep -q 'web-ui/server.js' '$ONLINE/setup.sh'"
ck "setup-airgapped.sh does stage it" "grep -q 'web-ui/server.js' '$AIR/setup-airgapped.sh'"

printf '\n%d passed, %d failed\n' "$PASS" "$FAIL"
[ "$FAIL" -eq 0 ]
6 changes: 4 additions & 2 deletions tutorials/hypervisor.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ against the cluster; it never invents data and confirms before it changes anythi

- `kubectl` on your machine (the agent runs it locally).
- A kubeconfig for the cluster — from your cluster UI (Rancher) → cluster → **Download KubeConfig**.
- RantaiClaw with an LLM provider (`rantaiclaw setup`) and the `hypervisor` skill
deployed (`./install.sh`).
- RantaiClaw with an LLM provider (`rantaiclaw setup`) and the `hypervisor` skill deployed. Which
command does that depends on where you got it: `./setup-airgapped.sh` from an airgapped bundle,
`./setup.sh` from an online bundle, or `./install.sh` from a git clone — the bundles do not ship
`install.sh`.

## 2. Give the agent the kubeconfig

Expand Down
17 changes: 16 additions & 1 deletion web-ui.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,22 @@ q() { if [ "$VERBOSE" = 1 ]; then "$@"; else "$@" >>"$LOG" 2>&1; fi; }
port_busy() { (exec 3<>"/dev/tcp/127.0.0.1/$1") 2>/dev/null && { exec 3>&- 3<&-; return 0; }; return 1; }

case "${1:-up}" in
stop) rantaiclaw ui stop --dir "$UIDIR" >/dev/null 2>&1 && say "✓ stopped" || say "nothing to stop"; exit 0 ;;
# `rantaiclaw ui stop` exits 0 whether or not anything was running, so its exit
# code cannot tell the two apart — an unconditional "✓ stopped" is what an
# operator reads right before pulling the console's files out from under it.
# Decide from the run marker `ui start` maintains, and report what really happened.
stop)
if [ ! -f "$UIDIR/.run" ]; then
say "nothing to stop (no console running from $UIDIR)"
exit 0
fi
rantaiclaw ui stop --dir "$UIDIR" >/dev/null 2>&1 || true
if [ -f "$UIDIR/.run" ]; then
say "✗ could not stop the console — try: rantaiclaw ui stop --dir \"$UIDIR\""
exit 1
fi
say "✓ stopped"
exit 0 ;;
up|"") ;;
*) say "usage: $0 [up|stop]"; exit 2 ;;
esac
Expand Down