Fix the workspace doctor never running (wrong path in the entrypoint) #2

Merged
mward4 merged 1 commits from fix/doctor-invocation-path into main 2026-09-17 22:22:11 -04:00
3 changed files with 55 additions and 4 deletions

No files matched your search

+15
View File
@@ -215,6 +215,21 @@ jobs:
DOCTOR_RC=0
docker exec "$SMOKE" dsh-workspace-doctor.mjs --check > /dev/null || DOCTOR_RC=$?
[ "$DOCTOR_RC" -le 1 ]
# ...and the entrypoint must actually invoke it. The doctor prints a
# "dsh-workspace-doctor:" line when it runs; the entrypoint logs a
# "workspace doctor:" line only when it could not. A direct
# `docker exec` above sails past a wrong path or a lost exec bit, so
# the boot log, not the binary, is what proves the wiring.
if ! docker logs "$SMOKE" 2>&1 | grep -q "^dsh-workspace-doctor:"; then
echo "the workspace doctor did not run at boot"
docker logs "$SMOKE" | tail -30
exit 1
fi
if docker logs "$SMOKE" 2>&1 | grep -q "workspace doctor:"; then
echo "the entrypoint could not run the workspace doctor"
docker logs "$SMOKE" | tail -30
exit 1
fi
OK=""
for i in $(seq 1 30); do
if docker exec "$SMOKE" node -e '
+18 -1
View File
@@ -233,6 +233,13 @@ Your DeepSeek API key can be set below (stored in the container env) or entered
</Container>
```
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.
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
trusts.
@@ -330,7 +337,17 @@ it fixes it at startup:
| Repairs | recreates missing workspace directories, and re-accounts chats whose recorded directory matches a project but which no project lists |
| Never | touches a session log, deletes a session, invents a project, or moves a chat into a project it did not run in |
| Before writing | copies the workspace registry to `workspace.json.bak-<timestamp>`; the write itself is atomic and in dsh's own format |
| By hand | `docker exec -u 1000:1000 <container> dsh-workspace-doctor.mjs --check` (add `--all --dry-run` to preview a repair) |
| By hand | report with `docker exec <container> dsh-workspace-doctor.mjs --check`; repair with the one-off container below |
To repair without waiting for a container start, stop the container first so nothing races
the registry write, then run the doctor against the state volume directly (`--entrypoint`
bypasses dsh, and the image's `PUID`/`PGID` are applied to what it writes):
```sh
docker run --rm --entrypoint /usr/local/bin/dsh-workspace-doctor.mjs \
-v /mnt/user/appdata/deepseek-harness:/home/node/.dsh \
gitea.milesward.dev/mward4/deepseek-harness:latest --all
```
The recreated directory is empty: this restores the *grouping*, not the files — those lived
in the container and nothing here can bring them back. Keep project data under `/workspace`
+22 -3
View File
@@ -137,17 +137,33 @@ if [ "$(id -u)" = 0 ]; then
# 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".
#
# 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
0|off|no) ;;
repair|all|1|yes)
/usr/local/bin/dsh-workspace-doctor --all \
if [ -n "$DOCTOR" ]; then
"$DOCTOR" --all \
|| log "workspace doctor: repair did not finish; starting dsh with the registry unchanged"
# The doctor runs as root here; hand what it wrote back to the runtime user.
chown "$PUID:$PGID" "$STATE/storages/workspace.json" "$STATE/storages/"workspace.json.bak-* 2>/dev/null || true
else
log "workspace doctor: dsh-workspace-doctor.mjs is not installed in this image;"
log " workspace grouping was NOT repaired. Update the image."
fi
;;
*)
/usr/local/bin/dsh-workspace-doctor --check \
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
@@ -163,6 +179,9 @@ if [ ! -w "$STATE" ]; then
log " chown -R $(id -u):$(id -g) <host path mounted at $STATE>"
exit 1
fi
/usr/local/bin/dsh-workspace-doctor --check \
DOCTOR="$(command -v dsh-workspace-doctor.mjs 2>/dev/null || true)"
if [ -n "$DOCTOR" ]; then
"$DOCTOR" --check \
|| log "workspace doctor: see the report above (running unprivileged, so it only reports)"
fi
exec dsh "$@"