diff --git a/.github/renovate.json b/.github/renovate.json index 98792f22..52cd8412 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -29,6 +29,17 @@ "datasourceTemplate": "deb", "depNameTemplate": "{{package}}" }, + { + "customType": "regex", + "managerFilePatterns": ["//Dockerfile$/"], + "matchStringsStrategy": "any", + "matchStrings": [ + "\"(?[a-z0-9][a-z0-9-]+) \\(>= (?[a-z0-9-:_+~.]+)\\)\"" + ], + "versioningTemplate": "deb", + "datasourceTemplate": "deb", + "depNameTemplate": "{{package}}" + }, { "customType": "regex", "managerFilePatterns": ["//Dockerfile$/"], diff --git a/code-server/DOCS.md b/code-server/DOCS.md index 5b14de2e..4c884876 100644 --- a/code-server/DOCS.md +++ b/code-server/DOCS.md @@ -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`). @@ -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 diff --git a/code-server/Dockerfile b/code-server/Dockerfile index a69aa78c..6904d47f 100755 --- a/code-server/Dockerfile +++ b/code-server/Dockerfile @@ -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 @@ -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 \ @@ -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 \ @@ -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 \ \ @@ -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 \ diff --git a/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/finish b/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/finish index b04a8146..55bbb68f 100755 --- a/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/finish +++ b/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/finish @@ -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 + 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 diff --git a/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/run b/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/run index 1aa45f93..14ffb0f8 100755 --- a/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/run +++ b/code-server/rootfs/etc/s6-overlay/s6-rc.d/code-server/run @@ -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[@]}" diff --git a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mosquitto b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mosquitto index 71c23cad..2eb85547 100755 --- a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mosquitto +++ b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mosquitto @@ -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 diff --git a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mysql b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mysql index 3e2270dd..7d4491e0 100755 --- a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mysql +++ b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-mysql @@ -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}" diff --git a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-user b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-user index 4bd03760..579ad6e9 100755 --- a/code-server/rootfs/etc/s6-overlay/scripts/01-vs-user +++ b/code-server/rootfs/etc/s6-overlay/scripts/01-vs-user @@ -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 @@ -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}" \ @@ -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" \ No newline at end of file +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 diff --git a/code-server/rootfs/root/.code-server/settings.json b/code-server/rootfs/root/.code-server/settings.json index 1625a0f1..56565ad5 100644 --- a/code-server/rootfs/root/.code-server/settings.json +++ b/code-server/rootfs/root/.code-server/settings.json @@ -1,7 +1,7 @@ { "files.associations": { "*.dash": "yaml", - "**/esphome/*.yaml": "esphome", + "**/esphome/**/*.yaml": "esphome", "**/homeassistant/*.yaml": "home-assistant" }, "files.watcherExclude": { diff --git a/code-server/rootfs/root/.zshrc b/code-server/rootfs/root/.zshrc index 28c6d4ca..76cf1ea1 100755 --- a/code-server/rootfs/root/.zshrc +++ b/code-server/rootfs/root/.zshrc @@ -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 diff --git a/code-server/rootfs/usr/local/bin/code b/code-server/rootfs/usr/local/bin/code new file mode 100755 index 00000000..ea03034a --- /dev/null +++ b/code-server/rootfs/usr/local/bin/code @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /usr/local/lib/code-server/bin/code-server "${@}"