- Refactor monolithic index.js (2646 lines) into src/{webex,integrations,
cards,flows,commands,services} modules; replace node-fetch/form-data
with native fetch/FormData; move all secrets to .env via dotenv
- Add dockerized remote SIW agent (docker/remote-agent/) with cross-arch
buildx packaging (arm64 Mac -> linux/amd64), idempotent install.sh
deploy bundle, and docker-free ZIP inspector for arch verification
- Bot hosts a WebSocket server; agent proxies SIW requests with a
per-request insecure:true flag, replacing the process-wide
NODE_TLS_REJECT_UNAUTHORIZED bypass
- Add ESLint flat config + Prettier, rewrite Dockerfile as non-root
multi-stage node:22-alpine build, README covering setup / deploy /
remote agent workflow
- Fix parseStoreArg to read trigger.prompt correctly (was indexing past
the framework's post-match slice); register /help as regex (string
matcher only compares the first token); switch catch-all to /.+/
(previous /.*/gim was stateful due to the g flag); remove
/fixDisplayNames command and its flow/card
Co-authored-by: Cursor <cursoragent@cursor.com>
138 lines
5.3 KiB
Bash
Executable file
138 lines
5.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# wbxStoreProvision Remote Agent — install / (re)start on a remote host.
|
|
#
|
|
# Run this after extracting the deploy ZIP:
|
|
# unzip wbxprov-remote-agent-<version>.zip
|
|
# cd wbxprov-remote-agent-<version>
|
|
# ./install.sh
|
|
#
|
|
# On first run: verifies the image tarball, loads it into Docker, and drops
|
|
# a starter .env so you can fill in WS_URL / WS_TOKEN. Re-runs are safe —
|
|
# the script is idempotent.
|
|
|
|
set -euo pipefail
|
|
|
|
# Move to the script's own directory so relative paths work regardless of
|
|
# where the user invoked it from.
|
|
cd "$(dirname "$0")"
|
|
|
|
RED=$'\033[0;31m'
|
|
GRN=$'\033[0;32m'
|
|
YLW=$'\033[1;33m'
|
|
RST=$'\033[0m'
|
|
|
|
log() { printf '%s[install]%s %s\n' "$GRN" "$RST" "$*"; }
|
|
warn() { printf '%s[install]%s %s\n' "$YLW" "$RST" "$*"; }
|
|
die() { printf '%s[install]%s %s\n' "$RED" "$RST" "$*" >&2; exit 1; }
|
|
|
|
# --- 1. Preflight ----------------------------------------------------------
|
|
|
|
command -v docker >/dev/null 2>&1 || die "Docker not found on PATH."
|
|
docker info >/dev/null 2>&1 \
|
|
|| die "Cannot talk to the Docker daemon. Is it running / do you have permission?"
|
|
|
|
# Detect either `docker compose` (v2 plugin) or the legacy `docker-compose`.
|
|
if docker compose version >/dev/null 2>&1; then
|
|
COMPOSE=(docker compose)
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
COMPOSE=(docker-compose)
|
|
else
|
|
die "Neither 'docker compose' nor 'docker-compose' is available. Install Docker Compose."
|
|
fi
|
|
|
|
[[ -f VERSION ]] || die "VERSION file missing from bundle — is this a valid deploy ZIP?"
|
|
VERSION="$(cat VERSION)"
|
|
|
|
IMAGE_TARBALL="wbxprov-remote-agent-${VERSION}.tar.gz"
|
|
[[ -f "$IMAGE_TARBALL" ]] || die "Image tarball not found: $IMAGE_TARBALL"
|
|
|
|
# --- 2. Verify checksum (optional; skip gracefully if no shasum tool) -----
|
|
|
|
if [[ -f SHA256SUMS ]]; then
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
log "Verifying SHA256 checksum..."
|
|
sha256sum -c SHA256SUMS >/dev/null || die "Checksum verification FAILED."
|
|
elif command -v shasum >/dev/null 2>&1; then
|
|
log "Verifying SHA256 checksum (macOS shasum)..."
|
|
shasum -a 256 -c SHA256SUMS >/dev/null || die "Checksum verification FAILED."
|
|
else
|
|
warn "No sha256sum/shasum tool found — skipping integrity check."
|
|
fi
|
|
log "Checksum OK."
|
|
else
|
|
warn "No SHA256SUMS file in bundle — skipping integrity check."
|
|
fi
|
|
|
|
# --- 3. Load the image -----------------------------------------------------
|
|
# ALWAYS docker load, unconditionally. `docker load` reassigns the tag to
|
|
# whatever's in the tarball and is a fast no-op when the layers are already
|
|
# present, so this is safe to re-run. We intentionally do NOT "skip if the
|
|
# tag already exists" — a stale image left over from a previous wrong-arch
|
|
# attempt has this exact tag, and skipping the load would hide the correct
|
|
# image in the tarball we're actually holding.
|
|
|
|
IMAGE_TAG="wbxprov-remote-agent:${VERSION}"
|
|
|
|
log "Loading Docker image from ${IMAGE_TARBALL}..."
|
|
docker load -i "$IMAGE_TARBALL"
|
|
|
|
# --- 3a. Platform sanity check --------------------------------------------
|
|
# Inspect the image we just (re)loaded — this is the ground truth for what
|
|
# was actually shipped in this ZIP, independent of anything that was on the
|
|
# host before. If the tarball was built for a different CPU architecture
|
|
# than this host, Docker will let it "run" but tini (and node) fail with
|
|
# cryptic errors like "exec format error". Catch that up front with a
|
|
# clear message.
|
|
|
|
IMAGE_ARCH="$(docker image inspect --format '{{.Architecture}}' "$IMAGE_TAG" 2>/dev/null || true)"
|
|
IMAGE_ID_SHORT="$(docker image inspect --format '{{.Id}}' "$IMAGE_TAG" 2>/dev/null | sed 's|^sha256:||' | cut -c1-12)"
|
|
|
|
HOST_ARCH_RAW="$(uname -m)"
|
|
case "$HOST_ARCH_RAW" in
|
|
x86_64|amd64) HOST_ARCH="amd64" ;;
|
|
aarch64|arm64) HOST_ARCH="arm64" ;;
|
|
armv7l) HOST_ARCH="arm" ;;
|
|
*) HOST_ARCH="$HOST_ARCH_RAW" ;;
|
|
esac
|
|
|
|
log "Loaded ${IMAGE_TAG} (id: ${IMAGE_ID_SHORT:-unknown}, arch: ${IMAGE_ARCH:-unknown}); host arch: ${HOST_ARCH}."
|
|
|
|
if [[ -z "$IMAGE_ARCH" ]]; then
|
|
die "Could not read image architecture from Docker — is the image really loaded?"
|
|
fi
|
|
|
|
if [[ "$IMAGE_ARCH" != "$HOST_ARCH" ]]; then
|
|
warn "Image architecture (${IMAGE_ARCH}) does not match this host (${HOST_ARCH})."
|
|
warn "The container would fail to start with 'exec /sbin/tini: exec format error'."
|
|
warn ""
|
|
warn "This means the ZIP was built for the wrong CPU. On the build host:"
|
|
warn " 1. git pull # make sure you have the fixed package.sh"
|
|
warn " 2. ./docker/remote-agent/package.sh --platform linux/${HOST_ARCH}"
|
|
warn "The updated package.sh verifies the architecture during build and"
|
|
warn "refuses to produce a ZIP that would fail this check."
|
|
die "Aborting install. Ship a linux/${HOST_ARCH} bundle and re-run this script."
|
|
fi
|
|
|
|
# --- 4. Bootstrap .env -----------------------------------------------------
|
|
|
|
if [[ ! -f .env ]]; then
|
|
if [[ -f .env.example ]]; then
|
|
cp .env.example .env
|
|
warn ".env did not exist — copied .env.example into place."
|
|
warn "EDIT .env now to set WS_URL and WS_TOKEN, then re-run this script."
|
|
exit 0
|
|
else
|
|
die ".env is missing and no .env.example is bundled. Cannot proceed."
|
|
fi
|
|
fi
|
|
|
|
# --- 5. Start the container -----------------------------------------------
|
|
|
|
log "Starting wbxprov-remote-agent (version ${VERSION})..."
|
|
"${COMPOSE[@]}" up -d
|
|
|
|
log "Done. Tail logs with:"
|
|
log " ${COMPOSE[*]} logs -f"
|
|
log "Stop with:"
|
|
log " ${COMPOSE[*]} down"
|