diff --git a/Dockerfile b/Dockerfile index 372f780..91c2f79 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,20 +7,10 @@ SHELL ["/bin/ash", "-o", "pipefail", "-c"] ARG BUILD_ARCH WORKDIR /usr/src -# Install rlwrap -ARG RLWRAP_VERSION -RUN apk add --no-cache --virtual .build-deps \ - build-base \ - readline-dev \ - ncurses-dev \ - && curl -L -s "https://github.com/hanslub42/rlwrap/releases/download/${RLWRAP_VERSION}/rlwrap-${RLWRAP_VERSION}.tar.gz" \ - | tar zxvf - -C /usr/src/ \ - && cd rlwrap-${RLWRAP_VERSION} \ - && ./configure \ - && make \ - && make install \ - && apk del .build-deps \ - && rm -rf /usr/src/* +# Install dependencies +RUN apk add --no-cache \ + bash-completion +# No longer need rlwrap; base image already provides Bash/readline # Install CLI ARG CLI_VERSION diff --git a/README.md b/README.md index ede7df1..87acb3d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # CLI for the Home Assistant Operating System -This is for the Home Assistant Operating System and is the login shell. +This is for the Home Assistant Operating System and is the login shell. \ No newline at end of file diff --git a/rootfs/etc/ha-cli/.repl_rc b/rootfs/etc/ha-cli/.repl_rc new file mode 100644 index 0000000..148564e --- /dev/null +++ b/rootfs/etc/ha-cli/.repl_rc @@ -0,0 +1,84 @@ +# ha REPL rcfile + + +# History configuration +HISTFILE=/tmp/.cli_history +HISTSIZE=1000 +HISTFILESIZE=2000 +PROMPT_COMMAND='history -a; history -c; history -r' + +# Prompt +PS1='\[\e[32m\]ha > \[\e[0m\]' + +# Intercept unknown commands and pass them to 'ha' +command_not_found_handle() { + # Execute as 'ha ' + ha "$@" + return $? +} + +# Friendly helpers +help() { + echo 'Note: Use "login" to enter operating system shell' + echo '' + echo '--------------------------------' + ha help +} +login() { + echo 'Entering OS shell...' + exit 10; + } + +# Load bash-completion core and ha completion if available +if command -v ha >/dev/null 2>&1; then + if [ -f /etc/bash_completion.d/ha ]; then + # Load from standard location (native HA completion registers itself for 'ha') + . /etc/bash_completion.d/ha + + # Wrapper function to inject 'ha' as first argument for all completions + if declare -F __start_ha >/dev/null 2>&1; then + __start_ha >/dev/null 2>&1 || true + + # Clear ALL existing completions to ensure our wrapper is used + while read -r cmd; do + complete -r "$cmd" 2>/dev/null || true + done < <(complete -p | awk '{print $NF}') + + # Universal completion handler - wraps everything as 'ha ...' + __ha_repl_complete() { + local cur prev words cword + + # Handle empty command line specially + if [[ ${#COMP_WORDS[@]} -eq 0 || ( ${#COMP_WORDS[@]} -eq 1 && -z "${COMP_WORDS[0]}" ) ]]; then + COMP_LINE="ha " + COMP_POINT=3 + COMP_WORDS=(ha "") + COMP_CWORD=1 + else + # Prepend 'ha' to existing words + COMP_LINE="ha $COMP_LINE" + COMP_POINT=$((COMP_POINT + 3)) + COMP_WORDS=(ha "${COMP_WORDS[@]}") + COMP_CWORD=$((COMP_CWORD + 1)) + fi + + COMPREPLY=() + __start_ha + } + + # Register our completion as the default for EVERYTHING + complete -D -F __ha_repl_complete # Default for any command + complete -E -F __ha_repl_complete # Empty command line + complete -I -F __ha_repl_complete 2>/dev/null || true # Initial word (bash 5+) + fi + + fi + + # Note: __start_ha is defined by the ha completion script + + # Use native completion only; no implicit injection or extra bindings. +else + echo 'Warning: ha command not found; commands will fail' >&2 +fi + +# Use commands with explicit 'ha' prefix; native completion supports 'ha ...' \ No newline at end of file diff --git a/rootfs/usr/bin/cli.sh b/rootfs/usr/bin/cli.sh index 67d5dba..7482ceb 100755 --- a/rootfs/usr/bin/cli.sh +++ b/rootfs/usr/bin/cli.sh @@ -1,24 +1,21 @@ #!/bin/bash +# Print banner (best-effort) ha banner || true -# Run CLI -COMMAND="" -while true; do - COMMAND="$(rlwrap -S $'\e[32mha > \e[0m' -H /tmp/.cli_history -o cat)" +# Create a minimal rcfile to drive an interactive Bash as our REPL +RC_FILE=/etc/ha-cli/.repl_rc +HISTFILE=/tmp/.cli_history - # Abort to host? - if [ "$COMMAND" == "help" ]; then - echo "Note: Use \"login\" to enter operating system shell" - elif [ "$COMMAND" == "login" ]; then - exit 10 - elif [ "$COMMAND" == "exit" ]; then - exit - elif [ -z "${COMMAND##ha *}" ]; then - echo "Note: Leading 'ha' is not necessary in this HA CLI" - COMMAND=$(echo "$COMMAND" | cut -b 3-) - fi +# Ensure history file exists +touch "$HISTFILE" 2>/dev/null || true +if command -v ha >/dev/null 2>&1; then + completion_file_content=$(ha completion bash 2>/dev/null || true) + if [ -n "$completion_file_content" ]; then + echo "$completion_file_content" >/etc/bash_completion.d/ha 2>/dev/null || true + fi +fi - echo "$COMMAND" | xargs -o ha - echo "" -done + +# Start interactive bash with our rcfile; no user profiles +exec bash --noprofile --rcfile "$RC_FILE" -i