diff --git a/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh b/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh index 11a4c3f..96b9931 100755 --- a/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh +++ b/packages/mosaic/framework/tools/fleet/test-start-agent-session.sh @@ -32,8 +32,15 @@ MOSAIC_AGENT_COMMAND='bash --noprofile --norc -i' \ "$START" "$AGENT" tmux -L "$SOCKET" has-session -t "=$AGENT:0.0" || fail "agent session was not created" -actual_dir=$(tmux -L "$SOCKET" display-message -p -t "=$AGENT:0.0" '#{pane_current_path}') -[ "$actual_dir" = "$WORKDIR" ] || fail "agent workdir mismatch: $actual_dir" +# Retry: pane_current_path briefly reflects the tmux server's cwd until the pane +# process establishes its own cwd (the -c start dir). Poll until it settles. +actual_dir="" +for _ in $(seq 1 30); do + actual_dir=$(tmux -L "$SOCKET" display-message -p -t "=$AGENT:0.0" '#{pane_current_path}') + [ "$actual_dir" = "$WORKDIR" ] && break + sleep 0.1 +done +[ "$actual_dir" = "$WORKDIR" ] || fail "agent workdir mismatch: $actual_dir (expected $WORKDIR)" # ── Test 2: idempotency (duplicate start prints 'already running') ───────────── MOSAIC_TMUX_SOCKET="$SOCKET" \ diff --git a/packages/mosaic/src/commands/fleet.ts b/packages/mosaic/src/commands/fleet.ts index eb0c462..e51ef0b 100644 --- a/packages/mosaic/src/commands/fleet.ts +++ b/packages/mosaic/src/commands/fleet.ts @@ -1453,15 +1453,19 @@ export function registerFleetAgentCommands( await runChecked(runner, buildAgentWatchCreateViewerCommand(agent, viewerName, socketName)); - const [bin, args] = splitCommand(buildAgentWatchAttachCommand(viewerName, socketName)); - const exitCode = await iRunner(bin, args); - - // Best-effort cleanup of the viewer session regardless of how the user detached. - // Errors here are intentionally suppressed — the agent session is unaffected. - const killResult = await runner( - ...splitCommand(buildAgentWatchKillViewerCommand(viewerName, socketName)), - ); - void killResult; // result is intentionally ignored + let exitCode = 0; + try { + const [bin, args] = splitCommand(buildAgentWatchAttachCommand(viewerName, socketName)); + exitCode = await iRunner(bin, args); + } finally { + // ALWAYS clean up the viewer session — even if attach threw or the process was + // interrupted — so stale grouped *-watch-* sessions never accumulate. Errors here + // are intentionally suppressed; the agent session is unaffected. + const killResult = await runner( + ...splitCommand(buildAgentWatchKillViewerCommand(viewerName, socketName)), + ); + void killResult; + } if (exitCode !== 0) { process.exitCode = exitCode;