mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 22:19:42 +02:00
fix(omp,remote): pin remote conversations on respawn so ctrl-d/ctrl-c 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.
This commit is contained in:
@@ -41,6 +41,15 @@ describe('mangleOmpWorkingDir', () => {
|
||||
const sibling = `${homedir()}-other/dev/foo`;
|
||||
expect(mangleOmpWorkingDir(sibling)).toBe(sibling.replace(/\//g, '-'));
|
||||
});
|
||||
|
||||
it('normalizes a trailing slash so a remote case path resolves to the same dir', () => {
|
||||
// Regression (2026-08-29): remote case paths are stored verbatim with a
|
||||
// trailing slash (e.g. `/home/user/dotfiles/`), but omp persists sessions
|
||||
// under the slash-less mangle (`-dotfiles`). Before the fix this produced
|
||||
// `-dotfiles-`, readdirSync returned null for an existing dir, and OMP
|
||||
// respawn pinning silently degraded to the ambiguous `--continue`.
|
||||
expect(mangleOmpWorkingDir(join(homedir(), 'dotfiles') + '/')).toBe('-dotfiles');
|
||||
});
|
||||
});
|
||||
|
||||
describe('findLatestOmpSessionId', () => {
|
||||
|
||||
@@ -172,6 +172,21 @@ describe('TmuxManager (unit)', () => {
|
||||
expect(command).toContain('exec "${SHELL:-/bin/sh}" -i -l -c');
|
||||
expect(command).toContain('claude --dangerously-skip-permissions');
|
||||
});
|
||||
|
||||
it('pins SSH-remote claude to the Codeman session id so a respawn resumes the same conversation', () => {
|
||||
// Regression (2026-08-29): remote claude was launched as a bare `claude …`,
|
||||
// so every reattach/respawn after a pane death (user ctrl-d or ctrl-c exit)
|
||||
// started a NEW conversation. The launch now mirrors the docker-claude shape:
|
||||
// `--session-id <id>` to create, with a `|| --resume <id>` fallback so the
|
||||
// idempotent re-run resumes instead of erroring ("already in use").
|
||||
const command = buildRemoteLaunchCommand({
|
||||
mode: 'claude',
|
||||
remote: { hostId: 'gpu-box', label: 'GPU Box', host: '10.0.0.42', username: 'ubuntu', remotePath: '/w' },
|
||||
sessionId: 'abc123def456',
|
||||
});
|
||||
expect(command).toContain('claude --dangerously-skip-permissions --session-id abc123def456');
|
||||
expect(command).toContain('claude --dangerously-skip-permissions --resume abc123def456');
|
||||
});
|
||||
});
|
||||
|
||||
describe('remote kill command builder', () => {
|
||||
|
||||
Reference in New Issue
Block a user