From 53bd52b137da19beafb91eeea38049ecd39b8f1a Mon Sep 17 00:00:00 2001 From: Jiayuan Date: Sat, 31 Jan 2026 18:49:16 +0800 Subject: [PATCH] feat(agent): add process list action for activity monitoring Add 'list' action to process tool that displays all registered processes with their ID, command, status, duration, and source (exec/process). Example output: ID COMMAND STATUS DURATION SOURCE 019c139c-dbb7-70ec-ab91-0a7fd2711043 curl -X POST running 15.2s [exec] Co-Authored-By: Claude Opus 4.5 --- src/agent/tools/process.ts | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/agent/tools/process.ts b/src/agent/tools/process.ts index 7de9b9c1..962b6a13 100644 --- a/src/agent/tools/process.ts +++ b/src/agent/tools/process.ts @@ -10,7 +10,7 @@ import { } from "./process-registry.js"; const ProcessSchema = Type.Object({ - action: Type.String({ description: "Action: start | status | stop | output | cleanup." }), + action: Type.String({ description: "Action: list | start | status | stop | output | cleanup." }), id: Type.Optional(Type.String({ description: "Process id for status/stop/output." })), command: Type.Optional(Type.String({ description: "Command to run for start." })), cwd: Type.Optional(Type.String({ description: "Working directory." })), @@ -28,7 +28,7 @@ export function createProcessTool(defaultCwd?: string): AgentTool { // Auto-cleanup old terminated processes on each invocation @@ -39,6 +39,41 @@ export function createProcessTool(defaultCwd?: string): AgentTool { + const running = entry.exitCode === null; + const durationMs = Date.now() - entry.startedAt; + const durationSec = (durationMs / 1000).toFixed(1); + return { + id: entry.id, + command: entry.command.length > 50 ? entry.command.slice(0, 47) + "..." : entry.command, + running, + exitCode: entry.exitCode, + duration: `${durationSec}s`, + source: entry.source, + }; + }); + + if (processes.length === 0) { + return { + content: [{ type: "text", text: "No processes in registry." }], + details: { processes: [] }, + }; + } + + const lines = processes.map((p) => { + const status = p.running ? "running" : `exited(${p.exitCode})`; + return `${p.id} ${p.command.padEnd(50)} ${status.padEnd(12)} ${p.duration.padStart(8)} [${p.source}]`; + }); + const header = "ID".padEnd(36) + " " + "COMMAND".padEnd(50) + " " + "STATUS".padEnd(12) + " " + "DURATION".padStart(8) + " SOURCE"; + const output = [header, "-".repeat(header.length), ...lines].join("\n"); + + return { + content: [{ type: "text", text: output }], + details: { processes }, + }; + } + if (action === "start") { const command = String(params.command ?? ""); if (!command) throw new Error("Missing command");