Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@
"datasourceTemplate": "deb",
"depNameTemplate": "{{package}}"
},
{
"customType": "regex",
"managerFilePatterns": ["//Dockerfile$/"],
"matchStringsStrategy": "any",
"matchStrings": [
"\"(?<package>[a-z0-9][a-z0-9-]+) \\(>= (?<currentValue>[a-z0-9-:_+~.]+)\\)\""
],
"versioningTemplate": "deb",
"datasourceTemplate": "deb",
"depNameTemplate": "{{package}}"
},
{
"customType": "regex",
"managerFilePatterns": ["//Dockerfile$/"],
Expand Down
29 changes: 29 additions & 0 deletions code-server/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,40 @@ custom-services/
If a custom service keeps the app from starting, set `log_level` to
`debug`. This skips all custom services until you set it back.

## Claude Code

Claude Code is not part of this app, but it runs in it and its login is kept
across restarts.

Install the `Anthropic.claude-code` extension from the Extensions view. It is
published on [Open VSX][open-vsx], the registry code-server uses for extensions
you install yourself, and it brings its own `claude` binary, so nothing else has
to be installed. GitHub Copilot, by contrast, is only published on the Microsoft
Marketplace and cannot be installed here.

Sign in from a terminal rather than the editor: the browser flow redirects to a
`vscode://` URL, which does not survive Home Assistant's ingress. Open a
terminal in VS Code, run `claude`, then use `/login` and paste back the code it
asks for.

Everything Claude Code stores is kept in `/data` instead of the home folder, so
your login survives restarts and updates of this app. That works through
`CLAUDE_CONFIG_DIR`, which this app exports before starting the code server;
terminals inside VS Code inherit it. A login left behind by an earlier version
of this app is copied over on the first start, without overwriting anything
already there.

The `claude` binary lives inside the extension folder under
`/data/code-server/extensions/`. Symlink it into `/usr/local/bin` if you want it
on your `PATH` in every terminal.

## Persistent data

The following survive restarts and updates:

- VS Code settings and extensions you install yourself
- `~/.ssh`, `~/.gitconfig` and the zsh history
- The Claude Code login and settings, if you install the extension

Common folders such as `homeassistant`, `share` and `addon_configs` are linked
into the workspace (`/root`).
Expand All @@ -89,6 +117,7 @@ The app keeps its default settings up to date until you change them.
To go back to the defaults, open a terminal in VS Code and run
`reset-settings`.

[open-vsx]: https://open-vsx.org
[hassio-addons]: https://github.com/hassio-addons/app-vscode
[ha-addons]: https://github.com/elcajon/ha-repository-edge
[my-ha-badge]: https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg
Expand Down
20 changes: 8 additions & 12 deletions code-server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
COPY requirements.txt /tmp/requirements.txt

# Setup base system
# renovate: datasource=deb depName=build-essential versioning=deb
ARG build_essential_version="12.12"
# renovate: datasource=deb depName=locales versioning=deb
ARG locales_version="2.41-12+deb13u4"
# renovate: datasource=deb depName=gnupg versioning=deb
Expand All @@ -140,7 +138,6 @@ RUN \
\
&& apt-get install -y --no-install-recommends \
ack=3.8.1-1 \
build-essential="${build_essential_version}" \
colordiff=1.0.21-1 \
git=1:2.47.3-0+deb13u1 \
iputils-ping=3:20240905-3 \
Expand All @@ -151,10 +148,8 @@ RUN \
nmap=7.95+dfsg-3 \
openssh-client="${openssh_client_version}" \
openssl=3.5.7-1~deb13u2 \
python3-dev=3.13.5-1 \
python3=3.13.5-1 \
unzip=6.0-29+deb13u1 \
wget \
zip=3.0-15+deb13u1 \
zsh=5.9-8+b24 \
less=668-1 \
Expand All @@ -164,13 +159,16 @@ RUN \
cron=3.0pl1-197 \
lsb-release=12.1-1 \
openssh-server="${openssh_server_version}" \
git-crypt \
php=2:8.4+96 \
php-curl=2:8.4+96 \
netcat-openbsd=1.229-1 \
htop=3.4.1-5 \
shellcheck=0.10.0-1 \
\
&& apt-get satisfy -y --no-install-recommends \
"git-crypt (>= 0.7.0-0.1+b1)" \
"wget (>= 1.25.0-2)" \
\
&& sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen \
&& locale-gen \
\
Expand Down Expand Up @@ -198,13 +196,11 @@ RUN \
\
&& sed -i -e "s#bin/bash#bin/zsh#" /etc/passwd \
\
&& apt-get purge -y --auto-remove \
build-essential \
python3-dev \
\
&& find /usr/local \
\( -type d -a -name test -o -name tests -o -name '__pycache__' \) \
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) \
\( \
\( -type d -a \( -name test -o -name tests -o -name '__pycache__' \) \) \
-o \( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \) \
\) \
-exec rm -rf '{}' + \
\
&& rm -fr \
Expand Down
26 changes: 21 additions & 5 deletions code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/finish
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,25 @@
# Home Assistant App: Code Server
# Take down the S6 supervision tree when the code server fails
# ==============================================================================
if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then
bashio::log.warning "code-server crashed, halting app"
/run/s6/basedir/bin/halt
fi
declare exit_code_container
exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
readonly exit_code_container
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="code-server"

bashio::log.info \
"Service ${service} exited with code ${exit_code_service}" \
"(by signal ${exit_code_signal})"

bashio::log.info "code-server stopped, restarting..."
if [[ "${exit_code_service}" -eq 256 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo $((128 + exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
fi
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
elif [[ "${exit_code_service}" -ne 0 ]]; then
if [[ "${exit_code_container}" -eq 0 ]]; then
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
fi
exec /run/s6/basedir/bin/halt
fi
5 changes: 5 additions & 0 deletions code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/run
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,10 @@ options+=(/root)
export HASS_SERVER="http://supervisor/core"
export HASS_TOKEN="${SUPERVISOR_TOKEN:-}"

# Keep the Claude Code configuration in the persistent data folder. The
# extension host and the integrated terminals inherit this, so both the
# extension and the claude binary use it.
export CLAUDE_CONFIG_DIR="/data/claude"

# Run the code server
exec code-server "${options[@]}"
6 changes: 4 additions & 2 deletions code-server/rootfs/etc/s6-overlay/scripts/01-vs-mosquitto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ if bashio::services.available "mqtt"; then
echo "--username ${username}"
} > /root/.config/mosquitto_sub

ln -s /root/.config/mosquitto_sub /root/.config/mosquitto_pub
ln -s /root/.config/mosquitto_sub /root/.config/mosquitto_rr
ln -sf /root/.config/mosquitto_sub /root/.config/mosquitto_pub \
|| bashio::log.warning 'Failed linking the mosquitto_pub configuration'
ln -sf /root/.config/mosquitto_sub /root/.config/mosquitto_rr \
|| bashio::log.warning 'Failed linking the mosquitto_rr configuration'
fi
2 changes: 1 addition & 1 deletion code-server/rootfs/etc/s6-overlay/scripts/01-vs-mysql
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if bashio::services.available "mysql"; then
port=$(bashio::services "mysql" "port")
username=$(bashio::services "mysql" "username")

mkdir -p /root/.config
mkdir -p /etc/mysql/conf.d
{
echo "[client]"
echo "host=${host}"
Expand Down
38 changes: 36 additions & 2 deletions code-server/rootfs/etc/s6-overlay/scripts/01-vs-user
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Persists user settings and installs custom user packages.
# ==============================================================================
readonly -a DIRECTORIES=(addon_configs addons backup homeassistant media share ssl)
readonly CLAUDE_USER_PATH=/data/claude
readonly GIT_USER_PATH=/data/git
readonly SSH_USER_PATH=/data/.ssh
readonly ZSH_HISTORY_FILE=/root/.zsh_history
Expand All @@ -24,7 +25,15 @@ if ! bashio::fs.directory_exists "${SSH_USER_PATH}"; then
|| bashio::exit.nok \
'Failed setting permissions on persistent .ssh folder'
fi
ln -sn "${SSH_USER_PATH}" ~/.ssh || bashio::log.warning "Failed linking .ssh"
# The image ships an empty ~/.ssh; without removing it, the link below
# would end up inside it as ~/.ssh/.ssh instead of replacing it.
if [[ -d ~/.ssh ]] && [[ ! -L ~/.ssh ]]; then
# Clean up the nested link left behind by earlier versions
rm -f ~/.ssh/.ssh
rmdir ~/.ssh \
|| bashio::log.warning "Not replacing non-empty ${HOME}/.ssh"
fi
ln -sfn "${SSH_USER_PATH}" ~/.ssh || bashio::log.warning "Failed linking .ssh"

# Sets up ZSH shell
touch "${ZSH_HISTORY_PERSISTANT_FILE}" \
Expand All @@ -51,4 +60,29 @@ if ! bashio::fs.file_exists "${GIT_USER_PATH}/.gitconfig"; then
touch "${GIT_USER_PATH}/.gitconfig" \
|| bashio::exit.nok 'Failed to create .gitconfig'
fi
ln -s "${GIT_USER_PATH}/.gitconfig" ~/.gitconfig || bashio::log.warning "Failed linking .gitconfig"
ln -s "${GIT_USER_PATH}/.gitconfig" ~/.gitconfig || bashio::log.warning "Failed linking .gitconfig"

# Store Claude Code settings & credentials in app data folder. The service
# points Claude Code here through CLAUDE_CONFIG_DIR, which covers both of the
# locations it would otherwise use: ~/.claude and ~/.claude.json.
if ! bashio::fs.directory_exists "${CLAUDE_USER_PATH}"; then
mkdir -p "${CLAUDE_USER_PATH}" \
|| bashio::exit.nok 'Failed to create a persistent Claude Code folder'

chmod 700 "${CLAUDE_USER_PATH}" \
|| bashio::exit.nok \
'Failed setting permissions on persistent Claude Code folder'
fi

# Migrate the non-persistent locations left behind by an older app version.
# Existing files are never overwritten, and the originals are left alone;
# they are simply no longer read once CLAUDE_CONFIG_DIR is set.
if bashio::fs.directory_exists ~/.claude; then
cp -a -n ~/.claude/. "${CLAUDE_USER_PATH}/" \
|| bashio::log.warning 'Failed migrating the Claude Code folder'
fi

if bashio::fs.file_exists ~/.claude.json; then
cp -a -n ~/.claude.json "${CLAUDE_USER_PATH}/.claude.json" \
|| bashio::log.warning 'Failed migrating the Claude Code configuration'
fi
2 changes: 1 addition & 1 deletion code-server/rootfs/root/.code-server/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"files.associations": {
"*.dash": "yaml",
"**/esphome/*.yaml": "esphome",
"**/esphome/**/*.yaml": "esphome",
"**/homeassistant/*.yaml": "home-assistant"
},
"files.watcherExclude": {
Expand Down
2 changes: 1 addition & 1 deletion code-server/rootfs/root/.zshrc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ source $ZSH/oh-my-zsh.sh
alias reset-settings="cp /root/.code-server/settings.json /data/code-server/User/settings.json && echo 'Setting restored!'"

# Home Assistant CLI
source <(ha completion zsh)
source <(ha completion zsh) && compdef _ha ha

# Change Docker autocompletion
# see https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/docker#settings
Expand Down
3 changes: 3 additions & 0 deletions code-server/rootfs/usr/local/bin/code
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

exec /usr/local/lib/code-server/bin/code-server "${@}"
Loading