aws-runtime-bridge 1.9.146 → 1.9.147

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 (32) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +6 -1
  2. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  3. package/dist/browser/browser-pool.d.ts +4 -0
  4. package/dist/browser/browser-pool.js +1 -1
  5. package/dist/desktop/built-in-desktop-tools.d.ts +6 -0
  6. package/dist/desktop/built-in-desktop-tools.js +1 -1
  7. package/dist/routes/background-tasks.js +4 -4
  8. package/dist/routes/instance.js +1 -1
  9. package/dist/routes/terminal.js +19 -19
  10. package/dist/services/builtin-commands/create-plugin.md +44 -0
  11. package/dist/services/changelog.d.ts +8 -0
  12. package/dist/services/changelog.js +17 -0
  13. package/dist/services/instance-features.d.ts +2 -0
  14. package/dist/services/instance-features.js +1 -1
  15. package/dist/services/plugin-manager.js +1 -1
  16. package/dist/utils/npm-version.d.ts +2 -0
  17. package/dist/utils/npm-version.js +1 -1
  18. package/package/acode/dist/background-command-manager.d.ts +4 -0
  19. package/package/acode/dist/background-command-manager.js +2 -2
  20. package/package/acode/dist/background-command-store.d.ts +2 -0
  21. package/package/acode/dist/built-in-file-tools.js +2 -2
  22. package/package/acode/dist/image-utils.d.ts +30 -1
  23. package/package/acode/dist/image-utils.js +1 -1
  24. package/package/acode/dist/runtime-environment.d.ts +3 -0
  25. package/package/acode/dist/runtime-environment.js +3 -0
  26. package/package/acode/dist/runtime.js +14 -14
  27. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +16 -0
  28. package/package/aws-client-agent-mcp/dist/mcp-server.js +20 -20
  29. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +16 -0
  30. package/package/aws-client-agent-mcp/dist/mcp-tools.js +7 -7
  31. package/package/aws-client-agent-mcp/dist/types.d.ts +10 -1
  32. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
- import{spawn as E}from"node:child_process";import{promises as A}from"node:fs";import{createInterface as I}from"node:readline";import{randomBytes as S}from"node:crypto";import{prepareShellCommand as O,shellExecutable as R}from"./builtins/shellCommandPreparation.js";import{createShellOutputDecoder as M,decodeShellOutputChunk as w}from"./builtins/shellOutputDecoder.js";import{BackgroundOutputRingBuffer as D}from"./background-output-ringbuffer.js";import{BackgroundCommandStore as F}from"./background-command-store.js";const z=1e3,G=30*60*1e3,N=24*60*60*1e3,B=50*1024*1024,C=16,_=256,W=256*1024,X=100,$=5e3,q=256,b=20,v=5*60*1e3,L=1024*1024;class k{constructor(){this.tasksByAgent=new Map,this.store=new F}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>=C)throw new x("too_many_tasks",`Agent ${i} has ${e.size} background tasks (limit ${C}). Kill or wait for completion first.`);if(this.globalCount()>=_)throw new x("global_limit_reached",`Global background task limit ${_} reached.`);const n=this.generateTaskId(e),o=t.timeoutMs===void 0?G:t.timeoutMs>0?Math.min(t.timeoutMs,N):0,s=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:o,inactivityTimeoutMs:s,child:null,ringBuffer:new D,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:M(),stderrDecoder:M(),stdoutText:"",stderrText:"",commandLineCount:0},c=new Promise(d=>{a.completionResolve=d});return e.set(n,a),this.spawnAndAttach(a,t).catch(d=>{a.ringBuffer.push(`[ACode] spawn failed: ${d?.message??String(d)}
1
+ import{spawn as E}from"node:child_process";import{promises as A}from"node:fs";import{createInterface as I}from"node:readline";import{randomBytes as S}from"node:crypto";import{prepareShellCommand as O,shellExecutable as R}from"./builtins/shellCommandPreparation.js";import{createShellOutputDecoder as M,decodeShellOutputChunk as w}from"./builtins/shellOutputDecoder.js";import{BackgroundOutputRingBuffer as D}from"./background-output-ringbuffer.js";import{BackgroundCommandStore as F}from"./background-command-store.js";const z=1e3,G=30*60*1e3,N=24*60*60*1e3,B=50*1024*1024,C=16,_=256,W=256*1024,X=100,$=5e3,q=256,b=20,v=5*60*1e3,L=1024*1024;class K{constructor(){this.tasksByAgent=new Map,this.store=new F}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>=C)throw new x("too_many_tasks",`Agent ${i} has ${e.size} background tasks (limit ${C}). Kill or wait for completion first.`);if(this.globalCount()>=_)throw new x("global_limit_reached",`Global background task limit ${_} reached.`);const n=this.generateTaskId(e),o=t.timeoutMs===void 0?G:t.timeoutMs>0?Math.min(t.timeoutMs,N):0,s=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,description:t.description,cwd:t.cwd,status:"running",startedAt:Date.now(),finishedAt:null,exitCode:null,signal:null,killedReason:null,timeoutMs:o,inactivityTimeoutMs:s,child:null,ringBuffer:new D,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:M(),stderrDecoder:M(),stdoutText:"",stderrText:"",commandLineCount:0},c=new Promise(d=>{a.completionResolve=d});return e.set(n,a),this.spawnAndAttach(a,t).catch(d=>{a.ringBuffer.push(`[ACode] spawn failed: ${d?.message??String(d)}
2
2
  `),this.finalizeTask(a,-1,null,"spawn_error")}),this.persistTask(a),{taskId:n,completion:c}}async spawnAndAttach(t,i){const e=R(),n=await O(i.commandText,i.workspaceRoot,e),o=process.platform==="win32",s=E(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,t.commandFilePath=n.commandFilePath,t.commandLineCount=n.commandLineCount,t.inactivityTimeoutMs>0&&this.scheduleInactivity(t),s.stdout?.on("data",r=>{const u=w(t.stdoutDecoder,r);this.onOutput(t,"stdout",u)}),s.stderr?.on("data",r=>{const u=w(t.stderrDecoder,r);this.onOutput(t,"stderr",u)}),s.on("error",r=>{this.onOutput(t,"stderr",`[ACode] child error: ${r.message}
3
3
  `),t.finalized||this.finalizeTask(t,-1,null,"child_error")}),s.on("close",(r,u)=>{const a=w(t.stdoutDecoder,void 0,!0),c=w(t.stderrDecoder,void 0,!0);if(a&&this.onOutput(t,"stdout",a),c&&this.onOutput(t,"stderr",c),t.ringBuffer.flush(),!t.finalized){const d=t.killedReason??null;this.finalizeTask(t,r,u,d??void 0)}}),t.timeoutMs>0&&(t.timeoutTimer=setTimeout(()=>{t.finalized||(t.killedReason="timeout",this.killProcessGroup(s))},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 o=i==="stdout"?"stdoutText":"stderrText";if(Buffer.byteLength(t[o],"utf-8")<L){const r=L-Buffer.byteLength(t[o],"utf-8");t[o]+=r>0?e.slice(0,r):""}if(t.inactivityTimeoutMs>0&&this.scheduleInactivity(t),t.outputBytes>=B){if(!t.outputTruncated){t.outputTruncated=!0;const r=`
4
4
  [ACode] output truncated at 50MB
5
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 s=(e.match(/\n/g)??[]).length;t.outputLineCount+=s,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>B?Promise.resolve():(t.outputWriteChain=t.outputWriteChain.then(()=>A.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 o;n?(o="killed",t.killedReason=n):i===0?o="completed":o="failed",t.status=o,t.exitCode=i,t.signal=e;const s=n==="inactivity"||t.inactivityTimedOut,r={taskId:t.taskId,exitCode:i,signal:e,timedOut:n==="timeout"||s,inactivityTimedOut:s,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:o,exitCode:i,signal:e,timedOut:n==="timeout"||s,aborted:!1,durationMs:t.finishedAt-t.startedAt},a=t.completionWaiters;t.completionWaiters=[];for(const c of a)c(u);if(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.outputSubscribers.size>0){const c=Array.from(t.outputSubscribers);t.outputSubscribers.clear();for(const d of c)try{d.onDone({status:o,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&&(A.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}}getTaskOutputSnapshot(t,i,e=500){const n=this.getTask(t,i);if(!n)return null;const o=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:o,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 o=!0;return()=>{o&&(o=!1,n.outputSubscribers.delete(e))}}async readOutput(t,i){const e=String(i.task_id??""),n=this.getTask(t,e),o=i.mode==="lines"||i.mode==="grep"?i.mode:"tail",s=Math.min(Math.max(1,i.line_size??100),X),r=Number.isFinite(i.start_line)&&(i.start_line??0)>0?Math.floor(i.start_line??0):0;if(!n)return{taskId:e,status:"killed",mode:o,lines:[],lineCount:0,metadata:{totalLines:0,totalBytes:0,returnedBytes:0,truncated:!1,outputTruncated:!1,hasMore:!1,nextStartLine:null,outputFile:""}};let u=[],a=!1,c=null;if(o==="tail"){const m=n.ringBuffer.tail(s),f=Math.max(0,n.outputLineCount-m.length);u=m.map((l,g)=>({line:f+g,text:l})),c=null}else if(o==="lines"){const m=n.ringBuffer.firstLineIndex(),f=m+n.ringBuffer.getLineCount();if(r>=m&&r<f)u=n.ringBuffer.offset(r,s).map((g,h)=>({line:r+h,text:g})),a=r+u.length<f,c=a?r+u.length:null;else if(r<f){const l=await this.readFromFile(n,"lines",r,s,0,0,void 0);u=l.rows,a=l.hasMore,c=l.nextStartLine}}else{const m=String(i.pattern??"");if(!m||m.length>q)return this._emptyResult(e,n,o);let f;try{f=new RegExp(m,"i")}catch{return this._emptyResult(e,n,o)}const l=Math.min(Math.max(0,i.context_before??0),b),g=Math.min(Math.max(0,i.context_after??0),b),h=await this.readFromFile(n,"grep",r,s,l,g,f);u=h.rows,a=h.hasMore,c=h.nextStartLine}const d=[];let p=0,T=!1;for(const m of u){const f=Buffer.byteLength(m.text,"utf-8")+1;if(d.length>=s||p+f>W){T=!0,a=!0;break}d.push(m),p+=f}const y=i.include_metadata!==!1;return{taskId:e,status:n.status,mode:o,lines:d,lineCount:d.length,metadata:y?{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:p,truncated:T,outputTruncated:n.outputTruncated,hasMore:a,nextStartLine:a?c:null,outputFile:n.outputPath}:void 0}}_emptyResult(t,i,e){return{taskId:t,status:i.status,mode:e,lines:[],lineCount:0,metadata:{totalLines:i.outputLineCount,totalBytes:i.outputBytes,returnedBytes:0,truncated:!1,outputTruncated:i.outputTruncated,hasMore:!1,nextStartLine:null,outputFile:i.outputPath}}}async readFromFile(t,i,e,n,o,s,r){const u=[],a=new Set;let c=0,d=!1;const p=[];let T=-1/0;try{const y=await A.open(t.outputPath,"r"),m=I({input:y.createReadStream({encoding:"utf-8"}),crlfDelay:1/0});for await(const f of m){const l=c;if(c++,i==="grep"&&l-e>=$&&l>=e){d=!0;break}if(l>=e){if(i==="lines"){if(u.length>=n){d=!0;break}a.has(l)||(a.add(l),u.push({line:l,text:f}))}else if(r.test(f)){for(const h of p)h.line>=e&&!a.has(h.line)&&(a.add(h.line),u.push(h));if(a.has(l)||(a.add(l),u.push({line:l,text:f})),T=l,u.length>=n){d=!0;break}}else if(o>0&&(p.push({line:l,text:f}),p.length>o&&p.shift()),T>=e&&l-T<=s&&!a.has(l)&&(a.add(l),u.push({line:l,text:f}),u.length>=n)){d=!0;break}}}m.close(),await y.close()}catch{return{rows:[],hasMore:!1,nextStartLine:null}}return d?{rows:u,hasMore:d,nextStartLine:c}:{rows:u,hasMore:d,nextStartLine:null}}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=c=>{u&&clearTimeout(u),r(c)};n.completionWaiters.push(a),e&&e>0&&(u=setTimeout(()=>{n.completionWaiters=n.completionWaiters.filter(c=>c!==a),r({taskId:i,status:"running",exitCode:null,signal:null,timedOut:!0,aborted:!1,durationMs:Date.now()-n.startedAt})},e),u.unref?.())});const s=(await this.store.readSession(t))?.tasks.find(r=>r.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,...s.outputPath?{outputFilePath:s.outputPath}:{}}:{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,...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 o=e.get(n);if(!o)continue;const s=o.completionWaiters;if(s.length===0)continue;o.completionWaiters=[];const r={taskId:n,status:"running",exitCode:null,signal:null,timedOut:!1,aborted:!0,durationMs:Date.now()-o.startedAt};for(const u of s)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)},z),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=S(4).toString("hex").slice(0,8);if(!t.has(e))return e}return S(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<v),await this.store.persistSession(t.agentId,i.tasks)}}class x extends Error{constructor(t,i){super(i),this.name="BackgroundTaskError",this.code=t}}const Q=new k;export{k as BackgroundCommandManager,x as BackgroundTaskError,Q as backgroundCommandManager};
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 o;n?(o="killed",t.killedReason=n):i===0?o="completed":o="failed",t.status=o,t.exitCode=i,t.signal=e;const s=n==="inactivity"||t.inactivityTimedOut,r={taskId:t.taskId,exitCode:i,signal:e,timedOut:n==="timeout"||s,inactivityTimedOut:s,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:o,exitCode:i,signal:e,timedOut:n==="timeout"||s,aborted:!1,durationMs:t.finishedAt-t.startedAt},a=t.completionWaiters;t.completionWaiters=[];for(const c of a)c(u);if(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.outputSubscribers.size>0){const c=Array.from(t.outputSubscribers);t.outputSubscribers.clear();for(const d of c)try{d.onDone({status:o,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&&(A.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,description:t.description,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 o=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:o,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 o=!0;return()=>{o&&(o=!1,n.outputSubscribers.delete(e))}}async readOutput(t,i){const e=String(i.task_id??""),n=this.getTask(t,e),o=i.mode==="lines"||i.mode==="grep"?i.mode:"tail",s=Math.min(Math.max(1,i.line_size??100),X),r=Number.isFinite(i.start_line)&&(i.start_line??0)>0?Math.floor(i.start_line??0):0;if(!n)return{taskId:e,status:"killed",mode:o,lines:[],lineCount:0,metadata:{totalLines:0,totalBytes:0,returnedBytes:0,truncated:!1,outputTruncated:!1,hasMore:!1,nextStartLine:null,outputFile:""}};let u=[],a=!1,c=null;if(o==="tail"){const m=n.ringBuffer.tail(s),f=Math.max(0,n.outputLineCount-m.length);u=m.map((l,g)=>({line:f+g,text:l})),c=null}else if(o==="lines"){const m=n.ringBuffer.firstLineIndex(),f=m+n.ringBuffer.getLineCount();if(r>=m&&r<f)u=n.ringBuffer.offset(r,s).map((g,h)=>({line:r+h,text:g})),a=r+u.length<f,c=a?r+u.length:null;else if(r<f){const l=await this.readFromFile(n,"lines",r,s,0,0,void 0);u=l.rows,a=l.hasMore,c=l.nextStartLine}}else{const m=String(i.pattern??"");if(!m||m.length>q)return this._emptyResult(e,n,o);let f;try{f=new RegExp(m,"i")}catch{return this._emptyResult(e,n,o)}const l=Math.min(Math.max(0,i.context_before??0),b),g=Math.min(Math.max(0,i.context_after??0),b),h=await this.readFromFile(n,"grep",r,s,l,g,f);u=h.rows,a=h.hasMore,c=h.nextStartLine}const d=[];let p=0,T=!1;for(const m of u){const f=Buffer.byteLength(m.text,"utf-8")+1;if(d.length>=s||p+f>W){T=!0,a=!0;break}d.push(m),p+=f}const y=i.include_metadata!==!1;return{taskId:e,status:n.status,mode:o,lines:d,lineCount:d.length,metadata:y?{totalLines:n.outputLineCount,totalBytes:n.outputBytes,returnedBytes:p,truncated:T,outputTruncated:n.outputTruncated,hasMore:a,nextStartLine:a?c:null,outputFile:n.outputPath}:void 0}}_emptyResult(t,i,e){return{taskId:t,status:i.status,mode:e,lines:[],lineCount:0,metadata:{totalLines:i.outputLineCount,totalBytes:i.outputBytes,returnedBytes:0,truncated:!1,outputTruncated:i.outputTruncated,hasMore:!1,nextStartLine:null,outputFile:i.outputPath}}}async readFromFile(t,i,e,n,o,s,r){const u=[],a=new Set;let c=0,d=!1;const p=[];let T=-1/0;try{const y=await A.open(t.outputPath,"r"),m=I({input:y.createReadStream({encoding:"utf-8"}),crlfDelay:1/0});for await(const f of m){const l=c;if(c++,i==="grep"&&l-e>=$&&l>=e){d=!0;break}if(l>=e){if(i==="lines"){if(u.length>=n){d=!0;break}a.has(l)||(a.add(l),u.push({line:l,text:f}))}else if(r.test(f)){for(const h of p)h.line>=e&&!a.has(h.line)&&(a.add(h.line),u.push(h));if(a.has(l)||(a.add(l),u.push({line:l,text:f})),T=l,u.length>=n){d=!0;break}}else if(o>0&&(p.push({line:l,text:f}),p.length>o&&p.shift()),T>=e&&l-T<=s&&!a.has(l)&&(a.add(l),u.push({line:l,text:f}),u.length>=n)){d=!0;break}}}m.close(),await y.close()}catch{return{rows:[],hasMore:!1,nextStartLine:null}}return d?{rows:u,hasMore:d,nextStartLine:c}:{rows:u,hasMore:d,nextStartLine:null}}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=c=>{u&&clearTimeout(u),r(c)};n.completionWaiters.push(a),e&&e>0&&(u=setTimeout(()=>{n.completionWaiters=n.completionWaiters.filter(c=>c!==a),r({taskId:i,status:"running",exitCode:null,signal:null,timedOut:!0,aborted:!1,durationMs:Date.now()-n.startedAt})},e),u.unref?.())});const s=(await this.store.readSession(t))?.tasks.find(r=>r.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,...s.outputPath?{outputFilePath:s.outputPath}:{}}:{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,...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 o=e.get(n);if(!o)continue;const s=o.completionWaiters;if(s.length===0)continue;o.completionWaiters=[];const r={taskId:n,status:"running",exitCode:null,signal:null,timedOut:!1,aborted:!0,durationMs:Date.now()-o.startedAt};for(const u of s)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)},z),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=S(4).toString("hex").slice(0,8);if(!t.has(e))return e}return S(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,description:t.description,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<v),await this.store.persistSession(t.agentId,i.tasks)}}class x extends Error{constructor(t,i){super(i),this.name="BackgroundTaskError",this.code=t}}const Q=new K;export{K as BackgroundCommandManager,x as BackgroundTaskError,Q as backgroundCommandManager};
7
7
 
@@ -6,6 +6,8 @@ export interface BackgroundTaskRecord {
6
6
  agentId: string;
7
7
  command: string;
8
8
  commandPreview: string;
9
+
10
+ description?: string;
9
11
  cwd: string;
10
12
  status: BackgroundTaskStatus;
11
13
  startedAt: number;
@@ -1,4 +1,4 @@
1
- import{randomUUID as nt}from"node:crypto";import{promises as w,createReadStream as X}from"node:fs";import it from"node:os";import d from"node:path";import Y from"node:readline";import{runShellCommand as at}from"./builtins/shellCommandRunner.js";import{createOutputEventCollector as rt}from"./builtins/commandOutputEvents.js";import{buildCommandOutputSpilloverContent as st,COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT as ct,countOutputLines as H,formatCommandOutputSpilloverStdout as lt,writeCommandArtifactFile as ut}from"./builtins/commandArtifacts.js";import{symbolsTool as dt}from"./built-in-symbols-tool.js";import{createListBackgroundCommandsTool as mt,createKillBackgroundCommandTool as ht,createReadBackgroundOutputTool as ft}from"./background-command-tools.js";import{detectImageFormatFromBuffer as pt,formatBytes as x,imageMediaType as K,readImageDimensions as wt,tryResizeWithSharp as gt}from"./image-utils.js";const _t=2e3,O=2e3,yt=50*1024,V=4096,bt=.3,kt=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"]),Tt=new Set(["png","jpg","jpeg","gif","webp"]),Z=20*1024*1024,L=10*1024*1024,D=Math.floor(3.75*1024*1024),C=2e3,Et=15e3,Pt=1e3,vt=1024*1024,xt=256*1024,$t=1e3,Rt=new Set([".git","node_modules","dist","build",".next",".nuxt",".cache",".turbo",".output","coverage",".nyc_output"]),se={fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow"};async function F(n,o,e){if(!n)return;const t=n.getLevel(o);if(t==="deny")throw new Error(`Operation blocked by tool permission policy (${o} = deny). Explain this restriction to the user if needed.`);if(t==="ask"&&!await n.requestPermission(o,e))throw new Error(`Operation denied by the user (${o}). Do not retry the same operation without asking the user.`)}function $(n){return n.replace(/\\/g,"/")}async function J(n){try{return await w.access(n),!0}catch{return!1}}function St(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 R(n,o,e){for(const t of o){const i=n[t];if(typeof i=="string")return i}throw new Error(`${e} is required`)}function I(n,o){for(const e of o){const t=n[e];if(typeof t=="string"&&t.trim())return t}}function U(n,o,e){for(const t of o){const i=n[t],a=typeof i=="number"?i:typeof i=="string"?Number(i):NaN;if(Number.isFinite(a)&&a>0)return Math.floor(a)}return e}function It(n,o,e){for(const t of o){const i=n[t],a=typeof i=="number"?i:typeof i=="string"?Number(i):NaN;if(Number.isFinite(a)&&a>0)return Math.floor(a);if(Number.isFinite(a)&&a===0)return 0}return e}async function Q(n){const o=d.extname(n).toLowerCase();if(kt.has(o))return!0;const e=await w.open(n,"r");try{const t=Buffer.alloc(V),{bytesRead:i}=await e.read(t,0,V,0);if(i===0)return!1;const a=t.subarray(0,i);if(a.includes(0))return!0;let r=0;for(let s=0;s<i;s++){const c=a[s];(c<9||c>13&&c<32)&&r++}return r/i>bt}finally{await e.close()}}function M(n,o){const e=d.resolve(o),t=d.relative(n,e);if(t.startsWith("..")||d.isAbsolute(t))throw new Error(`Target path is outside workspace: ${e}`);return e}function W(n){return n==="~"||n.startsWith("~/")?d.join(it.homedir(),n.slice(1)):n}async function Mt(n,o){const e=d.resolve(String(n||"").trim()),t=await w.realpath(e);if(!(await w.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);if(!o?.trim())return{workspaceRoot:t,cwd:t};const a=W(o.trim()),r=d.isAbsolute(a)?d.resolve(a):d.resolve(e,a),s=d.relative(e,r);if(s.startsWith("..")||d.isAbsolute(s))throw new Error(`Command cwd is outside workspace: ${r}`);const c=M(t,await w.realpath(r));if(!(await w.stat(c)).isDirectory())throw new Error(`Command cwd is not a directory: ${c}`);return{workspaceRoot:t,cwd:c}}async function Ot(n,o){const e=await w.realpath(d.dirname(o));M(n,e);try{if((await w.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 A(n,o){const e=d.resolve(String(n||"").trim()),t=await w.realpath(e);if(!(await w.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${e}`);const a=W(o.trim());if(!a)throw new Error("file_path is required");const r=d.isAbsolute(a)?d.resolve(a):d.resolve(e,a),s=d.relative(e,r);if(s.startsWith("..")||d.isAbsolute(s))throw new Error(`Target path is outside workspace: ${r}`);return{workspaceRoot:t,requestedPath:r,targetPath:M(t,d.join(t,s))}}async function tt(n,o,e){const t=d.resolve(String(n||"").trim()),i=await w.realpath(t);if(!(await w.stat(i)).isDirectory())throw new Error(`Workspace path is not a directory: ${t}`);const r=W(o.trim());if(!r)throw new Error("file_path is required");const s=d.isAbsolute(r)?d.resolve(r):d.resolve(t,r),c=d.relative(t,s),u=await w.realpath(s).catch(()=>s),l=d.relative(i,u);if(c.startsWith("..")||d.isAbsolute(c)||l.startsWith("..")||d.isAbsolute(l)){if(!e)throw new Error(`Target path is outside workspace: ${s}`);return await F(e,"fileReadOutside",{path:s}),{workspaceRoot:i,requestedPath:s,targetPath:u}}return{workspaceRoot:i,requestedPath:s,targetPath:M(i,u)}}async function et(n,o,e){const t=await A(n,o),i=d.dirname(t.targetPath),a=!await J(i);await w.mkdir(i,{recursive:!0}),await Ot(t.workspaceRoot,t.targetPath);const r=d.join(i,`.${d.basename(t.targetPath)}.${process.pid}.${nt()}.tmp`);try{await w.writeFile(r,e,"utf-8"),await w.rename(r,t.targetPath)}catch(s){throw await w.rm(r,{force:!0}),s}return{workspaceRoot:t.workspaceRoot,targetPath:t.targetPath,bytes:Buffer.byteLength(e,"utf-8"),createdParentDirectory:a}}async function Lt(n,o){const e=await A(n,o),t=M(e.workspaceRoot,await w.realpath(e.targetPath));if(!(await w.stat(t)).isFile())throw new Error(`Path is not a file: ${t}`);return{workspaceRoot:e.workspaceRoot,targetPath:t,content:await w.readFile(t,"utf-8")}}async function At(n,o,e,t,i){const a=await tt(n,o,i),r=a.targetPath;if(!(await w.stat(r)).isFile())throw new Error(`Path is not a file: ${r}`);if(await Q(r))return{workspaceRoot:a.workspaceRoot,targetPath:r,content:"[Binary file, content skipped]",isBinary:!0,truncated:!1,totalLines:0,shownFromLine:0,shownToLine:0};const c=X(r,{encoding:"utf-8"}),u=Y.createInterface({input:c,crlfDelay:1/0});try{const l=[];let g=0,h=0,y=0,m=!1,E=!1;const f=e-1;for await(const S of u){if(h++,g<f){g++;continue}if(l.length>=t){m=!0,g++;continue}let P=S;P.length>O&&(P=P.slice(0,O)+`... (line truncated to ${O} chars)`);const v=`${g+1}: ${P}`,T=Buffer.byteLength(v,"utf-8")+1;if(y+T>yt){E=!0;break}l.push(v),y+=T,g++}if(h>0&&l.length===0&&!m&&!E&&f>=h)throw new Error(`offset ${e} exceeds total line count ${h} in file: ${r}`);const k=l.length>0?e:0,b=l.length>0?e+l.length-1:0;let _;E?_=`Output capped at 50 KB. Showing lines ${k}-${b}. Use offset=${b+1} to continue.`:m?_=`Showing lines ${k}-${b} of ${h}. Use offset=${b+1} to continue.`:_=`End of file - total ${h} lines`;const p=l.length>0?l.join(`
1
+ import{randomUUID as nt}from"node:crypto";import{promises as p,createReadStream as X}from"node:fs";import it from"node:os";import d from"node:path";import Y from"node:readline";import{runShellCommand as at}from"./builtins/shellCommandRunner.js";import{createOutputEventCollector as rt}from"./builtins/commandOutputEvents.js";import{buildCommandOutputSpilloverContent as st,COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT as ct,countOutputLines as H,formatCommandOutputSpilloverStdout as lt,writeCommandArtifactFile as ut}from"./builtins/commandArtifacts.js";import{symbolsTool as dt}from"./built-in-symbols-tool.js";import{createListBackgroundCommandsTool as mt,createKillBackgroundCommandTool as ht,createReadBackgroundOutputTool as ft}from"./background-command-tools.js";import{detectImageFormatFromBuffer as pt,formatBytes as S,imageMediaType as K,readImageDimensions as gt,tryCompressImageWithSharp as wt,tryResizeWithSharp as _t}from"./image-utils.js";const yt=2e3,L=2e3,bt=50*1024,V=4096,kt=.3,vt=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"]),Et=new Set(["png","jpg","jpeg","gif","webp"]),J=20*1024*1024,A=10*1024*1024,D=Math.floor(3.75*1024*1024),C=2e3,xt=50*1024,Tt=100*1024,Pt=15e3,St=1e3,$t=1024*1024,Mt=256*1024,Rt=1e3,It=new Set([".git","node_modules","dist","build",".next",".nuxt",".cache",".turbo",".output","coverage",".nyc_output"]),de={fileReadOutside:"allow",commandExecution:"allow",fileModification:"allow"};async function N(n,e,o){if(!n)return;const t=n.getLevel(e);if(t==="deny")throw new Error(`Operation blocked by tool permission policy (${e} = deny). Explain this restriction to the user if needed.`);if(t==="ask"&&!await n.requestPermission(e,o))throw new Error(`Operation denied by the user (${e}). Do not retry the same operation without asking the user.`)}function $(n){return n.replace(/\\/g,"/")}async function Z(n){try{return await p.access(n),!0}catch{return!1}}function Ot(n,e){if(!e)return 0;let o=0,t=n.indexOf(e);for(;t>=0;)o+=1,t=n.indexOf(e,t+e.length);return o}function M(n,e,o){for(const t of e){const i=n[t];if(typeof i=="string")return i}throw new Error(`${o} is required`)}function R(n,e){for(const o of e){const t=n[o];if(typeof t=="string"&&t.trim())return t}}function U(n,e,o){for(const t of e){const i=n[t],a=typeof i=="number"?i:typeof i=="string"?Number(i):NaN;if(Number.isFinite(a)&&a>0)return Math.floor(a)}return o}function Lt(n,e,o){for(const t of e){const i=n[t],a=typeof i=="number"?i:typeof i=="string"?Number(i):NaN;if(Number.isFinite(a)&&a>0)return Math.floor(a);if(Number.isFinite(a)&&a===0)return 0}return o}function At(n){const e=n.compress;if(e==null)return"auto";if(typeof e=="boolean")return e;if(e==="auto")return"auto";if(e==="true")return!0;if(e==="false")return!1;throw new Error(`Invalid compress argument: ${JSON.stringify(e)} (expected true, false, or "auto")`)}async function Q(n){const e=d.extname(n).toLowerCase();if(vt.has(e))return!0;const o=await p.open(n,"r");try{const t=Buffer.alloc(V),{bytesRead:i}=await o.read(t,0,V,0);if(i===0)return!1;const a=t.subarray(0,i);if(a.includes(0))return!0;let s=0;for(let r=0;r<i;r++){const c=a[r];(c<9||c>13&&c<32)&&s++}return s/i>kt}finally{await o.close()}}function O(n,e){const o=d.resolve(e),t=d.relative(n,o);if(t.startsWith("..")||d.isAbsolute(t))throw new Error(`Target path is outside workspace: ${o}`);return o}function W(n){return n==="~"||n.startsWith("~/")?d.join(it.homedir(),n.slice(1)):n}async function Bt(n,e){const o=d.resolve(String(n||"").trim()),t=await p.realpath(o);if(!(await p.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${o}`);if(!e?.trim())return{workspaceRoot:t,cwd:t};const a=W(e.trim()),s=d.isAbsolute(a)?d.resolve(a):d.resolve(o,a),r=d.relative(o,s);if(r.startsWith("..")||d.isAbsolute(r))throw new Error(`Command cwd is outside workspace: ${s}`);const c=O(t,await p.realpath(s));if(!(await p.stat(c)).isDirectory())throw new Error(`Command cwd is not a directory: ${c}`);return{workspaceRoot:t,cwd:c}}async function Nt(n,e){const o=await p.realpath(d.dirname(e));O(n,o);try{if((await p.lstat(e)).isSymbolicLink())throw new Error(`Refusing to write through symbolic link: ${e}`)}catch(t){if((typeof t=="object"&&t!==null?Reflect.get(t,"code"):void 0)!=="ENOENT")throw t}}async function B(n,e){const o=d.resolve(String(n||"").trim()),t=await p.realpath(o);if(!(await p.stat(t)).isDirectory())throw new Error(`Workspace path is not a directory: ${o}`);const a=W(e.trim());if(!a)throw new Error("file_path is required");const s=d.isAbsolute(a)?d.resolve(a):d.resolve(o,a),r=d.relative(o,s);if(r.startsWith("..")||d.isAbsolute(r))throw new Error(`Target path is outside workspace: ${s}`);return{workspaceRoot:t,requestedPath:s,targetPath:O(t,d.join(t,r))}}async function tt(n,e,o){const t=d.resolve(String(n||"").trim()),i=await p.realpath(t);if(!(await p.stat(i)).isDirectory())throw new Error(`Workspace path is not a directory: ${t}`);const s=W(e.trim());if(!s)throw new Error("file_path is required");const r=d.isAbsolute(s)?d.resolve(s):d.resolve(t,s),c=d.relative(t,r),l=await p.realpath(r).catch(()=>r),u=d.relative(i,l);if(c.startsWith("..")||d.isAbsolute(c)||u.startsWith("..")||d.isAbsolute(u)){if(!o)throw new Error(`Target path is outside workspace: ${r}`);return await N(o,"fileReadOutside",{path:r}),{workspaceRoot:i,requestedPath:r,targetPath:l}}return{workspaceRoot:i,requestedPath:r,targetPath:O(i,l)}}async function et(n,e,o){const t=await B(n,e),i=d.dirname(t.targetPath),a=!await Z(i);await p.mkdir(i,{recursive:!0}),await Nt(t.workspaceRoot,t.targetPath);const s=d.join(i,`.${d.basename(t.targetPath)}.${process.pid}.${nt()}.tmp`);try{await p.writeFile(s,o,"utf-8"),await p.rename(s,t.targetPath)}catch(r){throw await p.rm(s,{force:!0}),r}return{workspaceRoot:t.workspaceRoot,targetPath:t.targetPath,bytes:Buffer.byteLength(o,"utf-8"),createdParentDirectory:a}}async function Ft(n,e){const o=await B(n,e),t=O(o.workspaceRoot,await p.realpath(o.targetPath));if(!(await p.stat(t)).isFile())throw new Error(`Path is not a file: ${t}`);return{workspaceRoot:o.workspaceRoot,targetPath:t,content:await p.readFile(t,"utf-8")}}async function Ct(n,e,o,t,i){const a=await tt(n,e,i),s=a.targetPath;if(!(await p.stat(s)).isFile())throw new Error(`Path is not a file: ${s}`);if(await Q(s))return{workspaceRoot:a.workspaceRoot,targetPath:s,content:"[Binary file, content skipped]",isBinary:!0,truncated:!1,totalLines:0,shownFromLine:0,shownToLine:0};const c=X(s,{encoding:"utf-8"}),l=Y.createInterface({input:c,crlfDelay:1/0});try{const u=[];let w=0,g=0,_=0,y=!1,h=!1;const P=o-1;for await(const f of l){if(g++,w<P){w++;continue}if(u.length>=t){y=!0,w++;continue}let b=f;b.length>L&&(b=b.slice(0,L)+`... (line truncated to ${L} chars)`);const x=`${w+1}: ${b}`,k=Buffer.byteLength(x,"utf-8")+1;if(_+k>bt){h=!0;break}u.push(x),_+=k,w++}if(g>0&&u.length===0&&!y&&!h&&P>=g)throw new Error(`offset ${o} exceeds total line count ${g} in file: ${s}`);const m=u.length>0?o:0,v=u.length>0?o+u.length-1:0;let E;h?E=`Output capped at 50 KB. Showing lines ${m}-${v}. Use offset=${v+1} to continue.`:y?E=`Showing lines ${m}-${v} of ${g}. Use offset=${v+1} to continue.`:E=`End of file - total ${g} lines`;const T=u.length>0?u.join(`
2
2
  `)+`
3
- `+_:_;return{workspaceRoot:a.workspaceRoot,targetPath:r,content:p,isBinary:!1,truncated:m||E,totalLines:E?-1:h,shownFromLine:k,shownToLine:b}}finally{u.close(),c.destroy()}}function q(n){return/^https?:\/\//i.test(n)}async function Ft(n){let o;try{o=new URL(n)}catch{throw new Error(`Invalid image URL: ${n}`)}if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`Unsupported image URL protocol: ${o.protocol} (only http/https)`);let e;try{e=await fetch(n,{signal:AbortSignal.timeout(Et)})}catch(u){const l=u instanceof Error?u.message:String(u);throw new Error(`Image URL fetch failed: ${n} (${l})`)}if(!e.ok)throw new Error(`Image URL fetch failed: ${n} (HTTP ${e.status})`);const t=(e.headers.get("content-type")||"").split(";")[0]?.trim().toLowerCase()||"";if(t&&!t.startsWith("image/"))throw new Error(`URL did not return an image (content-type: ${t}): ${n}`);const i=Number(e.headers.get("content-length")||"");if(Number.isFinite(i)&&i>L)throw new Error(`Image too large to fetch: ${n} (${x(i)} > ${x(L)})`);const a=e.body;if(!a){const u=await e.arrayBuffer();if(u.byteLength>L)throw new Error(`Image too large to fetch: ${n} (${x(u.byteLength)} > ${x(L)})`);return Buffer.from(u)}const r=a.getReader(),s=[];let c=0;for(;;){const{done:u,value:l}=await r.read();if(u)break;if(l){if(c+=l.byteLength,c>L)throw r.cancel().catch(()=>{}),new Error(`Image too large to fetch: ${n} (${x(c)} > ${x(L)})`);s.push(Buffer.from(l))}}return Buffer.concat(s,c)}async function Nt(n,o,e){let t,i;if(q(o))t=await Ft(o),i=o;else{const b=(await tt(n,o,e)).targetPath,_=await w.stat(b);if(!_.isFile())throw new Error(`Path is not a file: ${b}`);if(_.size>Z)throw new Error(`Image file too large to read: ${$(b)} (${x(_.size)} > ${x(Z)}). Downscale it first.`);t=await w.readFile(b),i=$(b)}if(t.length===0)throw new Error(`Image file is empty: ${i}`);const a=pt(t);if(!a)throw new Error(`Unsupported or corrupt image (unrecognized format): ${i}`);const r=wt(t);let s=a,c=t,u=r?.width,l=r?.height,g=!1;const h=await gt(t,a,{maxWidth:C,maxHeight:C,maxBytes:D});if(h)c=h.buffer,s=h.mediaType,u=h.width,l=h.height,g=h.changed;else if(t.length>D)throw new Error(`Image too large to inline: ${i} (${x(t.length)} > ${x(D)}). Downscale it first, e.g. via Bash: magick "${o}" -resize ${C}x${C} "${o}". Installing sharp enables automatic downscaling.`);const y=u&&l?`${u}x${l}`:"unknown dimensions",m=g&&r&&r.width!==u?` (resized from ${r.width}x${r.height})`:g?" (resized)":"",E=`[Image: ${i}, ${y}${m}, ${x(c.length)}]`,f=q(o)?d.basename(new URL(o).pathname)||"image":d.basename(i);return{ok:!0,filePath:i,content:E,isBinary:!1,image:{mediaType:K(s),width:u??null,height:l??null,originalWidth:r?.width??null,originalHeight:r?.height??null,resized:g,size:c.length},attachments:[{type:"image",name:f,mediaType:K(s),base64Data:c.toString("base64")}]}}function ot(n){let o="",e=0;for(;e<n.length;){const t=n[e];if(t==="*")o+="[^/]*";else if(t==="?")o+="[^/]";else if(t==="{"){const i=n.indexOf("}",e);if(i>=0){const a=n.slice(e+1,i);o+=`(${a.split(",").join("|")})`,e=i}else o+="\\{"}else if(t==="["){const i=n.indexOf("]",e);i>=0?(o+=n.slice(e,i+1),e=i):o+="\\["}else"+^$.()|\\".includes(t)?o+="\\"+t:o+=t;e++}return new RegExp(`^${o}$`)}async function Bt(n,o,e,t){const i=[];async function a(r){if(i.length>=t)return;const s=await w.readdir(r,{withFileTypes:!0});for(const c of s){if(i.length>=t)return;if(c.name.startsWith(".")&&c.isDirectory())continue;const u=d.join(r,c.name);if(c.isDirectory()){if(Rt.has(c.name))continue;await a(u)}else if(c.isFile()){if(o&&!o.test(c.name)||e&&e.test(c.name))continue;i.push(u)}}}return await a(n),i}async function Ct(n,o,e){if((await w.stat(n)).size>vt)return{matches:[],count:0};if(await Q(n))return{matches:[],count:0};const i=d.relative(o,n).replace(/\\/g,"/"),a=[];let r=0;const s=X(n,{encoding:"utf-8"}),c=Y.createInterface({input:s,crlfDelay:1/0});try{let u=0;for await(const l of c)if(u++,e.regex.test(l)){if(r++,e.collectContent){let g=l;if(g.length>O&&(g=g.slice(0,O)+`... (line truncated to ${O} chars)`),a.push({file:i,line:u,content:g}),a.length>=e.maxResults)break}if(e.stopOnFirstMatch)break}}finally{c.close(),s.destroy()}return{matches:a,count:r}}const Ut=12*60*6e4,Dt=30*6e4,Wt=6e4,qt=10*6e4;function jt(n,o,e){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 i=R(t,["file_path","filePath"],"file_path"),a=R(t,["content"],"content"),r=I(t,["reason"]),s=await A(n,i);await F(e,"fileModification",{operation:"write",path:s.targetPath});const c=await J(s.targetPath),u=c?await w.readFile(s.targetPath,"utf-8").catch(()=>null):null,l=await et(n,i,a);if(o){const g=d.relative(l.workspaceRoot,l.targetPath).replace(/\\/g,"/");await o({filePath:g,operation:c?"UPDATE":"CREATE",beforeContent:u,afterContent:a,reason:r})}return{ok:!0,filePath:$(l.targetPath),bytes:l.bytes,createdParentDirectory:l.createdParentDirectory}}}}function zt(n,o,e){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 i=R(t,["file_path","filePath"],"file_path"),a=R(t,["old_string","oldString"],"old_string"),r=R(t,["new_string","newString"],"new_string"),s=I(t,["reason"]);if(!a)throw new Error("old_string must not be empty");const c=await A(n,i);await F(e,"fileModification",{operation:"edit",path:c.targetPath});const u=await Lt(n,i),l=St(u.content,a);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 g=u.content.replace(a,r),h=await et(n,i,g);if(o){const y=d.relative(h.workspaceRoot,h.targetPath).replace(/\\/g,"/");await o({filePath:y,operation:"UPDATE",beforeContent:u.content,afterContent:g,reason:s})}return{ok:!0,filePath:$(h.targetPath),bytes:h.bytes}}}}function Gt(n,o,e){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 i=R(t,["file_path","filePath"],"file_path"),a=I(t,["reason"]),r=await A(n,i);await F(e,"fileModification",{operation:"delete",path:r.targetPath});const s=M(r.workspaceRoot,await w.realpath(r.targetPath).catch(()=>r.targetPath)),c=await w.stat(s).catch(()=>null);if(!c)throw new Error(`File does not exist: ${s}`);if(!c.isFile())throw new Error(`Path is not a file: ${s}`);const u=await w.readFile(s,"utf-8").catch(()=>null);if(await w.rm(s,{force:!0}),o){const l=d.relative(r.workspaceRoot,s).replace(/\\/g,"/");await o({filePath:l,operation:"DELETE",beforeContent:u,afterContent:null,reason:a})}return{ok:!0,filePath:$(s),deleted:!0}}}}function Xt(n,o){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. Images (.png/.jpg/.jpeg/.gif/.webp) and http(s) image URLs are also supported: the image is inlined into the conversation so you can see it (requires a model with image input). offset/limit are ignored for images; oversized images are automatically downscaled when sharp is available.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to read. Also accepts an http(s) URL pointing to an image."},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(e){const t=R(e,["file_path","filePath"],"file_path"),i=d.extname(t).toLowerCase().slice(1);if(q(t)||Tt.has(i))return await Nt(n,t,o);const a=U(e,["offset"],1),r=U(e,["limit"],_t),s=await At(n,t,a,r,o);return{ok:!0,filePath:$(s.targetPath),content:s.content,isBinary:s.isBinary,truncated:s.truncated,totalLines:s.totalLines,shownFromLine:s.shownFromLine,shownToLine:s.shownToLine}}}}function Yt(n,o,e,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 total timeout (timeout_ms) measured from command start \u2014 by default 30 minutes, after which the process is force-terminated; timeout_ms can raise this (up to 12 hours) or set 0 to disable. The tool returns stdout, stderr, exit code, and (if converted to background) a task_id. 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 moved to the BACKGROUND and the tool returns a task_id plus an explanation (backgrounded=true, reason=watchdog_timeout). The background command stays bound by the same total timeout (timeout_ms, default 30 minutes, still measured from command start) and can be managed via await_complete / list_background_commands / read_background_output / kill_background_command. For immediate backgrounding use wait_seconds=0, or wait_seconds=n>0 to wait n seconds then background.",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 total command timeout in milliseconds, measured from command start. Defaults to 1800000 (30 minutes) and is capped at 43200000 (12 hours). Set 0 to disable the timeout entirely (run until finished or killed)."},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 moved to the background and a task_id is returned (backgrounded=true, reason=watchdog_timeout). 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. The command remains bound by the total timeout (timeout_ms, default 30 minutes, measured from command start) whether foreground or background; 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(i,a){const r=R(i,["command"],"command").trim();if(!r)throw new Error("command must not be empty");const s=It(i,["timeout_ms","timeoutMs"],Dt),c=s===0?0:Math.min(s,Ut),u=U(i,["inactivity_timeout_ms","inactivityTimeoutMs"],Wt),l=Math.min(u,qt),g=I(i,["cwd"]),h=await Mt(n,g);await F(t,"commandExecution",{command:r,cwd:$(h.cwd)});const y=i.wait_seconds,E=typeof y=="number"&&Number.isFinite(y)?y:-1;if(e)return await Ht({deps:e,command:r,agentId:o,workspaceRoot:h.workspaceRoot,cwd:h.cwd,timeoutMs:c,inactivityTimeoutMs:l,waitSeconds:E,onOutput:a?.onOutput,settleSignal:a?.settleSignal});const f=await at({commandText:r,agentId:o,workspaceRoot:h.workspaceRoot,cwd:h.cwd,timeoutMs:c,inactivityTimeoutMs:l,onOutput:a?.onOutput,watchdogSignal:a?.settleSignal}),k={ok:f.exitCode===0&&!f.timedOut,tool:"Bash",command:r,cwd:$(h.cwd),exitCode:f.exitCode,signal:f.signal,timedOut:f.timedOut,inactivityTimedOut:f.inactivityTimedOut,watchdogInterrupted:f.watchdogInterrupted,timeoutMs:c,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?{...k,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."}:k}}}async function Ht(n){const{deps:o,command:e,agentId:t,workspaceRoot:i,cwd:a,timeoutMs:r,inactivityTimeoutMs:s,waitSeconds:c,onOutput:u,settleSignal:l}=n,g=u?rt({cwd:a,commandLineCount:0,onOutput:u}):void 0;let h=!!g;const y=()=>{h&&(h=!1,g?.close())};try{const{taskId:m,completion:E}=o.manager.startCommand({commandText:e,agentId:t,workspaceRoot:i,cwd:a,timeoutMs:r,inactivityTimeoutMs:s,onOutput:h?_=>{h&&g?.push(_.stream,_.text)}:void 0,onCompleted:o.emitCompleted});if(c===0)return o.manager.disableInactivityTimeout(t,m),y(),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:m,status:"backgrounded",reason:"immediate",message:`Command moved to background. Use await_complete(bg_cmd_ids=["${m}"]) to block until it finishes, read_background_output(task_id="${m}", mode="tail") to read output, list_background_commands to view all, or kill_background_command(task_id="${m}") to stop.`};const f=c===-1?0:Math.max(0,Math.floor(c*1e3)),k=[E];let b;c!==-1&&k.push(new Promise(_=>{b=setTimeout(()=>_("__timeout__"),f),b.unref?.()})),l&&k.push(l.then(()=>"__settle__"));try{const _=await Promise.race(k);if(_==="__settle__")return o.manager.disableInactivityTimeout(t,m),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:m,status:"backgrounded",reason:"watchdog_timeout",waitedMs:f,message:`Command still running after watchdog timeout; moved to background. Use await_complete(bg_cmd_ids=["${m}"]) to block until it finishes, read_background_output(task_id="${m}", mode="tail") to read output, or kill_background_command(task_id="${m}") to stop.`};if(_==="__timeout__")return o.manager.disableInactivityTimeout(t,m),{ok:!0,tool:"Bash",command:e,backgrounded:!0,taskId:m,status:"backgrounded",reason:"timeout",waitedMs:f,message:`Command still running after ${c}s; moved to background. Use await_complete(bg_cmd_ids=["${m}"]) to block until it finishes, or read_background_output(task_id="${m}", mode="tail") / kill_background_command(task_id="${m}") to inspect.`};const p=_;let S=p.stdout,P=p.stderr,v=p.outputSpilled,T=p.outputFilePath;if(!v&&H(`${p.stdout}${p.stderr}`)>ct){const N=await ut(t,"cmd","out",st({commandText:e,commandFilePath:p.commandFilePath,commandLineCount:p.commandLineCount,cwd:a,startedAt:new Date(Date.now()-p.durationMs),endedAt:new Date,exitCode:p.exitCode,signal:p.signal??null,timedOut:p.timedOut,inactivityTimedOut:p.inactivityTimedOut??!1,stdout:S,stderr:P}));S=lt($(N),H(`${p.stdout}${p.stderr}`)),v=!0,T=$(N)}return{ok:p.exitCode===0&&!p.timedOut,tool:"Bash",command:e,backgrounded:!1,taskId:m,exitCode:p.exitCode,signal:p.signal,timedOut:p.timedOut,inactivityTimedOut:p.inactivityTimedOut,timeoutMs:p.timeoutMs,inactivityTimeoutMs:p.inactivityTimeoutMs,durationMs:p.durationMs,outputSpilled:v,outputFilePath:T,outputLineCount:p.outputLineCount,commandFilePath:p.commandFilePath,commandLineCount:p.commandLineCount,stdout:S,stderr:P}}finally{b&&clearTimeout(b),y()}}catch(m){if(m?.code==="too_many_tasks"||m?.code==="global_limit_reached")return{ok:!1,tool:"Bash",command:e,backgrounded:!1,status:"not_executed",error:m.code,message:`Command was NOT executed: ${m.message}. Wait for some background tasks to finish/cleanup (per-agent limit 16, global 256), or reduce concurrent background commands, then retry.`};throw m}}function Kt(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=R(o,["pattern"],"pattern"),t=I(o,["path"])||".",i=I(o,["include"]),a=I(o,["exclude"]),r=o.case_insensitive===!0,s=(()=>{const T=o.output_mode;return T==="files_with_matches"||T==="count"?T:"content"})(),c=U(o,["max_results"],$t),u=r?"i":"";let l;try{l=new RegExp(e,u)}catch(T){throw new Error(`Invalid regex pattern: ${T instanceof Error?T.message:String(T)}`)}const g=i?ot(i):null,h=a?ot(a):null,y=await A(n,t),m=M(y.workspaceRoot,await w.realpath(y.targetPath)),E=await w.stat(m);let f;if(E.isFile())f=[m];else if(E.isDirectory())f=await Bt(m,g,h,Pt);else throw new Error(`Path is neither a file nor a directory: ${m}`);const k=[],b=[],_=[];let p=0,S=0,P=!1;for(const T of f){if(s==="content"&&k.length>=c){P=!0;break}const N={regex:l,maxResults:s==="content"?c-k.length:Number.MAX_SAFE_INTEGER,collectContent:s==="content",stopOnFirstMatch:s==="files_with_matches"},B=await Ct(T,y.workspaceRoot,N);if(B.count>0){const j=d.relative(y.workspaceRoot,T).replace(/\\/g,"/");if(_.push(j),p+=B.count,s==="content"){for(const z of B.matches){const G=Buffer.byteLength(z.content,"utf-8")+64;if(S+G>xt){P=!0;break}S+=G,k.push(z)}if(P)break;if(k.length>=c){P=!0;break}}else s==="count"&&b.push({file:j,count:B.count})}}const v={ok:!0,tool:"grep",pattern:e,searchPath:$(y.targetPath),outputMode:s,filesSearched:f.length,filesMatched:_.length,totalMatches:p,truncated:P};return s==="content"?v.matches=k:s==="files_with_matches"?v.matches=_:v.matches=b,v}}}function ce(n,o,e,t,i){const a=o||"unknown",r=[Xt(n,i),jt(n,e,i),zt(n,e,i),Gt(n,e,i),Kt(n),Yt(n,a,t,i),dt(n)];return t&&r.push(mt(a,t),ht(a,t),ft(a,t)),r}export{se as DEFAULT_TOOL_PERMISSION_POLICY,ce as createBuiltInFileTools,M as ensureInsideWorkspace,A as resolveWorkspaceTarget};
3
+ `+E:E;return{workspaceRoot:a.workspaceRoot,targetPath:s,content:T,isBinary:!1,truncated:y||h,totalLines:h?-1:g,shownFromLine:m,shownToLine:v}}finally{l.close(),c.destroy()}}function z(n){return/^https?:\/\//i.test(n)}async function Ut(n){let e;try{e=new URL(n)}catch{throw new Error(`Invalid image URL: ${n}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`Unsupported image URL protocol: ${e.protocol} (only http/https)`);let o;try{o=await fetch(n,{signal:AbortSignal.timeout(Pt)})}catch(l){const u=l instanceof Error?l.message:String(l);throw new Error(`Image URL fetch failed: ${n} (${u})`)}if(!o.ok)throw new Error(`Image URL fetch failed: ${n} (HTTP ${o.status})`);const t=(o.headers.get("content-type")||"").split(";")[0]?.trim().toLowerCase()||"";if(t&&!t.startsWith("image/"))throw new Error(`URL did not return an image (content-type: ${t}): ${n}`);const i=Number(o.headers.get("content-length")||"");if(Number.isFinite(i)&&i>A)throw new Error(`Image too large to fetch: ${n} (${S(i)} > ${S(A)})`);const a=o.body;if(!a){const l=await o.arrayBuffer();if(l.byteLength>A)throw new Error(`Image too large to fetch: ${n} (${S(l.byteLength)} > ${S(A)})`);return Buffer.from(l)}const s=a.getReader(),r=[];let c=0;for(;;){const{done:l,value:u}=await s.read();if(l)break;if(u){if(c+=u.byteLength,c>A)throw s.cancel().catch(()=>{}),new Error(`Image too large to fetch: ${n} (${S(c)} > ${S(A)})`);r.push(Buffer.from(u))}}return Buffer.concat(r,c)}async function Dt(n,e,o,t="auto"){let i,a;if(z(e))i=await Ut(e),a=e;else{const x=(await tt(n,e,o)).targetPath,k=await p.stat(x);if(!k.isFile())throw new Error(`Path is not a file: ${x}`);if(k.size>J)throw new Error(`Image file too large to read: ${$(x)} (${S(k.size)} > ${S(J)}). Downscale it first.`);i=await p.readFile(x),a=$(x)}if(i.length===0)throw new Error(`Image file is empty: ${a}`);const s=pt(i);if(!s)throw new Error(`Unsupported or corrupt image (unrecognized format): ${a}`);const r=gt(i);let c=s,l=i,u=r?.width,w=r?.height,g=null;if(t!==!1){const b=await wt(i,s,{normalMaxBytes:xt,clearMaxBytes:Tt});b?.compressed&&(l=b.buffer,c=b.mediaType,u=b.width,w=b.height,g={level:b.level,originalSize:b.originalSize})}let _=!1;const y=await _t(l,c,{maxWidth:C,maxHeight:C,maxBytes:D});if(y)l=y.buffer,c=y.mediaType,u=y.width,w=y.height,_=y.changed;else if(l.length>D)throw new Error(`Image too large to inline: ${a} (${S(l.length)} > ${S(D)}). Downscale it first, e.g. via Bash: magick "${e}" -resize ${C}x${C} "${e}". Installing sharp enables automatic downscaling.`);const h=u&&w?`${u}x${w}`:"unknown dimensions",P=_&&r&&r.width!==u?` (resized from ${r.width}x${r.height})`:_?" (resized)":"",m=g!==null?g.level:null,v=g!==null?Math.max(1,Math.round((1-l.length/g.originalSize)*100)):0,E=g!==null?`${S(l.length)} (compressed from ${S(g.originalSize)}, saved ${v}%, ${m} level)`:S(l.length),T=`[Image: ${a}, ${h}${P}, ${E}]`,f=z(e)?d.basename(new URL(e).pathname)||"image":d.basename(a);return{ok:!0,filePath:a,content:T,isBinary:!1,image:{mediaType:K(c),width:u??null,height:w??null,originalWidth:r?.width??null,originalHeight:r?.height??null,resized:_,size:l.length,compressed:g!==null,compressionLevel:m,compressionRatio:g!==null?Math.round((1-l.length/g.originalSize)*100)/100:null,originalSize:i.length},attachments:[{type:"image",name:f,mediaType:K(c),base64Data:l.toString("base64")}]}}function ot(n){let e="",o=0;for(;o<n.length;){const t=n[o];if(t==="*")e+="[^/]*";else if(t==="?")e+="[^/]";else if(t==="{"){const i=n.indexOf("}",o);if(i>=0){const a=n.slice(o+1,i);e+=`(${a.split(",").join("|")})`,o=i}else e+="\\{"}else if(t==="["){const i=n.indexOf("]",o);i>=0?(e+=n.slice(o,i+1),o=i):e+="\\["}else"+^$.()|\\".includes(t)?e+="\\"+t:e+=t;o++}return new RegExp(`^${e}$`)}async function Wt(n,e,o,t){const i=[];async function a(s){if(i.length>=t)return;const r=await p.readdir(s,{withFileTypes:!0});for(const c of r){if(i.length>=t)return;if(c.name.startsWith(".")&&c.isDirectory())continue;const l=d.join(s,c.name);if(c.isDirectory()){if(It.has(c.name))continue;await a(l)}else if(c.isFile()){if(e&&!e.test(c.name)||o&&o.test(c.name))continue;i.push(l)}}}return await a(n),i}async function zt(n,e,o){if((await p.stat(n)).size>$t)return{matches:[],count:0};if(await Q(n))return{matches:[],count:0};const i=d.relative(e,n).replace(/\\/g,"/"),a=[];let s=0;const r=X(n,{encoding:"utf-8"}),c=Y.createInterface({input:r,crlfDelay:1/0});try{let l=0;for await(const u of c)if(l++,o.regex.test(u)){if(s++,o.collectContent){let w=u;if(w.length>L&&(w=w.slice(0,L)+`... (line truncated to ${L} chars)`),a.push({file:i,line:l,content:w}),a.length>=o.maxResults)break}if(o.stopOnFirstMatch)break}}finally{c.close(),r.destroy()}return{matches:a,count:s}}const qt=12*60*6e4,jt=30*6e4,Gt=6e4,Xt=10*6e4;function Yt(n,e,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 i=M(t,["file_path","filePath"],"file_path"),a=M(t,["content"],"content"),s=R(t,["reason"]),r=await B(n,i);await N(o,"fileModification",{operation:"write",path:r.targetPath});const c=await Z(r.targetPath),l=c?await p.readFile(r.targetPath,"utf-8").catch(()=>null):null,u=await et(n,i,a);if(e){const w=d.relative(u.workspaceRoot,u.targetPath).replace(/\\/g,"/");await e({filePath:w,operation:c?"UPDATE":"CREATE",beforeContent:l,afterContent:a,reason:s})}return{ok:!0,filePath:$(u.targetPath),bytes:u.bytes,createdParentDirectory:u.createdParentDirectory}}}}function Ht(n,e,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 i=M(t,["file_path","filePath"],"file_path"),a=M(t,["old_string","oldString"],"old_string"),s=M(t,["new_string","newString"],"new_string"),r=R(t,["reason"]);if(!a)throw new Error("old_string must not be empty");const c=await B(n,i);await N(o,"fileModification",{operation:"edit",path:c.targetPath});const l=await Ft(n,i),u=Ot(l.content,a);if(u===0)throw new Error("old_string was not found in file");if(u>1)throw new Error(`old_string occurs ${u} times; provide a unique match`);const w=l.content.replace(a,s),g=await et(n,i,w);if(e){const _=d.relative(g.workspaceRoot,g.targetPath).replace(/\\/g,"/");await e({filePath:_,operation:"UPDATE",beforeContent:l.content,afterContent:w,reason:r})}return{ok:!0,filePath:$(g.targetPath),bytes:g.bytes}}}}function Kt(n,e,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 i=M(t,["file_path","filePath"],"file_path"),a=R(t,["reason"]),s=await B(n,i);await N(o,"fileModification",{operation:"delete",path:s.targetPath});const r=O(s.workspaceRoot,await p.realpath(s.targetPath).catch(()=>s.targetPath)),c=await p.stat(r).catch(()=>null);if(!c)throw new Error(`File does not exist: ${r}`);if(!c.isFile())throw new Error(`Path is not a file: ${r}`);const l=await p.readFile(r,"utf-8").catch(()=>null);if(await p.rm(r,{force:!0}),e){const u=d.relative(s.workspaceRoot,r).replace(/\\/g,"/");await e({filePath:u,operation:"DELETE",beforeContent:l,afterContent:null,reason:a})}return{ok:!0,filePath:$(r),deleted:!0}}}}function Vt(n,e){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. Images (.png/.jpg/.jpeg/.gif/.webp) and http(s) image URLs are also supported: the image is inlined into the conversation so you can see it (requires a model with image input). offset/limit are ignored for images. By default (compress='auto') images are compressed before inlining using a tiered ladder that judges by the compressed result, not the original size: lossless first (pixel-exact, dimensions preserved), then high-quality lossy downscaling only if the lossless result is still over 50 KB (normal level), then more aggressive downscaling if still over 100 KB (clear level). When compression applies, the result reports the compression level, compressed size, and compression ratio (e.g. saved 80%). Pass compress=true to also attempt compression, or compress=false to disable it (images exceeding the hard 2000px / 3.75MB inline limits are still auto-downscaled when sharp is available).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Workspace-relative file path to read. Also accepts an http(s) URL pointing to an image."},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."},compress:{anyOf:[{type:"boolean"},{type:"string",enum:["auto"]}],description:'Image compression mode (ignored for text files). "auto" (default): compress with a tiered ladder driven by the compressed result \u2014 lossless, then high-quality downscale if still >50 KB, then more aggressive if still >100 KB. true: same as auto. false: skip tiered compression entirely (hard inline limits still apply).'}},required:["file_path"],additionalProperties:!1},async execute(o){const t=M(o,["file_path","filePath"],"file_path"),i=d.extname(t).toLowerCase().slice(1);if(z(t)||Et.has(i))return await Dt(n,t,e,At(o));const a=U(o,["offset"],1),s=U(o,["limit"],yt),r=await Ct(n,t,a,s,e);return{ok:!0,filePath:$(r.targetPath),content:r.content,isBinary:r.isBinary,truncated:r.truncated,totalLines:r.totalLines,shownFromLine:r.shownFromLine,shownToLine:r.shownToLine}}}}function Jt(n,e,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 total timeout (timeout_ms) measured from command start \u2014 by default 30 minutes, after which the process is force-terminated; timeout_ms can raise this (up to 12 hours) or set 0 to disable. The tool returns stdout, stderr, exit code, and (if converted to background) a task_id. 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 moved to the BACKGROUND and the tool returns a task_id plus an explanation (backgrounded=true, reason=watchdog_timeout). The background command stays bound by the same total timeout (timeout_ms, default 30 minutes, still measured from command start) and can be managed via await_complete / list_background_commands / read_background_output / kill_background_command. For immediate backgrounding use wait_seconds=0, or wait_seconds=n>0 to wait n seconds then background.",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 total command timeout in milliseconds, measured from command start. Defaults to 1800000 (30 minutes) and is capped at 43200000 (12 hours). Set 0 to disable the timeout entirely (run until finished or killed)."},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 moved to the background and a task_id is returned (backgrounded=true, reason=watchdog_timeout). 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. The command remains bound by the total timeout (timeout_ms, default 30 minutes, measured from command start) whether foreground or background; inactivity_timeout_ms is ignored once backgrounded.",minimum:-1},description:{type:"string",description:"Short reason for running this command (what it does and why it is needed), shown to the user in the background commands panel. Always provide a concise reason, e.g. 'Start local dev server for manual verification'."}},required:["command"],additionalProperties:!1},async execute(i,a){const s=M(i,["command"],"command").trim();if(!s)throw new Error("command must not be empty");const r=Lt(i,["timeout_ms","timeoutMs"],jt),c=r===0?0:Math.min(r,qt),l=U(i,["inactivity_timeout_ms","inactivityTimeoutMs"],Gt),u=Math.min(l,Xt),w=R(i,["cwd"]),g=R(i,["description"]),_=await Bt(n,w);await N(t,"commandExecution",{command:s,cwd:$(_.cwd)});const y=i.wait_seconds,P=typeof y=="number"&&Number.isFinite(y)?y:-1;if(o)return await Zt({deps:o,command:s,agentId:e,workspaceRoot:_.workspaceRoot,cwd:_.cwd,timeoutMs:c,inactivityTimeoutMs:u,waitSeconds:P,description:g,onOutput:a?.onOutput,settleSignal:a?.settleSignal});const m=await at({commandText:s,agentId:e,workspaceRoot:_.workspaceRoot,cwd:_.cwd,timeoutMs:c,inactivityTimeoutMs:u,onOutput:a?.onOutput,watchdogSignal:a?.settleSignal}),v={ok:m.exitCode===0&&!m.timedOut,tool:"Bash",command:s,cwd:$(_.cwd),exitCode:m.exitCode,signal:m.signal,timedOut:m.timedOut,inactivityTimedOut:m.inactivityTimedOut,watchdogInterrupted:m.watchdogInterrupted,timeoutMs:c,inactivityTimeoutMs:u,durationMs:m.durationMs,outputSpilled:m.outputSpilled,outputFilePath:m.outputFilePath,outputLineCount:m.outputLineCount,commandFilePath:m.commandFilePath,commandLineCount:m.commandLineCount,stdout:m.stdout,stderr:m.stderr};return m.watchdogInterrupted?{...v,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"+(m.outputFilePath?` (full output spilled to "${m.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."}:v}}}async function Zt(n){const{deps:e,command:o,agentId:t,workspaceRoot:i,cwd:a,timeoutMs:s,inactivityTimeoutMs:r,waitSeconds:c,description:l,onOutput:u,settleSignal:w}=n,g=u?rt({cwd:a,commandLineCount:0,onOutput:u}):void 0;let _=!!g;const y=()=>{_&&(_=!1,g?.close())};try{const{taskId:h,completion:P}=e.manager.startCommand({commandText:o,agentId:t,workspaceRoot:i,cwd:a,description:l,timeoutMs:s,inactivityTimeoutMs:r,onOutput:_?T=>{_&&g?.push(T.stream,T.text)}:void 0,onCompleted:e.emitCompleted});if(c===0)return e.manager.disableInactivityTimeout(t,h),y(),{ok:!0,tool:"Bash",command:o,backgrounded:!0,taskId:h,status:"backgrounded",reason:"immediate",message:`Command moved to background. Use await_complete(bg_cmd_ids=["${h}"]) to block until it finishes, read_background_output(task_id="${h}", mode="tail") to read output, list_background_commands to view all, or kill_background_command(task_id="${h}") to stop.`};const m=c===-1?0:Math.max(0,Math.floor(c*1e3)),v=[P];let E;c!==-1&&v.push(new Promise(T=>{E=setTimeout(()=>T("__timeout__"),m),E.unref?.()})),w&&v.push(w.then(()=>"__settle__"));try{const T=await Promise.race(v);if(T==="__settle__")return e.manager.disableInactivityTimeout(t,h),{ok:!0,tool:"Bash",command:o,backgrounded:!0,taskId:h,status:"backgrounded",reason:"watchdog_timeout",waitedMs:m,message:`Command still running after watchdog timeout; moved to background. Use await_complete(bg_cmd_ids=["${h}"]) to block until it finishes, read_background_output(task_id="${h}", mode="tail") to read output, or kill_background_command(task_id="${h}") to stop.`};if(T==="__timeout__")return e.manager.disableInactivityTimeout(t,h),{ok:!0,tool:"Bash",command:o,backgrounded:!0,taskId:h,status:"backgrounded",reason:"timeout",waitedMs:m,message:`Command still running after ${c}s; moved to background. Use await_complete(bg_cmd_ids=["${h}"]) to block until it finishes, or read_background_output(task_id="${h}", mode="tail") / kill_background_command(task_id="${h}") to inspect.`};const f=T;let b=f.stdout,x=f.stderr,k=f.outputSpilled,F=f.outputFilePath;if(!k&&H(`${f.stdout}${f.stderr}`)>ct){const I=await ut(t,"cmd","out",st({commandText:o,commandFilePath:f.commandFilePath,commandLineCount:f.commandLineCount,cwd:a,startedAt:new Date(Date.now()-f.durationMs),endedAt:new Date,exitCode:f.exitCode,signal:f.signal??null,timedOut:f.timedOut,inactivityTimedOut:f.inactivityTimedOut??!1,stdout:b,stderr:x}));b=lt($(I),H(`${f.stdout}${f.stderr}`)),k=!0,F=$(I)}return{ok:f.exitCode===0&&!f.timedOut,tool:"Bash",command:o,backgrounded:!1,taskId:h,exitCode:f.exitCode,signal:f.signal,timedOut:f.timedOut,inactivityTimedOut:f.inactivityTimedOut,timeoutMs:f.timeoutMs,inactivityTimeoutMs:f.inactivityTimeoutMs,durationMs:f.durationMs,outputSpilled:k,outputFilePath:F,outputLineCount:f.outputLineCount,commandFilePath:f.commandFilePath,commandLineCount:f.commandLineCount,stdout:b,stderr:x}}finally{E&&clearTimeout(E),y()}}catch(h){if(h?.code==="too_many_tasks"||h?.code==="global_limit_reached")return{ok:!1,tool:"Bash",command:o,backgrounded:!1,status:"not_executed",error:h.code,message:`Command was NOT executed: ${h.message}. Wait for some background tasks to finish/cleanup (per-agent limit 16, global 256), or reduce concurrent background commands, then retry.`};throw h}}function Qt(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(e){const o=M(e,["pattern"],"pattern"),t=R(e,["path"])||".",i=R(e,["include"]),a=R(e,["exclude"]),s=e.case_insensitive===!0,r=(()=>{const k=e.output_mode;return k==="files_with_matches"||k==="count"?k:"content"})(),c=U(e,["max_results"],Rt),l=s?"i":"";let u;try{u=new RegExp(o,l)}catch(k){throw new Error(`Invalid regex pattern: ${k instanceof Error?k.message:String(k)}`)}const w=i?ot(i):null,g=a?ot(a):null,_=await B(n,t),y=O(_.workspaceRoot,await p.realpath(_.targetPath)),h=await p.stat(y);let P;if(h.isFile())P=[y];else if(h.isDirectory())P=await Wt(y,w,g,St);else throw new Error(`Path is neither a file nor a directory: ${y}`);const m=[],v=[],E=[];let T=0,f=0,b=!1;for(const k of P){if(r==="content"&&m.length>=c){b=!0;break}const F={regex:u,maxResults:r==="content"?c-m.length:Number.MAX_SAFE_INTEGER,collectContent:r==="content",stopOnFirstMatch:r==="files_with_matches"},I=await zt(k,_.workspaceRoot,F);if(I.count>0){const q=d.relative(_.workspaceRoot,k).replace(/\\/g,"/");if(E.push(q),T+=I.count,r==="content"){for(const j of I.matches){const G=Buffer.byteLength(j.content,"utf-8")+64;if(f+G>Mt){b=!0;break}f+=G,m.push(j)}if(b)break;if(m.length>=c){b=!0;break}}else r==="count"&&v.push({file:q,count:I.count})}}const x={ok:!0,tool:"grep",pattern:o,searchPath:$(_.targetPath),outputMode:r,filesSearched:P.length,filesMatched:E.length,totalMatches:T,truncated:b};return r==="content"?x.matches=m:r==="files_with_matches"?x.matches=E:x.matches=v,x}}}function me(n,e,o,t,i){const a=e||"unknown",s=[Vt(n,i),Yt(n,o,i),Ht(n,o,i),Kt(n,o,i),Qt(n),Jt(n,a,t,i),dt(n)];return t&&s.push(mt(a,t),ht(a,t),ft(a,t)),s}export{de as DEFAULT_TOOL_PERMISSION_POLICY,me as createBuiltInFileTools,O as ensureInsideWorkspace,B as resolveWorkspaceTarget};
4
4
 
@@ -39,14 +39,43 @@ interface SharpLike {
39
39
  png(options?: {
40
40
  compressionLevel?: number;
41
41
  palette?: boolean;
42
+ quality?: number;
43
+ }): SharpLike;
44
+ webp(options?: {
45
+ quality?: number;
46
+ lossless?: boolean;
42
47
  }): SharpLike;
43
48
  toBuffer(): Promise<Buffer>;
44
49
  }
45
- type SharpFactory = (input: Buffer) => SharpLike;
50
+ export type SharpFactory = (input: Buffer) => SharpLike;
46
51
 
47
52
  export declare function resetSharpCacheForTest(): void;
48
53
 
49
54
  export declare function setSharpFactoryForTest(factory: SharpFactory | null): void;
50
55
 
51
56
  export declare function tryResizeWithSharp(input: Buffer, format: ImageFormat, options: ResizeOptions): Promise<SharpResizeResult | null>;
57
+
58
+ export type CompressLevel = "lossy" | "normal" | "clear";
59
+ export interface CompressImageOptions {
60
+
61
+ normalMaxBytes: number;
62
+
63
+ clearMaxBytes: number;
64
+ }
65
+ export interface CompressImageResult {
66
+ buffer: Buffer;
67
+ mediaType: ImageFormat;
68
+ width: number;
69
+ height: number;
70
+
71
+ compressed: boolean;
72
+
73
+ level: CompressLevel | null;
74
+ originalSize: number;
75
+ compressedSize: number;
76
+
77
+ savedPercent: number;
78
+ }
79
+
80
+ export declare function tryCompressImageWithSharp(input: Buffer, format: ImageFormat, options: CompressImageOptions): Promise<CompressImageResult | null>;
52
81
  export {};
@@ -1,2 +1,2 @@
1
- function S(t){return`image/${t}`}function U(t){return t>=1024*1024?`${(t/(1024*1024)).toFixed(2)} MB`:t>=1024?`${(t/1024).toFixed(1)} KB`:`${t} B`}function f(t){return t.length<12?null:t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71?"png":t[0]===255&&t[1]===216&&t[2]===255?"jpeg":t[0]===71&&t[1]===73&&t[2]===70?"gif":t[0]===82&&t[1]===73&&t[2]===70&&t[3]===70&&t[8]===87&&t[9]===69&&t[10]===66&&t[11]===80?"webp":null}function w(t){if(!(t.length<24||t.toString("hex",0,8)!=="89504e470d0a1a0a"))return{width:t.readUInt32BE(16),height:t.readUInt32BE(20)}}function y(t){if(!(t.length<10||t.toString("ascii",0,6)!=="GIF87a"&&t.toString("ascii",0,6)!=="GIF89a"))return{width:t.readUInt16LE(6),height:t.readUInt16LE(8)}}function B(t){if(t.length<4||t[0]!==255||t[1]!==216)return;let n=2;for(;n+9<t.length;){if(t[n]!==255){n+=1;continue}const e=t[n+1],i=t.readUInt16BE(n+2);if(i<2)return;if(e>=192&&e<=207&&![196,200,204].includes(e)&&n+8<t.length)return{height:t.readUInt16BE(n+5),width:t.readUInt16BE(n+7)};n+=2+i}}function I(t){if(t.length<30||t.toString("ascii",0,4)!=="RIFF"||t.toString("ascii",8,12)!=="WEBP")return;const n=t.toString("ascii",12,16);if(n==="VP8X")return{width:1+t.readUIntLE(24,3),height:1+t.readUIntLE(27,3)};if(n==="VP8 ")return{width:t.readUInt16LE(26)&16383,height:t.readUInt16LE(28)&16383};if(n==="VP8L"&&t.length>=25){const e=t.readUInt32LE(21);return{width:(e&16383)+1,height:(e>>14&16383)+1}}}function E(t){const n=f(t);if(!n)return null;const i=(n==="png"?w:n==="gif"?y:n==="jpeg"?B:I)(t);return!i||!i.width||!i.height?null:i}let g;async function F(){return g===void 0&&(g=import("sharp").then(n=>{const e=n,i=typeof e=="function"?e:e.default;return typeof i=="function"?i:null}).catch(()=>null)),g}function M(){g=void 0}function T(t){g=Promise.resolve(t)}async function W(t,n,e){const i=await F();if(!i)return null;try{const o=await i(t).metadata();let d=o.width??0,s=o.height??0;if(!d||!s){const h=E(t);d=h?.width??0,s=h?.height??0}const x=d>0&&s>0,u=x&&d<=e.maxWidth&&s<=e.maxHeight;if(u&&t.length<=e.maxBytes)return{buffer:t,mediaType:n,width:d,height:s,changed:!1};if(u){if(n==="png"){const h=await i(t).png({compressionLevel:9,palette:!0}).toBuffer();if(h.length<=e.maxBytes)return{buffer:h,mediaType:"png",width:d,height:s,changed:!0}}for(const h of[80,60,40,20]){const c=await i(t).jpeg({quality:h}).toBuffer();if(c.length<=e.maxBytes)return{buffer:c,mediaType:"jpeg",width:d,height:s,changed:!0}}}let r=x?d:e.maxWidth,a=x?s:e.maxHeight;r>e.maxWidth&&(a=Math.round(a*e.maxWidth/r),r=e.maxWidth),a>e.maxHeight&&(r=Math.round(r*e.maxHeight/a),a=e.maxHeight),r=Math.max(1,r),a=Math.max(1,a);const m={fit:"inside",withoutEnlargement:!0};if(n==="png"){const h=await i(t).resize(r,a,m).png({compressionLevel:9,palette:!0}).toBuffer();if(h.length<=e.maxBytes)return{buffer:h,mediaType:"png",width:r,height:a,changed:!0}}for(const h of[80,60,40,20]){const c=await i(t).resize(r,a,m).jpeg({quality:h}).toBuffer();if(c.length<=e.maxBytes)return{buffer:c,mediaType:"jpeg",width:r,height:a,changed:!0}}const l=Math.min(r,1e3),p=Math.max(1,Math.round(a*l/Math.max(r,1)));return{buffer:await i(t).resize(l,p,m).jpeg({quality:20}).toBuffer(),mediaType:"jpeg",width:l,height:p,changed:!0}}catch{return null}}export{f as detectImageFormatFromBuffer,U as formatBytes,S as imageMediaType,E as readImageDimensions,M as resetSharpCacheForTest,T as setSharpFactoryForTest,W as tryResizeWithSharp};
1
+ function q(e){return`image/${e}`}function W(e){return e>=1024*1024?`${(e/(1024*1024)).toFixed(2)} MB`:e>=1024?`${(e/1024).toFixed(1)} KB`:`${e} B`}function S(e){return e.length<12?null:e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71?"png":e[0]===255&&e[1]===216&&e[2]===255?"jpeg":e[0]===71&&e[1]===73&&e[2]===70?"gif":e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70&&e[8]===87&&e[9]===69&&e[10]===66&&e[11]===80?"webp":null}function D(e){if(!(e.length<24||e.toString("hex",0,8)!=="89504e470d0a1a0a"))return{width:e.readUInt32BE(16),height:e.readUInt32BE(20)}}function F(e){if(!(e.length<10||e.toString("ascii",0,6)!=="GIF87a"&&e.toString("ascii",0,6)!=="GIF89a"))return{width:e.readUInt16LE(6),height:e.readUInt16LE(8)}}function v(e){if(e.length<4||e[0]!==255||e[1]!==216)return;let i=2;for(;i+9<e.length;){if(e[i]!==255){i+=1;continue}const r=e[i+1],l=e.readUInt16BE(i+2);if(l<2)return;if(r>=192&&r<=207&&![196,200,204].includes(r)&&i+8<e.length)return{height:e.readUInt16BE(i+5),width:e.readUInt16BE(i+7)};i+=2+l}}function z(e){if(e.length<30||e.toString("ascii",0,4)!=="RIFF"||e.toString("ascii",8,12)!=="WEBP")return;const i=e.toString("ascii",12,16);if(i==="VP8X")return{width:1+e.readUIntLE(24,3),height:1+e.readUIntLE(27,3)};if(i==="VP8 ")return{width:e.readUInt16LE(26)&16383,height:e.readUInt16LE(28)&16383};if(i==="VP8L"&&e.length>=25){const r=e.readUInt32LE(21);return{width:(r&16383)+1,height:(r>>14&16383)+1}}}function B(e){const i=S(e);if(!i)return null;const l=(i==="png"?D:i==="gif"?F:i==="jpeg"?v:z)(e);return!l||!l.width||!l.height?null:l}let x;async function M(){return x===void 0&&(x=import("sharp").then(i=>{const r=i,l=typeof r=="function"?r:r.default;return typeof l=="function"?l:null}).catch(()=>null)),x}function R(){x=void 0}function H(e){x=Promise.resolve(e)}async function O(e,i,r){const l=await M();if(!l)return null;try{const p=await l(e).metadata();let g=p.width??0,c=p.height??0;if(!g||!c){const d=B(e);g=d?.width??0,c=d?.height??0}const a=g>0&&c>0,h=a&&g<=r.maxWidth&&c<=r.maxHeight;if(h&&e.length<=r.maxBytes)return{buffer:e,mediaType:i,width:g,height:c,changed:!1};if(h){if(i==="png"){const d=await l(e).png({compressionLevel:9,palette:!0}).toBuffer();if(d.length<=r.maxBytes)return{buffer:d,mediaType:"png",width:g,height:c,changed:!0}}for(const d of[80,60,40,20]){const m=await l(e).jpeg({quality:d}).toBuffer();if(m.length<=r.maxBytes)return{buffer:m,mediaType:"jpeg",width:g,height:c,changed:!0}}}let n=a?g:r.maxWidth,t=a?c:r.maxHeight;n>r.maxWidth&&(t=Math.round(t*r.maxWidth/n),n=r.maxWidth),t>r.maxHeight&&(n=Math.round(n*r.maxHeight/t),t=r.maxHeight),n=Math.max(1,n),t=Math.max(1,t);const s={fit:"inside",withoutEnlargement:!0};if(i==="png"){const d=await l(e).resize(n,t,s).png({compressionLevel:9,palette:!0}).toBuffer();if(d.length<=r.maxBytes)return{buffer:d,mediaType:"png",width:n,height:t,changed:!0}}for(const d of[80,60,40,20]){const m=await l(e).resize(n,t,s).jpeg({quality:d}).toBuffer();if(m.length<=r.maxBytes)return{buffer:m,mediaType:"jpeg",width:n,height:t,changed:!0}}const o=Math.min(n,1e3),u=Math.max(1,Math.round(t*o/Math.max(n,1)));return{buffer:await l(e).resize(o,u,s).jpeg({quality:20}).toBuffer(),mediaType:"jpeg",width:o,height:u,changed:!0}}catch{return null}}const U=2e3,j=1e3;async function I(e){try{const i=await e();return i.length>0?i:null}catch{return null}}async function P(e,i,r){const l=await M();if(!l)return null;try{if(i==="gif")return c(null);const a=await p(l,e,i);if(a!==null&&a.buffer.length<=r.normalMaxBytes)return c({...a,level:"lossy"});const h=a!==null?{buffer:a.buffer,mediaType:a.mediaType}:{buffer:e,mediaType:i},n=await g(l,h.buffer,h.mediaType,{maxBytes:r.normalMaxBytes,targetDimension:U,qualityBias:"high"});if(n!==null&&n.buffer.length<=r.clearMaxBytes)return c({...n,level:"normal"});const t=n!==null?{buffer:n.buffer,mediaType:n.mediaType}:{buffer:h.buffer,mediaType:h.mediaType},s=await g(l,t.buffer,t.mediaType,{maxBytes:r.clearMaxBytes,targetDimension:j,qualityBias:"low"});return c(s!==null?{...s,level:"clear"}:n!==null?{...n,level:"normal"}:a!==null?{...a,level:"lossy"}:null)}catch{return null}async function p(a,h,n){const t=[];n==="png"?(t.push({mediaType:"png",encode:()=>a(h).png({compressionLevel:9}).toBuffer()}),t.push({mediaType:"webp",encode:()=>a(h).webp({lossless:!0}).toBuffer()})):n==="webp"&&t.push({mediaType:"webp",encode:()=>a(h).webp({lossless:!0}).toBuffer()});let s=null;for(const o of t){const u=await I(o.encode);u&&u.length<h.length&&(!s||u.length<s.buffer.length)&&(s={buffer:u,mediaType:o.mediaType})}return s}async function g(a,h,n,t){let s=B(h)?.width??0,o=B(h)?.height??0;s>t.targetDimension&&(o=Math.round(o*t.targetDimension/s),s=t.targetDimension),o>t.targetDimension&&(s=Math.round(s*t.targetDimension/o),o=t.targetDimension),s=Math.max(1,s),o=Math.max(1,o);const u={fit:"inside",withoutEnlargement:!0},T=n==="gif"?"png":n,d=[],m=t.qualityBias==="high"?[90,80,70]:[60,50,40],E=t.qualityBias==="high"?[80,70,60]:[50,40,30],L=t.qualityBias==="high"?[80,70,60]:[50,40,30];if(T==="png")for(const f of m)d.push({mediaType:"png",encode:()=>a(h).resize(s,o,u).png({compressionLevel:9,palette:!0,quality:f}).toBuffer()});for(const f of E)d.push({mediaType:"webp",encode:()=>a(h).resize(s,o,u).webp({quality:f}).toBuffer()});if(T!=="webp")for(const f of L)d.push({mediaType:"jpeg",encode:()=>a(h).resize(s,o,u).jpeg({quality:f}).toBuffer()});let y=null;for(const f of d){const w=await I(f.encode);if(w&&w.length<h.length&&((!y||w.length<y.buffer.length)&&(y={buffer:w,mediaType:f.mediaType}),y.buffer.length<=t.maxBytes))break}return y}function c(a){const h=B(e),n=a!==null,t=n?a.buffer:e,s=n?Math.max(0,Math.round((1-t.length/e.length)*100)):0;return{buffer:t,mediaType:n?a.mediaType:i,width:h?.width??0,height:h?.height??0,compressed:n,level:n?a.level:null,originalSize:e.length,compressedSize:t.length,savedPercent:s}}}export{S as detectImageFormatFromBuffer,W as formatBytes,q as imageMediaType,B as readImageDimensions,R as resetSharpCacheForTest,H as setSharpFactoryForTest,P as tryCompressImageWithSharp,O as tryResizeWithSharp};
2
2
 
@@ -0,0 +1,3 @@
1
+ import { type ShellExecutable } from "./builtins/shellCommandPreparation.js";
2
+
3
+ export declare function buildRuntimeEnvironmentPrompt(platform?: NodeJS.Platform, release?: string, shell?: ShellExecutable): string;
@@ -0,0 +1,3 @@
1
+ import r from"node:os";import m from"node:path";import{shellExecutable as a}from"./builtins/shellCommandPreparation.js";function c(n=process.platform,o=r.release(),i=a()){const s=n==="win32"?"Windows":n==="darwin"?"macOS":n==="linux"?"Linux":n,e=m.basename(i.command).toLowerCase(),l=n==="win32"?`Shell: ${e} (Windows) \u2014 commands run in a Windows shell, not a POSIX shell; Unix-only commands (rm, grep, sed, ...) may be unavailable, prefer Windows equivalents (rd, findstr, ...) or the built-in file tools.`:`Shell: ${e} \u2014 commands run in a POSIX shell.`;return["[Runtime Environment]",`Platform: ${s} (${n}, release ${o})`,l].join(`
2
+ `)}export{c as buildRuntimeEnvironmentPrompt};
3
+