aws-runtime-bridge 1.9.128 → 1.9.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/browser/browser-frame-encode.d.ts +16 -0
  2. package/dist/browser/browser-frame-encode.js +2 -0
  3. package/dist/browser/browser-pool.js +1 -1
  4. package/dist/browser/screencast-differ.d.ts +35 -0
  5. package/dist/browser/screencast-differ.js +2 -0
  6. package/dist/browser/screencast-manager.d.ts +32 -0
  7. package/dist/browser/screencast-manager.js +1 -1
  8. package/dist/browser/types.d.ts +48 -1
  9. package/dist/browser/types.js +1 -1
  10. package/dist/browser/ws-server.d.ts +1 -1
  11. package/dist/browser/ws-server.js +1 -1
  12. package/dist/routes/background-tasks.js +7 -1
  13. package/dist/routes/instance-tool-status.d.ts +4 -0
  14. package/dist/routes/instance-tool-status.js +2 -0
  15. package/dist/routes/instance.d.ts +0 -2
  16. package/dist/routes/instance.js +1 -1
  17. package/dist/services/acode-bg-manager.d.ts +36 -0
  18. package/dist/services/acode-bg-manager.js +2 -0
  19. package/dist/services/browser-session-manager.js +1 -1
  20. package/package/acode/dist/await-complete-tool.js +4 -4
  21. package/package/acode/dist/background-command-manager.d.ts +58 -0
  22. package/package/acode/dist/background-command-manager.js +5 -6
  23. package/package/acode/dist/background-command-tools.js +1 -1
  24. package/package/acode/dist/built-in-file-tools.js +2 -2
  25. package/package/acode/dist/builtins/shellCommandResult.d.ts +3 -0
  26. package/package/acode/dist/builtins/shellCommandResult.js +1 -1
  27. package/package/acode/dist/builtins/shellCommandRunner.d.ts +2 -0
  28. package/package/acode/dist/builtins/shellCommandRunner.js +1 -1
  29. package/package/acode/dist/runtime.js +7 -7
  30. package/package/acode/dist/sub-agent-tools.js +30 -26
  31. package/package/acode/dist/sub-agent-types.d.ts +1 -1
  32. package/package/acode/dist/tool-allocation.d.ts +4 -4
  33. package/package/acode/dist/tool-allocation.js +1 -1
  34. package/package/aws-client-agent-mcp/dist/mcp-server.js +1 -1
  35. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- const p=`Block and wait for one or more sub-agents AND/OR background commands to complete.
1
+ const g=`Block and wait for one or more sub-agents AND/OR background commands to complete.
2
2
 
3
3
  This is the unified replacement for the old await_sub_agents: it can wait for BOTH
4
4
  sub-agents (spawned via sub_agent) and background commands (started via Bash with
@@ -9,13 +9,13 @@ All specified items must reach a terminal state before this returns (JOIN semant
9
9
  - background command: completed / failed / killed
10
10
 
11
11
  Returns a structured result with each item's outcome. For background commands only a
12
- short status + exitCode is returned; use ReadBackgroundOutput(task_id, mode="tail")
12
+ short status + exitCode is returned; use read_background_output(task_id, mode="tail")
13
13
  to fetch full output.
14
14
 
15
15
  Guidelines:
16
16
  - Pass sub-agent IDs in 'sub_agent_ids' and/or background command task_ids in 'bg_cmd_ids'
17
17
  - At least one of the two arrays must be non-empty
18
18
  - Use timeout_ms to avoid waiting forever (0 = no timeout, default 0)
19
- - After this returns, call poll_message to receive any pending messages`;function h(o){return{kind:"builtin",toolName:"await_complete",exposedName:"await_complete",description:p,inputSchema:{type:"object",properties:{sub_agent_ids:{type:"array",items:{type:"string"},description:"Array of sub-agent IDs to wait for (from sub_agent). Empty if none."},bg_cmd_ids:{type:"array",items:{type:"string"},description:"Array of background command task_ids to wait for (from Bash wait_seconds or ListBackgroundCommands). Empty if none."},timeout_ms:{type:"number",description:"Maximum time to wait in milliseconds, applied to the whole JOIN. 0 = no timeout (wait forever). Default: 0."}},additionalProperties:!1},async execute(i){const l=typeof i.timeout_ms=="number"?i.timeout_ms:0,m=i.sub_agent_ids,c=i.bg_cmd_ids,n=Array.isArray(m)?m.filter(t=>typeof t=="string"&&t.trim().length>0):[],u=Array.isArray(c)?c.filter(t=>typeof t=="string"&&t.trim().length>0):[];if(n.length===0&&u.length===0)return{title:"await_complete validation error",output:"Invalid input: provide at least one of 'sub_agent_ids' or 'bg_cmd_ids'.",metadata:{error:!0}};if(n.length>0&&!o.awaitSubAgents)return{title:"await_complete error",output:"sub_agent_ids provided but sub-agent manager is not enabled for this agent.",metadata:{error:!0}};try{let t=[];n.length>0&&o.awaitSubAgents&&(t=await o.awaitSubAgents(n,l)??[]);let a=[];u.length>0&&(a=await o.awaitBgCommands(u,l));const e=[],g=[],d=[];if(t.length>0){e.push(`=== ${t.length} sub-agent(s) ===`);for(const s of t)e.push(`[${s.status}] ${s.subId}`),s.error?(e.push("<task_error>"),e.push(s.error),e.push("</task_error>")):(e.push("<task_result>"),e.push(s.output||"(empty output)"),e.push("</task_result>")),e.push(""),g.push(s)}if(a.length>0){e.push(`=== ${a.length} background command(s) ===`);for(const s of a){if(!s){e.push("[not_found] (unknown task_id)"),e.push(""),d.push(null);continue}const r=[];s.timedOut&&r.push("timed_out"),s.aborted&&r.push("aborted"),e.push(`[${s.status}] ${s.taskId} exit=${s.exitCode??"?"}`+(r.length?` (${r.join(",")})`:"")),e.push(""),d.push(s)}}return{title:`awaited ${t.length+a.length} item(s)`,output:e.join(`
20
- `),metadata:{total:t.length+a.length,sub_agents:g,bg_cmds:d}}}catch(t){return{title:"await_complete error",output:`Failed to await: ${t instanceof Error?t.message:String(t)}`,metadata:{error:!0}}}}}}export{h as createAwaitCompleteTool};
19
+ - After this returns, call poll_message to receive any pending messages`;function h(o){return{kind:"builtin",toolName:"await_complete",exposedName:"await_complete",description:g,inputSchema:{type:"object",properties:{sub_agent_ids:{type:"array",items:{type:"string"},description:"Array of sub-agent IDs to wait for (from sub_agent). Empty if none."},bg_cmd_ids:{type:"array",items:{type:"string"},description:"Array of background command task_ids to wait for (from Bash wait_seconds or list_background_commands). Empty if none."},timeout_ms:{type:"number",description:"Maximum time to wait in milliseconds, applied to the whole JOIN. 0 = no timeout (wait forever). Default: 0."}},additionalProperties:!1},async execute(i){const l=typeof i.timeout_ms=="number"?i.timeout_ms:0,m=i.sub_agent_ids,c=i.bg_cmd_ids,n=Array.isArray(m)?m.filter(t=>typeof t=="string"&&t.trim().length>0):[],u=Array.isArray(c)?c.filter(t=>typeof t=="string"&&t.trim().length>0):[];if(n.length===0&&u.length===0)return{title:"await_complete validation error",output:"Invalid input: provide at least one of 'sub_agent_ids' or 'bg_cmd_ids'.",metadata:{error:!0}};if(n.length>0&&!o.awaitSubAgents)return{title:"await_complete error",output:"sub_agent_ids provided but sub-agent manager is not enabled for this agent.",metadata:{error:!0}};try{let t=[];n.length>0&&o.awaitSubAgents&&(t=await o.awaitSubAgents(n,l)??[]);let a=[];u.length>0&&(a=await o.awaitBgCommands(u,l));const s=[],p=[],d=[];if(t.length>0){s.push(`=== ${t.length} sub-agent(s) ===`);for(const e of t)s.push(`[${e.status}] ${e.subId}`),e.error?(s.push("<task_error>"),s.push(e.error),s.push("</task_error>")):(s.push("<task_result>"),s.push(e.output||"(empty output)"),s.push("</task_result>")),s.push(""),p.push(e)}if(a.length>0){s.push(`=== ${a.length} background command(s) ===`);for(const e of a){if(!e){s.push("[not_found] (unknown task_id)"),s.push(""),d.push(null);continue}const r=[];e.timedOut&&r.push("timed_out"),e.aborted&&r.push("aborted"),s.push(`[${e.status}] ${e.taskId} exit=${e.exitCode??"?"}`+(r.length?` (${r.join(",")})`:"")+(e.outputFilePath?` output=${e.outputFilePath}`:"")),s.push(""),d.push(e)}}return{title:`awaited ${t.length+a.length} item(s)`,output:s.join(`
20
+ `),metadata:{total:t.length+a.length,sub_agents:p,bg_cmds:d}}}catch(t){return{title:"await_complete error",output:`Failed to await: ${t instanceof Error?t.message:String(t)}`,metadata:{error:!0}}}}}}export{h as createAwaitCompleteTool};
21
21
 
@@ -7,6 +7,19 @@ export interface BackgroundCommandResult {
7
7
  exitCode: number | null;
8
8
  signal: string | null;
9
9
  timedOut: boolean;
10
+
11
+ inactivityTimedOut?: boolean;
12
+
13
+ outputFilePath: string;
14
+
15
+ outputLineCount: number;
16
+
17
+ outputSpilled: boolean;
18
+
19
+ commandFilePath?: string;
20
+ commandLineCount: number;
21
+ timeoutMs: number;
22
+ inactivityTimeoutMs: number;
10
23
  stdout: string;
11
24
  stderr: string;
12
25
  durationMs: number;
@@ -22,6 +35,8 @@ export interface AwaitBgCommandResult {
22
35
 
23
36
  aborted: boolean;
24
37
  durationMs: number;
38
+
39
+ outputFilePath?: string;
25
40
  }
26
41
 
27
42
  export interface StartCommandInput {
@@ -30,6 +45,8 @@ export interface StartCommandInput {
30
45
  workspaceRoot: string;
31
46
  cwd: string;
32
47
  timeoutMs?: number;
48
+
49
+ inactivityTimeoutMs?: number;
33
50
  onOutput?: (event: {
34
51
  stream: "stdout" | "stderr";
35
52
  text: string;
@@ -63,6 +80,39 @@ export interface TaskSummary {
63
80
  outputLineCount: number;
64
81
  outputBytes: number;
65
82
  }
83
+
84
+ export interface TaskOutputSubscriber {
85
+
86
+ onLine: (event: {
87
+ stream: "stdout" | "stderr";
88
+ text: string;
89
+ seq: number;
90
+ }) => void;
91
+
92
+ onDone: (event: {
93
+ status: BackgroundTaskStatus;
94
+ exitCode: number | null;
95
+ signal: string | null;
96
+ }) => void;
97
+ }
98
+
99
+ export interface TaskOutputSnapshot {
100
+ taskId: string;
101
+ status: BackgroundTaskStatus;
102
+ exitCode: number | null;
103
+ signal: string | null;
104
+ startedAt: number;
105
+ finishedAt: number | null;
106
+ command: string;
107
+
108
+ lines: string[];
109
+
110
+ nextSeq: number;
111
+
112
+ totalLines: number;
113
+ totalBytes: number;
114
+ truncated: boolean;
115
+ }
66
116
  export interface ReadOutputArgs {
67
117
  task_id: string;
68
118
  mode?: "head" | "tail" | "offset" | "grep";
@@ -105,13 +155,21 @@ export declare class BackgroundCommandManager {
105
155
  completion: Promise<BackgroundCommandResult>;
106
156
  };
107
157
  private spawnAndAttach;
158
+
159
+ disableInactivityTimeout(agentId: string, taskId: string): boolean;
108
160
  private onOutput;
161
+
162
+ private scheduleInactivity;
109
163
  private appendToFile;
110
164
  private finalizeTask;
111
165
 
112
166
  private evictTask;
113
167
  listTasks(agentId: string, statusFilter?: string): TaskSummary[];
114
168
  private toSummary;
169
+
170
+ getTaskOutputSnapshot(agentId: string, taskId: string, tailLines?: number): TaskOutputSnapshot | null;
171
+
172
+ subscribeTaskOutput(agentId: string, taskId: string, subscriber: TaskOutputSubscriber): (() => void) | null;
115
173
  readOutput(agentId: string, args: ReadOutputArgs): Promise<ReadOutputResult>;
116
174
 
117
175
  private readFromFile;
@@ -1,8 +1,7 @@
1
- import{spawn as S}from"node:child_process";import{promises as g}from"node:fs";import{createInterface as P}from"node:readline";import{randomBytes as T}from"node:crypto";import{prepareShellCommand as I,shellExecutable as L}from"./builtins/shellCommandPreparation.js";import{createShellOutputDecoder as w,decodeShellOutputChunk as p}from"./builtins/shellOutputDecoder.js";import{BackgroundOutputRingBuffer as O}from"./background-output-ringbuffer.js";import{BackgroundCommandStore as R}from"./background-command-store.js";const b=1e3,A=10*60*1e3,B=50*1024*1024,y=16,C=256,x=256*1024,_=500,v=5e3,D=256,k=5*60*1e3;class z{constructor(){this.tasksByAgent=new Map,this.store=new R}globalCount(){let t=0;for(const i of this.tasksByAgent.values())t+=i.size;return t}startCommand(t){const i=t.agentId,e=this.getOrCreateBucket(i);if(e.size>=y)throw new M("too_many_tasks",`Agent ${i} has ${e.size} background tasks (limit ${y}). Kill or wait for completion first.`);if(this.globalCount()>=C)throw new M("global_limit_reached",`Global background task limit ${C} reached.`);const n=this.generateTaskId(e),o=Math.min(t.timeoutMs??A,A),s=this.store.outputPathFor(i,n),u=t.commandText.length>80?`${t.commandText.slice(0,77)}...`:t.commandText,r={taskId:n,agentId:i,command:t.commandText,commandPreview:u,cwd:t.cwd,status:"running",startedAt:Date.now(),finishedAt:null,exitCode:null,signal:null,killedReason:null,timeoutMs:o,child:null,ringBuffer:new O,outputPath:s,outputWriteChain:Promise.resolve(),outputTruncated:!1,outputLineCount:0,outputBytes:0,notified:!1,completionWaiters:[],onCompleted:t.onCompleted,onOutput:t.onOutput,timeoutTimer:null,killEscalationTimer:null,retentionTimer:null,finalized:!1,stdoutDecoder:w(),stderrDecoder:w()},l=new Promise(a=>{r.completionResolve=a});return e.set(n,r),this.spawnAndAttach(r,t).catch(a=>{r.ringBuffer.push(`[ACode] spawn failed: ${a?.message??String(a)}
2
- `),this.finalizeTask(r,-1,null,"spawn_error")}),this.persistTask(r),{taskId:n,completion:l}}async spawnAndAttach(t,i){const e=L(),n=await I(i.commandText,i.workspaceRoot,e),o=process.platform==="win32",s=S(e.command,[...e.argsPrefix,n.commandText],{cwd:i.cwd,env:process.env,detached:!o,stdio:["ignore","pipe","pipe"],windowsVerbatimArguments:o,windowsHide:!0});t.child=s,s.stdout?.on("data",u=>{const r=p(t.stdoutDecoder,u);this.onOutput(t,"stdout",r)}),s.stderr?.on("data",u=>{const r=p(t.stderrDecoder,u);this.onOutput(t,"stderr",r)}),s.on("error",u=>{this.onOutput(t,"stderr",`[ACode] child error: ${u.message}
3
- `),t.finalized||this.finalizeTask(t,-1,null,"child_error")}),s.on("close",(u,r)=>{const l=p(t.stdoutDecoder,void 0,!0),a=p(t.stderrDecoder,void 0,!0);if(l&&this.onOutput(t,"stdout",l),a&&this.onOutput(t,"stderr",a),t.ringBuffer.flush(),!t.finalized){const c=t.killedReason??null;this.finalizeTask(t,u,r,c??void 0)}}),t.timeoutTimer=setTimeout(()=>{t.finalized||(t.killedReason="timeout",this.killProcessGroup(s))},t.timeoutMs),t.timeoutTimer.unref?.()}onOutput(t,i,e){if(!e)return;if(t.outputBytes>=B){if(!t.outputTruncated){t.outputTruncated=!0;const o=`
1
+ import{spawn as L}from"node:child_process";import{promises as T}from"node:fs";import{createInterface as _}from"node:readline";import{randomBytes as g}from"node:crypto";import{prepareShellCommand as E,shellExecutable as I}from"./builtins/shellCommandPreparation.js";import{createShellOutputDecoder as y,decodeShellOutputChunk as p}from"./builtins/shellOutputDecoder.js";import{BackgroundOutputRingBuffer as O}from"./background-output-ringbuffer.js";import{BackgroundCommandStore as x}from"./background-command-store.js";const R=1e3,A=10*60*1e3,w=50*1024*1024,B=16,C=256,D=256*1024,S=500,F=5e3,z=256,v=5*60*1e3,M=1024*1024;class G{constructor(){this.tasksByAgent=new Map,this.store=new x}globalCount(){let t=0;for(const i of this.tasksByAgent.values())t+=i.size;return t}startCommand(t){const i=t.agentId,e=this.getOrCreateBucket(i);if(e.size>=B)throw new b("too_many_tasks",`Agent ${i} has ${e.size} background tasks (limit ${B}). Kill or wait for completion first.`);if(this.globalCount()>=C)throw new b("global_limit_reached",`Global background task limit ${C} reached.`);const n=this.generateTaskId(e),s=Math.min(t.timeoutMs??A,A),o=typeof t.inactivityTimeoutMs=="number"&&Number.isFinite(t.inactivityTimeoutMs)&&t.inactivityTimeoutMs>0?t.inactivityTimeoutMs:0,r=this.store.outputPathFor(i,n),u=t.commandText.length>80?`${t.commandText.slice(0,77)}...`:t.commandText,a={taskId:n,agentId:i,command:t.commandText,commandPreview:u,cwd:t.cwd,status:"running",startedAt:Date.now(),finishedAt:null,exitCode:null,signal:null,killedReason:null,timeoutMs:s,inactivityTimeoutMs:o,child:null,ringBuffer:new O,outputPath:r,outputWriteChain:Promise.resolve(),outputTruncated:!1,outputLineCount:0,outputBytes:0,notified:!1,completionWaiters:[],onCompleted:t.onCompleted,onOutput:t.onOutput,outputSeq:0,outputSubscribers:new Set,timeoutTimer:null,killEscalationTimer:null,retentionTimer:null,inactivityTimer:null,inactivityTimedOut:!1,finalized:!1,stdoutDecoder:y(),stderrDecoder:y(),stdoutText:"",stderrText:"",commandLineCount:0},l=new Promise(c=>{a.completionResolve=c});return e.set(n,a),this.spawnAndAttach(a,t).catch(c=>{a.ringBuffer.push(`[ACode] spawn failed: ${c?.message??String(c)}
2
+ `),this.finalizeTask(a,-1,null,"spawn_error")}),this.persistTask(a),{taskId:n,completion:l}}async spawnAndAttach(t,i){const e=I(),n=await E(i.commandText,i.workspaceRoot,e),s=process.platform==="win32",o=L(e.command,[...e.argsPrefix,n.commandText],{cwd:i.cwd,env:process.env,detached:!s,stdio:["ignore","pipe","pipe"],windowsVerbatimArguments:s,windowsHide:!0});t.child=o,t.commandFilePath=n.commandFilePath,t.commandLineCount=n.commandLineCount,t.inactivityTimeoutMs>0&&this.scheduleInactivity(t),o.stdout?.on("data",r=>{const u=p(t.stdoutDecoder,r);this.onOutput(t,"stdout",u)}),o.stderr?.on("data",r=>{const u=p(t.stderrDecoder,r);this.onOutput(t,"stderr",u)}),o.on("error",r=>{this.onOutput(t,"stderr",`[ACode] child error: ${r.message}
3
+ `),t.finalized||this.finalizeTask(t,-1,null,"child_error")}),o.on("close",(r,u)=>{const a=p(t.stdoutDecoder,void 0,!0),l=p(t.stderrDecoder,void 0,!0);if(a&&this.onOutput(t,"stdout",a),l&&this.onOutput(t,"stderr",l),t.ringBuffer.flush(),!t.finalized){const c=t.killedReason??null;this.finalizeTask(t,r,u,c??void 0)}}),t.timeoutTimer=setTimeout(()=>{t.finalized||(t.killedReason="timeout",this.killProcessGroup(o))},t.timeoutMs),t.timeoutTimer.unref?.()}disableInactivityTimeout(t,i){const e=this.getTask(t,i);return e?(e.inactivityTimeoutMs=0,e.inactivityTimer&&(clearTimeout(e.inactivityTimer),e.inactivityTimer=null),!0):!1}onOutput(t,i,e){if(!e)return;t.outputSeq++;const n=t.outputSeq;if(t.outputSubscribers.size>0)for(const r of t.outputSubscribers)try{r.onLine({stream:i,text:e,seq:n})}catch{}const s=i==="stdout"?"stdoutText":"stderrText";if(Buffer.byteLength(t[s],"utf-8")<M){const r=M-Buffer.byteLength(t[s],"utf-8");t[s]+=r>0?e.slice(0,r):""}if(t.inactivityTimeoutMs>0&&this.scheduleInactivity(t),t.outputBytes>=w){if(!t.outputTruncated){t.outputTruncated=!0;const r=`
4
4
  [ACode] output truncated at 50MB
5
- `;t.ringBuffer.push(o),this.appendToFile(t,o)}t.ringBuffer.push(e);return}t.ringBuffer.push(e),t.onOutput?.({stream:i,text:e});const n=(e.match(/\n/g)??[]).length;t.outputLineCount+=n,t.outputBytes+=Buffer.byteLength(e,"utf-8"),this.appendToFile(t,e)}appendToFile(t,i){return t.outputBytes>B?Promise.resolve():(t.outputWriteChain=t.outputWriteChain.then(()=>g.appendFile(t.outputPath,i,"utf-8")).catch(e=>{t.ringBuffer.push(`[ACode] output write failed: ${e?.message??e}
6
- `)}),t.outputWriteChain)}finalizeTask(t,i,e,n){if(t.finalized)return;t.finalized=!0,t.timeoutTimer&&(clearTimeout(t.timeoutTimer),t.timeoutTimer=null),t.killEscalationTimer&&(clearTimeout(t.killEscalationTimer),t.killEscalationTimer=null),t.child=null,t.finishedAt=Date.now();let o;n?(o="killed",t.killedReason=n):i===0?o="completed":o="failed",t.status=o,t.exitCode=i,t.signal=e;const s=t.ringBuffer.tail(1e3),u={taskId:t.taskId,exitCode:i,signal:e,timedOut:n==="timeout",stdout:s.join(`
7
- `),stderr:"",durationMs:t.finishedAt-t.startedAt};t.completionResolve?.(u);const r={taskId:t.taskId,status:o,exitCode:i,signal:e,timedOut:n==="timeout",aborted:!1,durationMs:t.finishedAt-t.startedAt},l=t.completionWaiters;t.completionWaiters=[];for(const a of l)a(r);this.persistTask(t),t.onCompleted?.({taskId:t.taskId,agentId:t.agentId,status:o,exitCode:i,signal:e,commandPreview:t.commandPreview,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,outputPath:t.outputPath,finishedAt:t.finishedAt,killedReason:t.killedReason}),t.retentionTimer=setTimeout(()=>{this.evictTask(t.agentId,t.taskId)},k),t.retentionTimer.unref?.()}evictTask(t,i){const e=this.tasksByAgent.get(t);if(!e)return;const n=e.get(i);n&&(g.unlink(n.outputPath).catch(()=>{}),e.delete(i),e.size===0&&this.tasksByAgent.delete(t))}listTasks(t,i){const e=this.tasksByAgent.get(t);if(!e)return[];const n=[];for(const o of e.values())i&&i!=="all"&&o.status!==i||n.push(this.toSummary(o));return n.sort((o,s)=>s.startedAt-o.startedAt)}toSummary(t){return{taskId:t.taskId,status:t.status,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes}}async readOutput(t,i){const e=String(i.task_id??""),n=this.getTask(t,e),o=i.mode??"tail",s=Math.min(Math.max(1,i.lines??50),_);if(!n)return{taskId:e,status:"killed",mode:o,lines:[],lineCount:0,metadata:{totalLines:0,totalBytes:0,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:""}};let u=[],r=!1;if(o==="head")u=n.ringBuffer.head(s);else if(o==="tail")u=n.ringBuffer.tail(s);else if(o==="offset"){const d=Math.max(0,i.offset??0),f=n.ringBuffer.offset(d,s);if(f.length>0||n.ringBuffer.hasLine(d))u=f;else{const h=await this.readFromFile(n,"offset",d,s,void 0);u=h.lines,r=h.hasMore}}else if(o==="grep"){const d=String(i.pattern??"");if(d.length>D)return{taskId:e,status:n.status,mode:o,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}};let f;try{f=new RegExp(d,"i")}catch{return{taskId:e,status:n.status,mode:o,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}}}const h=await this.readFromFile(n,"grep",0,s,f);u=h.lines,r=h.hasMore}let l=0;const a=[];let c=!1;for(const d of u){if(a.length>=_){c=!0,r=!0;break}const f=Buffer.byteLength(d,"utf-8")+1;if(l+f>x){c=!0,r=!0;break}a.push(d),l+=f}const m=i.include_metadata!==!1;return{taskId:e,status:n.status,mode:o,lines:a,lineCount:a.length,metadata:m?{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:l,truncated:c,hasMore:r,outputFile:n.outputPath}:void 0}}async readFromFile(t,i,e,n,o){const s=[];let u=!1,r=0,l=0;try{const a=await g.open(t.outputPath,"r"),c=P({input:a.createReadStream({encoding:"utf-8"}),crlfDelay:1/0});for await(const m of c){if(i==="grep"&&s.length>=v){u=!0;break}if(i==="offset"){if(r<e){r++;continue}if(l>=n){u=!0;break}s.push(m),l++,r++}else{if(o.test(m)){if(l>=n){u=!0;break}s.push(m),l++}r++}}c.close(),await a.close()}catch{return{lines:[],hasMore:!1}}return{lines:s,hasMore:u}}async awaitCompletion(t,i,e){return Promise.all(i.map(n=>this.awaitOne(t,n,e)))}async awaitOne(t,i,e){const n=this.getTask(t,i);if(n)return n.status!=="running"?this.taskToAwaitResult(n):new Promise(u=>{let r=null;const l=a=>{r&&clearTimeout(r),u(a)};n.completionWaiters.push(l),e&&e>0&&(r=setTimeout(()=>{n.completionWaiters=n.completionWaiters.filter(a=>a!==l),u({taskId:i,status:"running",exitCode:null,signal:null,timedOut:!0,aborted:!1,durationMs:Date.now()-n.startedAt})},e),r.unref?.())});const s=(await this.store.readSession(t))?.tasks.find(u=>u.taskId===i);return s?s.status!=="running"?{taskId:i,status:s.status,exitCode:s.exitCode,signal:s.signal,timedOut:s.killedReason==="timeout",aborted:!1,durationMs:(s.finishedAt??Date.now())-s.startedAt}:{taskId:i,status:"killed",exitCode:null,signal:null,timedOut:!1,aborted:!1,durationMs:(s.finishedAt??Date.now())-s.startedAt}:null}taskToAwaitResult(t){return{taskId:t.taskId,status:t.status,exitCode:t.exitCode,signal:t.signal,timedOut:t.killedReason==="timeout",aborted:!1,durationMs:(t.finishedAt??Date.now())-t.startedAt}}interruptAwaits(t,i){const e=this.tasksByAgent.get(t);if(e)for(const n of i){const o=e.get(n);if(!o)continue;const s=o.completionWaiters;if(s.length===0)continue;o.completionWaiters=[];const u={taskId:n,status:"running",exitCode:null,signal:null,timedOut:!1,aborted:!0,durationMs:Date.now()-o.startedAt};for(const r of s)r(u)}}async killTask(t,i){const e=this.getTask(t,i);return e?e.status!=="running"?{taskId:i,status:e.status,exitCode:e.exitCode??void 0}:e.child?(e.killedReason="user_kill",this.killProcessGroup(e.child)?(e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.killEscalationTimer=setTimeout(()=>{e.child&&!e.finalized&&this.killProcessGroup(e.child,!0)},b),e.killEscalationTimer.unref?.(),{taskId:i,status:"killed",signal:"SIGTERM"}):{taskId:i,status:e.status,error:"kill_failed",reason:"permission_denied"}):{taskId:i,status:e.status,error:"kill_failed",reason:"no_child"}:{taskId:i,status:"killed",error:"task_not_found"}}killProcessGroup(t,i=!1){const e=t.pid;if(!e)return!1;try{if(process.platform==="win32"){const n="/F",{spawnSync:o}=require("node:child_process");return o("taskkill",["/PID",String(e),"/T",n],{windowsHide:!0}),!0}try{process.kill(-e,i?"SIGKILL":"SIGTERM")}catch{process.kill(e,i?"SIGKILL":"SIGTERM")}return!0}catch{return!1}}async disposeAgent(t){const i=this.tasksByAgent.get(t);if(i){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="session_disposed",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}await this.store.deleteAgent(t)}async disposeAll(){for(const[t,i]of this.tasksByAgent){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="process_exit",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}}async reconcileOrphans(t){const i=await this.store.readSession(t);if(!i||i.tasks.length===0)return;let e=!1;for(const n of i.tasks)n.status==="running"&&(n.status="killed",n.killedReason="runtime_crashed",n.finishedAt=Date.now(),n.notified=!0,e=!0);e&&await this.store.persistSession(t,i.tasks)}async readSessionState(t){return this.store.readSession(t)}async markNotified(t,i){await this.store.markNotified(t,i)}getOrCreateBucket(t){let i=this.tasksByAgent.get(t);return i||(i=new Map,this.tasksByAgent.set(t,i)),i}getTask(t,i){const e=this.tasksByAgent.get(t);if(e&&/^[A-Za-z0-9]{8}$/.test(i))return e.get(i)}generateTaskId(t){for(let i=0;i<3;i++){const e=T(4).toString("hex").slice(0,8);if(!t.has(e))return e}return T(6).toString("hex").slice(0,8)}async persistTask(t){const i=await this.store.readSession(t.agentId)??{agentId:t.agentId,updatedAt:0,tasks:[]},e={taskId:t.taskId,agentId:t.agentId,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,status:t.status,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputPath:t.outputPath,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,notified:t.notified,killedReason:t.killedReason},n=i.tasks.findIndex(s=>s.taskId===t.taskId);n>=0?i.tasks[n]=e:i.tasks.push(e);const o=Date.now();i.tasks=i.tasks.filter(s=>s.status==="running"||!s.finishedAt||o-s.finishedAt<k),await this.store.persistSession(t.agentId,i.tasks)}}class M extends Error{constructor(t,i){super(i),this.name="BackgroundTaskError",this.code=t}}const Y=new z;export{z as BackgroundCommandManager,M as BackgroundTaskError,Y as backgroundCommandManager};
5
+ `;t.ringBuffer.push(r),this.appendToFile(t,r)}t.ringBuffer.push(e);return}t.ringBuffer.push(e),t.onOutput?.({stream:i,text:e});const o=(e.match(/\n/g)??[]).length;t.outputLineCount+=o,t.outputBytes+=Buffer.byteLength(e,"utf-8"),this.appendToFile(t,e)}scheduleInactivity(t){t.finalized||t.inactivityTimeoutMs<=0||(t.inactivityTimer&&clearTimeout(t.inactivityTimer),t.inactivityTimer=setTimeout(()=>{t.finalized||!t.child||(t.inactivityTimedOut=!0,t.killedReason="inactivity",this.killProcessGroup(t.child))},t.inactivityTimeoutMs),t.inactivityTimer.unref?.())}appendToFile(t,i){return t.outputBytes>w?Promise.resolve():(t.outputWriteChain=t.outputWriteChain.then(()=>T.appendFile(t.outputPath,i,"utf-8")).catch(e=>{t.ringBuffer.push(`[ACode] output write failed: ${e?.message??e}
6
+ `)}),t.outputWriteChain)}finalizeTask(t,i,e,n){if(t.finalized)return;t.finalized=!0,t.timeoutTimer&&(clearTimeout(t.timeoutTimer),t.timeoutTimer=null),t.killEscalationTimer&&(clearTimeout(t.killEscalationTimer),t.killEscalationTimer=null),t.inactivityTimer&&(clearTimeout(t.inactivityTimer),t.inactivityTimer=null),t.child=null,t.finishedAt=Date.now();let s;n?(s="killed",t.killedReason=n):i===0?s="completed":s="failed",t.status=s,t.exitCode=i,t.signal=e;const o=n==="inactivity"||t.inactivityTimedOut,r={taskId:t.taskId,exitCode:i,signal:e,timedOut:n==="timeout"||o,inactivityTimedOut:o,outputFilePath:t.outputPath,outputLineCount:t.outputLineCount,outputSpilled:t.outputTruncated,commandFilePath:t.commandFilePath,commandLineCount:t.commandLineCount,timeoutMs:t.timeoutMs,inactivityTimeoutMs:t.inactivityTimeoutMs,stdout:t.stdoutText,stderr:t.stderrText,durationMs:t.finishedAt-t.startedAt};t.completionResolve?.(r);const u={taskId:t.taskId,status:s,exitCode:i,signal:e,timedOut:n==="timeout"||o,aborted:!1,durationMs:t.finishedAt-t.startedAt},a=t.completionWaiters;t.completionWaiters=[];for(const l of a)l(u);if(this.persistTask(t),t.onCompleted?.({taskId:t.taskId,agentId:t.agentId,status:s,exitCode:i,signal:e,commandPreview:t.commandPreview,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,outputPath:t.outputPath,finishedAt:t.finishedAt,killedReason:t.killedReason}),t.outputSubscribers.size>0){const l=Array.from(t.outputSubscribers);t.outputSubscribers.clear();for(const c of l)try{c.onDone({status:s,exitCode:i,signal:e})}catch{}}t.retentionTimer=setTimeout(()=>{this.evictTask(t.agentId,t.taskId)},v),t.retentionTimer.unref?.()}evictTask(t,i){const e=this.tasksByAgent.get(t);if(!e)return;const n=e.get(i);n&&(T.unlink(n.outputPath).catch(()=>{}),e.delete(i),e.size===0&&this.tasksByAgent.delete(t))}listTasks(t,i){const e=this.tasksByAgent.get(t);if(!e)return[];const n=[];for(const s of e.values())i&&i!=="all"&&s.status!==i||n.push(this.toSummary(s));return n.sort((s,o)=>o.startedAt-s.startedAt)}toSummary(t){return{taskId:t.taskId,status:t.status,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes}}getTaskOutputSnapshot(t,i,e=500){const n=this.getTask(t,i);if(!n)return null;const s=n.ringBuffer.tail(e);return{taskId:n.taskId,status:n.status,exitCode:n.exitCode,signal:n.signal,startedAt:n.startedAt,finishedAt:n.finishedAt,command:n.command,lines:s,nextSeq:n.outputSeq+1,totalLines:n.outputLineCount,totalBytes:n.outputBytes,truncated:n.outputTruncated}}subscribeTaskOutput(t,i,e){const n=this.getTask(t,i);if(!n)return null;n.outputSubscribers.add(e);let s=!0;return()=>{s&&(s=!1,n.outputSubscribers.delete(e))}}async readOutput(t,i){const e=String(i.task_id??""),n=this.getTask(t,e),s=i.mode??"tail",o=Math.min(Math.max(1,i.lines??50),S);if(!n)return{taskId:e,status:"killed",mode:s,lines:[],lineCount:0,metadata:{totalLines:0,totalBytes:0,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:""}};let r=[],u=!1;if(s==="head")r=n.ringBuffer.head(o);else if(s==="tail")r=n.ringBuffer.tail(o);else if(s==="offset"){const d=Math.max(0,i.offset??0),f=n.ringBuffer.offset(d,o);if(f.length>0||n.ringBuffer.hasLine(d))r=f;else{const h=await this.readFromFile(n,"offset",d,o,void 0);r=h.lines,u=h.hasMore}}else if(s==="grep"){const d=String(i.pattern??"");if(d.length>z)return{taskId:e,status:n.status,mode:s,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}};let f;try{f=new RegExp(d,"i")}catch{return{taskId:e,status:n.status,mode:s,lines:[],lineCount:0,metadata:{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:0,truncated:!1,hasMore:!1,outputFile:n.outputPath}}}const h=await this.readFromFile(n,"grep",0,o,f);r=h.lines,u=h.hasMore}let a=0;const l=[];let c=!1;for(const d of r){if(l.length>=S){c=!0,u=!0;break}const f=Buffer.byteLength(d,"utf-8")+1;if(a+f>D){c=!0,u=!0;break}l.push(d),a+=f}const m=i.include_metadata!==!1;return{taskId:e,status:n.status,mode:s,lines:l,lineCount:l.length,metadata:m?{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:a,truncated:c,hasMore:u,outputFile:n.outputPath}:void 0}}async readFromFile(t,i,e,n,s){const o=[];let r=!1,u=0,a=0;try{const l=await T.open(t.outputPath,"r"),c=_({input:l.createReadStream({encoding:"utf-8"}),crlfDelay:1/0});for await(const m of c){if(i==="grep"&&o.length>=F){r=!0;break}if(i==="offset"){if(u<e){u++;continue}if(a>=n){r=!0;break}o.push(m),a++,u++}else{if(s.test(m)){if(a>=n){r=!0;break}o.push(m),a++}u++}}c.close(),await l.close()}catch{return{lines:[],hasMore:!1}}return{lines:o,hasMore:r}}async awaitCompletion(t,i,e){return Promise.all(i.map(n=>this.awaitOne(t,n,e)))}async awaitOne(t,i,e){const n=this.getTask(t,i);if(n)return n.status!=="running"?this.taskToAwaitResult(n):new Promise(r=>{let u=null;const a=l=>{u&&clearTimeout(u),r(l)};n.completionWaiters.push(a),e&&e>0&&(u=setTimeout(()=>{n.completionWaiters=n.completionWaiters.filter(l=>l!==a),r({taskId:i,status:"running",exitCode:null,signal:null,timedOut:!0,aborted:!1,durationMs:Date.now()-n.startedAt})},e),u.unref?.())});const o=(await this.store.readSession(t))?.tasks.find(r=>r.taskId===i);return o?o.status!=="running"?{taskId:i,status:o.status,exitCode:o.exitCode,signal:o.signal,timedOut:o.killedReason==="timeout",aborted:!1,durationMs:(o.finishedAt??Date.now())-o.startedAt,...o.outputPath?{outputFilePath:o.outputPath}:{}}:{taskId:i,status:"killed",exitCode:null,signal:null,timedOut:!1,aborted:!1,durationMs:(o.finishedAt??Date.now())-o.startedAt}:null}taskToAwaitResult(t){return{taskId:t.taskId,status:t.status,exitCode:t.exitCode,signal:t.signal,timedOut:t.killedReason==="timeout",aborted:!1,durationMs:(t.finishedAt??Date.now())-t.startedAt,...t.status!=="running"&&t.outputPath?{outputFilePath:t.outputPath}:{}}}interruptAwaits(t,i){const e=this.tasksByAgent.get(t);if(e)for(const n of i){const s=e.get(n);if(!s)continue;const o=s.completionWaiters;if(o.length===0)continue;s.completionWaiters=[];const r={taskId:n,status:"running",exitCode:null,signal:null,timedOut:!1,aborted:!0,durationMs:Date.now()-s.startedAt};for(const u of o)u(r)}}async killTask(t,i){const e=this.getTask(t,i);return e?e.status!=="running"?{taskId:i,status:e.status,exitCode:e.exitCode??void 0}:e.child?(e.killedReason="user_kill",this.killProcessGroup(e.child)?(e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.killEscalationTimer=setTimeout(()=>{e.child&&!e.finalized&&this.killProcessGroup(e.child,!0)},R),e.killEscalationTimer.unref?.(),{taskId:i,status:"killed",signal:"SIGTERM"}):{taskId:i,status:e.status,error:"kill_failed",reason:"permission_denied"}):{taskId:i,status:e.status,error:"kill_failed",reason:"no_child"}:{taskId:i,status:"killed",error:"task_not_found"}}killProcessGroup(t,i=!1){const e=t.pid;if(!e)return!1;try{if(process.platform==="win32"){const n="/F",{spawnSync:s}=require("node:child_process");return s("taskkill",["/PID",String(e),"/T",n],{windowsHide:!0}),!0}try{process.kill(-e,i?"SIGKILL":"SIGTERM")}catch{process.kill(e,i?"SIGKILL":"SIGTERM")}return!0}catch{return!1}}async disposeAgent(t){const i=this.tasksByAgent.get(t);if(i){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="session_disposed",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}await this.store.deleteAgent(t)}async disposeAll(){for(const[t,i]of this.tasksByAgent){for(const e of i.values())e.status==="running"&&e.child&&(e.killedReason="process_exit",this.killProcessGroup(e.child,!0)),e.timeoutTimer&&clearTimeout(e.timeoutTimer),e.killEscalationTimer&&clearTimeout(e.killEscalationTimer),e.retentionTimer&&clearTimeout(e.retentionTimer);this.tasksByAgent.delete(t)}}async reconcileOrphans(t){const i=await this.store.readSession(t);if(!i||i.tasks.length===0)return;let e=!1;for(const n of i.tasks)n.status==="running"&&(n.status="killed",n.killedReason="runtime_crashed",n.finishedAt=Date.now(),n.notified=!0,e=!0);e&&await this.store.persistSession(t,i.tasks)}async readSessionState(t){return this.store.readSession(t)}async markNotified(t,i){await this.store.markNotified(t,i)}getOrCreateBucket(t){let i=this.tasksByAgent.get(t);return i||(i=new Map,this.tasksByAgent.set(t,i)),i}getTask(t,i){const e=this.tasksByAgent.get(t);if(e&&/^[A-Za-z0-9]{8}$/.test(i))return e.get(i)}generateTaskId(t){for(let i=0;i<3;i++){const e=g(4).toString("hex").slice(0,8);if(!t.has(e))return e}return g(6).toString("hex").slice(0,8)}async persistTask(t){const i=await this.store.readSession(t.agentId)??{agentId:t.agentId,updatedAt:0,tasks:[]},e={taskId:t.taskId,agentId:t.agentId,command:t.command,commandPreview:t.commandPreview,cwd:t.cwd,status:t.status,startedAt:t.startedAt,finishedAt:t.finishedAt,exitCode:t.exitCode,signal:t.signal,outputPath:t.outputPath,outputLineCount:t.outputLineCount,outputBytes:t.outputBytes,notified:t.notified,killedReason:t.killedReason},n=i.tasks.findIndex(o=>o.taskId===t.taskId);n>=0?i.tasks[n]=e:i.tasks.push(e);const s=Date.now();i.tasks=i.tasks.filter(o=>o.status==="running"||!o.finishedAt||s-o.finishedAt<v),await this.store.persistSession(t.agentId,i.tasks)}}class b extends Error{constructor(t,i){super(i),this.name="BackgroundTaskError",this.code=t}}const U=new G;export{G as BackgroundCommandManager,b as BackgroundTaskError,U as backgroundCommandManager};
8
7
 
@@ -13,6 +13,6 @@ Query modes:
13
13
  - offset: from line X (0-based) take N lines (reads output file, bypasses memory cap)
14
14
  - grep: filter lines by regex (JS syntax, case-insensitive)
15
15
 
16
- Output capped at 256KB / 500 lines per call; truncated=true means more is available.`;function u(a,o){return{kind:"builtin",toolName:"ListBackgroundCommands",exposedName:"ListBackgroundCommands",description:s,inputSchema:{type:"object",properties:{status_filter:{type:"string",enum:["running","completed","failed","killed","all"],description:"Filter by status. Defaults to 'all'.",default:"all"}},additionalProperties:!1},async execute(t){const e=typeof t.status_filter=="string"?t.status_filter:"all",i=o.manager.listTasks(a,e);return{title:`${i.length} background commands`,output:JSON.stringify(i.map(n=>({taskId:n.taskId,status:n.status,command:n.commandPreview,cwd:n.cwd,startedAt:new Date(n.startedAt).toISOString(),finishedAt:n.finishedAt?new Date(n.finishedAt).toISOString():null,exitCode:n.exitCode,outputLineCount:n.outputLineCount,outputBytes:n.outputBytes})),null,2),metadata:{tasks:i,count:i.length}}}}}function l(a,o){return{kind:"builtin",toolName:"KillBackgroundCommand",exposedName:"KillBackgroundCommand",description:d,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id returned by Bash(wait_seconds=...) or ListBackgroundCommands."}},required:["task_id"],additionalProperties:!1},async execute(t){const e=typeof t.task_id=="string"?t.task_id:"",i=await o.manager.killTask(a,e);return{title:`kill ${e}: ${i.status}`,output:JSON.stringify(i,null,2),metadata:i}}}}function p(a,o){return{kind:"builtin",toolName:"ReadBackgroundOutput",exposedName:"ReadBackgroundOutput",description:r,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id to read output from."},mode:{type:"string",enum:["head","tail","offset","grep"],description:"head=first N, tail=last N (default), offset=from line X take N, grep=regex filter.",default:"tail"},lines:{type:"integer",description:"Number of lines (head/tail/offset). Default 50, max 500.",default:50,minimum:1,maximum:500},offset:{type:"integer",description:"Starting line number (0-based) for offset mode.",minimum:0},pattern:{type:"string",description:"Regex pattern for grep mode (JS syntax, case-insensitive)."},include_metadata:{type:"boolean",description:"Include totalLines/totalBytes/truncated/hasMore/outputFile in response.",default:!0}},required:["task_id"],additionalProperties:!1},async execute(t){const e=await o.manager.readOutput(a,{task_id:typeof t.task_id=="string"?t.task_id:"",mode:t.mode==="head"||t.mode==="tail"||t.mode==="offset"||t.mode==="grep"?t.mode:"tail",lines:typeof t.lines=="number"?t.lines:50,offset:typeof t.offset=="number"?t.offset:0,pattern:typeof t.pattern=="string"?t.pattern:void 0,include_metadata:t.include_metadata!==!1});return{title:`read ${e.taskId} (${e.mode}): ${e.lineCount} lines`,output:e.lines.join(`
16
+ Output capped at 256KB / 500 lines per call; truncated=true means more is available.`;function u(a,o){return{kind:"builtin",toolName:"list_background_commands",exposedName:"list_background_commands",description:s,inputSchema:{type:"object",properties:{status_filter:{type:"string",enum:["running","completed","failed","killed","all"],description:"Filter by status. Defaults to 'all'.",default:"all"}},additionalProperties:!1},async execute(t){const e=typeof t.status_filter=="string"?t.status_filter:"all",i=o.manager.listTasks(a,e);return{title:`${i.length} background commands`,output:JSON.stringify(i.map(n=>({taskId:n.taskId,status:n.status,command:n.commandPreview,cwd:n.cwd,startedAt:new Date(n.startedAt).toISOString(),finishedAt:n.finishedAt?new Date(n.finishedAt).toISOString():null,exitCode:n.exitCode,outputLineCount:n.outputLineCount,outputBytes:n.outputBytes})),null,2),metadata:{tasks:i,count:i.length}}}}}function l(a,o){return{kind:"builtin",toolName:"kill_background_command",exposedName:"kill_background_command",description:d,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id returned by Bash(wait_seconds=...) or list_background_commands."}},required:["task_id"],additionalProperties:!1},async execute(t){const e=typeof t.task_id=="string"?t.task_id:"",i=await o.manager.killTask(a,e);return{title:`kill ${e}: ${i.status}`,output:JSON.stringify(i,null,2),metadata:i}}}}function p(a,o){return{kind:"builtin",toolName:"read_background_output",exposedName:"read_background_output",description:r,inputSchema:{type:"object",properties:{task_id:{type:"string",description:"The task_id to read output from."},mode:{type:"string",enum:["head","tail","offset","grep"],description:"head=first N, tail=last N (default), offset=from line X take N, grep=regex filter.",default:"tail"},lines:{type:"integer",description:"Number of lines (head/tail/offset). Default 50, max 500.",default:50,minimum:1,maximum:500},offset:{type:"integer",description:"Starting line number (0-based) for offset mode.",minimum:0},pattern:{type:"string",description:"Regex pattern for grep mode (JS syntax, case-insensitive)."},include_metadata:{type:"boolean",description:"Include totalLines/totalBytes/truncated/hasMore/outputFile in response.",default:!0}},required:["task_id"],additionalProperties:!1},async execute(t){const e=await o.manager.readOutput(a,{task_id:typeof t.task_id=="string"?t.task_id:"",mode:t.mode==="head"||t.mode==="tail"||t.mode==="offset"||t.mode==="grep"?t.mode:"tail",lines:typeof t.lines=="number"?t.lines:50,offset:typeof t.offset=="number"?t.offset:0,pattern:typeof t.pattern=="string"?t.pattern:void 0,include_metadata:t.include_metadata!==!1});return{title:`read ${e.taskId} (${e.mode}): ${e.lineCount} lines`,output:e.lines.join(`
17
17
  `),metadata:e}}}}export{l as createKillBackgroundCommandTool,u as createListBackgroundCommandsTool,p as createReadBackgroundOutputTool};
18
18
 
@@ -1,4 +1,4 @@
1
- import{randomUUID as K}from"node:crypto";import{promises as u,createReadStream as N}from"node:fs";import H from"node:os";import d from"node:path";import U from"node:readline";import{runShellCommand as V}from"./builtins/shellCommandRunner.js";import{symbolsTool as Z}from"./built-in-symbols-tool.js";import{createListBackgroundCommandsTool as J,createKillBackgroundCommandTool as Q,createReadBackgroundOutputTool as tt}from"./background-command-tools.js";const et=2e3,M=2e3,ot=50*1024,D=4096,nt=.3,it=new Set([".png",".jpg",".jpeg",".gif",".bmp",".ico",".webp",".tiff",".tif",".zip",".gz",".tar",".rar",".7z",".bz2",".xz",".lz",".exe",".dll",".so",".dylib",".bin",".o",".a",".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".mp3",".mp4",".avi",".mov",".wav",".flv",".mkv",".ogg",".woff",".woff2",".ttf",".otf",".eot",".class",".jar",".war",".ear",".pyc",".pyo",".node",".sqlite",".db",".mdb",".wasm"]),rt=1e3,at=1024*1024,st=256*1024,ct=1e3,lt=new Set([".git","node_modules","dist","build",".next",".nuxt",".cache",".turbo",".output","coverage",".nyc_output"]);function b(n){return n.replace(/\\/g,"/")}async function W(n){try{return await u.access(n),!0}catch{return!1}}function ut(n,o){if(!o)return 0;let t=0,e=n.indexOf(o);for(;e>=0;)t+=1,e=n.indexOf(o,e+o.length);return t}function P(n,o,t){for(const e of o){const r=n[e];if(typeof r=="string")return r}throw new Error(`${t} is required`)}function E(n,o){for(const t of o){const e=n[t];if(typeof e=="string"&&e.trim())return e}}function C(n,o,t){for(const e of o){const r=n[e],i=typeof r=="number"?r:typeof r=="string"?Number(r):NaN;if(Number.isFinite(i)&&i>0)return Math.floor(i)}return t}async function j(n){const o=d.extname(n).toLowerCase();if(it.has(o))return!0;const t=await u.open(n,"r");try{const e=Buffer.alloc(D),{bytesRead:r}=await t.read(e,0,D,0);if(r===0)return!1;const i=e.subarray(0,r);if(i.includes(0))return!0;let c=0;for(let a=0;a<r;a++){const l=i[a];(l<9||l>13&&l<32)&&c++}return c/r>nt}finally{await t.close()}}function S(n,o){const t=d.resolve(o),e=d.relative(n,t);if(e.startsWith("..")||d.isAbsolute(e))throw new Error(`Target path is outside workspace: ${t}`);return t}function q(n){return n==="~"||n.startsWith("~/")?d.join(H.homedir(),n.slice(1)):n}async function dt(n,o){const t=d.resolve(String(n||"").trim()),e=await u.realpath(t);if(!(await u.stat(e)).isDirectory())throw new Error(`Workspace path is not a directory: ${t}`);if(!o?.trim())return{workspaceRoot:e,cwd:e};const i=q(o.trim()),c=d.isAbsolute(i)?d.resolve(i):d.resolve(t,i),a=d.relative(t,c);if(a.startsWith("..")||d.isAbsolute(a))throw new Error(`Command cwd is outside workspace: ${c}`);const l=S(e,await u.realpath(c));if(!(await u.stat(l)).isDirectory())throw new Error(`Command cwd is not a directory: ${l}`);return{workspaceRoot:e,cwd:l}}async function pt(n,o){const t=await u.realpath(d.dirname(o));S(n,t);try{if((await u.lstat(o)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${o}`)}catch(e){if((typeof e=="object"&&e!==null?Reflect.get(e,"code"):void 0)!=="ENOENT")throw e}}async function O(n,o){const t=d.resolve(String(n||"").trim()),e=await u.realpath(t);if(!(await u.stat(e)).isDirectory())throw new Error(`Workspace path is not a directory: ${t}`);const i=q(o.trim());if(!i)throw new Error("file_path is required");const c=d.isAbsolute(i)?d.resolve(i):d.resolve(t,i),a=d.relative(t,c);if(a.startsWith("..")||d.isAbsolute(a))throw new Error(`Target path is outside workspace: ${c}`);return{workspaceRoot:e,requestedPath:c,targetPath:S(e,d.join(e,a))}}async function G(n,o,t){const e=await O(n,o),r=d.dirname(e.targetPath),i=!await W(r);await u.mkdir(r,{recursive:!0}),await pt(e.workspaceRoot,e.targetPath);const c=d.join(r,`.${d.basename(e.targetPath)}.${process.pid}.${K()}.tmp`);try{await u.writeFile(c,t,"utf-8"),await u.rename(c,e.targetPath)}catch(a){throw await u.rm(c,{force:!0}),a}return{workspaceRoot:e.workspaceRoot,targetPath:e.targetPath,bytes:Buffer.byteLength(t,"utf-8"),createdParentDirectory:i}}async function ft(n,o){const t=await O(n,o),e=S(t.workspaceRoot,await u.realpath(t.targetPath));if(!(await u.stat(e)).isFile())throw new Error(`Path is not a file: ${e}`);return{workspaceRoot:t.workspaceRoot,targetPath:e,content:await u.readFile(e,"utf-8")}}async function mt(n,o,t,e){const r=await O(n,o),i=S(r.workspaceRoot,await u.realpath(r.targetPath));if(!(await u.stat(i)).isFile())throw new Error(`Path is not a file: ${i}`);if(await j(i))return{workspaceRoot:r.workspaceRoot,targetPath:i,content:"[Binary file, content skipped]",isBinary:!0,truncated:!1,totalLines:0,shownFromLine:0,shownToLine:0};const a=N(i,{encoding:"utf-8"}),l=U.createInterface({input:a,crlfDelay:1/0});try{const s=[];let m=0,f=0,g=0,w=!1,p=!1;const _=t-1;for await(const L of l){if(f++,m<_){m++;continue}if(s.length>=e){w=!0,m++;continue}let T=L;T.length>M&&(T=T.slice(0,M)+`... (line truncated to ${M} chars)`);const v=`${m+1}: ${T}`,R=Buffer.byteLength(v,"utf-8")+1;if(g+R>ot){p=!0;break}s.push(v),g+=R,m++}if(f>0&&s.length===0&&!w&&!p&&_>=f)throw new Error(`offset ${t} exceeds total line count ${f} in file: ${i}`);const h=s.length>0?t:0,y=s.length>0?t+s.length-1:0;let x;p?x=`Output capped at 50 KB. Showing lines ${h}-${y}. Use offset=${y+1} to continue.`:w?x=`Showing lines ${h}-${y} of ${f}. Use offset=${y+1} to continue.`:x=`End of file - total ${f} lines`;const B=s.length>0?s.join(`
1
+ import{randomUUID as H}from"node:crypto";import{promises as d,createReadStream as N}from"node:fs";import K from"node:os";import p from"node:path";import U from"node:readline";import{runShellCommand as V}from"./builtins/shellCommandRunner.js";import{createOutputEventCollector as Z}from"./builtins/commandOutputEvents.js";import{symbolsTool as J}from"./built-in-symbols-tool.js";import{createListBackgroundCommandsTool as Q,createKillBackgroundCommandTool as tt,createReadBackgroundOutputTool as et}from"./background-command-tools.js";const ot=2e3,F=2e3,nt=50*1024,D=4096,it=.3,at=new Set([".png",".jpg",".jpeg",".gif",".bmp",".ico",".webp",".tiff",".tif",".zip",".gz",".tar",".rar",".7z",".bz2",".xz",".lz",".exe",".dll",".so",".dylib",".bin",".o",".a",".pdf",".doc",".docx",".xls",".xlsx",".ppt",".pptx",".mp3",".mp4",".avi",".mov",".wav",".flv",".mkv",".ogg",".woff",".woff2",".ttf",".otf",".eot",".class",".jar",".war",".ear",".pyc",".pyo",".node",".sqlite",".db",".mdb",".wasm"]),rt=1e3,st=1024*1024,ct=256*1024,lt=1e3,ut=new Set([".git","node_modules","dist","build",".next",".nuxt",".cache",".turbo",".output","coverage",".nyc_output"]);function v(n){return n.replace(/\\/g,"/")}async function W(n){try{return await d.access(n),!0}catch{return!1}}function dt(n,o){if(!o)return 0;let e=0,t=n.indexOf(o);for(;t>=0;)e+=1,t=n.indexOf(o,t+o.length);return e}function T(n,o,e){for(const t of o){const a=n[t];if(typeof a=="string")return a}throw new Error(`${e} is required`)}function O(n,o){for(const e of o){const t=n[e];if(typeof t=="string"&&t.trim())return t}}function I(n,o,e){for(const t of o){const a=n[t],i=typeof a=="number"?a:typeof a=="string"?Number(a):NaN;if(Number.isFinite(i)&&i>0)return Math.floor(i)}return e}async function j(n){const o=p.extname(n).toLowerCase();if(at.has(o))return!0;const e=await d.open(n,"r");try{const t=Buffer.alloc(D),{bytesRead:a}=await e.read(t,0,D,0);if(a===0)return!1;const i=t.subarray(0,a);if(i.includes(0))return!0;let c=0;for(let r=0;r<a;r++){const s=i[r];(s<9||s>13&&s<32)&&c++}return c/a>it}finally{await e.close()}}function M(n,o){const e=p.resolve(o),t=p.relative(n,e);if(t.startsWith("..")||p.isAbsolute(t))throw new Error(`Target path is outside workspace: ${e}`);return e}function q(n){return n==="~"||n.startsWith("~/")?p.join(K.homedir(),n.slice(1)):n}async function pt(n,o){const e=p.resolve(String(n||"").trim()),t=await d.realpath(e);if(!(await d.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);if(!o?.trim())return{workspaceRoot:t,cwd:t};const i=q(o.trim()),c=p.isAbsolute(i)?p.resolve(i):p.resolve(e,i),r=p.relative(e,c);if(r.startsWith("..")||p.isAbsolute(r))throw new Error(`Command cwd is outside workspace: ${c}`);const s=M(t,await d.realpath(c));if(!(await d.stat(s)).isDirectory())throw new Error(`Command cwd is not a directory: ${s}`);return{workspaceRoot:t,cwd:s}}async function mt(n,o){const e=await d.realpath(p.dirname(o));M(n,e);try{if((await d.lstat(o)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${o}`)}catch(t){if((typeof t=="object"&&t!==null?Reflect.get(t,"code"):void 0)!=="ENOENT")throw t}}async function C(n,o){const e=p.resolve(String(n||"").trim()),t=await d.realpath(e);if(!(await d.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);const i=q(o.trim());if(!i)throw new Error("file_path is required");const c=p.isAbsolute(i)?p.resolve(i):p.resolve(e,i),r=p.relative(e,c);if(r.startsWith("..")||p.isAbsolute(r))throw new Error(`Target path is outside workspace: ${c}`);return{workspaceRoot:t,requestedPath:c,targetPath:M(t,p.join(t,r))}}async function G(n,o,e){const t=await C(n,o),a=p.dirname(t.targetPath),i=!await W(a);await d.mkdir(a,{recursive:!0}),await mt(t.workspaceRoot,t.targetPath);const c=p.join(a,`.${p.basename(t.targetPath)}.${process.pid}.${H()}.tmp`);try{await d.writeFile(c,e,"utf-8"),await d.rename(c,t.targetPath)}catch(r){throw await d.rm(c,{force:!0}),r}return{workspaceRoot:t.workspaceRoot,targetPath:t.targetPath,bytes:Buffer.byteLength(e,"utf-8"),createdParentDirectory:i}}async function ft(n,o){const e=await C(n,o),t=M(e.workspaceRoot,await d.realpath(e.targetPath));if(!(await d.stat(t)).isFile())throw new Error(`Path is not a file: ${t}`);return{workspaceRoot:e.workspaceRoot,targetPath:t,content:await d.readFile(t,"utf-8")}}async function ht(n,o,e,t){const a=await C(n,o),i=M(a.workspaceRoot,await d.realpath(a.targetPath));if(!(await d.stat(i)).isFile())throw new Error(`Path is not a file: ${i}`);if(await j(i))return{workspaceRoot:a.workspaceRoot,targetPath:i,content:"[Binary file, content skipped]",isBinary:!0,truncated:!1,totalLines:0,shownFromLine:0,shownToLine:0};const r=N(i,{encoding:"utf-8"}),s=U.createInterface({input:r,crlfDelay:1/0});try{const l=[];let h=0,m=0,b=0,y=!1,u=!1;const f=e-1;for await(const k of s){if(m++,h<f){h++;continue}if(l.length>=t){y=!0,h++;continue}let w=k;w.length>F&&(w=w.slice(0,F)+`... (line truncated to ${F} chars)`);const R=`${h+1}: ${w}`,S=Buffer.byteLength(R,"utf-8")+1;if(b+S>nt){u=!0;break}l.push(R),b+=S,h++}if(m>0&&l.length===0&&!y&&!u&&f>=m)throw new Error(`offset ${e} exceeds total line count ${m} in file: ${i}`);const _=l.length>0?e:0,g=l.length>0?e+l.length-1:0;let P;u?P=`Output capped at 50 KB. Showing lines ${_}-${g}. Use offset=${g+1} to continue.`:y?P=`Showing lines ${_}-${g} of ${m}. Use offset=${g+1} to continue.`:P=`End of file - total ${m} lines`;const E=l.length>0?l.join(`
2
2
  `)+`
3
- `+x:x;return{workspaceRoot:r.workspaceRoot,targetPath:i,content:B,isBinary:!1,truncated:w||p,totalLines:p?-1:f,shownFromLine:h,shownToLine:y}}finally{l.close(),a.destroy()}}function X(n){let o="",t=0;for(;t<n.length;){const e=n[t];if(e==="*")o+="[^/]*";else if(e==="?")o+="[^/]";else if(e==="{"){const r=n.indexOf("}",t);if(r>=0){const i=n.slice(t+1,r);o+=`(${i.split(",").join("|")})`,t=r}else o+="\\{"}else if(e==="["){const r=n.indexOf("]",t);r>=0?(o+=n.slice(t,r+1),t=r):o+="\\["}else"+^$.()|\\".includes(e)?o+="\\"+e:o+=e;t++}return new RegExp(`^${o}$`)}async function ht(n,o,t,e){const r=[];async function i(c){if(r.length>=e)return;const a=await u.readdir(c,{withFileTypes:!0});for(const l of a){if(r.length>=e)return;if(l.name.startsWith(".")&&l.isDirectory())continue;const s=d.join(c,l.name);if(l.isDirectory()){if(lt.has(l.name))continue;await i(s)}else if(l.isFile()){if(o&&!o.test(l.name)||t&&t.test(l.name))continue;r.push(s)}}}return await i(n),r}async function wt(n,o,t){if((await u.stat(n)).size>at)return{matches:[],count:0};if(await j(n))return{matches:[],count:0};const r=d.relative(o,n).replace(/\\/g,"/"),i=[];let c=0;const a=N(n,{encoding:"utf-8"}),l=U.createInterface({input:a,crlfDelay:1/0});try{let s=0;for await(const m of l)if(s++,t.regex.test(m)){if(c++,t.collectContent){let f=m;if(f.length>M&&(f=f.slice(0,M)+`... (line truncated to ${M} chars)`),i.push({file:r,line:s,content:f}),i.length>=t.maxResults)break}if(t.stopOnFirstMatch)break}}finally{l.close(),a.destroy()}return{matches:i,count:c}}const z=10*6e4,gt=z,_t=6e4,yt=10*6e4;function kt(n,o){return{kind:"builtin",toolName:"write_file",exposedName:"write_file",description:"Create or overwrite a UTF-8 text file inside the current workspace. Parent directories are created automatically.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to write."},content:{type:"string",description:"Complete UTF-8 file content."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path","content"],additionalProperties:!1},async execute(t){const e=P(t,["file_path","filePath"],"file_path"),r=P(t,["content"],"content"),i=E(t,["reason"]),c=await O(n,e),a=await W(c.targetPath),l=a?await u.readFile(c.targetPath,"utf-8").catch(()=>null):null,s=await G(n,e,r);if(o){const m=d.relative(s.workspaceRoot,s.targetPath).replace(/\\/g,"/");await o({filePath:m,operation:a?"UPDATE":"CREATE",beforeContent:l,afterContent:r,reason:i})}return{ok:!0,tool:"write_file",workspacePath:b(s.workspaceRoot),filePath:b(s.targetPath),bytes:s.bytes,createdParentDirectory:s.createdParentDirectory}}}}function bt(n,o){return{kind:"builtin",toolName:"edit_file",exposedName:"edit_file",description:"Replace exactly one occurrence of old_string with new_string in a UTF-8 workspace text file.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to edit."},old_string:{type:"string",description:"Existing text to replace. Must occur exactly once."},new_string:{type:"string",description:"Replacement text."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path","old_string","new_string"],additionalProperties:!1},async execute(t){const e=P(t,["file_path","filePath"],"file_path"),r=P(t,["old_string","oldString"],"old_string"),i=P(t,["new_string","newString"],"new_string"),c=E(t,["reason"]);if(!r)throw new Error("old_string must not be empty");const a=await ft(n,e),l=ut(a.content,r);if(l===0)throw new Error("old_string was not found in file");if(l>1)throw new Error(`old_string occurs ${l} times; provide a unique match`);const s=a.content.replace(r,i),m=await G(n,e,s);if(o){const f=d.relative(m.workspaceRoot,m.targetPath).replace(/\\/g,"/");await o({filePath:f,operation:"UPDATE",beforeContent:a.content,afterContent:s,reason:c})}return{ok:!0,tool:"edit_file",workspacePath:b(m.workspaceRoot),filePath:b(m.targetPath),replacements:1,bytes:m.bytes}}}}function Pt(n,o){return{kind:"builtin",toolName:"delete_file",exposedName:"delete_file",description:"Delete a file inside the current workspace. Returns an error if the file does not exist.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to delete."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path"],additionalProperties:!1},async execute(t){const e=P(t,["file_path","filePath"],"file_path"),r=E(t,["reason"]),i=await O(n,e),c=S(i.workspaceRoot,await u.realpath(i.targetPath).catch(()=>i.targetPath)),a=await u.stat(c).catch(()=>null);if(!a)throw new Error(`File does not exist: ${c}`);if(!a.isFile())throw new Error(`Path is not a file: ${c}`);const l=await u.readFile(c,"utf-8").catch(()=>null);if(await u.rm(c,{force:!0}),o){const s=d.relative(i.workspaceRoot,c).replace(/\\/g,"/");await o({filePath:s,operation:"DELETE",beforeContent:l,afterContent:null,reason:r})}return{ok:!0,tool:"delete_file",workspacePath:b(i.workspaceRoot),filePath:b(c),deleted:!0}}}}function xt(n){return{kind:"builtin",toolName:"read_file",exposedName:"read_file",description:"Read a UTF-8 text file inside the current workspace. Returns content with line numbers in the format '<line>: <content>'. Supports offset (1-indexed line number to start from) and limit (max lines to return, default 2000). Output is capped at 2000 lines or 50 KB, whichever is reached first. Individual lines longer than 2000 characters are truncated. Avoid tiny repeated slices (e.g. 30-line chunks); read a larger window if more context is needed.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to read."},offset:{type:"number",description:"Line number to start reading from (1-indexed). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to return. Defaults to 2000."}},required:["file_path"],additionalProperties:!1},async execute(o){const t=P(o,["file_path","filePath"],"file_path"),e=C(o,["offset"],1),r=C(o,["limit"],et),i=await mt(n,t,e,r);return{ok:!0,tool:"read_file",workspacePath:b(i.workspaceRoot),filePath:b(i.targetPath),content:i.content,isBinary:i.isBinary,truncated:i.truncated,totalLines:i.totalLines,shownFromLine:i.shownFromLine,shownToLine:i.shownToLine}}}}function vt(n,o,t){return{kind:"builtin",toolName:"Bash",exposedName:"Bash",description:"Execute a shell command in the current workspace. Use for local diagnostics, builds, tests, and OS commands. The command runs with a bounded timeout and returns stdout, stderr, and exit code. Set wait_seconds to 0 or n>0 to move long-running commands to the background and return a task_id immediately (or after n seconds); then use ListBackgroundCommands / ReadBackgroundOutput / KillBackgroundCommand to manage them.",inputSchema:{type:"object",properties:{command:{type:"string",description:"Shell command to execute."},cwd:{type:"string",description:"Optional workspace-relative working directory. Defaults to the workspace root."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds. Defaults to 600000 and is capped at 600000."},inactivity_timeout_ms:{type:"number",description:"Optional no-output timeout in milliseconds. Defaults to 60000 and is capped at 600000. Only applies to foreground (wait_seconds=-1); ignored once a command moves to background."},wait_seconds:{type:"number",description:"How long to block waiting for the command to finish. -1 (default): block until completion (current behavior, capped at timeout_ms). 0: spawn and immediately move to background, return task_id. n>0: wait up to n seconds; if still running, move to background and return task_id. Background commands remain subject to timeout_ms (total upper bound); inactivity_timeout_ms is ignored once backgrounded.",default:-1,minimum:-1},description:{type:"string",description:"Optional short reason for running the command."}},required:["command"],additionalProperties:!1},async execute(e,r){const i=P(e,["command"],"command").trim();if(!i)throw new Error("command must not be empty");const c=C(e,["timeout_ms","timeoutMs"],gt),a=Math.min(c,z),l=C(e,["inactivity_timeout_ms","inactivityTimeoutMs"],_t),s=Math.min(l,yt),m=E(e,["cwd"]),f=await dt(n,m),g=e.wait_seconds,w=typeof g=="number"&&Number.isFinite(g)?g:-1;if(w!==-1&&t)return await Tt({deps:t,command:i,agentId:o,workspaceRoot:f.workspaceRoot,cwd:f.cwd,timeoutMs:a,waitSeconds:w,settleSignal:r?.settleSignal});const p=await V({commandText:i,agentId:o,workspaceRoot:f.workspaceRoot,cwd:f.cwd,timeoutMs:a,inactivityTimeoutMs:s,onOutput:r?.onOutput});return{ok:p.exitCode===0&&!p.timedOut,tool:"Bash",command:i,cwd:b(f.cwd),exitCode:p.exitCode,signal:p.signal,timedOut:p.timedOut,inactivityTimedOut:p.inactivityTimedOut,timeoutMs:a,inactivityTimeoutMs:s,durationMs:p.durationMs,outputSpilled:p.outputSpilled,outputFilePath:p.outputFilePath,outputLineCount:p.outputLineCount,commandFilePath:p.commandFilePath,commandLineCount:p.commandLineCount,stdout:p.stdout,stderr:p.stderr}}}}async function Tt(n){const{deps:o,command:t,agentId:e,workspaceRoot:r,cwd:i,timeoutMs:c,waitSeconds:a,settleSignal:l}=n;try{const{taskId:s,completion:m}=o.manager.startCommand({commandText:t,agentId:e,workspaceRoot:r,cwd:i,timeoutMs:c,onCompleted:o.emitCompleted});if(a===0)return{ok:!0,tool:"Bash",command:t,backgrounded:!0,taskId:s,status:"backgrounded",reason:"immediate",message:`Command moved to background. Use ListBackgroundCommands to view, ReadBackgroundOutput(task_id="${s}", mode="tail") to read output, KillBackgroundCommand(task_id="${s}") to stop.`};const f=Math.max(0,Math.floor(a*1e3));let g;const w=new Promise(_=>{g=setTimeout(()=>_("__timeout__"),f),g.unref?.()}),p=l?l.then(()=>"__settle__"):Promise.resolve("__never__");try{const _=await Promise.race([m,w,p]);if(_==="__settle__")return{ok:!0,tool:"Bash",command:t,backgrounded:!0,taskId:s,status:"backgrounded",reason:"watchdog_timeout",waitedMs:f,message:`Command still running after watchdog timeout; moved to background. Use ListBackgroundCommands / ReadBackgroundOutput(task_id="${s}", mode="tail") to inspect.`};if(_==="__timeout__")return{ok:!0,tool:"Bash",command:t,backgrounded:!0,taskId:s,status:"backgrounded",reason:"timeout",waitedMs:f,message:`Command still running after ${a}s; moved to background. Use ListBackgroundCommands / ReadBackgroundOutput(task_id="${s}", mode="tail") to inspect.`};const h=_;return{ok:h.exitCode===0&&!h.timedOut,tool:"Bash",command:t,backgrounded:!1,taskId:s,exitCode:h.exitCode,signal:h.signal,timedOut:h.timedOut,durationMs:h.durationMs,stdout:h.stdout,stderr:h.stderr}}finally{g&&clearTimeout(g)}}catch(s){if(s?.code==="too_many_tasks"||s?.code==="global_limit_reached")return{ok:!1,tool:"Bash",command:t,backgrounded:!1,error:s.code,message:s.message};throw s}}function Rt(n){return{kind:"builtin",toolName:"grep",exposedName:"grep",description:"Search file contents using regular expressions within the workspace. Returns matched lines with file paths and line numbers. Supports include/exclude glob patterns, case-insensitive matching, and three output modes (content, files_with_matches, count). Searches recursively through directories, skipping binary files, hidden directories, and common build/dependency directories (node_modules, .git, dist, etc.).",inputSchema:{type:"object",properties:{pattern:{type:"string",description:"Regular expression pattern to search for in file contents."},path:{type:"string",description:"Workspace-relative file or directory path to search in. Defaults to the workspace root."},include:{type:"string",description:"Glob pattern to filter files by name (e.g. '*.ts', '*.{js,ts}'). Only matching files are searched."},exclude:{type:"string",description:"Glob pattern to exclude files by name (e.g. '*.test.ts'). Matching files are skipped."},case_insensitive:{type:"boolean",description:"Case-insensitive matching. Default false."},output_mode:{type:"string",enum:["content","files_with_matches","count"],description:"Output format: 'content' returns matched lines with line numbers (default), 'files_with_matches' returns only file paths with matches, 'count' returns match counts per file."},max_results:{type:"number",description:"Maximum number of matched lines to return (content mode). Default 1000."}},required:["pattern"],additionalProperties:!1},async execute(o){const t=P(o,["pattern"],"pattern"),e=E(o,["path"])||".",r=E(o,["include"]),i=E(o,["exclude"]),c=o.case_insensitive===!0,a=(()=>{const k=o.output_mode;return k==="files_with_matches"||k==="count"?k:"content"})(),l=C(o,["max_results"],ct),s=c?"i":"";let m;try{m=new RegExp(t,s)}catch(k){throw new Error(`Invalid regex pattern: ${k instanceof Error?k.message:String(k)}`)}const f=r?X(r):null,g=i?X(i):null,w=await O(n,e),p=S(w.workspaceRoot,await u.realpath(w.targetPath)),_=await u.stat(p);let h;if(_.isFile())h=[p];else if(_.isDirectory())h=await ht(p,f,g,rt);else throw new Error(`Path is neither a file nor a directory: ${p}`);const y=[],x=[],B=[];let L=0,T=0,v=!1;for(const k of h){if(a==="content"&&y.length>=l){v=!0;break}const Y={regex:m,maxResults:a==="content"?l-y.length:Number.MAX_SAFE_INTEGER,collectContent:a==="content",stopOnFirstMatch:a==="files_with_matches"},A=await wt(k,w.workspaceRoot,Y);if(A.count>0){const I=d.relative(w.workspaceRoot,k).replace(/\\/g,"/");if(B.push(I),L+=A.count,a==="content"){for(const $ of A.matches){const F=Buffer.byteLength($.content,"utf-8")+64;if(T+F>st){v=!0;break}T+=F,y.push($)}if(v)break;if(y.length>=l){v=!0;break}}else a==="count"&&x.push({file:I,count:A.count})}}const R={ok:!0,tool:"grep",pattern:t,searchPath:b(w.targetPath),outputMode:a,filesSearched:h.length,filesMatched:B.length,totalMatches:L,truncated:v};return a==="content"?R.matches=y:a==="files_with_matches"?R.matches=B:R.matches=x,R}}}function It(n,o,t,e){const r=o||"unknown",i=[xt(n),kt(n,t),bt(n,t),Pt(n,t),Rt(n),vt(n,r,e),Z(n)];return e&&i.push(J(r,e),Q(r,e),tt(r,e)),i}export{It as createBuiltInFileTools,S as ensureInsideWorkspace,O as resolveWorkspaceTarget};
3
+ `+P:P;return{workspaceRoot:a.workspaceRoot,targetPath:i,content:E,isBinary:!1,truncated:y||u,totalLines:u?-1:m,shownFromLine:_,shownToLine:g}}finally{s.close(),r.destroy()}}function X(n){let o="",e=0;for(;e<n.length;){const t=n[e];if(t==="*")o+="[^/]*";else if(t==="?")o+="[^/]";else if(t==="{"){const a=n.indexOf("}",e);if(a>=0){const i=n.slice(e+1,a);o+=`(${i.split(",").join("|")})`,e=a}else o+="\\{"}else if(t==="["){const a=n.indexOf("]",e);a>=0?(o+=n.slice(e,a+1),e=a):o+="\\["}else"+^$.()|\\".includes(t)?o+="\\"+t:o+=t;e++}return new RegExp(`^${o}$`)}async function wt(n,o,e,t){const a=[];async function i(c){if(a.length>=t)return;const r=await d.readdir(c,{withFileTypes:!0});for(const s of r){if(a.length>=t)return;if(s.name.startsWith(".")&&s.isDirectory())continue;const l=p.join(c,s.name);if(s.isDirectory()){if(ut.has(s.name))continue;await i(l)}else if(s.isFile()){if(o&&!o.test(s.name)||e&&e.test(s.name))continue;a.push(l)}}}return await i(n),a}async function gt(n,o,e){if((await d.stat(n)).size>st)return{matches:[],count:0};if(await j(n))return{matches:[],count:0};const a=p.relative(o,n).replace(/\\/g,"/"),i=[];let c=0;const r=N(n,{encoding:"utf-8"}),s=U.createInterface({input:r,crlfDelay:1/0});try{let l=0;for await(const h of s)if(l++,e.regex.test(h)){if(c++,e.collectContent){let m=h;if(m.length>F&&(m=m.slice(0,F)+`... (line truncated to ${F} chars)`),i.push({file:a,line:l,content:m}),i.length>=e.maxResults)break}if(e.stopOnFirstMatch)break}}finally{s.close(),r.destroy()}return{matches:i,count:c}}const z=10*6e4,_t=z,yt=6e4,bt=10*6e4;function kt(n,o){return{kind:"builtin",toolName:"write_file",exposedName:"write_file",description:"Create or overwrite a UTF-8 text file inside the current workspace. Parent directories are created automatically.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to write."},content:{type:"string",description:"Complete UTF-8 file content."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path","content"],additionalProperties:!1},async execute(e){const t=T(e,["file_path","filePath"],"file_path"),a=T(e,["content"],"content"),i=O(e,["reason"]),c=await C(n,t),r=await W(c.targetPath),s=r?await d.readFile(c.targetPath,"utf-8").catch(()=>null):null,l=await G(n,t,a);if(o){const h=p.relative(l.workspaceRoot,l.targetPath).replace(/\\/g,"/");await o({filePath:h,operation:r?"UPDATE":"CREATE",beforeContent:s,afterContent:a,reason:i})}return{ok:!0,tool:"write_file",workspacePath:v(l.workspaceRoot),filePath:v(l.targetPath),bytes:l.bytes,createdParentDirectory:l.createdParentDirectory}}}}function Pt(n,o){return{kind:"builtin",toolName:"edit_file",exposedName:"edit_file",description:"Replace exactly one occurrence of old_string with new_string in a UTF-8 workspace text file.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to edit."},old_string:{type:"string",description:"Existing text to replace. Must occur exactly once."},new_string:{type:"string",description:"Replacement text."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path","old_string","new_string"],additionalProperties:!1},async execute(e){const t=T(e,["file_path","filePath"],"file_path"),a=T(e,["old_string","oldString"],"old_string"),i=T(e,["new_string","newString"],"new_string"),c=O(e,["reason"]);if(!a)throw new Error("old_string must not be empty");const r=await ft(n,t),s=dt(r.content,a);if(s===0)throw new Error("old_string was not found in file");if(s>1)throw new Error(`old_string occurs ${s} times; provide a unique match`);const l=r.content.replace(a,i),h=await G(n,t,l);if(o){const m=p.relative(h.workspaceRoot,h.targetPath).replace(/\\/g,"/");await o({filePath:m,operation:"UPDATE",beforeContent:r.content,afterContent:l,reason:c})}return{ok:!0,tool:"edit_file",workspacePath:v(h.workspaceRoot),filePath:v(h.targetPath),replacements:1,bytes:h.bytes}}}}function xt(n,o){return{kind:"builtin",toolName:"delete_file",exposedName:"delete_file",description:"Delete a file inside the current workspace. Returns an error if the file does not exist.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to delete."},reason:{type:"string",description:"Optional reason for this change, e.g. what bug is being fixed. Helps humans understand the change later."}},required:["file_path"],additionalProperties:!1},async execute(e){const t=T(e,["file_path","filePath"],"file_path"),a=O(e,["reason"]),i=await C(n,t),c=M(i.workspaceRoot,await d.realpath(i.targetPath).catch(()=>i.targetPath)),r=await d.stat(c).catch(()=>null);if(!r)throw new Error(`File does not exist: ${c}`);if(!r.isFile())throw new Error(`Path is not a file: ${c}`);const s=await d.readFile(c,"utf-8").catch(()=>null);if(await d.rm(c,{force:!0}),o){const l=p.relative(i.workspaceRoot,c).replace(/\\/g,"/");await o({filePath:l,operation:"DELETE",beforeContent:s,afterContent:null,reason:a})}return{ok:!0,tool:"delete_file",workspacePath:v(i.workspaceRoot),filePath:v(c),deleted:!0}}}}function vt(n){return{kind:"builtin",toolName:"read_file",exposedName:"read_file",description:"Read a UTF-8 text file inside the current workspace. Returns content with line numbers in the format '<line>: <content>'. Supports offset (1-indexed line number to start from) and limit (max lines to return, default 2000). Output is capped at 2000 lines or 50 KB, whichever is reached first. Individual lines longer than 2000 characters are truncated. Avoid tiny repeated slices (e.g. 30-line chunks); read a larger window if more context is needed.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to read."},offset:{type:"number",description:"Line number to start reading from (1-indexed). Defaults to 1."},limit:{type:"number",description:"Maximum number of lines to return. Defaults to 2000."}},required:["file_path"],additionalProperties:!1},async execute(o){const e=T(o,["file_path","filePath"],"file_path"),t=I(o,["offset"],1),a=I(o,["limit"],ot),i=await ht(n,e,t,a);return{ok:!0,tool:"read_file",workspacePath:v(i.workspaceRoot),filePath:v(i.targetPath),content:i.content,isBinary:i.isBinary,truncated:i.truncated,totalLines:i.totalLines,shownFromLine:i.shownFromLine,shownToLine:i.shownToLine}}}}function Tt(n,o,e){return{kind:"builtin",toolName:"Bash",exposedName:"Bash",description:"Execute a shell command in the current workspace. Use for local diagnostics, builds, tests, and OS commands. The command runs with a bounded timeout and returns stdout, stderr, exit code, and (if interrupted) partial output. By default (wait_seconds omitted or -1) the command runs in the FOREGROUND and streams output in real time; if the 5-minute adapter watchdog fires while it is still running, the command is interrupted and the partial output produced so far is returned (large output is spilled to a file via outputFilePath to avoid context overflow), with watchdogInterrupted=true. For long-running commands use wait_seconds=0 or n>0 to run in the BACKGROUND, then manage them via list_background_commands / read_background_output / kill_background_command / await_complete.",inputSchema:{type:"object",properties:{command:{type:"string",description:"Shell command to execute."},cwd:{type:"string",description:"Optional workspace-relative working directory. Defaults to the workspace root."},timeout_ms:{type:"number",description:"Optional timeout in milliseconds. Defaults to 600000 and is capped at 600000."},inactivity_timeout_ms:{type:"number",description:"Optional no-output timeout in milliseconds. Defaults to 60000 and is capped at 600000."},wait_seconds:{type:"number",description:"How to wait for the command to finish. Omitted values (or -1, the default): run in the FOREGROUND until completion; if the 5-minute adapter watchdog fires first, the command is interrupted and only the partial output already produced is returned (watchdogInterrupted=true; large output spills to outputFilePath). 0: spawn and immediately execute in the background, return task_id. n>0: wait up to n seconds; if still running, move to the background and return task_id. Background commands remain subject to timeout_ms (total upper bound); inactivity_timeout_ms is ignored once backgrounded.",minimum:-1},description:{type:"string",description:"Optional short reason for running the command."}},required:["command"],additionalProperties:!1},async execute(t,a){const i=T(t,["command"],"command").trim();if(!i)throw new Error("command must not be empty");const c=I(t,["timeout_ms","timeoutMs"],_t),r=Math.min(c,z),s=I(t,["inactivity_timeout_ms","inactivityTimeoutMs"],yt),l=Math.min(s,bt),h=O(t,["cwd"]),m=await pt(n,h),b=t.wait_seconds,u=typeof b=="number"&&Number.isFinite(b)?b:-1;if(u!==-1&&e)return await Rt({deps:e,command:i,agentId:o,workspaceRoot:m.workspaceRoot,cwd:m.cwd,timeoutMs:r,inactivityTimeoutMs:l,waitSeconds:u,onOutput:a?.onOutput,settleSignal:a?.settleSignal});const f=await V({commandText:i,agentId:o,workspaceRoot:m.workspaceRoot,cwd:m.cwd,timeoutMs:r,inactivityTimeoutMs:l,onOutput:a?.onOutput,watchdogSignal:a?.settleSignal}),_={ok:f.exitCode===0&&!f.timedOut,tool:"Bash",command:i,cwd:v(m.cwd),exitCode:f.exitCode,signal:f.signal,timedOut:f.timedOut,inactivityTimedOut:f.inactivityTimedOut,watchdogInterrupted:f.watchdogInterrupted,timeoutMs:r,inactivityTimeoutMs:l,durationMs:f.durationMs,outputSpilled:f.outputSpilled,outputFilePath:f.outputFilePath,outputLineCount:f.outputLineCount,commandFilePath:f.commandFilePath,commandLineCount:f.commandLineCount,stdout:f.stdout,stderr:f.stderr};return f.watchdogInterrupted?{..._,message:"Command was interrupted by the adapter watchdog after ~5 minutes of synchronous (foreground) execution. Only the partial output produced so far is returned above"+(f.outputFilePath?` (full output spilled to "${f.outputFilePath}"; read it if you need more)`:"")+". For long-running commands, re-run with wait_seconds=0 (or n>0) to execute in the background, then manage via await_complete / list_background_commands / read_background_output / kill_background_command."}:_}}}async function Rt(n){const{deps:o,command:e,agentId:t,workspaceRoot:a,cwd:i,timeoutMs:c,inactivityTimeoutMs:r,waitSeconds:s,onOutput:l,settleSignal:h}=n,m=l?Z({cwd:i,commandLineCount:0,onOutput:l}):void 0;let b=!!m;const y=()=>{b&&(b=!1,m?.close())};try{const{taskId:u,completion:f}=o.manager.startCommand({commandText:e,agentId:t,workspaceRoot:a,cwd:i,timeoutMs:c,inactivityTimeoutMs:r,onOutput:b?k=>{b&&m?.push(k.stream,k.text)}:void 0,onCompleted:o.emitCompleted});if(s===0)return o.manager.disableInactivityTimeout(t,u),y(),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:u,status:"backgrounded",reason:"immediate",message:`Command moved to background. Use await_complete(bg_cmd_ids=["${u}"]) to block until it finishes, read_background_output(task_id="${u}", mode="tail") to read output, list_background_commands to view all, or kill_background_command(task_id="${u}") to stop.`};const _=s===-1?0:Math.max(0,Math.floor(s*1e3));let g,P;s===-1?P=Promise.resolve("__never__"):P=new Promise(k=>{g=setTimeout(()=>k("__timeout__"),_),g.unref?.()});const E=h?h.then(()=>"__settle__"):Promise.resolve("__never__");try{const k=await Promise.race([f,P,E]);if(k==="__settle__")return o.manager.disableInactivityTimeout(t,u),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:u,status:"backgrounded",reason:"watchdog_timeout",waitedMs:_,message:`Command still running after watchdog timeout; moved to background. Use await_complete(bg_cmd_ids=["${u}"]) to block until it finishes, read_background_output(task_id="${u}", mode="tail") to read output, or kill_background_command(task_id="${u}") to stop.`};if(k==="__timeout__")return o.manager.disableInactivityTimeout(t,u),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:u,status:"backgrounded",reason:"timeout",waitedMs:_,message:`Command still running after ${s}s; moved to background. Use await_complete(bg_cmd_ids=["${u}"]) to block until it finishes, or read_background_output(task_id="${u}", mode="tail") / kill_background_command(task_id="${u}") to inspect.`};const w=k;return{ok:w.exitCode===0&&!w.timedOut,tool:"Bash",command:e,backgrounded:!1,taskId:u,exitCode:w.exitCode,signal:w.signal,timedOut:w.timedOut,inactivityTimedOut:w.inactivityTimedOut,timeoutMs:w.timeoutMs,inactivityTimeoutMs:w.inactivityTimeoutMs,durationMs:w.durationMs,outputSpilled:w.outputSpilled,outputFilePath:w.outputFilePath,outputLineCount:w.outputLineCount,commandFilePath:w.commandFilePath,commandLineCount:w.commandLineCount,stdout:w.stdout,stderr:w.stderr}}finally{g&&clearTimeout(g),y()}}catch(u){if(u?.code==="too_many_tasks"||u?.code==="global_limit_reached")return{ok:!1,tool:"Bash",command:e,backgrounded:!1,status:"not_executed",error:u.code,message:`Command was NOT executed: ${u.message}. Wait for some background tasks to finish/cleanup (per-agent limit 16, global 256), or reduce concurrent background commands, then retry.`};throw u}}function Et(n){return{kind:"builtin",toolName:"grep",exposedName:"grep",description:"Search file contents using regular expressions within the workspace. Returns matched lines with file paths and line numbers. Supports include/exclude glob patterns, case-insensitive matching, and three output modes (content, files_with_matches, count). Searches recursively through directories, skipping binary files, hidden directories, and common build/dependency directories (node_modules, .git, dist, etc.).",inputSchema:{type:"object",properties:{pattern:{type:"string",description:"Regular expression pattern to search for in file contents."},path:{type:"string",description:"Workspace-relative file or directory path to search in. Defaults to the workspace root."},include:{type:"string",description:"Glob pattern to filter files by name (e.g. '*.ts', '*.{js,ts}'). Only matching files are searched."},exclude:{type:"string",description:"Glob pattern to exclude files by name (e.g. '*.test.ts'). Matching files are skipped."},case_insensitive:{type:"boolean",description:"Case-insensitive matching. Default false."},output_mode:{type:"string",enum:["content","files_with_matches","count"],description:"Output format: 'content' returns matched lines with line numbers (default), 'files_with_matches' returns only file paths with matches, 'count' returns match counts per file."},max_results:{type:"number",description:"Maximum number of matched lines to return (content mode). Default 1000."}},required:["pattern"],additionalProperties:!1},async execute(o){const e=T(o,["pattern"],"pattern"),t=O(o,["path"])||".",a=O(o,["include"]),i=O(o,["exclude"]),c=o.case_insensitive===!0,r=(()=>{const x=o.output_mode;return x==="files_with_matches"||x==="count"?x:"content"})(),s=I(o,["max_results"],lt),l=c?"i":"";let h;try{h=new RegExp(e,l)}catch(x){throw new Error(`Invalid regex pattern: ${x instanceof Error?x.message:String(x)}`)}const m=a?X(a):null,b=i?X(i):null,y=await C(n,t),u=M(y.workspaceRoot,await d.realpath(y.targetPath)),f=await d.stat(u);let _;if(f.isFile())_=[u];else if(f.isDirectory())_=await wt(u,m,b,rt);else throw new Error(`Path is neither a file nor a directory: ${u}`);const g=[],P=[],E=[];let k=0,w=0,R=!1;for(const x of _){if(r==="content"&&g.length>=s){R=!0;break}const Y={regex:h,maxResults:r==="content"?s-g.length:Number.MAX_SAFE_INTEGER,collectContent:r==="content",stopOnFirstMatch:r==="files_with_matches"},$=await gt(x,y.workspaceRoot,Y);if($.count>0){const L=p.relative(y.workspaceRoot,x).replace(/\\/g,"/");if(E.push(L),k+=$.count,r==="content"){for(const A of $.matches){const B=Buffer.byteLength(A.content,"utf-8")+64;if(w+B>ct){R=!0;break}w+=B,g.push(A)}if(R)break;if(g.length>=s){R=!0;break}}else r==="count"&&P.push({file:L,count:$.count})}}const S={ok:!0,tool:"grep",pattern:e,searchPath:v(y.targetPath),outputMode:r,filesSearched:_.length,filesMatched:E.length,totalMatches:k,truncated:R};return r==="content"?S.matches=g:r==="files_with_matches"?S.matches=E:S.matches=P,S}}}function Bt(n,o,e,t){const a=o||"unknown",i=[vt(n),kt(n,e),Pt(n,e),xt(n,e),Et(n),Tt(n,a,t),J(n)];return t&&i.push(Q(a,t),tt(a,t),et(a,t)),i}export{Bt as createBuiltInFileTools,M as ensureInsideWorkspace,C as resolveWorkspaceTarget};
4
4
 
@@ -7,6 +7,8 @@ export interface ShellCommandResult {
7
7
  readonly durationMs: number;
8
8
  readonly timedOut: boolean;
9
9
  readonly inactivityTimedOut: boolean;
10
+
11
+ readonly watchdogInterrupted?: boolean;
10
12
  readonly outputSpilled: boolean;
11
13
  readonly outputFilePath?: string;
12
14
  readonly outputLineCount: number;
@@ -21,6 +23,7 @@ interface ClosedShellCommandInput {
21
23
  readonly startedAt: Date;
22
24
  readonly timedOut: boolean;
23
25
  readonly inactivityTimedOut: boolean;
26
+ readonly watchdogInterrupted?: boolean;
24
27
  readonly prepared: PreparedShellCommand;
25
28
  readonly agentId: string;
26
29
  readonly workspaceRoot: string;
@@ -1,2 +1,2 @@
1
- import{buildCommandOutputSpilloverContent as i,COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT as r,countOutputLines as l,formatCommandOutputSpilloverStdout as n,toDisplayPath as s,truncateOutput as a,writeCommandArtifactFile as u}from"./commandArtifacts.js";async function c(t,e){return u(t,"cmd","out",e)}function m(t){return{exitCode:t.exitCode,signal:t.signal,stdout:t.stdout,stderr:t.stderr,durationMs:t.endedAt.getTime()-t.startedAt.getTime(),timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,outputSpilled:t.outputSpilled,outputLineCount:t.outputLineCount,...t.outputFilePath?{outputFilePath:t.outputFilePath}:{},...t.commandFilePath?{commandFilePath:t.commandFilePath}:{},commandLineCount:t.commandLineCount}}async function O(t){const e=new Date,d=l(`${t.stdout}${t.stderr}`);if(d>r){const o=await c(t.agentId,i({commandText:t.prepared.originalCommandText,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount,cwd:t.cwd,startedAt:t.startedAt,endedAt:e,exitCode:t.exitCode,signal:t.signal,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,stdout:t.stdout,stderr:t.stderr}));return m({exitCode:t.exitCode,signal:t.signal,stdout:n(o,d),stderr:"",startedAt:t.startedAt,endedAt:e,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,outputSpilled:!0,outputFilePath:s(o),outputLineCount:d,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount})}return m({exitCode:t.exitCode,signal:t.signal,stdout:a(t.stdout).text,stderr:a(t.stderr).text,startedAt:t.startedAt,endedAt:e,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,outputSpilled:!1,outputLineCount:d,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount})}export{O as resolveClosedShellCommand};
1
+ import{buildCommandOutputSpilloverContent as m,COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT as i,countOutputLines as l,formatCommandOutputSpilloverStdout as n,toDisplayPath as c,truncateOutput as a,writeCommandArtifactFile as u}from"./commandArtifacts.js";async function s(t,e){return u(t,"cmd","out",e)}function r(t){return{exitCode:t.exitCode,signal:t.signal,stdout:t.stdout,stderr:t.stderr,durationMs:t.endedAt.getTime()-t.startedAt.getTime(),timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,...t.watchdogInterrupted?{watchdogInterrupted:!0}:{},outputSpilled:t.outputSpilled,outputLineCount:t.outputLineCount,...t.outputFilePath?{outputFilePath:t.outputFilePath}:{},...t.commandFilePath?{commandFilePath:t.commandFilePath}:{},commandLineCount:t.commandLineCount}}async function O(t){const e=new Date,d=l(`${t.stdout}${t.stderr}`);if(d>i){const o=await s(t.agentId,m({commandText:t.prepared.originalCommandText,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount,cwd:t.cwd,startedAt:t.startedAt,endedAt:e,exitCode:t.exitCode,signal:t.signal,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,stdout:t.stdout,stderr:t.stderr}));return r({exitCode:t.exitCode,signal:t.signal,stdout:n(o,d),stderr:"",startedAt:t.startedAt,endedAt:e,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,watchdogInterrupted:t.watchdogInterrupted,outputSpilled:!0,outputFilePath:c(o),outputLineCount:d,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount})}return r({exitCode:t.exitCode,signal:t.signal,stdout:a(t.stdout).text,stderr:a(t.stderr).text,startedAt:t.startedAt,endedAt:e,timedOut:t.timedOut,inactivityTimedOut:t.inactivityTimedOut,watchdogInterrupted:t.watchdogInterrupted,outputSpilled:!1,outputLineCount:d,commandFilePath:t.prepared.commandFilePath,commandLineCount:t.prepared.commandLineCount})}export{O as resolveClosedShellCommand};
2
2
 
@@ -9,6 +9,8 @@ export interface RunShellCommandOptions {
9
9
  readonly timeoutMs: number;
10
10
  readonly inactivityTimeoutMs: number;
11
11
  readonly onOutput?: CommandOutputSink;
12
+
13
+ readonly watchdogSignal?: Promise<unknown>;
12
14
  }
13
15
  export type { ShellCommandResult };
14
16
  export declare function runShellCommand(options: RunShellCommandOptions): Promise<ShellCommandResult>;
@@ -1,2 +1,2 @@
1
- import{spawn as y}from"node:child_process";import{createOutputEventCollector as A}from"./commandOutputEvents.js";import{prepareShellCommand as D,shellExecutable as M}from"./shellCommandPreparation.js";import{resolveClosedShellCommand as R}from"./shellCommandResult.js";import{createShellOutputDecoder as I,decodeShellOutputChunk as d}from"./shellOutputDecoder.js";const g=1e3;async function F(t){const u=M(),c=await D(t.commandText,t.workspaceRoot,u);return new Promise((E,s)=>{const L=new Date,r=y(u.command,[...u.argsPrefix,c.commandText],{cwd:t.cwd,env:process.env,windowsVerbatimArguments:process.platform==="win32",windowsHide:!0}),i=A({cwd:t.cwd,commandLineCount:c.commandLineCount,commandFilePath:c.commandFilePath,onOutput:t.onOutput});let f="",p="",l=!1,T=!1,n,o;const w=I(),h=I(),S=()=>{o&&clearTimeout(o),n&&clearTimeout(n),o=void 0,n=void 0},v=()=>{n||(n=setTimeout(()=>{r.killed||r.kill("SIGKILL")},g),n.unref?.())},a=setTimeout(()=>{l=!0,r.kill("SIGTERM"),v()},t.timeoutMs);a.unref?.();const m=()=>{o&&clearTimeout(o),o=setTimeout(()=>{T=!0,l=!0,r.kill("SIGTERM"),v()},t.inactivityTimeoutMs),o.unref?.()};m();const k=e=>{e&&(f+=e,i.push("stdout",e),m())},C=e=>{e&&(p+=e,i.push("stderr",e),m())};r.stdout?.on("data",e=>{k(d(w,e))}),r.stderr?.on("data",e=>{C(d(h,e))}),r.on("error",e=>{clearTimeout(a),S(),i.close(),s(e)}),r.on("close",(e,O)=>{clearTimeout(a),S(),k(d(w,void 0,!0)),C(d(h,void 0,!0)),i.close(),R({exitCode:e,signal:O,stdout:f,stderr:p,startedAt:L,timedOut:l,inactivityTimedOut:T,prepared:c,agentId:t.agentId,workspaceRoot:t.workspaceRoot,cwd:t.cwd}).then(E,s)})})}export{F as runShellCommand};
1
+ import{spawn as R}from"node:child_process";import{createOutputEventCollector as A}from"./commandOutputEvents.js";import{prepareShellCommand as D,shellExecutable as G}from"./shellCommandPreparation.js";import{resolveClosedShellCommand as P}from"./shellCommandResult.js";import{createShellOutputDecoder as E,decodeShellOutputChunk as a}from"./shellOutputDecoder.js";const K=1e3;async function B(t){const i=G(),l=await D(t.commandText,t.workspaceRoot,i);return new Promise((L,w)=>{const O=new Date,r=R(i.command,[...i.argsPrefix,l.commandText],{cwd:t.cwd,env:process.env,windowsVerbatimArguments:process.platform==="win32",windowsHide:!0}),c=A({cwd:t.cwd,commandLineCount:l.commandLineCount,commandFilePath:l.commandFilePath,onOutput:t.onOutput});let T="",h="",d=!1,S=!1,I=!1,m=!1,n,o;const g=E(),k=E(),s=()=>{o&&clearTimeout(o),n&&clearTimeout(n),o=void 0,n=void 0},f=()=>{n||(n=setTimeout(()=>{r.killed||r.kill("SIGKILL")},K),n.unref?.())},u=setTimeout(()=>{d=!0,r.kill("SIGTERM"),f()},t.timeoutMs);u.unref?.();const p=()=>{o&&clearTimeout(o),o=setTimeout(()=>{S=!0,d=!0,r.kill("SIGTERM"),f()},t.inactivityTimeoutMs),o.unref?.()};p();const y=()=>{m||r.killed||(I=!0,d=!0,clearTimeout(u),s(),r.kill("SIGTERM"),f())};t.watchdogSignal&&t.watchdogSignal.then(y,()=>{});const v=e=>{e&&(T+=e,c.push("stdout",e),p())},C=e=>{e&&(h+=e,c.push("stderr",e),p())};r.stdout?.on("data",e=>{v(a(g,e))}),r.stderr?.on("data",e=>{C(a(k,e))}),r.on("error",e=>{m=!0,clearTimeout(u),s(),c.close(),w(e)}),r.on("close",(e,M)=>{m=!0,clearTimeout(u),s(),v(a(g,void 0,!0)),C(a(k,void 0,!0)),c.close(),P({exitCode:e,signal:M,stdout:T,stderr:h,startedAt:O,timedOut:d,inactivityTimedOut:S,watchdogInterrupted:I,prepared:l,agentId:t.agentId,workspaceRoot:t.workspaceRoot,cwd:t.cwd}).then(L,w)})})}export{B as runShellCommand};
2
2