fix: add execFileAsync timeouts, use satisfies for plugin exports

- Add { timeout: 30_000 } to all execFileAsync calls (tmux, ps) per
  CLAUDE.md convention to prevent hanging on stuck processes
- Replace `const plugin: PluginModule<Agent>` with inline
  `export default { ... } satisfies PluginModule<Agent>` to preserve
  narrow literal types on manifest fields

Addresses Bugbot review comments on PR #5.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Prateek 2026-02-13 19:17:59 +05:30
parent f3151c2004
commit 42d601869d
3 changed files with 10 additions and 13 deletions

View File

@ -80,7 +80,7 @@ function createAiderAgent(): Agent {
handle.id,
"-F",
"#{pane_tty}",
]);
], { timeout: 30_000 });
const ttys = ttyOut
.trim()
.split("\n")
@ -88,7 +88,7 @@ function createAiderAgent(): Agent {
.filter(Boolean);
if (ttys.length === 0) return false;
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"]);
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"], { timeout: 30_000 });
const ttySet = new Set(ttys.map((t) => t.replace(/^\/dev\//, "")));
const processRe = /(?:^|\/)aider(?:\s|$)/;
for (const line of psOut.split("\n")) {
@ -137,5 +137,4 @@ export function create(): Agent {
return createAiderAgent();
}
const plugin: PluginModule<Agent> = { manifest, create };
export default plugin;
export default { manifest, create } satisfies PluginModule<Agent>;

View File

@ -245,7 +245,7 @@ async function findClaudeProcess(handle: RuntimeHandle): Promise<number | null>
handle.id,
"-F",
"#{pane_tty}",
]);
], { timeout: 30_000 });
// Iterate all pane TTYs (multi-pane sessions) — succeed on any match
const ttys = ttyOut
.trim()
@ -257,7 +257,7 @@ async function findClaudeProcess(handle: RuntimeHandle): Promise<number | null>
// Use `args` instead of `comm` so we can match the CLI name even when
// the process runs via a wrapper (e.g. node, python). `comm` would
// report "node" instead of "claude" in those cases.
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"]);
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"], { timeout: 30_000 });
const ttySet = new Set(ttys.map((t) => t.replace(/^\/dev\//, "")));
// Match "claude" as a word boundary — prevents false positives on
// names like "claude-code" or paths that merely contain the substring.
@ -362,7 +362,7 @@ function createClaudeCodeAgent(): Agent {
"-p",
"-S",
"-15",
]);
], { timeout: 30_000 });
output = stdout;
}
} catch {
@ -445,5 +445,4 @@ export function create(): Agent {
return createClaudeCodeAgent();
}
const plugin: PluginModule<Agent> = { manifest, create };
export default plugin;
export default { manifest, create } satisfies PluginModule<Agent>;

View File

@ -84,7 +84,7 @@ function createCodexAgent(): Agent {
handle.id,
"-F",
"#{pane_tty}",
]);
], { timeout: 30_000 });
const ttys = ttyOut
.trim()
.split("\n")
@ -92,7 +92,7 @@ function createCodexAgent(): Agent {
.filter(Boolean);
if (ttys.length === 0) return false;
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"]);
const { stdout: psOut } = await execFileAsync("ps", ["-eo", "pid,tty,args"], { timeout: 30_000 });
const ttySet = new Set(ttys.map((t) => t.replace(/^\/dev\//, "")));
const processRe = /(?:^|\/)codex(?:\s|$)/;
for (const line of psOut.split("\n")) {
@ -141,5 +141,4 @@ export function create(): Agent {
return createCodexAgent();
}
const plugin: PluginModule<Agent> = { manifest, create };
export default plugin;
export default { manifest, create } satisfies PluginModule<Agent>;