# 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