From c398febf0fa0794a33c1e82de6e89c7bd0dbc058 Mon Sep 17 00:00:00 2001 From: dsh agent Date: Thu, 17 Sep 2026 22:26:21 -0400 Subject: [PATCH] Default the workspace doctor to repair MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing repaired on a plain container update: the image defaulted to `warn`, which reports lost grouping and stops there, so a project directory an update erased stayed erased unless the operator set DSH_WORKSPACE_DOCTOR=repair — a field an existing Unraid container never receives, because Unraid does not add variables a template gained later. Bake DSH_WORKSPACE_DOCTOR=repair into the image and make that the entrypoint's fallback, so an update heals itself with no configuration: missing project directories are recreated and the chats orphaned with them are re-accounted at startup, with the registry backed up first and session logs untouched. `warn` reports without repairing, `off` is silent, and an unrecognised value repairs rather than silently doing nothing. README: the doctor is described as the default with the variable as an opt-out, and the Unraid note now says an existing container needs no new field. --- Dockerfile | 4 ++++ README.md | 26 +++++++++++++------------- docker-entrypoint.sh | 31 ++++++++++++++++--------------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Dockerfile b/Dockerfile index 23f91d71f7..dd77900317 100644 --- a/Dockerfile +++ b/Dockerfile @@ -62,11 +62,15 @@ RUN set -eux; \ # installs) lives inside the mounted state volume, never the rootfs. # PUID/PGID: the ids dsh runs as; the entrypoint aligns the state volume to # them at startup. Unraid's share default is 99:100. +# DSH_WORKSPACE_DOCTOR: the entrypoint's workspace-grouping step. `repair` is +# the default so an update heals the projects whose directories the update +# erased; `warn` reports without repairing, `off` is silent. ENV DSH_HOME=/home/node/.dsh \ PNPM_HOME=/home/node/.dsh/.pnpm \ XDG_CACHE_HOME=/home/node/.dsh/.cache \ XDG_STATE_HOME=/home/node/.dsh/.state \ XDG_CONFIG_HOME=/home/node/.dsh/.config \ + DSH_WORKSPACE_DOCTOR=repair \ PUID=1000 \ PGID=1000 diff --git a/README.md b/README.md index 598e8b1ff9..a35bf8ad2e 100644 --- a/README.md +++ b/README.md @@ -123,10 +123,11 @@ Three things went wrong with the alternatives, and this repo is shaped by each: - **Workspace grouping is checked before every start.** A project directory outside the mounted `/workspace` and state volume does not survive a container update, and dsh joins a session to its project only at creation — so those chats collect under "Ungrouped" and - stay there. The entrypoint reports every such project and every recoverable chat, and - with `DSH_WORKSPACE_DOCTOR=repair` recreates the missing directories and re-accounts the - orphaned sessions at startup. Session logs are never touched; the workspace registry is - backed up first. See [Chats land in Ungrouped after an update](#chats-land-in-ungrouped-after-an-update). + stay there. Before every start the entrypoint recreates the missing project directories + and re-accounts the orphaned chats, so an update heals itself with no configuration. + Session logs are never touched; the workspace registry is backed up first. + `DSH_WORKSPACE_DOCTOR=warn` reports without repairing, `=off` is silent. See + [Chats land in Ungrouped after an update](#chats-land-in-ungrouped-after-an-update). #### Operations - **Upstream mirror.** The `master` branch and the `dsh-v*` tags track GitHub exactly, @@ -229,16 +230,15 @@ Your DeepSeek API key can be set below (stored in the container env) or entered 1000 1000 0 - repair + repair ``` An **existing** container keeps the fields it was created with: Unraid does not add a -variable a template gained later, so the Workspace Doctor row above does nothing until you -add it by hand (Docker → Edit → *Add another Path, Port, Variable, Label or Device* → -Variable, key `DSH_WORKSPACE_DOCTOR`, value `repair`) or re-apply the template. Without it -the container stays on the image default (`warn`): it reports lost grouping at every start -but never repairs it. +variable a template gained later. That is fine here — the image default is already +`repair`, so the Workspace Doctor row above only matters if you want to differ from it +(`warn` reports without repairing, `off` is silent), set by hand under Docker → Edit → +*Add another Path, Port, Variable, Label or Device* → Variable. Behind a Cloudflare Tunnel, add the public hostname as a `--trusted-host` and have the tunnel rewrite `Host` to that name (and strip `Origin`) so the fence sees a name it @@ -257,7 +257,7 @@ trusts. | `/home/node/.dsh` | `DSH_HOME` — settings, credentials, sessions, plugins, pnpm store/cache/config. **Mount this.** Taken over at startup. | | `/workspace` | The agent's working directory (`WORKDIR`). Mount only what the agent may read and modify. Mount point made writable; contents untouched unless `DSH_CHOWN_WORKSPACE=1`. | | `/opt/deepseek-harness/web.cordis.patch.yml` | The baked bind patch: `webserver.host: 0.0.0.0`, `port: 3080` | -| Env | `PUID`, `PGID`, `DSH_CHOWN_WORKSPACE`, `DSH_WORKSPACE_DOCTOR` (`warn` default, `repair` fixes lost grouping, `off` is silent), plus `DSH_HOME` / `PNPM_HOME` / `XDG_*` pinned into the state volume | +| Env | `PUID`, `PGID`, `DSH_CHOWN_WORKSPACE`, `DSH_WORKSPACE_DOCTOR` (`repair` default — reports and repairs lost grouping at every start; `warn` reports only, `off` is silent), plus `DSH_HOME` / `PNPM_HOME` / `XDG_*` pinned into the state volume | | Labels | `dev.milesward.dsh-version`, `.pnpm-version`, `.base-digest`, `.recipe-hash` — what CI's freshness check reads | Four rules that are easy to get wrong: @@ -329,8 +329,8 @@ runs once per state volume, on the first project, and never again.) Two conseque chat into it. The old chats stay under "Ungrouped". Before every start the entrypoint reports this — each project with its storage, each -missing directory, every chat it could recover — and with `DSH_WORKSPACE_DOCTOR=repair` -it fixes it at startup: +missing directory, every chat it could recover — and repairs it, with no configuration to +set. `DSH_WORKSPACE_DOCTOR=warn` reports without repairing, `=off` is silent: | | | |---|---| diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 60e2b052e8..a603bc138c 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -133,19 +133,29 @@ if [ "$(id -u)" = 0 ]; then # session is created, against the project directory's canonical path — and a # directory outside the mounted /workspace and state volume does not survive # a container update. Those chats then collect under "Ungrouped" for good, - # because the one-time history bootstrap never runs again. Report it always; - # recreate the directories and re-account the orphaned sessions when asked - # (backup first, session logs never touched). See README: - # "Chats land in Ungrouped after an update". + # because the one-time history bootstrap never runs again. The default is to + # repair: recreate the directories and re-account the orphaned sessions + # (backup first, session logs never touched), so a container update heals + # itself with no configuration. DSH_WORKSPACE_DOCTOR=warn only reports, + # =off is silent. See README: "Chats land in Ungrouped after an update". # # Resolve it by name: the installed file is dsh-workspace-doctor.mjs, and a # path spelled out here is exactly how a "not found" reaches production. The # CI smoke test asserts this step's output appears in the boot log, so a # rename or a wrong spelling fails the build instead of the container start. DOCTOR="$(command -v dsh-workspace-doctor.mjs 2>/dev/null || true)" - case "${DSH_WORKSPACE_DOCTOR:-warn}" in + case "${DSH_WORKSPACE_DOCTOR:-repair}" in 0|off|no) ;; - repair|all|1|yes) + warn|check|report) + if [ -n "$DOCTOR" ]; then + "$DOCTOR" --check \ + || log "workspace doctor: see the report above; DSH_WORKSPACE_DOCTOR defaults to repair, so this start was told not to fix it" + else + log "workspace doctor: dsh-workspace-doctor.mjs is not installed in this image;" + log " workspace grouping was NOT checked. Update the image." + fi + ;; + *) if [ -n "$DOCTOR" ]; then "$DOCTOR" --all \ || log "workspace doctor: repair did not finish; starting dsh with the registry unchanged" @@ -156,15 +166,6 @@ if [ "$(id -u)" = 0 ]; then log " workspace grouping was NOT repaired. Update the image." fi ;; - *) - if [ -n "$DOCTOR" ]; then - "$DOCTOR" --check \ - || log "workspace doctor: see the report above - set DSH_WORKSPACE_DOCTOR=repair to fix it at startup" - else - log "workspace doctor: dsh-workspace-doctor.mjs is not installed in this image;" - log " workspace grouping was NOT checked. Update the image." - fi - ;; esac export HOME="$HOME_DIR" -- 2.54.0