Skip to content
Draft
18 changes: 4 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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" \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this makes RLWRAP_VERSION in the build.yaml obsolete.

| 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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It provides some of the functions used by the completion script, I'll take another look but pretty sure its needed

# No longer need rlwrap; base image already provides Bash/readline

# Install CLI
ARG CLI_VERSION
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit; but looks like some newline issue after the revert, this change shouldn't be here.

1 change: 0 additions & 1 deletion build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ cosign:
identity: https://github.com/home-assistant/plugin-cli/.*
args:
CLI_VERSION: 4.45.0
RLWRAP_VERSION: 0.46.1
labels:
io.hass.type: cli
org.opencontainers.image.title: Home Assistant CLI Plugin
Expand Down
70 changes: 70 additions & 0 deletions rootfs/etc/ha-cli/.repl_rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ha REPL rcfile


# Prompt
PS1='\[\e[32m\]ha > \[\e[0m\]'

# Intercept unknown commands and pass them to 'ha'
command_not_found_handle() {
# Execute as 'ha <command> <args>'
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;
}
Comment on lines +14 to +24
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some formatting issues here.


# 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
# 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() {
# 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

# Use native completion only; no implicit injection or extra bindings.
else
echo 'Warning: ha command not found; commands will fail' >&2
fi
30 changes: 12 additions & 18 deletions rootfs/usr/bin/cli.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
#!/bin/bash

# Print banner (best-effort)
ha banner || true

# Run CLI
COMMAND=""
while true; do
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously EOF (Ctrl+D) didn't exit this loop, while it does exit the REPL in the current implementation. We should also set set -o ignoreeof so only Ctrl+C exits it.

COMMAND="$(rlwrap -S $'\e[32mha > \e[0m' -H /tmp/.cli_history -o cat)"
# Set rcfile to drive an interactive Bash as our REPL
RC_FILE=/etc/ha-cli/.repl_rc

# 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
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