Typing `ai-sandbox --` gave nothing, and a policy surface this wide (egress modes, mounts, the agents share, the pi bridge, per-subcommand flags) is not something to retype from memory. Nothing in the script or install.sh emitted completions, so this adds one as a standalone file rather than growing the script. It mirrors parse_args() plus the per-subcommand parsers, and follows the same rules the script does: a non-flag word that is not a subcommand ends sandbox parsing, so after it the completer offers nothing rather than flags that would silently become harness arguments; build, update, doctor and clean only offer the flags they actually accept, since each dies on an unknown one; inspect takes the full policy set, so it gets the full list. Values complete from local state only -- --net and --harness from their fixed modes, --env from exported host variables, --mount and --workdir from directories, --allow from the two documented allow files. Nothing here resolves a name or touches the network. Aliases that point at the script (alias pi=ai-sandbox) register too, which is why the source line belongs after the alias in ~/.bashrc. Verified by driving COMP_WORDS for each case above and diffing the flag list against parse_args(); bash -n is clean. Note the Makefile lint list does not yet include contrib/, so shellcheck has not seen this file. LLM-Generated: true
82 lines
4.2 KiB
Bash
Executable File
82 lines
4.2 KiB
Bash
Executable File
# bash completion for ai-sandbox.
|
|
#
|
|
# Install (either):
|
|
# mkdir -p ~/.local/share/bash-completion/completions
|
|
# cp contrib/ai-sandbox.bash ~/.local/share/bash-completion/completions/ai-sandbox
|
|
# or source it from ~/.bashrc -- put the `source` line *after* the alias, since
|
|
# bash needs `complete` registered under the alias name (`alias pi=ai-sandbox`).
|
|
#
|
|
# The flag list mirrors parse_args() in bin/ai-sandbox -- keep them in sync.
|
|
_ai_sandbox_completions() {
|
|
local cur prev word first="" sub="" i
|
|
if type _get_comp_words_by_ref >/dev/null 2>&1; then
|
|
_get_comp_words_by_ref -n : cur prev
|
|
else
|
|
cur="${COMP_WORDS[COMP_CWORD]}"; prev="${COMP_WORDS[COMP_CWORD-1]:-}"
|
|
fi
|
|
|
|
local subs="build update doctor gate ps clean inspect version help"
|
|
# flags that consume the next word, so their values are not mistaken for
|
|
# positional (harness) arguments.
|
|
local value_flags=" --net --allow --allow-file --proxy --mount --workdir --agents-dir
|
|
--env --env-file --base-image --install --harness --pi-token-env --cpus --memory
|
|
--pids --tmpfs-size --name --label "
|
|
|
|
# Walk the words before the cursor to find the subcommand, skipping option values.
|
|
local skip=0
|
|
for ((i = 1; i < COMP_CWORD; i++)); do
|
|
word="${COMP_WORDS[i]}"
|
|
if (( skip )); then skip=0; continue; fi
|
|
if [[ "$word" == --* && "$value_flags" == *" $word "* ]]; then skip=1; continue; fi
|
|
[[ "$word" == -* ]] && continue
|
|
[[ -z "$first" ]] && first="$word"
|
|
done
|
|
[[ " $subs " == *" $first "* ]] && sub="$first"
|
|
|
|
case "$prev" in # values of the flag just typed
|
|
--net) COMPREPLY=( $(compgen -W "none allow full" -- "$cur") ); return ;;
|
|
--harness) COMPREPLY=( $(compgen -W "pi codex claude none" -- "$cur") ); return ;;
|
|
--env) COMPREPLY=( $(compgen -A export -- "$cur") ); return ;;
|
|
--allow) # hosts already in the allow files; no DNS, no network
|
|
local hosts
|
|
hosts="$(sed 's/#.*//' "$HOME/.config/ai-sandbox/allow" ./.ai-sandbox/allow 2>/dev/null | tr ',[:space:]' '\n\n')"
|
|
COMPREPLY=( $(compgen -W "$hosts" -- "$cur") )
|
|
(( ${#COMPREPLY[@]} )) || COMPREPLY=( "$cur" ) # don't fall back to filenames
|
|
return ;;
|
|
--proxy) COMPREPLY=( "$cur" ); return ;;
|
|
--allow-file|--env-file) COMPREPLY=( $(compgen -f -- "$cur") ); return ;;
|
|
--mount|--agents-dir|--workdir) COMPREPLY=( $(compgen -d -- "$cur") ); return ;;
|
|
esac
|
|
|
|
# A non-flag word before the cursor that is not a subcommand means the rest goes
|
|
# to the harness: ai-sandbox stops parsing there, so offer nothing, not sandbox flags.
|
|
[[ -n "$first" && -z "$sub" ]] && return 1
|
|
|
|
[[ -z "$first" && "$cur" != -* ]] && { COMPREPLY=( $(compgen -W "$subs" -- "$cur") ); return; }
|
|
|
|
# subcommand-specific flags (each subcommand dies on anything else);
|
|
# `inspect` takes the full policy flag set, so it falls through to the list below.
|
|
case "$sub" in
|
|
build) COMPREPLY=( $(compgen -W "--rebuild -f --refresh-base -B --gate" -- "$cur") ); return ;;
|
|
update) COMPREPLY=( $(compgen -W "--check --no-gate" -- "$cur") ); return ;;
|
|
doctor) COMPREPLY=( $(compgen -W "--deep -d" -- "$cur") ); return ;;
|
|
clean) COMPREPLY=( $(compgen -W "--all -a --volumes -V" -- "$cur") ); return ;;
|
|
gate) COMPREPLY=( $(compgen -W "up down status logs" -- "$cur") ); return ;;
|
|
ps|version) return 1 ;;
|
|
esac
|
|
|
|
COMPREPLY=( $(compgen -W \
|
|
"--net --allow --allow-file --proxy --no-gate --mount --no-cwd --workdir --home-cache --ephemeral-home --read-only --agents --no-agents --agents-dir --env --env-file --base-image --install --harness --pi-token-env --no-pi-token-env --no-pi-config --cpus --memory --pids --tmpfs-size --shell --interactive --no-tty --keep --name --label --no-build --dry-run --print-policy --print-entrypoint --print-containerfile --allow-unenforced --insecure-keep-root --strict-args -h --help -V" \
|
|
-- "$cur") )
|
|
}
|
|
|
|
complete -o default -F _ai_sandbox_completions ai-sandbox 2>/dev/null || true
|
|
if [[ $- == *i* ]]; then # also complete the harness alias
|
|
for _aisb in $(compgen -A alias 2>/dev/null); do
|
|
if alias "$_aisb" 2>/dev/null | grep -q 'ai-sandbox'; then
|
|
complete -o default -F _ai_sandbox_completions "$_aisb" 2>/dev/null || true
|
|
fi
|
|
done
|
|
unset _aisb
|
|
fi
|