Seven new lib tools — covers the remaining Bryan-requested gaps.
lib/nc-engine.sh
- Cloverleaf process control. Wraps shipped binaries (hcienginestop,
hcienginerun, hcienginerestart, hciengineroutetest). Every action
is Y/N confirmed AND journaled into engine-actions.tsv.
- Subcommands: stop, start, bounce/restart, status, resend-ib,
resend-ob, route-test, testxlate, tpstest.
lib/nc-status.sh
- Runtime status, v1-modelled. Subcommands: sites, threads, not-up,
connections, queued, raw. Auto-discovers hcienginestat / tstat /
connstatus binaries; falls back to file-presence heuristics.
lib/nc-table.sh
- Read+CRUD for .tbl lookup tables. Subcommands: list, show, pairs
(→csv/tsv), lookup, reverse-lookup, add, delete, create, replace.
- All modifications journal-backed. Composes csv-to-table /
table-to-csv for format conversion.
lib/nc-xlate.sh
- Visualize .xlt files. Parses the TCL nested-block ops format.
Subcommands: list, show, ops (TSV), tree (ASCII flow), summary
(counts + segments + tables touched), diff (cross-xlate).
- Confirmed working against Epic_ADT_CodaMetrix.xlt: identified
12 PATHCOPY + 1 COPY ops across MSH/EVN/PID/PV1/PV2/PD1/ZPD/ZPV/
AL1/GT1/IN1/IN2.
lib/nc-smat-diff.sh
- Cross-env smat content diff. Samples N msgs from each side,
pairs by configurable HL7 field (default MSH.10 = control ID),
hl7-diffs each pair with --ignore MSH.7. Outputs per-pair reports
+ master _summary.md with paired/A-only/B-only counts.
lib/nc-create-thread.sh
- High-level: create a new protocol + optionally splice a route from
an existing thread to the new one. Both writes journal-backed.
Confirmed end-to-end: created to_metrics_test outbound + routed
IB_ADT_muxS → to_metrics_test via journal entries 001+002.
lib/nc-tclgen.sh
- TCL UPOC scaffolding from intent. Templates: tps-presc, tps-postsc,
tps-iclkill, xlate-helper, trxid, ack, field-rewrite. Produces
clean syntax-correct TCL ready to edit.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
192 lines
11 KiB
Bash
Executable File
192 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install-larry.sh — bootstrap Larry-Anywhere on a fresh remote shell.
|
|
# No root, no package install, no sudo. Writes only into $LARRY_HOME.
|
|
#
|
|
# Usage:
|
|
# curl -fsSL <BASE_URL>/install-larry.sh | bash
|
|
#
|
|
# Or with explicit base URL:
|
|
# LARRY_BASE_URL=https://example.com/larry-anywhere bash install-larry.sh
|
|
#
|
|
# Env vars:
|
|
# LARRY_HOME install location (default: $HOME/.larry)
|
|
# LARRY_BASE_URL where to fetch files from (no trailing slash)
|
|
# LARRY_BIN_DIR where to symlink the `larry` command (default: $HOME/bin)
|
|
set -eu
|
|
|
|
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
|
|
# Canonical hosting: bojj27/cloverleaf-larry on GitHub, branch main, raw view.
|
|
# Override via env if you fork or mirror elsewhere.
|
|
LARRY_BASE_URL="${LARRY_BASE_URL:-https://raw.githubusercontent.com/bojj27/cloverleaf-larry/main}"
|
|
LARRY_BIN_DIR="${LARRY_BIN_DIR:-$HOME/bin}"
|
|
|
|
C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'; C_GREEN=$'\033[32m'
|
|
C_YELLOW=$'\033[33m'; C_RED=$'\033[31m'; C_CYAN=$'\033[36m'
|
|
|
|
say() { printf '%s%sinstall-larry>%s %s\n' "$C_CYAN" "$C_BOLD" "$C_RESET" "$*"; }
|
|
ok() { printf ' %s✓%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
|
|
warn() { printf ' %s!%s %s\n' "$C_YELLOW" "$C_RESET" "$*"; }
|
|
die() { printf '%serror:%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; exit 1; }
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Detect platform
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
UNAME_S="$(uname -s 2>/dev/null || echo unknown)"
|
|
PLATFORM=""
|
|
case "$UNAME_S" in
|
|
Linux*) PLATFORM="linux" ;;
|
|
Darwin*) PLATFORM="darwin" ;;
|
|
CYGWIN*|MINGW*|MSYS*) PLATFORM="windows-cygwin" ;; # MobaXterm lives here
|
|
*) PLATFORM="unknown" ;;
|
|
esac
|
|
|
|
ARCH="$(uname -m 2>/dev/null || echo unknown)"
|
|
case "$ARCH" in
|
|
x86_64|amd64) ARCH_NORM="amd64" ;;
|
|
aarch64|arm64) ARCH_NORM="arm64" ;;
|
|
i?86) ARCH_NORM="i386" ;;
|
|
*) ARCH_NORM="$ARCH" ;;
|
|
esac
|
|
|
|
say "platform: $PLATFORM/$ARCH_NORM • LARRY_HOME=$LARRY_HOME"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Check required commands
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
command -v bash >/dev/null 2>&1 || die "bash not found"
|
|
command -v curl >/dev/null 2>&1 || die "curl not found"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Make dirs
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
mkdir -p "$LARRY_HOME"/{agents,sessions,bin,lib} || die "cannot create $LARRY_HOME"
|
|
chmod 700 "$LARRY_HOME" 2>/dev/null || true
|
|
ok "created $LARRY_HOME"
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Fetch the scripts. If LARRY_BASE_URL is not set, try to detect being run
|
|
# from a local checkout (sibling files present) — copy locally instead.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" 2>/dev/null && pwd)" || SCRIPT_DIR=""
|
|
|
|
fetch() {
|
|
# $1 = remote relative path, $2 = local destination
|
|
if [ -n "$LARRY_BASE_URL" ]; then
|
|
say "fetching $1"
|
|
curl -fsSL --max-time 30 "$LARRY_BASE_URL/$1" -o "$2" \
|
|
&& ok "$2" || die "failed to fetch $1"
|
|
elif [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/$1" ]; then
|
|
cp "$SCRIPT_DIR/$1" "$2" && ok "copied $1 (local)"
|
|
else
|
|
die "no LARRY_BASE_URL set and $1 not found in script dir"
|
|
fi
|
|
}
|
|
|
|
fetch larry.sh "$LARRY_HOME/larry.sh"
|
|
fetch larry-tunnel.sh "$LARRY_HOME/larry-tunnel.sh"
|
|
fetch agents/larry.md "$LARRY_HOME/agents/larry.md"
|
|
fetch agents/clover.md "$LARRY_HOME/agents/clover.md"
|
|
fetch agents/cloverleaf-cheatsheet.md "$LARRY_HOME/agents/cloverleaf-cheatsheet.md"
|
|
fetch agents/regress.md "$LARRY_HOME/agents/regress.md"
|
|
fetch larry-rollback.sh "$LARRY_HOME/larry-rollback.sh"
|
|
fetch larry-auth.sh "$LARRY_HOME/larry-auth.sh"
|
|
fetch lib/oauth.sh "$LARRY_HOME/lib/oauth.sh"
|
|
fetch lib/lessons.sh "$LARRY_HOME/lib/lessons.sh"
|
|
fetch lib/hl7-sanitize.sh "$LARRY_HOME/lib/hl7-sanitize.sh"
|
|
fetch lib/hl7-desanitize.sh "$LARRY_HOME/lib/hl7-desanitize.sh"
|
|
fetch lib/each.sh "$LARRY_HOME/lib/each.sh"
|
|
fetch lib/each-site.sh "$LARRY_HOME/lib/each-site.sh"
|
|
fetch lib/len2nl.sh "$LARRY_HOME/lib/len2nl.sh"
|
|
fetch lib/csv-to-table.sh "$LARRY_HOME/lib/csv-to-table.sh"
|
|
fetch lib/table-to-csv.sh "$LARRY_HOME/lib/table-to-csv.sh"
|
|
fetch lib/nc-engine.sh "$LARRY_HOME/lib/nc-engine.sh"
|
|
fetch lib/nc-status.sh "$LARRY_HOME/lib/nc-status.sh"
|
|
fetch lib/nc-table.sh "$LARRY_HOME/lib/nc-table.sh"
|
|
fetch lib/nc-xlate.sh "$LARRY_HOME/lib/nc-xlate.sh"
|
|
fetch lib/nc-smat-diff.sh "$LARRY_HOME/lib/nc-smat-diff.sh"
|
|
fetch lib/nc-create-thread.sh "$LARRY_HOME/lib/nc-create-thread.sh"
|
|
fetch lib/nc-tclgen.sh "$LARRY_HOME/lib/nc-tclgen.sh"
|
|
fetch lib/nc-parse.sh "$LARRY_HOME/lib/nc-parse.sh"
|
|
fetch lib/nc-inbound.sh "$LARRY_HOME/lib/nc-inbound.sh"
|
|
fetch lib/nc-make-jump.sh "$LARRY_HOME/lib/nc-make-jump.sh"
|
|
fetch lib/hl7-field.sh "$LARRY_HOME/lib/hl7-field.sh"
|
|
fetch lib/nc-msgs.sh "$LARRY_HOME/lib/nc-msgs.sh"
|
|
fetch lib/nc-document.sh "$LARRY_HOME/lib/nc-document.sh"
|
|
fetch lib/nc-diff-interface.sh "$LARRY_HOME/lib/nc-diff-interface.sh"
|
|
fetch lib/nc-find.sh "$LARRY_HOME/lib/nc-find.sh"
|
|
fetch lib/nc-insert-protocol.sh "$LARRY_HOME/lib/nc-insert-protocol.sh"
|
|
fetch lib/hl7-diff.sh "$LARRY_HOME/lib/hl7-diff.sh"
|
|
fetch lib/nc-regression.sh "$LARRY_HOME/lib/nc-regression.sh"
|
|
fetch lib/journal.sh "$LARRY_HOME/lib/journal.sh"
|
|
fetch VERSION "$LARRY_HOME/VERSION"
|
|
fetch MANUAL.md "$LARRY_HOME/MANUAL.md"
|
|
chmod +x "$LARRY_HOME/larry.sh" "$LARRY_HOME/larry-tunnel.sh" "$LARRY_HOME/larry-rollback.sh" "$LARRY_HOME/larry-auth.sh" "$LARRY_HOME/lib/"*.sh
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# jq fallback — download static binary into $LARRY_HOME/bin/ if missing
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
if ! command -v jq >/dev/null 2>&1 && [ ! -x "$LARRY_HOME/bin/jq" ]; then
|
|
say "jq not found — fetching static binary into $LARRY_HOME/bin/jq"
|
|
JQ_BASE="https://github.com/jqlang/jq/releases/download/jq-1.7.1"
|
|
JQ_URL=""
|
|
case "$PLATFORM/$ARCH_NORM" in
|
|
linux/amd64) JQ_URL="$JQ_BASE/jq-linux-amd64" ;;
|
|
linux/arm64) JQ_URL="$JQ_BASE/jq-linux-arm64" ;;
|
|
linux/i386) JQ_URL="$JQ_BASE/jq-linux-i386" ;;
|
|
darwin/amd64) JQ_URL="$JQ_BASE/jq-macos-amd64" ;;
|
|
darwin/arm64) JQ_URL="$JQ_BASE/jq-macos-arm64" ;;
|
|
windows-cygwin/amd64) JQ_URL="$JQ_BASE/jq-windows-amd64.exe" ;;
|
|
windows-cygwin/i386) JQ_URL="$JQ_BASE/jq-windows-i386.exe" ;;
|
|
*) warn "no jq binary known for $PLATFORM/$ARCH_NORM — install jq manually" ;;
|
|
esac
|
|
if [ -n "$JQ_URL" ]; then
|
|
local_jq="$LARRY_HOME/bin/jq"
|
|
case "$PLATFORM" in windows-cygwin) local_jq="$LARRY_HOME/bin/jq.exe" ;; esac
|
|
if curl -fsSL --max-time 60 "$JQ_URL" -o "$local_jq"; then
|
|
chmod +x "$local_jq"
|
|
ok "jq -> $local_jq"
|
|
else
|
|
warn "could not download jq from $JQ_URL"
|
|
fi
|
|
fi
|
|
else
|
|
ok "jq available"
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Drop a `larry` shim onto PATH (best-effort)
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
mkdir -p "$LARRY_BIN_DIR" 2>/dev/null || true
|
|
if [ -d "$LARRY_BIN_DIR" ] && [ -w "$LARRY_BIN_DIR" ]; then
|
|
cat > "$LARRY_BIN_DIR/larry" <<EOF
|
|
#!/usr/bin/env bash
|
|
# Auto-generated by install-larry.sh
|
|
export LARRY_HOME="${LARRY_HOME}"
|
|
exec "${LARRY_HOME}/larry.sh" "\$@"
|
|
EOF
|
|
chmod +x "$LARRY_BIN_DIR/larry"
|
|
ok "shim: $LARRY_BIN_DIR/larry"
|
|
case ":$PATH:" in
|
|
*":$LARRY_BIN_DIR:"*) : ;;
|
|
*) warn "$LARRY_BIN_DIR is not on PATH — add 'export PATH=\"$LARRY_BIN_DIR:\$PATH\"' to your shell rc" ;;
|
|
esac
|
|
else
|
|
warn "cannot write to $LARRY_BIN_DIR — invoke larry directly as: $LARRY_HOME/larry.sh"
|
|
fi
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Done
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
echo ""
|
|
say "install complete (no system changes were made; everything lives under $LARRY_HOME)"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1) export ANTHROPIC_API_KEY=sk-ant-... (or larry will prompt on first run)"
|
|
echo " 2) larry (or $LARRY_HOME/larry.sh)"
|
|
echo " 3) larry /path/to/cloverleaf/site_root (to start with a working dir)"
|
|
echo ""
|
|
echo "Reverse SSH tunnel (optional, run in another shell or backgrounded):"
|
|
echo " $LARRY_HOME/larry-tunnel.sh --serveo # zero-config"
|
|
echo " $LARRY_HOME/larry-tunnel.sh --hop=user@bjnoela.com:22 # your hop"
|
|
echo ""
|