cloverleaf-larry/lib/nc-status.sh
Bryan Johnson a0502e2ec6 v0.4.2: operational layer — engine ctrl, tables CRUD, xlate viz, smat-diff, create-thread, tclgen
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>
2026-05-26 11:11:30 -07:00

153 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# nc-status.sh — Cloverleaf engine runtime status. Native v3 wrapper around
# the shipped status/tstat binaries — modelled on v1 `status`, `tstats`,
# `tstat`, `thread_status`, `procstatus`, `dstatus`, `connstatus`, `not_up`.
#
# Subcommands:
# sites site-level status (daemon + processes + threads)
# threads thread-level status (port, state, host)
# not-up only threads not in 'up' state
# connections raw connection state (from connstatus binary if available)
# queued threads with messages queued
# raw pass-through to the underlying tstat binary
#
# Flags (where applicable):
# --site SITE single site; default = all sites under $HCIROOT
# --filter REGEX match on thread name
# --format text|tsv default text
#
# This is V1-modeled but native-bash. The exact binary names depend on the
# Cloverleaf version; we auto-discover under $HCIROOT/bin (and server/bin).
set -o pipefail
NC_SELF="$0"
die() { printf 'nc-status: %s\n' "$*" >&2; exit 1; }
warn() { printf 'nc-status: %s\n' "$*" >&2; }
resolve_binary() {
local name="$1"
if command -v "$name" >/dev/null 2>&1; then command -v "$name"; return; fi
for d in "${HCIROOT:-}/bin" "${HCIROOT:-}/server/bin"; do
[ -x "$d/$name" ] && { echo "$d/$name"; return; }
done
return 1
}
list_sites() {
local root="${HCIROOT:-}"
[ -d "$root" ] || die "no \$HCIROOT or it doesn't exist"
find "$root" -mindepth 1 -maxdepth 2 -name NetConfig -type f 2>/dev/null \
| xargs -I{} dirname {} 2>/dev/null \
| xargs -I{} basename {} 2>/dev/null \
| sort -u
}
cmd_sites() {
local target_site=""
local format="text"
while [ $# -gt 0 ]; do
case "$1" in
--site) shift; target_site="$1" ;;
--format) shift; format="$1" ;;
*) die "unknown flag: $1" ;;
esac
shift
done
local hcienginestat; hcienginestat=$(resolve_binary hcienginestat 2>/dev/null || true)
local sites_to_check
if [ -n "$target_site" ]; then sites_to_check="$target_site"; else sites_to_check=$(list_sites); fi
[ "$format" = "tsv" ] && printf 'site\tstate\tdetail\n'
while IFS= read -r s; do
[ -z "$s" ] && continue
local detail="" state="?"
if [ -n "$hcienginestat" ]; then
detail=$(HCISITE="$s" "$hcienginestat" 2>&1 || true)
if echo "$detail" | grep -qiE 'running|active|up'; then state="up"
elif echo "$detail" | grep -qiE 'stopped|down'; then state="down"
else state="unknown"; fi
else
# Fallback: check for lock file / pid file as a poor-man's check
if [ -e "${HCIROOT:-}/$s/lock" ] || [ -e "${HCIROOT:-}/$s/exec/processes" ]; then
state="config-present"
fi
fi
if [ "$format" = "tsv" ]; then
printf '%s\t%s\t%s\n' "$s" "$state" "$(echo "$detail" | head -1)"
else
printf '== %-20s [%s] ==\n%s\n' "$s" "$state" "$(echo "$detail" | head -10)"
fi
done <<< "$sites_to_check"
}
cmd_threads() {
local target_site="${HCISITE:-}"
local filter=""
local format="text"
while [ $# -gt 0 ]; do
case "$1" in
--site) shift; target_site="$1" ;;
--filter) shift; filter="$1" ;;
--format) shift; format="$1" ;;
*) die "unknown flag: $1" ;;
esac
shift
done
local tstat; tstat=$(resolve_binary tstat) || die "tstat binary not found under \$HCIROOT/bin or PATH"
local args=()
[ -n "$target_site" ] && args+=("-s" "$target_site")
local output; output=$(HCISITE="$target_site" "$tstat" "${args[@]}" 2>&1 || true)
if [ -n "$filter" ]; then
output=$(printf '%s' "$output" | grep -E -- "$filter")
fi
if [ "$format" = "tsv" ]; then
# Best-effort: parse the tstat output into TSV
printf '%s\n' "$output" | awk 'NR>1 && NF>0 { gsub(/ +/, "\t"); print }'
else
printf '%s\n' "$output"
fi
}
cmd_not_up() {
local site="${HCISITE:-}"
local filter=""
while [ $# -gt 0 ]; do
case "$1" in
--site) shift; site="$1" ;;
--filter) shift; filter="$1" ;;
*) die "unknown flag: $1" ;;
esac
shift
done
cmd_threads --site "$site" ${filter:+--filter "$filter"} \
| awk 'NR==1 || tolower($0) !~ /\<up\>/'
}
cmd_connections() {
local connstatus; connstatus=$(resolve_binary connstatus 2>/dev/null) || die "connstatus binary not found"
"$connstatus" "$@"
}
cmd_queued() {
local site="${HCISITE:-}"
cmd_threads --site "$site" "$@" \
| awk 'NR==1 || tolower($0) ~ /queued|obq|ibq/'
}
cmd_raw() {
local tstat; tstat=$(resolve_binary tstat) || die "tstat binary not found"
"$tstat" "$@"
}
SUB="${1:-sites}"
case "$SUB" in
sites) shift; cmd_sites "$@" ;;
threads) shift; cmd_threads "$@" ;;
not-up) shift; cmd_not_up "$@" ;;
connections) shift; cmd_connections "$@" ;;
queued) shift; cmd_queued "$@" ;;
raw) shift; cmd_raw "$@" ;;
help|-h|--help) sed -n '2,25p' "$NC_SELF" ;;
*) die "unknown subcommand: $SUB" ;;
esac