From f464a22bc3037308ee41c790ad9fd3070fdfc3d6 Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Fri, 6 Nov 2026 03:06:47 +0100 Subject: [PATCH] fix(adopt): bring the docker and ssh transports up to master Docker discovery now spawns dockerEngineArgv(), not the shell-quoted buildDockerBaseArgs(): execFile passed those quotes through, so docker --context "'default'" failed and every container behind a named context or remote daemon read as unreachable. The ssh probe and attach gain withRemoteTmuxPath() like every other remote tmux call, run in an explicit sh because the guard chain is POSIX and the remote login shell may be fish, and the probe holds a slot of the remote-ssh limiter and execs ssh so a timeout reaches it. Notes from a remote scan are no longer dropped, and every note now opens with its location. The adopted branch of killSession no longer blocks the event loop on docker or tmux, kills the in-container view by exact name, and clears the pane-exit and reconnect state the non-owned remote branch does. An adopted wrapper reports no injected statusline, since nothing could carry it. Key tables on the foreign server are left alone on purpose, and the invocation now says so. Co-Authored-By: Claude Opus 5.5 --- src/docker-hosts.ts | 2 +- src/foreign-tmux-discovery.ts | 74 +++++++++++++----- src/foreign-tmux.ts | 28 ++++++- src/tmux-manager.ts | 25 +++--- test/foreign-tmux.test.ts | 143 +++++++++++++++++++++++++++++++++- 5 files changed, 237 insertions(+), 35 deletions(-) diff --git a/src/docker-hosts.ts b/src/docker-hosts.ts index f2ce722d..45b8d17b 100644 --- a/src/docker-hosts.ts +++ b/src/docker-hosts.ts @@ -1014,7 +1014,7 @@ export function resolveDockerCredentialArtifacts( * string; argv arrays must NOT carry literal quotes (mirror of docker-export's * dockerArgv). */ -function dockerEngineArgv(docker: Pick): string[] { +export function dockerEngineArgv(docker: Pick): string[] { const argv: string[] = [docker.engine === 'podman' ? 'podman' : 'docker']; if (docker.context) argv.push('--context', docker.context); if (docker.daemonHost) argv.push('-H', docker.daemonHost); diff --git a/src/foreign-tmux-discovery.ts b/src/foreign-tmux-discovery.ts index 6c5e46a2..4921c610 100644 --- a/src/foreign-tmux-discovery.ts +++ b/src/foreign-tmux-discovery.ts @@ -34,16 +34,16 @@ import { promisify } from 'node:util'; import { buildForeignProbeScript, classifyForeignPaneMode, + foreignRemoteShellCommand, foreignSessionId, isAdoptableSessionName, isAdoptableSocketPath, isCodemanOwnedPane, parseForeignProbeOutput, } from './foreign-tmux.js'; -import { buildDockerBaseArgs, shellescape } from './docker-hosts.js'; -import { buildSshConnectionArgs, remoteSshTarget } from './remote-hosts.js'; -import { readDockerCases, readDockerHosts } from './docker-hosts.js'; -import { readRemoteHosts } from './remote-hosts.js'; +import { dockerEngineArgv, readDockerCases, readDockerHosts } from './docker-hosts.js'; +import { buildSshConnectionArgs, readRemoteHosts, remoteSshTarget, shellescape } from './remote-hosts.js'; +import { runWithRemoteSshLimit } from './remote-ssh-limiter.js'; import { resolveTmuxSocketName, getDataDir } from './config/instance.js'; import { FOREIGN_CACHE_TTL_MS, FOREIGN_PROBE_MAX_BYTES, FOREIGN_PROBE_TIMEOUT_MS } from './config/foreign-tmux.js'; import type { ForeignDiscoveryResult, ForeignTmuxSession } from './types/foreign-tmux.js'; @@ -63,13 +63,18 @@ const PROBE_OPTS = { /** * Turn one probe's stdout into candidates. Shared by all three transports, so a * container's sessions and the host's are classified by identical rules. + * + * `where` opens every note this scan writes (`local`, `docker `, `remote + *