Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/agent-manager/src/__tests__/terminal/TmuxManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ describe('TmuxManager', () => {
expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();
});

it('returns the matching pane PID when the agent replaces the shell', async () => {
setExecFileHandler((cmd, args) => {
if (cmd === 'tmux' && args[0] === 'list-panes') return '100\n';
if (cmd === 'pgrep') return new Error('no children');
if (cmd === 'ps' && args[1] === '100') return '/usr/local/bin/claude';
return '';
});
expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(100);
});

it('returns the matching descendant when found', async () => {
// pane 100 → child 200 (claude) — no grandchildren
setExecFileHandler((cmd, args) => {
Expand Down
12 changes: 5 additions & 7 deletions packages/agent-manager/src/terminal/TmuxManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class TmuxManager {
/**
* Find the actual agent process PID inside a tmux pane.
*
* Strategy: BFS the process tree, return the deepest descendant whose
* Strategy: BFS the process tree, return the deepest process whose
* `ps` command line is accepted by `matches`. The caller supplies the
* matcher so this method has no agent-type knowledge.
*
Expand All @@ -51,7 +51,7 @@ export class TmuxManager {
* - Subprocess case: shell → claude (matches) → MCP server child (doesn't match)
* → returns claude, not the subprocess
*
* Returns null when no descendant matches yet (agent still starting); the
* Returns null when no process matches yet (agent still starting); the
* caller's poll loop retries.
*/
async findAgentPid(session: string, matches: (psCommand: string) => boolean): Promise<number | null> {
Expand All @@ -67,11 +67,9 @@ export class TmuxManager {
if (visited.has(pid)) continue;
visited.add(pid);

if (pid !== panePid) {
const command = await this.getProcessCommand(pid);
if (command && matches(command)) {
deepestMatch = pid;
}
const command = await this.getProcessCommand(pid);
if (command && matches(command)) {
deepestMatch = pid;
}

const children = await this.pgrepChildren(pid);
Expand Down
Loading