e969234ca5
gates / consistency-and-conventions (push) Successful in 1m28s
- lib/registry.sh: shared query API over POS_* headers (reg_scan, reg_list, reg_lookup, reg_tools_in, reg_each, reg_config_scopes/keys). Replaces per-consumer sed/grep header parsing. - bin/pos-tree + bin/pos _pos_category_help(): migrated to registry API. Category help now shows [deps: ...] annotations. Tree output preserved. - New optional headers # POS_DEPS: and # POS_EXAMPLES: in tool metadata. Added to pos-network-download (aria2c jq curl), pos-media-sync (lsblk jq), pos-system-backup (tar), pos-docker-ps (docker) as initial adopters. - scripts/gen-docs.sh: extended tools array with deps/examples fields; conditional column rendering in gen_dispatch; deps annotation in gen_tree. Fixed URL-unsafe // joiner (→ middle dot ·) and \x1f caption delimiter collision in config-ui. - bin/pos-ai-alias: rewrote activation from bash aliases (source-time-frozen) to executable wrapper scripts at ~/.local/bin. Staleness eliminated: edits apply on next invocation with no shell reload. _alias_sync() reconciliation on every subcommand, marker-guarded lifecycle, collision refusal, legacy .sh retirement. Fixed dup-table bug (option 4 no-op). - lib/config-ui.sh: @caption/@[KEY=alt] conditional captions, *providers=<tag> tagged wildcards, uniform typography tier (bold/cyan/dim), honest prompt. Active provider keys bold, inactive dimmed with reason. Backward-compatible. - bin/pos-system-uninstall: marker-scan for wrapper script cleanup. - Docs synced: AGENTS.md (new headers + registry), DOC/SCRIPTS.md (registry section + lib list), DOC/POS.md (alias wrapper activation), MAINTENANCE.md (M-024). Lint fixed: pos-ai-alias registered in INTERACTIVE_CMDS. Gates: make gen && make check && make lint = 0 FAIL, 0 WARN
119 lines
3.5 KiB
Bash
Executable File
119 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
# POS: tree — Show the pos CLI command tree: categories, commands, and subcommands
|
|
# POS_FLAGS: --depth
|
|
|
|
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
|
|
source "$(dirname "$0")/../lib/registry.sh" 2>/dev/null || source "$(dirname "$0")/registry.sh"
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: pos tree [--depth N]
|
|
|
|
Print the `pos` command tree: every category, command, and subcommand the
|
|
dispatcher can reach, annotated with each tool's # POS: description.
|
|
|
|
pos tree Full command tree
|
|
pos tree --depth N Limit nesting depth (1 = root only)
|
|
pos tree --help This help
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
depth=""
|
|
case "${1:-}" in
|
|
-h|--help) usage ;;
|
|
--depth)
|
|
[ $# -ge 2 ] || err "--depth requires a number"
|
|
depth="$2"
|
|
[[ "$depth" =~ ^[0-9]+$ ]] || err "--depth must be a number"
|
|
shift 2
|
|
;;
|
|
-*) err "unknown flag: $1" ;;
|
|
esac
|
|
|
|
self="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
declare -A children meta
|
|
maxw=0
|
|
|
|
# add <parent> <word> <type> <desc> — parent "/" is the root.
|
|
add() {
|
|
local parent="$1" word="$2" type="$3" desc="$4" path
|
|
if [ "$parent" = "/" ]; then path="$word"; else path="$parent/$word"; fi
|
|
children["$parent"]+=" $word"
|
|
meta["$path"]="$type|$desc"
|
|
}
|
|
|
|
reg_scan "$self"
|
|
|
|
for tool_key in $(reg_list); do
|
|
cat="$(reg_lookup "$tool_key" cat)"
|
|
desc="$(reg_lookup "$tool_key" desc)"
|
|
sc="$(reg_lookup "$tool_key" subcmds)"
|
|
deps="$(reg_lookup "$tool_key" deps)"
|
|
name="${tool_key}"
|
|
if [ -n "$deps" ]; then
|
|
desc="$desc [deps: $deps]"
|
|
fi
|
|
words=(${name//-/ })
|
|
parent="/"
|
|
for ((i=0; i<${#words[@]}; i++)); do
|
|
word="${words[$i]}"
|
|
if [ "$parent" = "/" ]; then path="$word"; else path="$parent/$word"; fi
|
|
if [ $((i + 1)) -eq ${#words[@]} ]; then
|
|
add "$parent" "$word" "tool" "$desc"
|
|
else
|
|
[ -n "${meta[$path]:-}" ] || add "$parent" "$word" "cat" ""
|
|
fi
|
|
parent="$path"
|
|
done
|
|
for s in $sc; do
|
|
add "$parent" "$s" "sub" ""
|
|
done
|
|
done
|
|
|
|
# pad = widest "pos <full path>" leaf, so descriptions align
|
|
for p in "${!meta[@]}"; do
|
|
case "${meta[$p]%%|*}" in
|
|
tool|sub)
|
|
len=$(( ${#p} + 4 ))
|
|
[ "$len" -gt "$maxw" ] && maxw=$len
|
|
;;
|
|
esac
|
|
done
|
|
|
|
render() {
|
|
local parent="$1" prefix="$2" lvl="$3"
|
|
if [ -n "$depth" ] && [ "$lvl" -ge "$depth" ]; then return; fi
|
|
local -a kids
|
|
mapfile -t kids < <(printf '%s\n' ${children[$parent]:-} | sort -u)
|
|
local i word path type desc conn nextpref last
|
|
for ((i=0; i<${#kids[@]}; i++)); do
|
|
word="${kids[$i]}"
|
|
if [ "$parent" = "/" ]; then path="$word"; else path="$parent/$word"; fi
|
|
last=$(( i == ${#kids[@]} - 1 ))
|
|
if [ "$last" -eq 1 ]; then conn="└── "; nextpref="$prefix "; else conn="├── "; nextpref="$prefix│ "; fi
|
|
type="${meta[$path]%%|*}"
|
|
desc="${meta[$path]#*|}"
|
|
case "$type" in
|
|
cat)
|
|
printf '%s%s%s/\n' "$prefix" "$conn" "$word"
|
|
render "$path" "$nextpref" $((lvl+1))
|
|
;;
|
|
tool)
|
|
printf '%s%s%-*s# %s\n' "$prefix" "$conn" "$((maxw+1))" "pos ${path//\// }" "$desc"
|
|
if [ -n "${children[$path]:-}" ]; then
|
|
render "$path" "$nextpref" $((lvl+1))
|
|
fi
|
|
;;
|
|
sub)
|
|
printf '%s%s%s\n' "$prefix" "$conn" "pos ${path//\// }"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
printf 'pos\n'
|
|
render "/" "" 1
|