mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 18:39:33 +01:00
fix(remote): bootstrap PATH consistently for remote tmux (johoja12/Codeman#15)
This commit is contained in:
1 parent
002de32a08
commit
5b9445de9e
8 files changed
+223
-19
No files matched your search
+20
-3
@@ -89,6 +89,19 @@ export function remoteLoginShellCommand(command: string): string {
|
||||
return `exec ${REMOTE_LOGIN_SHELL} -i -l -c ${shellescape(command)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remote tmux runs in sshd's non-interactive shell, which may omit Homebrew and
|
||||
* per-user binaries. Keep every remote tmux operation on the same PATH. Quoting
|
||||
* the entire assignment preserves spaces in HOME/inherited PATH under dash too.
|
||||
* CLI commands still use their existing login-shell/configuration handling.
|
||||
*/
|
||||
export function withRemoteTmuxPath(command: string): string {
|
||||
return (
|
||||
'export PATH="$HOME/.opencode/bin:$HOME/.local/bin:$HOME/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"; ' +
|
||||
command
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The CLI text a location overlay should launch for `mode`, or null when this build has no
|
||||
* entry for it. `overlays.<location>.command` when the entry names one, otherwise the bare
|
||||
@@ -228,7 +241,11 @@ export function buildRemoteTmuxCheckCommand(
|
||||
host: Pick<RemoteHost, 'username' | 'host' | 'port'> & RemoteSshOptions
|
||||
): string {
|
||||
// ConnectTimeout is now a default of buildSshConnectionArgs (shared with the launch).
|
||||
return [...buildSshConnectionArgs(host), remoteSshTarget(host), "'command -v tmux'"].join(' ');
|
||||
return [
|
||||
...buildSshConnectionArgs(host),
|
||||
remoteSshTarget(host),
|
||||
shellescape(withRemoteTmuxPath('command -v tmux')),
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
export interface RemoteTmuxCheckResult {
|
||||
@@ -368,7 +385,7 @@ export function buildRemoteSessionAliveCommand(
|
||||
): string {
|
||||
const [ssh, ...connectionArgs] = buildSshConnectionArgs(host);
|
||||
const remoteCmd = `tmux -L codeman-remote has-session -t ${shellescape(remoteSessionName)} 2>/dev/null`;
|
||||
return [ssh, ...connectionArgs, remoteSshTarget(host), shellescape(remoteCmd)].join(' ');
|
||||
return [ssh, ...connectionArgs, remoteSshTarget(host), shellescape(withRemoteTmuxPath(remoteCmd))].join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,7 +470,7 @@ export function buildRemoteListSessionsCommand(
|
||||
// separators (tmux expands them); `2>/dev/null` is inside the quoted command.
|
||||
const remoteCmd =
|
||||
'tmux -L codeman list-sessions -F "#{session_name}\\t#{session_attached}\\t#{session_created}\\t#{session_windows}" 2>/dev/null';
|
||||
parts.push(remoteSshTarget(host), shellescape(remoteCmd));
|
||||
parts.push(remoteSshTarget(host), shellescape(withRemoteTmuxPath(remoteCmd)));
|
||||
return parts.join(' ');
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,13 @@ import { exec } from 'node:child_process';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { promisify } from 'node:util';
|
||||
import type { SessionRemote } from './types/session.js';
|
||||
import { buildSshConnectionArgs, classifyRemoteAliveExit, remoteSshTarget, shellescape } from './remote-hosts.js';
|
||||
import {
|
||||
buildSshConnectionArgs,
|
||||
classifyRemoteAliveExit,
|
||||
remoteSshTarget,
|
||||
shellescape,
|
||||
withRemoteTmuxPath,
|
||||
} from './remote-hosts.js';
|
||||
import { RemoteSshSlotTimeoutError, runWithRemoteSshLimit } from './remote-ssh-limiter.js';
|
||||
import { remoteTmuxLocation } from './tmux-manager.js';
|
||||
|
||||
@@ -153,7 +159,7 @@ export function buildRemoteScrollbackCommand(
|
||||
marker: string
|
||||
): string {
|
||||
const { socket, sessionName } = remoteTmuxLocation(remote, sessionId);
|
||||
const script = buildRemoteScrollbackScript(socket, sessionName, historyLines, tailBytes, marker);
|
||||
const script = withRemoteTmuxPath(buildRemoteScrollbackScript(socket, sessionName, historyLines, tailBytes, marker));
|
||||
// `exec` so a timeout kill reaches ssh itself, not only the local `sh -c`.
|
||||
return ['exec', ...buildSshConnectionArgs(remote), remoteSshTarget(remote), shellescape(script)].join(' ');
|
||||
}
|
||||
|
||||
+18
-3
@@ -84,6 +84,7 @@ import {
|
||||
remoteLoginShellCommand,
|
||||
remoteSshTarget,
|
||||
remoteTmuxSessionAlive,
|
||||
withRemoteTmuxPath,
|
||||
} from './remote-hosts.js';
|
||||
import {
|
||||
buildDockerBaseArgs,
|
||||
@@ -1381,7 +1382,14 @@ export function buildRemoteLaunchCommand(options: {
|
||||
// `ssh -o BatchMode=yes` (preserving the historical token order), then the rest
|
||||
// of the connection args, then the target and the quoted tmux invocation.
|
||||
const [ssh, batchMode, ...connectionArgs] = buildSshConnectionArgs(remote);
|
||||
const sshParts = [ssh, batchMode, '-t', ...connectionArgs, remoteSshTarget(remote), shellescape(tmuxInvocation)];
|
||||
const sshParts = [
|
||||
ssh,
|
||||
batchMode,
|
||||
'-t',
|
||||
...connectionArgs,
|
||||
remoteSshTarget(remote),
|
||||
shellescape(withRemoteTmuxPath(tmuxInvocation)),
|
||||
];
|
||||
return sshParts.join(' ');
|
||||
}
|
||||
|
||||
@@ -1398,7 +1406,7 @@ export function buildRemoteKillCommand(options: { remote: SessionRemote; session
|
||||
const remoteName = remoteTmuxSessionName(sessionId);
|
||||
const killCmd = `tmux -L ${REMOTE_TMUX_SOCKET} kill-session -t ${shellescape(remoteName)}`;
|
||||
const [ssh, ...connectionArgs] = buildSshConnectionArgs(remote);
|
||||
return [ssh, ...connectionArgs, remoteSshTarget(remote), shellescape(killCmd)].join(' ');
|
||||
return [ssh, ...connectionArgs, remoteSshTarget(remote), shellescape(withRemoteTmuxPath(killCmd))].join(' ');
|
||||
}
|
||||
|
||||
// ========== Docker cases (COD-Docker) ==========
|
||||
@@ -1777,7 +1785,14 @@ export function resolveDockerLaunchOptions(
|
||||
export function buildRemoteAttachCommand(remote: SessionRemote, remoteSessionName: string): string {
|
||||
const tmuxInvocation = `tmux -L codeman attach -t ${shellescape(remoteSessionName)}`;
|
||||
const [ssh, batchMode, ...connectionArgs] = buildSshConnectionArgs(remote);
|
||||
const sshParts = [ssh, batchMode, '-t', ...connectionArgs, remoteSshTarget(remote), shellescape(tmuxInvocation)];
|
||||
const sshParts = [
|
||||
ssh,
|
||||
batchMode,
|
||||
'-t',
|
||||
...connectionArgs,
|
||||
remoteSshTarget(remote),
|
||||
shellescape(withRemoteTmuxPath(tmuxInvocation)),
|
||||
];
|
||||
return sshParts.join(' ');
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user