mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
fix: adopted tmux targets, hung servers and the attach chain (release review)
Names tmux reads as target syntax (`@1`, `%1`, `=eq`, a bare `~`) passed the has-session guard by name and then joined something else in new-session -t: another session, or a fresh shell on the foreign server. They are refused at discovery now, and take the existing skipped note. One stopped tmux server emptied the whole local list and left a stuck client per scan. Each server now gets a bounded ping with stdout at /dev/null first, because a tmux client hands dups of its stdout to the server: a stopped server holds our pipe open after the client is dead, so a watchdog around list-panes cannot work. The probe runs in its own process group, all three transports keep the rows read before a failure, and a missed ping becomes a note. The attach and the probe pass -u, so a POSIX-locale container no longer garbles the tab or lists a non-ASCII name as underscores. A docker attach gets the same TERM and COLORTERM an owned container's exec gets. A missing tmux no longer reads as "session is gone", and the launch line's `$` now reaches bash unexpanded, so the ssh attach's PATH line is expanded at the far end, as the probe's already was. fix-plan/write, fix-plan/read and ralph-prompt/write refuse an adopted session: its workingDir is the neutral /tmp, so they read and wrote a predictable name in a folder anyone can write to. FOREIGN_MAX_SOCKETS is gone: it capped nothing, and a real cap in glob order would never reach `default` on a box with many `codeman-*` sockets (this one has 212). Closing an adopted tab re-reads the outside-sessions list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
36d8942744
commit
aa40cca343
9 files changed
+620
-81
No files matched your search
+10
-13
@@ -29,6 +29,7 @@ import {
|
||||
buildForeignAttachCommand,
|
||||
buildForeignDockerAttachCommand,
|
||||
buildForeignRemoteAttachCommand,
|
||||
quoteAdoptLaunch,
|
||||
} from './foreign-tmux.js';
|
||||
import { execSync, exec, execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
@@ -2730,13 +2731,11 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
// ⚠️ An adopted pane is never `cd`'d: it only attaches, and its `workingDir`
|
||||
// is the neutral wrapper folder, not where the foreign pane is.
|
||||
const launchCmd = remote || docker || adopt ? fullCmd : `cd ${JSON.stringify(workingDir)} && ${fullCmd}`;
|
||||
execSync(
|
||||
`${this.tmux()} respawn-pane -k -c ${TMUX_LAUNCH_CWD} -t "${muxName}" bash -c ${JSON.stringify(launchCmd)}`,
|
||||
{
|
||||
timeout: EXEC_TIMEOUT_MS,
|
||||
stdio: 'ignore',
|
||||
}
|
||||
);
|
||||
const launchArg = adopt ? quoteAdoptLaunch(launchCmd) : JSON.stringify(launchCmd);
|
||||
execSync(`${this.tmux()} respawn-pane -k -c ${TMUX_LAUNCH_CWD} -t "${muxName}" bash -c ${launchArg}`, {
|
||||
timeout: EXEC_TIMEOUT_MS,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
// Wait for tmux session to be queryable
|
||||
await new Promise((resolve) => setTimeout(resolve, TMUX_CREATION_WAIT_MS));
|
||||
@@ -2994,12 +2993,10 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
// ⚠️ An adopted pane is never `cd`'d: it only attaches, and its `workingDir`
|
||||
// is the neutral wrapper folder, not where the foreign pane is.
|
||||
const launchCmd = remote || docker || adopt ? fullCmd : `cd ${JSON.stringify(workingDir)} && ${fullCmd}`;
|
||||
await execAsync(
|
||||
`${this.tmux()} respawn-pane -k -c ${TMUX_LAUNCH_CWD} -t "${muxName}" bash -c ${JSON.stringify(launchCmd)}`,
|
||||
{
|
||||
timeout: EXEC_TIMEOUT_MS,
|
||||
}
|
||||
);
|
||||
const launchArg = adopt ? quoteAdoptLaunch(launchCmd) : JSON.stringify(launchCmd);
|
||||
await execAsync(`${this.tmux()} respawn-pane -k -c ${TMUX_LAUNCH_CWD} -t "${muxName}" bash -c ${launchArg}`, {
|
||||
timeout: EXEC_TIMEOUT_MS,
|
||||
});
|
||||
// Wait for the respawned process to start
|
||||
await new Promise((resolve) => setTimeout(resolve, TMUX_CREATION_WAIT_MS));
|
||||
// The pane now runs a fresh command, so whatever the last read observed of
|
||||
|
||||
Reference in new issue
Block a user