Skip to content

Commit 37206bc

Browse files
committed
feat: read output timeout
1 parent 684fd7f commit 37206bc

4 files changed

Lines changed: 67 additions & 11 deletions

File tree

src/server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
335335
name: "read_output",
336336
description: `
337337
Read new output from a running terminal session.
338+
Set timeout_ms for long running commands.
338339
339340
${CMD_PREFIX_DESCRIPTION}`,
340341
inputSchema: zodToJsonSchema(ReadOutputArgsSchema),

src/terminal-manager.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ export class TerminalManager {
126126
return null;
127127
}
128128

129+
/**
130+
* Get a session by PID
131+
* @param pid Process ID
132+
* @returns The session or undefined if not found
133+
*/
134+
getSession(pid: number): TerminalSession | undefined {
135+
return this.sessions.get(pid);
136+
}
137+
129138
forceTerminate(pid: number): boolean {
130139
const session = this.sessions.get(pid);
131140
if (!session) {

src/tools/execute.ts

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,66 @@ export async function executeCommand(args: unknown): Promise<ServerResult> {
6262
}
6363

6464
export async function readOutput(args: unknown): Promise<ServerResult> {
65-
const parsed = ReadOutputArgsSchema.safeParse(args);
66-
if (!parsed.success) {
67-
return {
68-
content: [{ type: "text", text: `Error: Invalid arguments for read_output: ${parsed.error}` }],
69-
isError: true,
70-
};
71-
}
65+
const parsed = ReadOutputArgsSchema.safeParse(args);
66+
if (!parsed.success) {
67+
return {
68+
content: [{ type: "text", text: `Error: Invalid arguments for read_output: ${parsed.error}` }],
69+
isError: true,
70+
};
71+
}
72+
73+
const { pid, timeout_ms = 5000 } = parsed.data;
74+
75+
// Check if the process exists
76+
const session = terminalManager.getSession(pid);
77+
if (!session) {
78+
return {
79+
content: [{ type: "text", text: `No session found for PID ${pid}` }],
80+
isError: true,
81+
};
82+
}
83+
// Wait for output with timeout
84+
let output = "";
85+
let timeoutReached = false;
86+
try {
87+
// Create a promise that resolves when new output is available or when timeout is reached
88+
const outputPromise:Promise<string> = new Promise<string>((resolve) => {
89+
// Check for initial output
90+
const initialOutput = terminalManager.getNewOutput(pid);
91+
if (initialOutput && initialOutput.length > 0) {
92+
resolve(initialOutput);
93+
return;
94+
}
95+
96+
// Setup an interval to poll for output
97+
const interval = setInterval(() => {
98+
const newOutput = terminalManager.getNewOutput(pid);
99+
if (newOutput && newOutput.length > 0) {
100+
clearInterval(interval);
101+
resolve(newOutput);
102+
}
103+
}, 300); // Check every 300ms
104+
105+
// Set a timeout to stop waiting
106+
setTimeout(() => {
107+
clearInterval(interval);
108+
timeoutReached = true;
109+
resolve(terminalManager.getNewOutput(pid) || "");
110+
}, timeout_ms);
111+
});
112+
113+
output = await outputPromise;
114+
} catch (error) {
115+
return {
116+
content: [{ type: "text", text: `Error reading output: ${error}` }],
117+
isError: true,
118+
};
119+
}
72120

73-
const output = terminalManager.getNewOutput(parsed.data.pid);
74121
return {
75122
content: [{
76123
type: "text",
77-
text: output === null
78-
? `No session found for PID ${parsed.data.pid}`
79-
: output || 'No new output available'
124+
text: output || 'No new output available' + (timeoutReached ? ' (timeout reached)' : '')
80125
}],
81126
};
82127
}

src/tools/schemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const ExecuteCommandArgsSchema = z.object({
2222

2323
export const ReadOutputArgsSchema = z.object({
2424
pid: z.number(),
25+
timeout_ms: z.number().optional(),
2526
});
2627

2728
export const ForceTerminateArgsSchema = z.object({

0 commit comments

Comments
 (0)