feat: nested pos subcommands — POS_SUBCMDS header, nested category help + completion
This commit is contained in:
@@ -47,6 +47,11 @@ summary (newest last).
|
|||||||
|
|
||||||
## Done (summary, newest last)
|
## Done (summary, newest last)
|
||||||
|
|
||||||
|
- 2026-08-06: Nested `pos` subcommands — `# POS_SUBCMDS:` header annotation (telegram,
|
||||||
|
docker-compose, docker-vbox) + `make gen` emits a `_pos_subcmds` completion map;
|
||||||
|
nested tools (`telegram listener`) auto-list under their parent instead of as a
|
||||||
|
flat sibling (`telegram-listener`) in `pos <category>` and tab-completion; generic
|
||||||
|
tool-level completion (subcommands + flags + `--help`).
|
||||||
- 2026-08-06: Telegram **listener** — `pos communication telegram listener`:
|
- 2026-08-06: Telegram **listener** — `pos communication telegram listener`:
|
||||||
interactive `/command` → bash map editor + owner-only polling daemon as a
|
interactive `/command` → bash map editor + owner-only polling daemon as a
|
||||||
systemd user service (map in `~/.config/linux_post_install/telegram_commands.env`,
|
systemd user service (map in `~/.config/linux_post_install/telegram_commands.env`,
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ System-wide flag store at `/usr/local/share/linux_post_install/flags/`:
|
|||||||
### Adding a New Tool
|
### Adding a New Tool
|
||||||
|
|
||||||
1. Create `bin/pos-<category>-<command>` from `templates/pos-tool.sh` — must be executable (`100755`); it auto-appears in `pos <category> --help` (filename-derived, no registration)
|
1. Create `bin/pos-<category>-<command>` from `templates/pos-tool.sh` — must be executable (`100755`); it auto-appears in `pos <category> --help` (filename-derived, no registration)
|
||||||
2. Add the `# POS: <cat> <cmd> — <one-line description>` header right after the shebang (plus `# POS_FLAGS: ...` for flag-style tools) — this is the single source of truth for the generated docs
|
2. Add the `# POS: <cat> <cmd> — <one-line description>` header right after the shebang (plus `# POS_FLAGS: ...` for flag-style tools and `# POS_SUBCMDS: ...` for multi-command tools) — this is the single source of truth for the generated docs; nested tools (`pos-<cat>-<a>-<b>`) auto-list under their parent tool
|
||||||
3. Add to `INTERACTIVE_CMDS` in `bin/pos` if it reads stdin
|
3. Add to `INTERACTIVE_CMDS` in `bin/pos` if it reads stdin
|
||||||
4. Add system deps to `PACKAGES` array in `preinstall.sh` (if needed); non-apt/manual installers → `command -v` guard in the tool instead
|
4. Add system deps to `PACKAGES` array in `preinstall.sh` (if needed); non-apt/manual installers → `command -v` guard in the tool instead
|
||||||
5. Add config logic to `postinstall.sh` (if needed, with `.gitignore` for secrets); runtime tool config → `~/.config/linux_post_install/<tool>.env` (600)
|
5. Add config logic to `postinstall.sh` (if needed, with `.gitignore` for secrets); runtime tool config → `~/.config/linux_post_install/<tool>.env` (600)
|
||||||
@@ -532,13 +532,13 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
|||||||
| `bin/flag-clear` | 21 | Unset a flag |
|
| `bin/flag-clear` | 21 | Unset a flag |
|
||||||
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
| `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) |
|
||||||
<!-- GEN:START filetable -->
|
<!-- GEN:START filetable -->
|
||||||
| `bin/pos` | 219 | CLI dispatcher with smart arg matching + logging + category help |
|
| `bin/pos` | 267 | CLI dispatcher with smart arg matching + logging + category help |
|
||||||
| `bin/pos-communication-telegram-listener` | 408 | Telegram bot listener: map /command → bash, run them on chat messages |
|
| `bin/pos-communication-telegram-listener` | 408 | Telegram bot listener: map /command → bash, run them on chat messages |
|
||||||
| `bin/pos-communication-telegram` | 274 | Send Telegram messages/files/links/stickers via Bot API (send, test, config set) |
|
| `bin/pos-communication-telegram` | 275 | Send Telegram messages/files/links/stickers via Bot API (send, test, config set) |
|
||||||
| `bin/pos-docker-compose` | 364 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
| `bin/pos-docker-compose` | 365 | Docker Compose service manager (ls/up/down/restart/logs/update/config) |
|
||||||
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
|
| `bin/pos-docker-health` | 110 | One-glance container health dashboard (exits 1 if unhealthy) |
|
||||||
| `bin/pos-docker-ps` | 128 | Enhanced container overview (health, IPs, ports, uptime) |
|
| `bin/pos-docker-ps` | 128 | Enhanced container overview (health, IPs, ports, uptime) |
|
||||||
| `bin/pos-docker-vbox` | 157 | Disposable Docker-based VMs (create/enter/start/stop/rm/ls) |
|
| `bin/pos-docker-vbox` | 158 | Disposable Docker-based VMs (create/enter/start/stop/rm/ls) |
|
||||||
| `bin/pos-entertainment-config` | 98 | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) |
|
| `bin/pos-entertainment-config` | 98 | Show or edit the entertainment config (ENABLED auto-trigger list, weather location) |
|
||||||
| `bin/pos-entertainment-disable` | 32 | Disable a plugin's auto-trigger (remove it from ENABLED) |
|
| `bin/pos-entertainment-disable` | 32 | Disable a plugin's auto-trigger (remove it from ENABLED) |
|
||||||
| `bin/pos-entertainment-enable` | 50 | Enable an auto-trigger for a plugin on a schedule |
|
| `bin/pos-entertainment-enable` | 50 | Enable an auto-trigger for a plugin on a schedule |
|
||||||
@@ -557,7 +557,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:`
|
|||||||
| `bin/pos-system-nfs-client` | 138 | Mount NFS shares (ephemeral or persistent systemd mount units) |
|
| `bin/pos-system-nfs-client` | 138 | Mount NFS shares (ephemeral or persistent systemd mount units) |
|
||||||
| `bin/pos-system-nfs-server` | 134 | Manage the NFS kernel server (status, share/unshare exports, enable/disable) |
|
| `bin/pos-system-nfs-server` | 134 | Manage the NFS kernel server (status, share/unshare exports, enable/disable) |
|
||||||
| `bin/pos-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) |
|
| `bin/pos-usb-server` | 218 | USB Redirector server control (--ls, --share; prompts when args omitted) |
|
||||||
| `completions/pos.bash` | 190 | Dynamic bash completion |
|
| `completions/pos.bash` | 215 | Dynamic bash completion |
|
||||||
<!-- GEN:END filetable -->
|
<!-- GEN:END filetable -->
|
||||||
| `apps/install.sh` | 171 | App install/uninstall picker/orchestrator |
|
| `apps/install.sh` | 171 | App install/uninstall picker/orchestrator |
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -125,8 +125,10 @@ esac
|
|||||||
```bash
|
```bash
|
||||||
# POS: <category> <command> — one-line description rendered by `make gen`
|
# POS: <category> <command> — one-line description rendered by `make gen`
|
||||||
# POS_FLAGS: --flag1 --flag2 # ONLY for flag-style tools
|
# POS_FLAGS: --flag1 --flag2 # ONLY for flag-style tools
|
||||||
|
# POS_SUBCMDS: sub1 sub2 # ONLY for multi-command tools
|
||||||
```
|
```
|
||||||
The description feeds the dispatch table, bin tree and file table in `DOC/AGENT_Context_Project.md`; `POS_FLAGS` feeds flag completion in `completions/pos.bash`. Both update via `make gen`.
|
The description feeds the dispatch table, bin tree and file table in `DOC/AGENT_Context_Project.md`; `POS_FLAGS` feeds flag completion and `POS_SUBCMDS` feeds subcommand completion in `completions/pos.bash` (both update via `make gen`).
|
||||||
|
- Nested tools (e.g. `bin/pos-communication-telegram-listener`) are auto-detected from filenames: the trailing segment (`listener`) is offered as a subcommand of the parent tool (`communication-telegram`) in `pos <category> --help` and tab-completion, instead of appearing as a flat sibling (`telegram-listener`). The flat dash-form (`pos communication telegram-listener`) still dispatches.
|
||||||
- Optionally add an EXAMPLES line in `bin/pos` `usage()` to showcase the tool in `pos --help`.
|
- Optionally add an EXAMPLES line in `bin/pos` `usage()` to showcase the tool in `pos --help`.
|
||||||
- If the command **reads stdin** (prompts/selection), add it to `INTERACTIVE_CMDS` in `bin/pos` — see [The `pos` CLI](#the-pos-cli).
|
- If the command **reads stdin** (prompts/selection), add it to `INTERACTIVE_CMDS` in `bin/pos` — see [The `pos` CLI](#the-pos-cli).
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ _pos_commands() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ── Category list (sorted, filename-derived) ─────────────────────
|
# ── Category list (sorted, filename-derived) ─────────────────────
|
||||||
|
# Nested sub-tools (pos-<cat>-<a>-<b> where pos-<cat>-<a> exists) are
|
||||||
|
# omitted from the cheat-sheet line — they are shown under their parent tool.
|
||||||
_pos_category_list() {
|
_pos_category_list() {
|
||||||
local -A cats=()
|
local -A cats=()
|
||||||
local cmd cat f
|
local cmd cat f
|
||||||
@@ -36,10 +38,19 @@ _pos_category_list() {
|
|||||||
[ "$cat" = "$cmd" ] && continue
|
[ "$cat" = "$cmd" ] && continue
|
||||||
cats["$cat"]+="${cmd#*-} "
|
cats["$cat"]+="${cmd#*-} "
|
||||||
done
|
done
|
||||||
local c line subs joined
|
local c subs joined s s2 top=() is_nested
|
||||||
for c in $(printf '%s\n' "${!cats[@]}" | sort); do
|
for c in $(printf '%s\n' "${!cats[@]}" | sort); do
|
||||||
subs=(${cats[$c]})
|
subs=(${cats[$c]})
|
||||||
joined="$(IFS='|'; echo "${subs[*]}")"
|
top=()
|
||||||
|
for s in "${subs[@]}"; do
|
||||||
|
is_nested=0
|
||||||
|
for s2 in "${subs[@]}"; do
|
||||||
|
[ "$s2" = "$s" ] && continue
|
||||||
|
if [[ "$s" == "$s2-"* ]]; then is_nested=1; break; fi
|
||||||
|
done
|
||||||
|
[ "$is_nested" -eq 1 ] || top+=("$s")
|
||||||
|
done
|
||||||
|
joined="$(IFS='|'; echo "${top[*]}")"
|
||||||
printf " %-14s%s\n" "$c" "$joined"
|
printf " %-14s%s\n" "$c" "$joined"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@@ -55,11 +66,36 @@ _pos_category_exists() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pos_category_help() {
|
_pos_category_help() {
|
||||||
local cat="$1" sub subs=()
|
local cat="$1" f
|
||||||
local f
|
local files=() s d
|
||||||
for f in "$self"/pos-"$cat"-*; do
|
for f in "$self"/pos-"$cat"-*; do
|
||||||
[ -x "$f" ] || continue
|
[ -x "$f" ] || continue
|
||||||
subs+=("${f##*/pos-$cat-}")
|
files+=("${f##*/pos-$cat-}")
|
||||||
|
done
|
||||||
|
mapfile -t files < <(printf '%s\n' "${files[@]}" | sort -u)
|
||||||
|
|
||||||
|
local -A desc subcmds
|
||||||
|
local sc
|
||||||
|
for s in "${files[@]}"; do
|
||||||
|
d="$(sed -n '/^# POS: /{s/^# POS: //;p;q}' "$self/pos-$cat-$s" 2>/dev/null)"
|
||||||
|
[ -n "$d" ] && desc["$s"]="${d#*— }"
|
||||||
|
sc="$(sed -n '/^# POS_SUBCMDS: /{s/^# POS_SUBCMDS: //;p;q}' "$self/pos-$cat-$s" 2>/dev/null)"
|
||||||
|
[ -n "$sc" ] && subcmds["$s"]="$sc"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Nested sub-tools: pos-<cat>-<a>-<b> lists "b" under <a>.
|
||||||
|
local s2 extra
|
||||||
|
for s in "${files[@]}"; do
|
||||||
|
for s2 in "${files[@]}"; do
|
||||||
|
[ "$s2" = "$s" ] && continue
|
||||||
|
if [[ "$s2" == "$s-"* ]]; then
|
||||||
|
extra="${s2#$s-}"
|
||||||
|
case " ${subcmds[$s]:-} " in
|
||||||
|
*" $extra "*) ;;
|
||||||
|
*) subcmds["$s"]="${subcmds[$s]:-}${subcmds[$s]:+ }$extra" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "pos $cat — $cat tools"
|
echo "pos $cat — $cat tools"
|
||||||
@@ -68,7 +104,19 @@ _pos_category_help() {
|
|||||||
echo " pos $cat <command> [args]"
|
echo " pos $cat <command> [args]"
|
||||||
echo
|
echo
|
||||||
echo "COMMANDS"
|
echo "COMMANDS"
|
||||||
printf " %s\n" "${subs[@]}"
|
local is_nested c
|
||||||
|
for s in "${files[@]}"; do
|
||||||
|
is_nested=0
|
||||||
|
for s2 in "${files[@]}"; do
|
||||||
|
[ "$s2" = "$s" ] && continue
|
||||||
|
if [[ "$s" == "$s2-"* ]]; then is_nested=1; break; fi
|
||||||
|
done
|
||||||
|
[ "$is_nested" -eq 1 ] && continue
|
||||||
|
printf ' %-28s%s\n' "$s" "${desc[$s]:-}"
|
||||||
|
for c in ${subcmds[$s]:-}; do
|
||||||
|
printf ' %s %s\n' "$s" "$c"
|
||||||
|
done
|
||||||
|
done
|
||||||
echo
|
echo
|
||||||
echo "Run 'pos $cat <command> --help' for details on a command."
|
echo "Run 'pos $cat <command> --help' for details on a command."
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# POS: communication telegram — Send Telegram messages/files/links/stickers via Bot API (send, test, config set)
|
# POS: communication telegram — Send Telegram messages/files/links/stickers via Bot API (send, test, config set)
|
||||||
# POS_FLAGS: --send --type --caption --parse-mode --no-preview --token --chat-id
|
# POS_FLAGS: --send --type --caption --parse-mode --no-preview --token --chat-id
|
||||||
|
# POS_SUBCMDS: send test config
|
||||||
|
|
||||||
CONFIG_DIR="$HOME/.config/linux_post_install"
|
CONFIG_DIR="$HOME/.config/linux_post_install"
|
||||||
CONFIG_FILE="$CONFIG_DIR/telegram.env"
|
CONFIG_FILE="$CONFIG_DIR/telegram.env"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# POS: docker compose — Docker Compose service manager (ls/up/down/restart/logs/update/config)
|
# POS: docker compose — Docker Compose service manager (ls/up/down/restart/logs/update/config)
|
||||||
|
# POS_SUBCMDS: ls installed up down restart logs update config
|
||||||
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
|
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
|
||||||
|
|
||||||
SCALE_DIR="/usr/local/share/linux_post_install/scale-tail/services"
|
SCALE_DIR="/usr/local/share/linux_post_install/scale-tail/services"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# POS: docker vbox — Disposable Docker-based VMs (create/enter/start/stop/rm/ls)
|
# POS: docker vbox — Disposable Docker-based VMs (create/enter/start/stop/rm/ls)
|
||||||
|
# POS_SUBCMDS: create enter stop start rm ls
|
||||||
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
|
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
|
|||||||
+48
-23
@@ -11,6 +11,12 @@ _pos_flags[system-backup]="--service"
|
|||||||
_pos_flags[system-health]="--send --markdown"
|
_pos_flags[system-health]="--send --markdown"
|
||||||
_pos_flags[usb-server]="--ls --ls-shared --share --unshare --auto-share --callback --close-callback --auto-connect --disconnect --nickname --timeout --port --info --version"
|
_pos_flags[usb-server]="--ls --ls-shared --share --unshare --auto-share --callback --close-callback --auto-connect --disconnect --nickname --timeout --port --info --version"
|
||||||
# GEN:END posflags
|
# GEN:END posflags
|
||||||
|
# GEN:START possubcmds
|
||||||
|
declare -A _pos_subcmds
|
||||||
|
_pos_subcmds[communication-telegram]="send test config listener"
|
||||||
|
_pos_subcmds[docker-compose]="ls installed up down restart logs update config"
|
||||||
|
_pos_subcmds[docker-vbox]="create enter stop start rm ls"
|
||||||
|
# GEN:END possubcmds
|
||||||
|
|
||||||
_pos() {
|
_pos() {
|
||||||
local cur prev words cword
|
local cur prev words cword
|
||||||
@@ -39,11 +45,29 @@ _pos() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# ── Build category→subcommand map ──────────────────────────
|
# ── Build category→subcommand map ──────────────────────────
|
||||||
|
# Nested sub-tools (pos-<cat>-<a>-<b> where pos-<cat>-<a> exists) are
|
||||||
|
# offered under their parent tool, not at the category level.
|
||||||
local -A cat_cmds
|
local -A cat_cmds
|
||||||
|
local -A nested
|
||||||
|
local cmd2 c2 cat2 sub2
|
||||||
for cmd in "${all_cmds[@]}"; do
|
for cmd in "${all_cmds[@]}"; do
|
||||||
local cat="${cmd%%-*}"
|
local cat="${cmd%%-*}"
|
||||||
local sub="${cmd#*-}"
|
local sub="${cmd#*-}"
|
||||||
if [ "$cat" != "$cmd" ]; then
|
if [ "$cat" != "$cmd" ]; then
|
||||||
|
for cmd2 in "${all_cmds[@]}"; do
|
||||||
|
cat2="${cmd2%%-*}"
|
||||||
|
sub2="${cmd2#*-}"
|
||||||
|
if [ "$cat2" = "$cat" ] && [ "$sub2" != "$sub" ] && [[ "$sub" == "$sub2-"* ]]; then
|
||||||
|
nested["$cmd"]=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
for cmd in "${all_cmds[@]}"; do
|
||||||
|
local cat="${cmd%%-*}"
|
||||||
|
local sub="${cmd#*-}"
|
||||||
|
if [ "$cat" != "$cmd" ] && [ -z "${nested[$cmd]:-}" ]; then
|
||||||
cat_cmds["$cat"]+="${sub} "
|
cat_cmds["$cat"]+="${sub} "
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -58,6 +82,26 @@ _pos() {
|
|||||||
COMPREPLY=($(compgen -W "${cat_cmds[$cat]:-} --help" -- "$cur"))
|
COMPREPLY=($(compgen -W "${cat_cmds[$cat]:-} --help" -- "$cur"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Complete subcommands + flags + --help for a tool chain, walking up to
|
||||||
|
# the nearest tool that declares anything (e.g. "telegram send" → telegram flags).
|
||||||
|
_pos_complete_tool() {
|
||||||
|
local key="$1" k opts
|
||||||
|
k="$key"
|
||||||
|
while [ -n "$k" ]; do
|
||||||
|
if [ -n "${_pos_subcmds[$k]:-}" ] || [ -n "${_pos_flags[$k]:-}" ]; then
|
||||||
|
if [ "$k" = "$key" ]; then
|
||||||
|
opts="${_pos_subcmds[$k]:-} ${_pos_flags[$k]:-} --help"
|
||||||
|
else
|
||||||
|
opts="${_pos_flags[$k]:-} --help"
|
||||||
|
fi
|
||||||
|
COMPREPLY=($(compgen -W "$opts" -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
k="${k%-*}"
|
||||||
|
done
|
||||||
|
COMPREPLY=($(compgen -W "--help" -- "$cur"))
|
||||||
|
}
|
||||||
|
|
||||||
_pos_complete_compose_services() {
|
_pos_complete_compose_services() {
|
||||||
local scale_dir="/usr/local/share/linux_post_install/scale-tail/services"
|
local scale_dir="/usr/local/share/linux_post_install/scale-tail/services"
|
||||||
if [ -d "$scale_dir" ]; then
|
if [ -d "$scale_dir" ]; then
|
||||||
@@ -83,11 +127,6 @@ _pos() {
|
|||||||
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
COMPREPLY=($(compgen -W "$names" -- "$cur"))
|
||||||
}
|
}
|
||||||
|
|
||||||
_pos_complete_flags() {
|
|
||||||
local tool="$1"
|
|
||||||
COMPREPLY=($(compgen -W "${_pos_flags[$tool]:-} --help" -- "$cur"))
|
|
||||||
}
|
|
||||||
|
|
||||||
_pos_entertainment_plugins() {
|
_pos_entertainment_plugins() {
|
||||||
local d f name out=()
|
local d f name out=()
|
||||||
for d in /usr/local/bin "$pos_dir/../entertainment"; do
|
for d in /usr/local/bin "$pos_dir/../entertainment"; do
|
||||||
@@ -124,26 +163,14 @@ _pos() {
|
|||||||
docker-vbox)
|
docker-vbox)
|
||||||
_pos_complete_docker_vbox_cmds
|
_pos_complete_docker_vbox_cmds
|
||||||
;;
|
;;
|
||||||
usb-server)
|
|
||||||
_pos_complete_flags usb-server
|
|
||||||
;;
|
|
||||||
communication-telegram)
|
|
||||||
_pos_complete_flags communication-telegram
|
|
||||||
;;
|
|
||||||
entertainment-send)
|
|
||||||
_pos_complete_flags entertainment-send
|
|
||||||
;;
|
|
||||||
entertainment-enable|entertainment-disable)
|
entertainment-enable|entertainment-disable)
|
||||||
_pos_entertainment_plugins
|
_pos_entertainment_plugins
|
||||||
;;
|
;;
|
||||||
entertainment-config)
|
entertainment-config)
|
||||||
COMPREPLY=($(compgen -W "set --help" -- "$cur"))
|
COMPREPLY=($(compgen -W "set --help" -- "$cur"))
|
||||||
;;
|
;;
|
||||||
network-hotspot)
|
*)
|
||||||
_pos_complete_flags network-hotspot
|
_pos_complete_tool "${words[1]}-${words[2]}"
|
||||||
;;
|
|
||||||
system-backup)
|
|
||||||
_pos_complete_flags system-backup
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
@@ -163,10 +190,8 @@ _pos() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
communication-telegram)
|
*)
|
||||||
case "${words[3]}" in
|
_pos_complete_tool "${words[1]}-${words[2]}-${words[3]}"
|
||||||
send|--send) _pos_complete_flags communication-telegram ;;
|
|
||||||
esac
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
|||||||
+31
-7
@@ -9,6 +9,7 @@ set -euo pipefail
|
|||||||
# - bin/pos-* filenames → category, subcommand
|
# - bin/pos-* filenames → category, subcommand
|
||||||
# - "# POS:" header line → one-line description
|
# - "# POS:" header line → one-line description
|
||||||
# - "# POS_FLAGS:" line → flag completion list (flag-style tools only)
|
# - "# POS_FLAGS:" line → flag completion list (flag-style tools only)
|
||||||
|
# - "# POS_SUBCMDS:" line → subcommand completion list (multi-command tools)
|
||||||
|
|
||||||
root="$(cd "$(dirname "$0")/.." && pwd)"
|
root="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
mode="write"
|
mode="write"
|
||||||
@@ -17,7 +18,7 @@ mode="write"
|
|||||||
ctx="$root/DOC/AGENT_Context_Project.md"
|
ctx="$root/DOC/AGENT_Context_Project.md"
|
||||||
comp="$root/completions/pos.bash"
|
comp="$root/completions/pos.bash"
|
||||||
|
|
||||||
# ── Collect tools: "cat|sub|desc|flags" ────────────────────────
|
# ── Collect tools: "cat|sub|desc|flags|subcmds" ────────────────
|
||||||
tools=()
|
tools=()
|
||||||
for f in "$root"/bin/pos-*; do
|
for f in "$root"/bin/pos-*; do
|
||||||
[ -x "$f" ] || continue
|
[ -x "$f" ] || continue
|
||||||
@@ -28,7 +29,8 @@ for f in "$root"/bin/pos-*; do
|
|||||||
[ -n "$desc" ] || { echo "gen-docs: no '# POS:' header in $f" >&2; exit 1; }
|
[ -n "$desc" ] || { echo "gen-docs: no '# POS:' header in $f" >&2; exit 1; }
|
||||||
desc="${desc#*— }"
|
desc="${desc#*— }"
|
||||||
flags="$(sed -n '/^# POS_FLAGS: /{s/^# POS_FLAGS: //;p;q}' "$f")"
|
flags="$(sed -n '/^# POS_FLAGS: /{s/^# POS_FLAGS: //;p;q}' "$f")"
|
||||||
tools+=("$cat|$sub|$desc|$flags")
|
subcmds="$(sed -n '/^# POS_SUBCMDS: /{s/^# POS_SUBCMDS: //;p;q}' "$f")"
|
||||||
|
tools+=("$cat|$sub|$desc|$flags|$subcmds")
|
||||||
done
|
done
|
||||||
mapfile -t tools < <(printf '%s\n' "${tools[@]}" | sort)
|
mapfile -t tools < <(printf '%s\n' "${tools[@]}" | sort)
|
||||||
|
|
||||||
@@ -36,12 +38,12 @@ mapfile -t tools < <(printf '%s\n' "${tools[@]}" | sort)
|
|||||||
gen_tree() {
|
gen_tree() {
|
||||||
local width=0 cat sub desc flags name t
|
local width=0 cat sub desc flags name t
|
||||||
for t in "${tools[@]}"; do
|
for t in "${tools[@]}"; do
|
||||||
IFS='|' read -r cat sub desc flags <<<"$t"
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
name="pos-$cat-$sub"
|
name="pos-$cat-$sub"
|
||||||
[ ${#name} -gt "$width" ] && width=${#name}
|
[ ${#name} -gt "$width" ] && width=${#name}
|
||||||
done
|
done
|
||||||
for t in "${tools[@]}"; do
|
for t in "${tools[@]}"; do
|
||||||
IFS='|' read -r cat sub desc flags <<<"$t"
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
name="pos-$cat-$sub"
|
name="pos-$cat-$sub"
|
||||||
printf '│ ├── %-*s# %s\n' "$((width + 1))" "$name" "$desc"
|
printf '│ ├── %-*s# %s\n' "$((width + 1))" "$name" "$desc"
|
||||||
done
|
done
|
||||||
@@ -50,7 +52,7 @@ gen_tree() {
|
|||||||
gen_dispatch() {
|
gen_dispatch() {
|
||||||
local cat sub desc flags t
|
local cat sub desc flags t
|
||||||
for t in "${tools[@]}"; do
|
for t in "${tools[@]}"; do
|
||||||
IFS='|' read -r cat sub desc flags <<<"$t"
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
printf '| %s | %s | `pos-%s-%s` | %s |\n' "$cat" "$sub" "$cat" "$sub" "$desc"
|
printf '| %s | %s | `pos-%s-%s` | %s |\n' "$cat" "$sub" "$cat" "$sub" "$desc"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@@ -72,7 +74,7 @@ gen_filetable() {
|
|||||||
local cat sub desc flags name t
|
local cat sub desc flags name t
|
||||||
printf '| `bin/pos` | %s | CLI dispatcher with smart arg matching + logging + category help |\n' "$(wc -l < "$root/bin/pos")"
|
printf '| `bin/pos` | %s | CLI dispatcher with smart arg matching + logging + category help |\n' "$(wc -l < "$root/bin/pos")"
|
||||||
for t in "${tools[@]}"; do
|
for t in "${tools[@]}"; do
|
||||||
IFS='|' read -r cat sub desc flags <<<"$t"
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
name="bin/pos-$cat-$sub"
|
name="bin/pos-$cat-$sub"
|
||||||
printf '| `%s` | %s | %s |\n' "$name" "$(wc -l < "$root/$name")" "$desc"
|
printf '| `%s` | %s | %s |\n' "$name" "$(wc -l < "$root/$name")" "$desc"
|
||||||
done
|
done
|
||||||
@@ -83,12 +85,33 @@ gen_posflags() {
|
|||||||
local cat sub desc flags t
|
local cat sub desc flags t
|
||||||
echo "declare -A _pos_flags"
|
echo "declare -A _pos_flags"
|
||||||
for t in "${tools[@]}"; do
|
for t in "${tools[@]}"; do
|
||||||
IFS='|' read -r cat sub desc flags <<<"$t"
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
[ -n "$flags" ] || continue
|
[ -n "$flags" ] || continue
|
||||||
printf '_pos_flags[%s-%s]="%s"\n' "$cat" "$sub" "$flags"
|
printf '_pos_flags[%s-%s]="%s"\n' "$cat" "$sub" "$flags"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gen_possubcmds() {
|
||||||
|
# Subcommand completion: "# POS_SUBCMDS:" list + nested sub-tools from
|
||||||
|
# filenames (pos-<cat>-<sub>-<extra> → "extra" completes under <cat>-<sub>).
|
||||||
|
local cat sub desc flags subcmds rest f t
|
||||||
|
echo "declare -A _pos_subcmds"
|
||||||
|
for t in "${tools[@]}"; do
|
||||||
|
IFS='|' read -r cat sub desc flags subcmds <<<"$t"
|
||||||
|
subcmds="${subcmds:-}"
|
||||||
|
for f in "$root"/bin/pos-"$cat"-"$sub"-*; do
|
||||||
|
[ -x "$f" ] || continue
|
||||||
|
rest="${f##*/pos-$cat-$sub-}"
|
||||||
|
case " $subcmds " in
|
||||||
|
*" $rest "*) ;;
|
||||||
|
*) subcmds="${subcmds:+$subcmds }$rest" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[ -n "$subcmds" ] || continue
|
||||||
|
printf '_pos_subcmds[%s-%s]="%s"\n' "$cat" "$sub" "$subcmds"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# Section index of AGENT_Context itself: maps each "## " heading to its
|
# Section index of AGENT_Context itself: maps each "## " heading to its
|
||||||
# line range. Excludes the "Document Map" heading (this block).
|
# line range. Excludes the "Document Map" heading (this block).
|
||||||
gen_docmap() {
|
gen_docmap() {
|
||||||
@@ -155,6 +178,7 @@ regen_block "$ctx" tree
|
|||||||
regen_block "$ctx" dispatch
|
regen_block "$ctx" dispatch
|
||||||
regen_block "$ctx" selfcontained
|
regen_block "$ctx" selfcontained
|
||||||
regen_block "$comp" posflags
|
regen_block "$comp" posflags
|
||||||
|
regen_block "$comp" possubcmds
|
||||||
regen_block "$ctx" filetable
|
regen_block "$ctx" filetable
|
||||||
|
|
||||||
# docmap is self-referential: its own block size shifts the section line
|
# docmap is self-referential: its own block size shifts the section line
|
||||||
|
|||||||
Reference in New Issue
Block a user