diff --git a/claws/openclaw/sageox-distill/SKILL.md b/claws/openclaw/sageox-distill/SKILL.md index b69479e4..40a3cb45 100644 --- a/claws/openclaw/sageox-distill/SKILL.md +++ b/claws/openclaw/sageox-distill/SKILL.md @@ -1,7 +1,7 @@ --- name: sageox-distill description: "Sync, index, and distill team activity across SageOx-enabled repositories. Keeps your team's knowledge base up to date by syncing repo contexts, indexing GitHub PRs/issues, and running the SageOx distillation pipeline." -version: 0.2.1 +version: 0.3.0 metadata: { "openclaw": @@ -93,32 +93,44 @@ runs. Re-validate every read. The `ox` CLI install state is recorded in `~/.openclaw/memory/sageox-ox-install.json`. On every run of this -skill, invoke the bundled readiness gate: +skill, invoke the bundled install-and-update gate: ```bash bash scripts/update-ox.sh ``` +The script reads the ox release this skill pins from +`scripts/install-ox-curl.sh` (the source of truth, with its +`OX_INSTALL_REF` and per-platform sha256s reviewed at skill publish). +If the installed binary doesn't match that pin, it re-runs +`install-ox-curl.sh` to upgrade in place — so picking up a newer ox +no longer requires the user to manually re-enter the install flow. + Contract: -- **Stdout:** nothing on success -- **Stderr:** on any failure, a two-line message — an `error:` line - describing what's wrong, followed by a `fix:` line with the - remediation. Surface both verbatim to the user. -- **Exit:** `0` ox is pinned, installed, and reports the expected - version (continue to § 4); `2` ox is not usable — one of: state file - missing, binary missing at `$HOME/.local/bin/ox`, `ox` on PATH - resolves to a different binary, binary fails to run, or binary - reports a version other than the one recorded in - `sageox-ox-install.json`. On exit `2`, STOP, read - [`references/INSTALL.md`](references/INSTALL.md), follow the install - flow, then re-run this script to confirm. - -There is no per-run auto-update. The curl install pins a specific `ox` -release by tag and sha256; users pick up newer releases by re-running -`clawhub install` for this skill after a new skill version publishes. -The user can say **"reinstall ox"** at any time to re-enter the flow in -[`references/INSTALL.md`](references/INSTALL.md). +- **Stdout:** nothing when ox is already at the skill's pin; download / + verify / extract progress when an in-place upgrade runs. +- **Stderr:** on failure, surface stderr verbatim to the user — do not + trim, reformat, or summarize. Most failure paths emit an `error:` + line followed by a `fix:` line, but some emit a single line and + others include captured command stderr (e.g. when `ox version` + itself fails to run), so the line count is not fixed. +- **Exit:** + - `0` — ox is ready (either already current, or upgraded in place); + continue to § 4. + - `2` — initial install required. One of: state file missing, binary + missing at `$HOME/.local/bin/ox`, `ox` on PATH resolves to a + different binary, or the binary fails to run. STOP, read + [`references/INSTALL.md`](references/INSTALL.md), follow the + install flow, then re-run this script to confirm. + - `3` — an in-place upgrade was attempted but `install-ox-curl.sh` + failed (download error, checksum mismatch, etc.). Surface its + stderr to the user and stop. + +The script does not introduce dynamic "latest" resolution — the pin +still lives in `install-ox-curl.sh` and is reviewed at skill publish. +Users can say **"reinstall ox"** at any time to re-enter the manual +flow in [`references/INSTALL.md`](references/INSTALL.md). **Do not install `ox` via Homebrew or any package manager** (e.g. `brew install sageox/tap/ox`, `apt`, `dnf`, `pacman`). The tap exists diff --git a/claws/openclaw/sageox-distill/references/INSTALL.md b/claws/openclaw/sageox-distill/references/INSTALL.md index 2500d8c5..c1783eea 100644 --- a/claws/openclaw/sageox-distill/references/INSTALL.md +++ b/claws/openclaw/sageox-distill/references/INSTALL.md @@ -61,8 +61,19 @@ It should exit `0` with no stderr. ## Upgrading `ox` -The curl flow pins a specific `ox` release by tag and sha256. There is -no per-run auto-update. To pick up a newer release, re-run -`scripts/install-ox-curl.sh` from a version of this skill that pins the -newer release — typically by re-running `clawhub install` for the -skill after a new skill version publishes. +The curl flow pins a specific `ox` release by tag and sha256. The pin +itself only moves when the skill is republished with new +`OX_INSTALL_REF` and sha256 constants in `scripts/install-ox-curl.sh` +(reviewed at skill publish — there is no dynamic "latest" resolution). + +What changed in skill version ≥0.3.0 (distill) / ≥0.4.0 (summary): +`scripts/update-ox.sh` now closes the loop on every run. It compares +the installed binary's `ox version` against the skill's current pin, +and when they differ, it re-invokes `scripts/install-ox-curl.sh` +automatically to converge. Users no longer have to manually re-enter +this install flow just to pick up a newer pinned release after a +`clawhub install` of a refreshed skill. + +To force a reinstall (for example, after `~/.local/bin/ox` was +deleted), users can still say **"reinstall ox"** to re-enter the flow +above. diff --git a/claws/openclaw/sageox-distill/scripts/install-ox-curl.sh b/claws/openclaw/sageox-distill/scripts/install-ox-curl.sh index 6857c2ad..1dd710ff 100644 --- a/claws/openclaw/sageox-distill/scripts/install-ox-curl.sh +++ b/claws/openclaw/sageox-distill/scripts/install-ox-curl.sh @@ -25,17 +25,17 @@ set -euo pipefail -OX_INSTALL_REF="v0.6.4" +OX_INSTALL_REF="v0.7.2" OX_VERSION="${OX_INSTALL_REF#v}" OX_REPO="sageox/ox" # sha256(ox___.tar.gz) — from the checksums.txt asset # on the pinned release. Lock these when bumping OX_INSTALL_REF. -OX_SHA256_darwin_amd64="a1e256a2ab1d1a3dfec5330ff9737be020a1ef36d133087f6c0b9e03255ddfe3" -OX_SHA256_darwin_arm64="91c36bd0bfec6651078394e3fdf300b78f2babcd8caf70eba436e3b6ea1c2bed" -OX_SHA256_linux_amd64="fe93cd0c093226c51347efe7dd9cd2d5bb055f3523e55a7b887eb2bc8d0312df" -OX_SHA256_linux_arm64="826c9d8eb8387cf029fad6f521a8be86887336e4fe89c97bae4708a99c218897" -OX_SHA256_freebsd_amd64="f1a5cc3c42675e5c1a10b299c0cae4e7407d5f18d722fc2a10009c9365c4ceb0" +OX_SHA256_darwin_amd64="ea055f19af0d95ff92a863c25a7375c5312b91c55ceb4de6f39b7d7f6bd1aec4" +OX_SHA256_darwin_arm64="4e4ec64a11b478f5ef820a910aaeb34d293bbc77e93461abbb8e841d2ea7d1c0" +OX_SHA256_linux_amd64="db0535adaeca92afe64f4046029457132d2f3bb74c5e57c69da78ae443721d26" +OX_SHA256_linux_arm64="5c705067fce9770b65d2c2db33cc29c2401b8549b1cfcb23d10b3d1f5b06f804" +OX_SHA256_freebsd_amd64="635c4feacb7b859ebf0808311023f559dab4ed86e28a6c10f06bbaeb7b75c6d9" command -v curl >/dev/null 2>&1 || { echo "error: curl is required" >&2; exit 3; } command -v tar >/dev/null 2>&1 || { echo "error: tar is required" >&2; exit 3; } diff --git a/claws/openclaw/sageox-distill/scripts/update-ox.sh b/claws/openclaw/sageox-distill/scripts/update-ox.sh index 74a892d9..e4a253bd 100644 --- a/claws/openclaw/sageox-distill/scripts/update-ox.sh +++ b/claws/openclaw/sageox-distill/scripts/update-ox.sh @@ -1,29 +1,46 @@ #!/usr/bin/env bash -# update-ox.sh — "is the pinned ox install usable?" readiness gate for -# every invocation of this skill. +# update-ox.sh — keep the pinned ox install in sync with the version this +# skill ships. On every invocation: # -# Reads ~/.openclaw/memory/sageox-ox-install.json to confirm the install -# state exists, then verifies that `ox` on PATH resolves to the pinned -# install at $HOME/.local/bin/ox. A bare `command -v ox` is insufficient: -# if an older system ox (e.g. /usr/local/bin/ox) appears before -# $HOME/.local/bin on PATH, `command -v` would silently resolve to it -# and defeat the pinned-release contract. The curl install path has no -# per-run update — users re-run install-ox-curl.sh to bump the pinned -# release. +# 1. Confirm the install state file and the binary at the pinned path +# exist, and that `command -v ox` resolves to the pinned path (not a +# system ox earlier on PATH). +# 2. Read the version this skill pins from sibling install-ox-curl.sh — +# that file is the source of truth, with its OX_INSTALL_REF and the +# matching per-platform sha256 constants reviewed at skill publish. +# 3. If the installed binary's version doesn't match the skill's pin, +# re-run install-ox-curl.sh to upgrade in place. The install script +# downloads, sha256-verifies, extracts, and rewrites the state file +# — same code path as a fresh install — so we converge on the new +# pin without forcing the user back through the manual install flow. +# +# This script does NOT introduce dynamic "latest" resolution from the +# internet. It only closes the loop between "skill ships a new pinned +# version" and "the installed binary catches up." The supply-chain +# guarantee (sha256-pinned releases reviewed at skill publish) is +# preserved. # # Usage: update-ox.sh # -# Stdout: nothing on success -# Stderr: one-line "needs install", "not at pinned path", or "PATH -# order wrong" signal +# Stdout: nothing on success, human-readable progress during an upgrade +# Stderr: install/path diagnostics surfaced verbatim — most paths emit +# an `error:` line followed by a `fix:` line, but some emit a +# single line and others (e.g. when `ox version` itself fails) +# include captured command stderr, so line count is not fixed. +# On upgrade failure, install-ox-curl.sh's stderr is also passed +# through. # Exit: -# 0 — pinned ox is ready, agent should proceed to the next prerequisite -# 2 — ox is not usable (no state file, binary missing at pinned path, -# or PATH resolves to a different ox); agent must read -# references/INSTALL.md and run the install flow before continuing +# 0 — pinned ox is ready (either already current, or upgraded in place) +# 2 — initial install required (state file missing, binary missing at +# pinned path, or PATH resolves elsewhere). Agent must read +# references/INSTALL.md and run the install flow. +# 3 — an upgrade was attempted but install-ox-curl.sh failed (download +# error, checksum mismatch, etc.). Surface its stderr to the user. set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INSTALL_SCRIPT="$SCRIPT_DIR/install-ox-curl.sh" STATE_FILE="$HOME/.openclaw/memory/sageox-ox-install.json" EXPECTED_OX="$HOME/.local/bin/ox" @@ -52,31 +69,55 @@ if [ "$resolved_ox" != "$EXPECTED_OX" ]; then exit 2 fi -# Verify the binary itself still reports the pinned version. The path -# check above proves PATH order is right; this check proves the bytes -# behind the path haven't been replaced or corrupted since install. -# `jq` is required by the skill (see SKILL.md § 2), so it's guaranteed -# present by the time this script runs. -expected_ref="$(jq -r '.ox_install_ref // empty' "$STATE_FILE" 2>/dev/null || true)" -if [ -z "$expected_ref" ]; then - echo "error: $STATE_FILE is missing ox_install_ref" >&2 - echo "fix: re-run the install flow from references/INSTALL.md" >&2 +# Read the release tag this skill currently pins. install-ox-curl.sh is +# the source of truth — it ships next to this script, and its +# OX_INSTALL_REF + per-platform sha256 constants are reviewed at skill +# publish. update-ox.sh just trails that pin: if the installed binary +# doesn't match, we re-run install-ox-curl.sh to converge. +if [ ! -f "$INSTALL_SCRIPT" ]; then + echo "error: install script missing at $INSTALL_SCRIPT" >&2 + echo "fix: reinstall this skill via clawhub" >&2 exit 2 fi -expected_version="${expected_ref#v}" +# awk over grep|head|sed: a no-match grep exits non-zero, and under +# `set -euo pipefail` that would silently abort the script inside this +# command substitution before the empty-check below ever ran. awk +# always exits 0 (printing nothing when the pattern doesn't match), so +# control reaches the empty-check and emits the proper remediation. +skill_pin="$(awk -F'"' '/^OX_INSTALL_REF="/ { print $2; exit }' "$INSTALL_SCRIPT")" +if [ -z "$skill_pin" ]; then + echo "error: could not read OX_INSTALL_REF from $INSTALL_SCRIPT" >&2 + echo "fix: reinstall this skill via clawhub" >&2 + exit 2 +fi +skill_version="${skill_pin#v}" +# Verify the binary still runs and report its version. A binary that +# exists on disk but fails to execute (libc mismatch, corruption, etc.) +# is a hard install error, not a drift-to-fix. if ! version_output="$("$EXPECTED_OX" version 2>&1)"; then echo "error: $EXPECTED_OX failed to run" >&2 echo "$version_output" >&2 echo "fix: re-run the install flow from references/INSTALL.md" >&2 exit 2 fi - first_line="$(printf '%s\n' "$version_output" | head -n1)" -if [ "$first_line" != "ox $expected_version" ]; then - echo "error: $EXPECTED_OX reports '$first_line', expected 'ox $expected_version'" >&2 - echo "fix: re-run the install flow from references/INSTALL.md" >&2 - exit 2 + +# Happy path: installed binary matches the skill's current pin. +if [ "$first_line" = "ox $skill_version" ]; then + exit 0 +fi + +# Drift detected. The skill has been updated to pin a different ox +# version than what's installed. Re-run install-ox-curl.sh to upgrade +# (or downgrade — the skill's pin always wins). The install script +# rewrites the state file on success, so the next invocation sees the +# new state. +echo "ox is at '$first_line' but skill pins '$skill_pin' — upgrading..." +if ! bash "$INSTALL_SCRIPT"; then + echo "error: failed to upgrade ox to $skill_pin" >&2 + echo "fix: re-run scripts/install-ox-curl.sh manually and surface its stderr" >&2 + exit 3 fi exit 0 diff --git a/claws/openclaw/sageox-summary/SKILL.md b/claws/openclaw/sageox-summary/SKILL.md index b5bdbde3..6a60bb29 100644 --- a/claws/openclaw/sageox-summary/SKILL.md +++ b/claws/openclaw/sageox-summary/SKILL.md @@ -1,7 +1,7 @@ --- name: sageox-summary description: "Generate an overall team summary covering the last 24 hours across all SageOx-enabled teams. Reads distilled daily entries via `ox distill history` and produces a structured, Slack-ready overview." -version: 0.3.1 +version: 0.4.0 metadata: { "openclaw": @@ -92,32 +92,44 @@ runs. Re-validate every read. The `ox` CLI install state is recorded in `~/.openclaw/memory/sageox-ox-install.json`. On every run of this -skill, invoke the bundled readiness gate: +skill, invoke the bundled install-and-update gate: ```bash bash scripts/update-ox.sh ``` +The script reads the ox release this skill pins from +`scripts/install-ox-curl.sh` (the source of truth, with its +`OX_INSTALL_REF` and per-platform sha256s reviewed at skill publish). +If the installed binary doesn't match that pin, it re-runs +`install-ox-curl.sh` to upgrade in place — so picking up a newer ox +no longer requires the user to manually re-enter the install flow. + Contract: -- **Stdout:** nothing on success -- **Stderr:** on any failure, a two-line message — an `error:` line - describing what's wrong, followed by a `fix:` line with the - remediation. Surface both verbatim to the user. -- **Exit:** `0` ox is pinned, installed, and reports the expected - version (continue to § 4); `2` ox is not usable — one of: state file - missing, binary missing at `$HOME/.local/bin/ox`, `ox` on PATH - resolves to a different binary, binary fails to run, or binary - reports a version other than the one recorded in - `sageox-ox-install.json`. On exit `2`, STOP, read - [`references/INSTALL.md`](references/INSTALL.md), follow the install - flow, then re-run this script to confirm. - -There is no per-run auto-update. The curl install pins a specific `ox` -release by tag and sha256; users pick up newer releases by re-running -`clawhub install` for this skill after a new skill version publishes. -The user can say **"reinstall ox"** at any time to re-enter the flow in -[`references/INSTALL.md`](references/INSTALL.md). +- **Stdout:** nothing when ox is already at the skill's pin; download / + verify / extract progress when an in-place upgrade runs. +- **Stderr:** on failure, surface stderr verbatim to the user — do not + trim, reformat, or summarize. Most failure paths emit an `error:` + line followed by a `fix:` line, but some emit a single line and + others include captured command stderr (e.g. when `ox version` + itself fails to run), so the line count is not fixed. +- **Exit:** + - `0` — ox is ready (either already current, or upgraded in place); + continue to § 4. + - `2` — initial install required. One of: state file missing, binary + missing at `$HOME/.local/bin/ox`, `ox` on PATH resolves to a + different binary, or the binary fails to run. STOP, read + [`references/INSTALL.md`](references/INSTALL.md), follow the + install flow, then re-run this script to confirm. + - `3` — an in-place upgrade was attempted but `install-ox-curl.sh` + failed (download error, checksum mismatch, etc.). Surface its + stderr to the user and stop. + +The script does not introduce dynamic "latest" resolution — the pin +still lives in `install-ox-curl.sh` and is reviewed at skill publish. +Users can say **"reinstall ox"** at any time to re-enter the manual +flow in [`references/INSTALL.md`](references/INSTALL.md). **Do not install `ox` via Homebrew or any package manager** (e.g. `brew install sageox/tap/ox`, `apt`, `dnf`, `pacman`). The tap exists diff --git a/claws/openclaw/sageox-summary/references/INSTALL.md b/claws/openclaw/sageox-summary/references/INSTALL.md index 2500d8c5..c1783eea 100644 --- a/claws/openclaw/sageox-summary/references/INSTALL.md +++ b/claws/openclaw/sageox-summary/references/INSTALL.md @@ -61,8 +61,19 @@ It should exit `0` with no stderr. ## Upgrading `ox` -The curl flow pins a specific `ox` release by tag and sha256. There is -no per-run auto-update. To pick up a newer release, re-run -`scripts/install-ox-curl.sh` from a version of this skill that pins the -newer release — typically by re-running `clawhub install` for the -skill after a new skill version publishes. +The curl flow pins a specific `ox` release by tag and sha256. The pin +itself only moves when the skill is republished with new +`OX_INSTALL_REF` and sha256 constants in `scripts/install-ox-curl.sh` +(reviewed at skill publish — there is no dynamic "latest" resolution). + +What changed in skill version ≥0.3.0 (distill) / ≥0.4.0 (summary): +`scripts/update-ox.sh` now closes the loop on every run. It compares +the installed binary's `ox version` against the skill's current pin, +and when they differ, it re-invokes `scripts/install-ox-curl.sh` +automatically to converge. Users no longer have to manually re-enter +this install flow just to pick up a newer pinned release after a +`clawhub install` of a refreshed skill. + +To force a reinstall (for example, after `~/.local/bin/ox` was +deleted), users can still say **"reinstall ox"** to re-enter the flow +above. diff --git a/claws/openclaw/sageox-summary/scripts/install-ox-curl.sh b/claws/openclaw/sageox-summary/scripts/install-ox-curl.sh index 6857c2ad..1dd710ff 100644 --- a/claws/openclaw/sageox-summary/scripts/install-ox-curl.sh +++ b/claws/openclaw/sageox-summary/scripts/install-ox-curl.sh @@ -25,17 +25,17 @@ set -euo pipefail -OX_INSTALL_REF="v0.6.4" +OX_INSTALL_REF="v0.7.2" OX_VERSION="${OX_INSTALL_REF#v}" OX_REPO="sageox/ox" # sha256(ox___.tar.gz) — from the checksums.txt asset # on the pinned release. Lock these when bumping OX_INSTALL_REF. -OX_SHA256_darwin_amd64="a1e256a2ab1d1a3dfec5330ff9737be020a1ef36d133087f6c0b9e03255ddfe3" -OX_SHA256_darwin_arm64="91c36bd0bfec6651078394e3fdf300b78f2babcd8caf70eba436e3b6ea1c2bed" -OX_SHA256_linux_amd64="fe93cd0c093226c51347efe7dd9cd2d5bb055f3523e55a7b887eb2bc8d0312df" -OX_SHA256_linux_arm64="826c9d8eb8387cf029fad6f521a8be86887336e4fe89c97bae4708a99c218897" -OX_SHA256_freebsd_amd64="f1a5cc3c42675e5c1a10b299c0cae4e7407d5f18d722fc2a10009c9365c4ceb0" +OX_SHA256_darwin_amd64="ea055f19af0d95ff92a863c25a7375c5312b91c55ceb4de6f39b7d7f6bd1aec4" +OX_SHA256_darwin_arm64="4e4ec64a11b478f5ef820a910aaeb34d293bbc77e93461abbb8e841d2ea7d1c0" +OX_SHA256_linux_amd64="db0535adaeca92afe64f4046029457132d2f3bb74c5e57c69da78ae443721d26" +OX_SHA256_linux_arm64="5c705067fce9770b65d2c2db33cc29c2401b8549b1cfcb23d10b3d1f5b06f804" +OX_SHA256_freebsd_amd64="635c4feacb7b859ebf0808311023f559dab4ed86e28a6c10f06bbaeb7b75c6d9" command -v curl >/dev/null 2>&1 || { echo "error: curl is required" >&2; exit 3; } command -v tar >/dev/null 2>&1 || { echo "error: tar is required" >&2; exit 3; } diff --git a/claws/openclaw/sageox-summary/scripts/update-ox.sh b/claws/openclaw/sageox-summary/scripts/update-ox.sh index 74a892d9..e4a253bd 100644 --- a/claws/openclaw/sageox-summary/scripts/update-ox.sh +++ b/claws/openclaw/sageox-summary/scripts/update-ox.sh @@ -1,29 +1,46 @@ #!/usr/bin/env bash -# update-ox.sh — "is the pinned ox install usable?" readiness gate for -# every invocation of this skill. +# update-ox.sh — keep the pinned ox install in sync with the version this +# skill ships. On every invocation: # -# Reads ~/.openclaw/memory/sageox-ox-install.json to confirm the install -# state exists, then verifies that `ox` on PATH resolves to the pinned -# install at $HOME/.local/bin/ox. A bare `command -v ox` is insufficient: -# if an older system ox (e.g. /usr/local/bin/ox) appears before -# $HOME/.local/bin on PATH, `command -v` would silently resolve to it -# and defeat the pinned-release contract. The curl install path has no -# per-run update — users re-run install-ox-curl.sh to bump the pinned -# release. +# 1. Confirm the install state file and the binary at the pinned path +# exist, and that `command -v ox` resolves to the pinned path (not a +# system ox earlier on PATH). +# 2. Read the version this skill pins from sibling install-ox-curl.sh — +# that file is the source of truth, with its OX_INSTALL_REF and the +# matching per-platform sha256 constants reviewed at skill publish. +# 3. If the installed binary's version doesn't match the skill's pin, +# re-run install-ox-curl.sh to upgrade in place. The install script +# downloads, sha256-verifies, extracts, and rewrites the state file +# — same code path as a fresh install — so we converge on the new +# pin without forcing the user back through the manual install flow. +# +# This script does NOT introduce dynamic "latest" resolution from the +# internet. It only closes the loop between "skill ships a new pinned +# version" and "the installed binary catches up." The supply-chain +# guarantee (sha256-pinned releases reviewed at skill publish) is +# preserved. # # Usage: update-ox.sh # -# Stdout: nothing on success -# Stderr: one-line "needs install", "not at pinned path", or "PATH -# order wrong" signal +# Stdout: nothing on success, human-readable progress during an upgrade +# Stderr: install/path diagnostics surfaced verbatim — most paths emit +# an `error:` line followed by a `fix:` line, but some emit a +# single line and others (e.g. when `ox version` itself fails) +# include captured command stderr, so line count is not fixed. +# On upgrade failure, install-ox-curl.sh's stderr is also passed +# through. # Exit: -# 0 — pinned ox is ready, agent should proceed to the next prerequisite -# 2 — ox is not usable (no state file, binary missing at pinned path, -# or PATH resolves to a different ox); agent must read -# references/INSTALL.md and run the install flow before continuing +# 0 — pinned ox is ready (either already current, or upgraded in place) +# 2 — initial install required (state file missing, binary missing at +# pinned path, or PATH resolves elsewhere). Agent must read +# references/INSTALL.md and run the install flow. +# 3 — an upgrade was attempted but install-ox-curl.sh failed (download +# error, checksum mismatch, etc.). Surface its stderr to the user. set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INSTALL_SCRIPT="$SCRIPT_DIR/install-ox-curl.sh" STATE_FILE="$HOME/.openclaw/memory/sageox-ox-install.json" EXPECTED_OX="$HOME/.local/bin/ox" @@ -52,31 +69,55 @@ if [ "$resolved_ox" != "$EXPECTED_OX" ]; then exit 2 fi -# Verify the binary itself still reports the pinned version. The path -# check above proves PATH order is right; this check proves the bytes -# behind the path haven't been replaced or corrupted since install. -# `jq` is required by the skill (see SKILL.md § 2), so it's guaranteed -# present by the time this script runs. -expected_ref="$(jq -r '.ox_install_ref // empty' "$STATE_FILE" 2>/dev/null || true)" -if [ -z "$expected_ref" ]; then - echo "error: $STATE_FILE is missing ox_install_ref" >&2 - echo "fix: re-run the install flow from references/INSTALL.md" >&2 +# Read the release tag this skill currently pins. install-ox-curl.sh is +# the source of truth — it ships next to this script, and its +# OX_INSTALL_REF + per-platform sha256 constants are reviewed at skill +# publish. update-ox.sh just trails that pin: if the installed binary +# doesn't match, we re-run install-ox-curl.sh to converge. +if [ ! -f "$INSTALL_SCRIPT" ]; then + echo "error: install script missing at $INSTALL_SCRIPT" >&2 + echo "fix: reinstall this skill via clawhub" >&2 exit 2 fi -expected_version="${expected_ref#v}" +# awk over grep|head|sed: a no-match grep exits non-zero, and under +# `set -euo pipefail` that would silently abort the script inside this +# command substitution before the empty-check below ever ran. awk +# always exits 0 (printing nothing when the pattern doesn't match), so +# control reaches the empty-check and emits the proper remediation. +skill_pin="$(awk -F'"' '/^OX_INSTALL_REF="/ { print $2; exit }' "$INSTALL_SCRIPT")" +if [ -z "$skill_pin" ]; then + echo "error: could not read OX_INSTALL_REF from $INSTALL_SCRIPT" >&2 + echo "fix: reinstall this skill via clawhub" >&2 + exit 2 +fi +skill_version="${skill_pin#v}" +# Verify the binary still runs and report its version. A binary that +# exists on disk but fails to execute (libc mismatch, corruption, etc.) +# is a hard install error, not a drift-to-fix. if ! version_output="$("$EXPECTED_OX" version 2>&1)"; then echo "error: $EXPECTED_OX failed to run" >&2 echo "$version_output" >&2 echo "fix: re-run the install flow from references/INSTALL.md" >&2 exit 2 fi - first_line="$(printf '%s\n' "$version_output" | head -n1)" -if [ "$first_line" != "ox $expected_version" ]; then - echo "error: $EXPECTED_OX reports '$first_line', expected 'ox $expected_version'" >&2 - echo "fix: re-run the install flow from references/INSTALL.md" >&2 - exit 2 + +# Happy path: installed binary matches the skill's current pin. +if [ "$first_line" = "ox $skill_version" ]; then + exit 0 +fi + +# Drift detected. The skill has been updated to pin a different ox +# version than what's installed. Re-run install-ox-curl.sh to upgrade +# (or downgrade — the skill's pin always wins). The install script +# rewrites the state file on success, so the next invocation sees the +# new state. +echo "ox is at '$first_line' but skill pins '$skill_pin' — upgrading..." +if ! bash "$INSTALL_SCRIPT"; then + echo "error: failed to upgrade ox to $skill_pin" >&2 + echo "fix: re-run scripts/install-ox-curl.sh manually and surface its stderr" >&2 + exit 3 fi exit 0