Make the toolkit usable BY HAND without the `larry tools <name>` prefix. - bin/ of thin wrappers (tbn/tbp/tbh/tbpr/where/paths/route_test + a full-name passthrough per operator tool). Installer symlinks them into LARRY_BIN_DIR so `tbn adt` runs directly. Each resolves lib/ via bin/_nc_common.sh (LARRY_LIB_DIR -> ../lib -> $LARRY_HOME/lib) and execs the matching tool. - -h/--help on every wrapper. - bin/nc-completion.bash: dynamic bash completion, 3 levels (command / SITE / THREAD) enumerated LIVE from the NetConfig tree under $HCIROOT via the same lib/nc-parse.sh the tools use; cached per (HCIROOT, newest-NetConfig-mtime). Installer appends a guarded source line to the user's bash rc. - fixtures/integrator: durable 3-site demo (epic->ancout->codamx) with cross- site fan-out + fan-in and a multi-route inbound. RESOLVES the v0.9.3 fixture conflict: cross-site destination blocks are XS_*-prefixed so they never collide with a local protocol name (a collision makes nc-paths _xsite_down_targets suppress the cross-site hop, lib/nc-paths.sh:378). - DEFERRED: fetch-token.sh broker wiring (broker contract still finalizing). VERSION+LARRY_VERSION -> 0.9.4; MANIFEST regenerated (--check clean); bash -n clean; verified live on .135 (short commands off PATH + all 3 completion levels). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
163 lines
6.8 KiB
Bash
163 lines
6.8 KiB
Bash
# nc-completion.bash — dynamic bash tab-completion for the Cloverleaf-Larry
|
|
# short commands. Source this file (the installer adds it to your shell rc):
|
|
#
|
|
# source /path/to/cloverleaf-larry/bin/nc-completion.bash
|
|
#
|
|
# THREE LEVELS, all enumerated LIVE off the NetConfig site tree under $HCIROOT
|
|
# (never a static list — it reflects exactly what the tools see right now):
|
|
#
|
|
# 1. COMMAND NAMES — `tb<TAB>` → tbn tbp tbh tbpr ; `nc-<TAB>` → nc-find …
|
|
# 2. SITE NAMES — `tbn <TAB>` → adt ancout codamx epic …
|
|
# 3. THREAD NAMES — `paths <TAB>`, `route_test --source-thread <TAB>`,
|
|
# `where <TAB>` → IB_ADT_epic MUX_ADT_ancout …
|
|
#
|
|
# Sites/threads are read through the SAME parser the tools use (lib/nc-parse.sh
|
|
# via bin/_nc_common.sh), so completion can never drift from reality. Results
|
|
# are cached per (HCIROOT, mtime-of-tree) for the life of the shell so repeated
|
|
# TABs are instant; the cache invalidates automatically when a NetConfig under
|
|
# $HCIROOT changes.
|
|
|
|
# Locate _nc_common.sh relative to THIS completion file (works for both the repo
|
|
# layout and an installed copy). Sourced once at load.
|
|
if [ -z "${_NC_COMPLETION_COMMON:-}" ]; then
|
|
_ncc_self="${BASH_SOURCE[0]}"
|
|
_NC_COMPLETION_COMMON="$(cd "$(dirname "$_ncc_self")" 2>/dev/null && pwd)/_nc_common.sh"
|
|
unset _ncc_self
|
|
fi
|
|
|
|
# --- cache key = HCIROOT + newest NetConfig mtime (cheap staleness check) ----
|
|
_nc_comp_cachekey() {
|
|
local root="${HCIROOT:-}"
|
|
[ -n "$root" ] && [ -d "$root" ] || { printf 'none'; return; }
|
|
local newest
|
|
newest="$(find "$root" -maxdepth 2 -name NetConfig -printf '%T@\n' 2>/dev/null | sort -rn | head -1)"
|
|
printf '%s@%s' "$root" "${newest:-0}"
|
|
}
|
|
|
|
# --- live site list (cached) -------------------------------------------------
|
|
_NC_COMP_SITES_KEY=""; _NC_COMP_SITES=""
|
|
_nc_comp_sites() {
|
|
local key; key="$(_nc_comp_cachekey)"
|
|
if [ "$key" != "$_NC_COMP_SITES_KEY" ]; then
|
|
[ -f "$_NC_COMPLETION_COMMON" ] && . "$_NC_COMPLETION_COMMON"
|
|
_NC_COMP_SITES="$(_nc_sites 2>/dev/null | tr '\n' ' ')"
|
|
_NC_COMP_SITES_KEY="$key"
|
|
fi
|
|
printf '%s' "$_NC_COMP_SITES"
|
|
}
|
|
|
|
# --- live thread list (cached) -----------------------------------------------
|
|
_NC_COMP_THREADS_KEY=""; _NC_COMP_THREADS=""
|
|
_nc_comp_threads() {
|
|
local key; key="$(_nc_comp_cachekey)"
|
|
if [ "$key" != "$_NC_COMP_THREADS_KEY" ]; then
|
|
[ -f "$_NC_COMPLETION_COMMON" ] && . "$_NC_COMPLETION_COMMON"
|
|
_NC_COMP_THREADS="$(_nc_threads 2>/dev/null | tr '\n' ' ')"
|
|
_NC_COMP_THREADS_KEY="$key"
|
|
fi
|
|
printf '%s' "$_NC_COMP_THREADS"
|
|
}
|
|
|
|
# --- generic completer: offer sites + threads (union) for a name argument ----
|
|
# Most short commands take "a site OR a thread"; offering both satisfies every
|
|
# documented level (tbn→sites, paths/where→threads) without over-fitting.
|
|
_nc_complete_names() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
|
local pool="$(_nc_comp_sites) $(_nc_comp_threads)"
|
|
COMPREPLY=( $(compgen -W "$pool" -- "$cur") )
|
|
}
|
|
|
|
# --- threads-only completer (route_test --source-thread, paths, where) -------
|
|
_nc_complete_threads_only() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
|
COMPREPLY=( $(compgen -W "$(_nc_comp_threads)" -- "$cur") )
|
|
}
|
|
|
|
# --- sites-only completer ----------------------------------------------------
|
|
_nc_complete_sites_only() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}"
|
|
COMPREPLY=( $(compgen -W "$(_nc_comp_sites)" -- "$cur") )
|
|
}
|
|
|
|
# --- per-command completers ---------------------------------------------------
|
|
# tbn: thread-name search, but a site name is the natural first thing operators
|
|
# type (tbn adt) — so offer the union (sites + threads). Same for tbh/tbpr.
|
|
_nc_complete_tbn() { _nc_complete_names; }
|
|
_nc_complete_tbh() { _nc_complete_names; }
|
|
_nc_complete_tbpr() {
|
|
# process-name search → no live process index; fall back to threads+sites.
|
|
_nc_complete_names
|
|
}
|
|
|
|
# tbp: v1 "thread by port". The task wants this to surface thread names on TAB,
|
|
# so we complete against threads (the operator can still type a bare port).
|
|
_nc_complete_tbp() { _nc_complete_threads_only; }
|
|
|
|
# where: positional <thread>.
|
|
_nc_complete_where() { _nc_complete_threads_only; }
|
|
|
|
# paths: first arg <thread>, optional 2nd arg <site>, then flags.
|
|
_nc_complete_paths() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
case "$cur" in
|
|
-*) COMPREPLY=( $(compgen -W "--up --down --site-only --all --site --format --hciroot" -- "$cur") ); return ;;
|
|
esac
|
|
case "$prev" in
|
|
--site) _nc_complete_sites_only; return ;;
|
|
--format) COMPREPLY=( $(compgen -W "v1 table tsv jsonl nodes" -- "$cur") ); return ;;
|
|
esac
|
|
# 1st positional → thread; 2nd positional → site. Count prior non-flag words.
|
|
local i nonflag=0
|
|
for ((i=1; i<COMP_CWORD; i++)); do
|
|
case "${COMP_WORDS[i]}" in -*) ;; *) ((nonflag++)) ;; esac
|
|
done
|
|
if [ "$nonflag" -eq 0 ]; then _nc_complete_threads_only
|
|
elif [ "$nonflag" -eq 1 ]; then _nc_complete_sites_only
|
|
else _nc_complete_names; fi
|
|
}
|
|
|
|
# route_test: <thread> <file>, or --source-thread <thread> [--file <file>].
|
|
_nc_complete_route_test() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
case "$prev" in
|
|
--source-thread|--thread) _nc_complete_threads_only; return ;;
|
|
--file) COMPREPLY=( $(compgen -f -- "$cur") ); return ;;
|
|
esac
|
|
case "$cur" in
|
|
-*) COMPREPLY=( $(compgen -W "--source-thread --file --dry-run" -- "$cur") ); return ;;
|
|
esac
|
|
# bare first positional → thread; subsequent → file path.
|
|
local i nonflag=0
|
|
for ((i=1; i<COMP_CWORD; i++)); do
|
|
case "${COMP_WORDS[i]}" in --source-thread|--thread|--file) ((i++)) ;; -*) ;; *) ((nonflag++)) ;; esac
|
|
done
|
|
if [ "$nonflag" -eq 0 ]; then _nc_complete_threads_only
|
|
else COMPREPLY=( $(compgen -f -- "$cur") ); fi
|
|
}
|
|
|
|
# nc-find: mode-aware (after --name/--where/etc, offer names; after --port, nothing).
|
|
_nc_complete_nc_find() {
|
|
local cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
case "$prev" in
|
|
--name|--where) _nc_complete_names; return ;;
|
|
--process) _nc_complete_threads_only; return ;;
|
|
--format) COMPREPLY=( $(compgen -W "table tsv jsonl" -- "$cur") ); return ;;
|
|
--hciroot) COMPREPLY=( $(compgen -d -- "$cur") ); return ;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W "--name --port --host --process --where --xlate --tclproc --format --hciroot --case-sensitive" -- "$cur") )
|
|
}
|
|
|
|
# nc-paths shares the paths completer.
|
|
_nc_complete_nc_paths() { _nc_complete_paths; }
|
|
|
|
# Register. Short commands first (the headline ergonomics), then full names.
|
|
complete -F _nc_complete_tbn tbn
|
|
complete -F _nc_complete_tbp tbp
|
|
complete -F _nc_complete_tbh tbh
|
|
complete -F _nc_complete_tbpr tbpr
|
|
complete -F _nc_complete_where where
|
|
complete -F _nc_complete_paths paths
|
|
complete -F _nc_complete_route_test route_test
|
|
complete -F _nc_complete_nc_find nc-find
|
|
complete -F _nc_complete_nc_paths nc-paths
|