fix: note the silent skip of codeman-named tmux sessions and two adopted details (release review)

A session named codeman-* or claudeman-* on any socket is dropped with no
note, which contradicted the docs. paneCwd is absent for an adopted session,
and only a claude wrapper reports statusLineExporter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-06 08:23:43 +01:00
1 parent 1c4cef1ccc
commit 3e5211e18b
3 files changed
+6 -4

No files matched your search

+3 -2
View File
@@ -986,7 +986,7 @@ the directory the session's local tmux pane is in now (`#{pane_current_path}`),
the web UI uses as the base for a relative path printed in the terminal. It is
never restored after a restart (it is written to `state.json` with the rest of the
session state but not read back), absent for remote,
Docker, direct-PTY and rediscovered sessions and for a session split into several panes,
Docker, adopted, direct-PTY and rediscovered sessions and for a session split into several panes,
and never a confinement root: file routes stay confined to `workingDir`.
tmux reports the resolved directory, so for a workspace reached through a symlink a
directory at or under the resolved workspace is reported in `workingDir`'s spelling.
@@ -1166,7 +1166,8 @@ gave nothing, each opening with where it came from (`local`, `docker <name>`,
pass to a shell, or whose name tmux reads as a target rather than a name (one starting
with `=`, `@` or `%`, or a bare `~`), is skipped and counted in a note. A tmux server that
does not answer within 2 seconds costs only its own rows and gets a note, and a scan cut
short keeps the rows it read and says so in one. Sessions on a Codeman socket never appear.
short keeps the rows it read and says so in one. Sessions on a Codeman socket never appear,
and neither does a session named `codeman-*` or `claudeman-*` on any other socket, with no note.
`POST /api/v1/sessions/adopt` wraps one, with `{ "id": "...", "docker": true, "remote":
true }` (the two flags must match the listing the id came from; `name` and
+1 -1
View File
@@ -109,7 +109,7 @@ Input arriving during a wake is buffered: a chunk over 4 KB is dropped whole, ne
**One wrapper per target.** `foreignTargetKey()` is the ONE key, read by the adopt route and `adoptedBy`, built from the location, the host identity, the socket and the name: a socket and a name alone collide across containers and hosts. Both read live `Session`s, since the mux record only exists after the first attach.
**No workspace.** ⚠️ An adopted session keeps its connection on `adopt.remote`/`adopt.docker`, so `session.remote` and `session.docker` are undefined, and its `workingDir` is the neutral `/tmp`. Code that branches on those two reads an in-container or over-ssh adoption as a local session working in `/tmp`. So anything that treats `workingDir` as the session's workspace must also test `session.isAdopted` (`adopt` on a pure view): uploads, the upload GC, git status, git fetch and its scheduler, the image watcher, Read My Mind's git signals, the Discord folder, `last-response`, guarded input and Ralph's `@fix_plan.md` and `@ralph_prompt.md` routes all do. The file surfaces (Files panel, File Viewer and its edit mode) still treat `/tmp` as the workspace, which is harmless: it is world-writable anyway, and adoption is admin-only in multi-user mode. A wrapper reports `statusLineExporter: 'remote'`, which is also what keeps keep-warm off it.
**No workspace.** ⚠️ An adopted session keeps its connection on `adopt.remote`/`adopt.docker`, so `session.remote` and `session.docker` are undefined, and its `workingDir` is the neutral `/tmp`. Code that branches on those two reads an in-container or over-ssh adoption as a local session working in `/tmp`. So anything that treats `workingDir` as the session's workspace must also test `session.isAdopted` (`adopt` on a pure view): uploads, the upload GC, git status, git fetch and its scheduler, the image watcher, Read My Mind's git signals, the Discord folder, `last-response`, guarded input and Ralph's `@fix_plan.md` and `@ralph_prompt.md` routes all do. The file surfaces (Files panel, File Viewer and its edit mode) still treat `/tmp` as the workspace, which is harmless: it is world-writable anyway, and adoption is admin-only in multi-user mode. A claude wrapper reports `statusLineExporter: 'remote'`, which is also what keeps keep-warm off it.
**Lifecycle.** `paneExitApplies` is false for a wrapper, so an attach that ended is never `paneExit` and the sweep never closes the tab. ⚠️ `remain-on-exit` still keeps Codeman's own tmux client on the dead pane, where a pid and `busy` hid it and both attach routes refused it, so `detachEndedAdoptedAttaches()` detaches that client on the reconnect watcher's tick: the tab closes nothing, its pid goes null, and selecting it (or "Go to tab" once a session of that name is back) runs the guard again. Boot recovery re-attaches a dead wrapper, which prints that the session is gone and exits. Reboot restore refuses one, since all Codeman ever had was an attach command. ⚠️ A wrapper that cannot start fails the start, and selecting the tab tries it again (`_failAdoptedStart()`). It never takes the direct-PTY fallback, which would run a new local `claude --dangerously-skip-permissions` or a server-account shell in `/tmp` under the foreign session's name, and `runPrompt()` refuses it for the same reason.
+2 -1
View File
@@ -313,7 +313,8 @@ button, and **Rescan** runs it again.
- **A short line in the block says why a session is missing.** One whose name holds unusual
characters is skipped, and so is one named so that tmux reads the name as something else (it
starts with `=`, `@` or `%`, or is a bare `~`). Rename it with `tmux rename-session`. A tmux
server that stopped answering costs only its own sessions.
server that stopped answering costs only its own sessions. The one silent case: a session
named `codeman-*` or `claudeman-*` counts as Codeman's own and is left out with no line.
Only sockets in tmux's own folder are scanned, so `tmux -L <name>` is found and
`tmux -S /custom/path` is not. In multi-user mode the block is for admins, since it shows