Skip to content

fix(omp,remote): thread remote-omp resume/continue through respawn and reattach - #362

Open
timkjr wants to merge 2 commits into
Ark0N:masterfrom
timkjr:feat/omp-remote-continuation
Open

fix(omp,remote): thread remote-omp resume/continue through respawn and reattach#362
timkjr wants to merge 2 commits into
Ark0N:masterfrom
timkjr:feat/omp-remote-continuation

Conversation

@timkjr

Copy link
Copy Markdown

Summary

Follow-up to #353 (OMP backend) — this is the remote-continuation threading work that was deliberately split out at the time because it can't apply without OmpConfig existing upstream.

Two fixes, found live 2026-08-29 on a remote OMP/Claude node, both stemming from the same root cause: a dead/dropped remote pane relaunched the agent as a brand-new conversation instead of resuming.

  1. fix(omp,remote): pin remote conversations on respawn

    • SSH-remote claude was launched as bare claude --dangerously-skip-permissions, so any remote-respawn (COD-108 reattachRemote re-running the idempotent launch command) started a fresh conversation every time. Pinned it to the deterministic Codeman session id (--session-id <id> to create, || --resume <id> fallback so the idempotent re-run resumes instead of erroring "already in use") — mirrors the existing docker-claude shape.
    • OMP --resume pinning silently degraded to ambiguous --continue whenever a case path ended in a trailing slash (a remote case's remotePath is stored verbatim, e.g. /home/user/dotfiles/). mangleOmpWorkingDir produced -dotfiles- while omp persists sessions under -dotfiles, so lookup never matched. Normalized the trailing slash before mangling.
  2. fix(remote): never auto-revive a remote session after a clean agent exit

    • The COD-108 reconnect watcher treated any dead local pane as a dropped transport and re-ran the pane command — so a normal ctrl-c/ctrl-d on a remote omp/opencode/claude session auto-spawned a fresh agent (claude only looked correct because its --session-id || --resume fallback happened to resume it, with a loud "already in use" error first).
    • Now distinguishes a transport drop from an intentional exit: only reconnects when the durable remote tmux session (codeman-ssh-*) is verifiably still alive on the remote host, probed via ssh has-session, fails closed (skips) when gone or unknown. The probe is cached per-session and fired async so the 5s watcher tick never blocks on ssh.
    • Threads ompConfig/resumeSessionId into the remote command builders so a dead-pane respawn of an omp session resumes (--resume <id>) or continues (--continue) instead of launching bare omp.

Test plan

  • npm run typecheck — clean
  • Full suite: 6358 tests, 6345 passed, 12 skipped, 0 failed (one unrelated environment failure — missing node_modules/.bin/prettier in a fresh worktree — resolved by npm install, confirmed passing after)
  • test/remote-shared-sessions.test.ts (most directly touched) — all passing, including the omp --resume/--continue command-building cases
  • test/remote-auto-reconnect.test.ts — new cases for remote-gone / remote-unknown (fail closed) / remote-alive (legitimate reconnect still works)
  • test/omp-session-resolver.test.ts, test/tmux-manager.test.ts — trailing-slash normalization and SSH-remote claude session-id pinning

🤖 Generated with Claude Code

timkjr added 2 commits August 30, 2026 22:56
… resumes instead of relaunching fresh
Two independent defects made ANY clean exit from a remote SSH session (user
ctrl-d or ctrl-c, or a dropped pane) relaunch the agent as a NEW conversation:
1. SSH-remote claude was launched as a bare `claude --dangerously-skip-permissions`,
so the remote-respawn path (COD-108 reattachRemote re-running the idempotent
launch command) started a fresh conversation every time. Pin it to the
deterministic Codeman session id, mirroring the docker-claude shape
(claudeDockerPaneCommand): `--session-id <id>` to create, with the
`|| --resume <id>` fallback so the idempotent re-run resumes instead of
erroring with "already in use". A per-host commands.claude override still wins.
2. OMP --resume pinning silently degraded to ambiguous `--continue` whenever a
case path ended in a trailing slash (e.g. remote `remotePath` stored verbatim
as `/home/user/dotfiles/`): mangleOmpWorkingDir produced `-dotfiles-` while
omp persists sessions under `-dotfiles`, readdirSync returned null for an
existing dir, and findLatestOmpSessionId/resolveAndClaimOmpSessionId never
matched. Normalize the trailing slash before mangling (new exported
stripTrailingSlash) and compare the session header cwd against the same
normalized value.
Both were found live 2026-08-29 on a remote OMP/Claude node: ctrl-c and ctrl-d
behaved identically, both relaunching a fresh session.
The COD-108 reconnect watcher treated any dead local pane as a dropped
transport and re-ran the pane command — so a normal ctrl-c/ctrl-d on a
remote omp/opencode/claude auto-spawned a FRESH agent (claude only
looked correct because its '--session-id || --resume' fallback resumed,
with a loud 'already in use' error first).
Distinguish a transport drop from an intentional exit: only reconnect
when the durable remote tmux session (codeman-ssh-*) is verifiably
still alive on the remote host. A clean exit tears that session down;
the watcher now probes it via ssh has-session and skips (remote-gone)
when it is gone OR unknown (fail closed). The probe is cached
per-session and fired async so the 5s tick never blocks on ssh.
Also thread ompConfig/resumeSessionId into the remote builders so a
dead-pane respawn of an omp session resumes (--resume <id>) or
continues (--continue) instead of launching bare omp.
Tests: 3 new cases pinning remote-gone / unknown / alive decisions;
remote omp resume + --continue fallback. Verified live: all three
remote CLIs stay dead after exit.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@timkjr