mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 23:19:43 +02:00
Merge pull request #362 from timkjr/feat/omp-remote-continuation
fix(omp,remote): thread remote-omp resume/continue through respawn and reattach
This commit is contained in:
+69
-8
@@ -827,8 +827,11 @@ export function buildRemoteLaunchCommand(options: {
|
||||
sessionId: string;
|
||||
claudeMode?: ClaudeMode;
|
||||
allowedTools?: string;
|
||||
/** OMP only — resume/continue overrides for the remote omp relaunch (dead-pane respawn). */
|
||||
ompConfig?: OmpConfig;
|
||||
resumeSessionId?: string;
|
||||
}): string {
|
||||
const { mode, remote, sessionId, claudeMode, allowedTools } = options;
|
||||
const { mode, remote, sessionId, claudeMode, allowedTools, ompConfig, resumeSessionId } = options;
|
||||
// §6.3: honor the session's EFFECTIVE claude permission mode on remote instead of
|
||||
// hardcoding --dangerously-skip-permissions, so a non-granted multi-user user's
|
||||
// downgraded 'auto' actually reaches the remote agent (the default command otherwise
|
||||
@@ -837,11 +840,66 @@ export function buildRemoteLaunchCommand(options: {
|
||||
// `defaultRemoteCommandForMode`: `claude` lives under a per-user PATH entry that
|
||||
// only an interactive login shell resolves (see that function's comment).
|
||||
const override = remote.commands?.[mode];
|
||||
const modeCommand = override
|
||||
? override
|
||||
: mode === 'claude'
|
||||
? remoteLoginShellCommand(`claude${buildClaudePermissionFlags(claudeMode, allowedTools)}`)
|
||||
: defaultRemoteCommandForMode(mode);
|
||||
let modeCommand: string;
|
||||
if (override) {
|
||||
modeCommand = override;
|
||||
} else if (mode === 'claude') {
|
||||
// Deterministic conversation pinning for SSH-remote claude (mirrors the
|
||||
// docker-claude shape in claudeDockerPaneCommand, INCLUDING the distinct
|
||||
// resumeId branch it declares — this used to only mirror the same-id
|
||||
// fallback shape, silently dropping an explicit resumeSessionId that
|
||||
// differs from sessionId, e.g. a resume-from-history launch): the FIRST
|
||||
// run creates the conversation under --session-id <sessionId>; a respawn
|
||||
// / reattach re-runs the same idempotent command, --session-id exits
|
||||
// non-zero ("already in use"), and the `||` fallback RESUMES that same
|
||||
// conversation. Without a pinned id, every reattach relaunched a bare
|
||||
// `claude` and started a NEW conversation (found live 2026-08-29: remote
|
||||
// claude ctrl-d / ctrl-c relaunched a fresh session). A per-host
|
||||
// `commands.claude` override stays authoritative (admin's explicit
|
||||
// choice) and skips this entirely.
|
||||
const permFlags = buildClaudePermissionFlags(claudeMode, allowedTools);
|
||||
const cmd = `claude${permFlags}`;
|
||||
// Defense in depth, mirroring claudeDockerPaneCommand's own belt-and-braces check:
|
||||
// sessionId is server-minted and always safe in practice, but this command is built
|
||||
// as a single shellescaped string and then executed as shell code on the remote
|
||||
// host, so an unsafe value here is validated rather than trusted.
|
||||
if (!RESUME_ID_SAFE.test(sessionId)) {
|
||||
modeCommand = remoteLoginShellCommand(cmd);
|
||||
} else {
|
||||
const rid = resumeSessionId && RESUME_ID_SAFE.test(resumeSessionId) ? resumeSessionId : undefined;
|
||||
modeCommand = remoteLoginShellCommand(
|
||||
rid && rid !== sessionId
|
||||
? `${cmd} --resume ${rid} || ${cmd} --session-id ${sessionId}`
|
||||
: `${cmd} --session-id ${sessionId} || ${cmd} --resume ${sessionId}`
|
||||
);
|
||||
}
|
||||
} else if (mode === 'omp') {
|
||||
// Remote OMP respawn must RESUME the same conversation instead of
|
||||
// relaunching fresh (found live 2026-08-29: remote ctrl-c/ctrl-d relaunched
|
||||
// a brand-new omp session). The pinned id, when known, is passed as an
|
||||
// explicit --resume; otherwise fall back to omp's own "most recent"
|
||||
// --continue so a dead-pane respawn still lands back in the conversation.
|
||||
// Rendered through the CLI registry (buildSpawnCommandFromRegistry), the
|
||||
// SAME mode-agnostic path local/docker spawns use — not appendResumeFlag(),
|
||||
// which would hand the id to the login shell as $0 after the quoted `-c
|
||||
// 'omp'`, and not a raw buildOmpCommand() call, which the registry refactor
|
||||
// (#347) deleted. Gives every registry CLI with a resume form this
|
||||
// behaviour for free, and the flags can't drift from the local builder.
|
||||
const ompEntry = getCli('omp');
|
||||
const ompCmd = ompEntry
|
||||
? (buildSpawnCommandFromRegistry(ompEntry, {
|
||||
mode: 'omp',
|
||||
sessionId,
|
||||
ompConfig: {
|
||||
...ompConfig,
|
||||
resumeSessionId: resumeSessionId || ompConfig?.resumeSessionId,
|
||||
},
|
||||
}) ?? 'omp')
|
||||
: 'omp';
|
||||
modeCommand = remoteLoginShellCommand(ompCmd);
|
||||
} else {
|
||||
modeCommand = defaultRemoteCommandForMode(mode);
|
||||
}
|
||||
const remoteName = remoteTmuxSessionName(sessionId);
|
||||
|
||||
// Innermost: the command tmux runs in the new pane. Run via `/bin/sh -c` by
|
||||
@@ -1309,6 +1367,9 @@ function buildRemoteSessionCommand(options: {
|
||||
sessionId: string;
|
||||
claudeMode?: ClaudeMode;
|
||||
allowedTools?: string;
|
||||
/** OMP only — resume/continue overrides for a remote omp relaunch. */
|
||||
ompConfig?: OmpConfig;
|
||||
resumeSessionId?: string;
|
||||
}): string {
|
||||
const { remote, sessionId } = options;
|
||||
if (remote.owned === false) {
|
||||
@@ -1882,7 +1943,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
const fullCmd = docker
|
||||
? buildDockerLaunchCommand(resolveDockerLaunchOptions(mode, docker, sessionId, resumeSessionId))
|
||||
: remote
|
||||
? buildRemoteSessionCommand({ mode, remote, sessionId, claudeMode, allowedTools })
|
||||
? buildRemoteSessionCommand({ mode, remote, sessionId, claudeMode, allowedTools, ompConfig, resumeSessionId })
|
||||
: localFullCmd;
|
||||
|
||||
// Create tmux session in three steps to handle cold-start (no server running)
|
||||
@@ -2133,7 +2194,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
const fullCmd = docker
|
||||
? buildDockerLaunchCommand(resolveDockerLaunchOptions(mode, docker, sessionId, resumeSessionId))
|
||||
: remote
|
||||
? buildRemoteSessionCommand({ mode, remote, sessionId, claudeMode, allowedTools })
|
||||
? buildRemoteSessionCommand({ mode, remote, sessionId, claudeMode, allowedTools, ompConfig, resumeSessionId })
|
||||
: localFullCmd;
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user