@code-yeongyu/senpi 2026.11.15-2 → 2026.11.15-3
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.
- package/CHANGELOG.md +19 -0
- package/dist/bundle/chunks/{chunk-Q4RJ4WLE.js → chunk-225TDKTA.js} +4 -4
- package/dist/bundle/chunks/{chunk-QSU2456D.js → chunk-3KR3CDGM.js} +1 -1
- package/dist/bundle/chunks/{chunk-AOTHPTMU.js → chunk-5GCZFK4X.js} +2 -2
- package/dist/bundle/chunks/{chunk-BMADOJHZ.js → chunk-5QIFH624.js} +1 -1
- package/dist/bundle/chunks/{chunk-THYIV26N.js → chunk-GQEXLLWJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-3RILB2OD.js → chunk-OJOPOUAY.js} +9 -9
- package/dist/bundle/chunks/{chunk-64FJ4QQJ.js → chunk-PPCAJQDJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-74HCKLRH.js → chunk-TEXE4HT6.js} +1 -1
- package/dist/bundle/chunks/{chunk-RRFDLGX6.js → chunk-TNYFCGI7.js} +156 -156
- package/dist/bundle/chunks/{cli-main-GNQY2LTU.js → cli-main-CV3ODX4A.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-D3DNH6XL.js → hand-entry-2NN7ZTY6.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-ATBPY4M5.js → interactive-mode-TGHZWM2T.js} +1 -1
- package/dist/bundle/chunks/{main-OMFVSMUR.js → main-B7WEY4JW.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-ACQ5N4UB.js → multi-session-host-53YLL2OD.js} +1 -1
- package/dist/bundle/chunks/{package-manager-cli-2VMRV4HL.js → package-manager-cli-2U54AVKW.js} +1 -1
- package/dist/bundle/chunks/{role-BTH5PVME.js → role-4IXZZAL4.js} +1 -1
- package/dist/bundle/chunks/{rpc-mode-XUK5SYKH.js → rpc-mode-RRYXENML.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-VO3X4OE3.js → runtime-session-KKHEYZOH.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-Y5EIFFPY.js → session-control-endpoint-HVULSIUR.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +331 -331
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session.d.ts +6 -0
- package/dist/core/agent-session.js +34 -3
- package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.d.ts +2 -0
- package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/failover.d.ts +2 -0
- package/dist/core/extensions/builtin/anthropic-subscription/failover.js +22 -4
- package/dist/core/extensions/builtin/anthropic-subscription/index.js +7 -2
- package/dist/core/extensions/builtin/anthropic-subscription/limit-recheck.d.ts +15 -0
- package/dist/core/extensions/builtin/anthropic-subscription/limit-recheck.js +55 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.d.ts +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +1 -0
- package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +8 -5
- package/dist/core/extensions/builtin/anthropic-subscription/stream.d.ts +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/stream.js +3 -1
- package/dist/core/extensions/builtin/terminal/extension-state.js +15 -0
- package/dist/core/extensions/builtin/terminal/notify.d.ts +2 -1
- package/dist/core/extensions/builtin/terminal/notify.js +15 -6
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +5 -1
- package/dist/core/extensions/builtin/terminal/session-bundle.js +41 -1
- package/dist/core/extensions/builtin/terminal/tools/context.d.ts +4 -0
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.js +5 -0
- package/dist/core/extensions/types.d.ts +7 -0
- package/dist/core/run-background-jobs.d.ts +33 -0
- package/dist/core/run-background-jobs.js +47 -0
- package/dist/core/tools/bash-core.d.ts +50 -0
- package/dist/core/tools/bash-core.js +169 -0
- package/dist/core/tools/bash-schema.d.ts +48 -0
- package/dist/core/tools/bash-schema.js +34 -0
- package/dist/core/tools/bash.d.ts +4 -70
- package/dist/core/tools/bash.js +32 -409
- package/dist/core/tools/coding-tools-core.d.ts +24 -0
- package/dist/core/tools/coding-tools-core.js +14 -0
- package/dist/core/tools/edit-core.d.ts +56 -0
- package/dist/core/tools/edit-core.js +175 -0
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.js +0 -32
- package/dist/core/tools/edit-preview.d.ts +7 -0
- package/dist/core/tools/edit-preview.js +34 -0
- package/dist/core/tools/edit.d.ts +5 -43
- package/dist/core/tools/edit.js +10 -158
- package/dist/core/tools/encoding.d.ts +10 -0
- package/dist/core/tools/encoding.js +58 -0
- package/dist/core/tools/file-tool-host.d.ts +25 -0
- package/dist/core/tools/file-tool-host.js +109 -0
- package/dist/core/tools/fs-error-code.d.ts +2 -0
- package/dist/core/tools/fs-error-code.js +15 -0
- package/dist/core/tools/machine-output-spill.d.ts +11 -0
- package/dist/core/tools/machine-output-spill.js +65 -0
- package/dist/core/tools/machine.d.ts +4 -24
- package/dist/core/tools/machine.js +4 -44
- package/dist/core/tools/output-accumulator-core.d.ts +84 -0
- package/dist/core/tools/output-accumulator-core.js +200 -0
- package/dist/core/tools/output-accumulator.d.ts +9 -61
- package/dist/core/tools/output-accumulator.js +90 -265
- package/dist/core/tools/path-utils.js +3 -48
- package/dist/core/tools/posix-signals.d.ts +3 -0
- package/dist/core/tools/posix-signals.js +113 -0
- package/dist/core/tools/read-core.d.ts +64 -0
- package/dist/core/tools/read-core.js +180 -0
- package/dist/core/tools/read-text.d.ts +23 -0
- package/dist/core/tools/read-text.js +90 -0
- package/dist/core/tools/read.d.ts +6 -47
- package/dist/core/tools/read.js +13 -218
- package/dist/core/tools/renderers/bash.d.ts +0 -1
- package/dist/core/tools/renderers/bash.js +0 -1
- package/dist/core/tools/renderers/edit.d.ts +1 -1
- package/dist/core/tools/renderers/edit.js +1 -1
- package/dist/core/tools/secret-output-redactor.js +2 -1
- package/dist/core/tools/shell-operations.d.ts +53 -0
- package/dist/core/tools/shell-operations.js +115 -0
- package/dist/core/tools/shell-output.d.ts +20 -0
- package/dist/core/tools/shell-output.js +152 -0
- package/dist/core/tools/tail-window.js +5 -7
- package/dist/core/tools/tool-machine.d.ts +30 -0
- package/dist/core/tools/tool-machine.js +47 -0
- package/dist/core/tools/truncate.js +15 -14
- package/dist/core/tools/write-core.d.ts +47 -0
- package/dist/core/tools/write-core.js +108 -0
- package/dist/core/tools/write-result.d.ts +0 -1
- package/dist/core/tools/write-result.js +0 -13
- package/dist/core/tools/write.d.ts +6 -31
- package/dist/core/tools/write.js +25 -77
- package/dist/core/turn-origin.d.ts +4 -2
- package/dist/core/turn-origin.js +15 -8
- package/dist/modes/interactive/session-control-session-commands.js +1 -1
- package/dist/modes/rpc/connection-handler.js +2 -2
- package/dist/modes/rpc/effect-commands.d.ts +1 -4
- package/dist/modes/rpc/method-classes-schema-session.d.ts +1 -0
- package/dist/modes/rpc/method-classes-schema-session.js +5 -1
- package/dist/modes/rpc/method-classes-schema.d.ts +1 -0
- package/dist/modes/rpc/pause-command-validation.js +2 -0
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +2 -4
- package/dist/modes/rpc/rpc-session-command-types.d.ts +1 -0
- package/dist/modes/rpc/session-control-actions-data.d.ts +7 -3
- package/dist/modes/rpc/session-control-actions-data.js +12 -6
- package/dist/tools-core.d.ts +14 -0
- package/dist/tools-core.js +9 -0
- package/dist/utils/image-mime.d.ts +4 -0
- package/dist/utils/image-mime.js +99 -0
- package/dist/utils/mime.d.ts +1 -1
- package/dist/utils/mime.js +2 -97
- package/docs/extensions.md +7 -1
- package/docs/rpc.md +14 -0
- package/package.json +11 -7
- package/vendor/senpi-machine-ops/files/local-files.js +34 -5
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{Text,truncateToWidth,visibleWidth}from"./chunk-4PMRUR4L.js";import{rotateLogIfNeeded}from"./chunk-LPYBKMPT.js";import{getShellConfig}from"./chunk-ZJUL5ODW.js";import{engineTrustAction}from"./chunk-R7J5TEYK.js";import{redactSecrets}from"./chunk-62OVOJPI.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId,isStaleExtensionContextError}from"./chunk-IHES3JES.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-SODMQEHO.js";import{typebox_exports}from"./chunk-MIENF2YK.js";import{TOOL_CHILD_LEDGER_ENV,TOOL_CHILD_REENTRY_ENV,TOOL_CHILD_REFS_ROOT_ENV,rememberToolChildReentry,scrubToolChildEnv,toolChildReentry}from"./chunk-OXNWERO4.js";import{BACKGROUND_START_GRACE_MS,DEFAULT_COLS,DEFAULT_MAX_SESSIONS,DEFAULT_ROWS,FOREGROUND_ENV_OVERRIDES,KILLED_SESSION_EXIT_GRACE_MS,SecretOutputRedactor,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,encodeKeys,loadPty,safeRegExp}from"./chunk-AOTHPTMU.js";import{processIsRunning,processStartTimeMs,readProcessStartTime,sameProcessStartMs}from"./chunk-O5RYI3IW.js";import{adoptedEngineTrust}from"./chunk-RFFMEA4B.js";var ToolChildJobError=class extends Error{constructor(code,message){super(message),this.code=code,this.name="ToolChildJobError"}};var WakeAdmissionError=class extends Error{constructor(bytes){super(`wake_too_large: ${bytes} bytes exceeds the ${TOOL_CHILD_LIMITS.wakePendingBytes}-byte pending budget`),this.code="wake_too_large",this.name="WakeAdmissionError"}},WakeAdmission=class{#pending=new Map;#blocked=[];#pendingBytes=0;get pending(){return this.#pending.size}get blocked(){return this.#blocked.length}send(wakeId,bytes){return bytes>TOOL_CHILD_LIMITS.wakePendingBytes?Promise.reject(new WakeAdmissionError(bytes)):this.#blocked.length===0&&this.#fits(bytes)?(this.#admit(wakeId,bytes),Promise.resolve()):new Promise(release=>{this.#blocked.push({wakeId,bytes,release})})}ack(wakeId){let bytes=this.#pending.get(wakeId);if(bytes!==void 0){this.#pending.delete(wakeId),this.#pendingBytes-=bytes;for(let next=this.#blocked[0];next!==void 0&&this.#fits(next.bytes);next=this.#blocked[0])this.#blocked.shift(),this.#admit(next.wakeId,next.bytes),next.release()}}#fits(bytes){return this.#pending.size<TOOL_CHILD_LIMITS.wakePending&&this.#pendingBytes+bytes<=TOOL_CHILD_LIMITS.wakePendingBytes}#admit(wakeId,bytes){this.#pending.set(wakeId,bytes),this.#pendingBytes+=bytes}};function hostCallCapacity(){return TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE+TOOL_CHILD_LIMITS.HOST_CALL_WAITING}var HostCallAdmission=class{#active=new Set;#waiting=[];get active(){return this.#active.size}get waiting(){return this.#waiting.length}submit(callId){return this.#active.has(callId)||this.#waiting.includes(callId)?refuse(callId,"host_call_duplicate"):this.#active.size<TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE&&this.#waiting.length===0?(this.#active.add(callId),{state:"active"}):this.#active.size+this.#waiting.length>=hostCallCapacity()?refuse(callId,"host_call_capacity"):(this.#waiting.push(callId),{state:"waiting"})}settle(callId){if(!this.#active.delete(callId)){let index=this.#waiting.indexOf(callId);index>=0&&this.#waiting.splice(index,1);return}let next=this.#waiting.shift();return next!==void 0&&this.#active.add(next),next}};function refuse(callId,code){return{state:"refused",frame:{type:"host_call_refused",callId,code}}}import{createHash,randomBytes}from"node:crypto";import{createReadStream}from"node:fs";import{mkdir,readFile,rm as rm2,stat,writeFile}from"node:fs/promises";import{dirname}from"node:path";import{readdir,rm}from"node:fs/promises";import{join}from"node:path";function refGenerationDir(root,generation){return join(root,`gen-${generation}`)}function refFilePath(root,ref){if(!isRefId(ref.refId))throw new Error(`invalid ref id: ${JSON.stringify(ref.refId)}`);return join(refGenerationDir(root,ref.generation),"refs",ref.refId)}async function teardownRefGeneration(root,generation){await rm(refGenerationDir(root,generation),{recursive:!0,force:!0})}var PayloadRefError=class extends Error{constructor(code,message,reason){super(`${code}: ${message}`),this.name="PayloadRefError",this.code=code,this.reason=reason}},PayloadRefWriter=class{#root;#now;#pending=new Map;#ownedBytes=0;constructor(options){this.generation=options.generation,this.budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#root=options.root,this.#now=options.now??Date.now}get ownedBytes(){return this.#ownedBytes}async create(payload){let size=payload.byteLength;if(this.#ownedBytes+size>this.budget)throw new PayloadRefError("ref_budget_exceeded",`${size} bytes on top of ${this.#ownedBytes} owned exceeds ${this.budget}`);this.#ownedBytes+=size;let ref={refId:randomBytes(12).toString("hex"),generation:this.generation,bytes:size,sha256:createHash("sha256").update(payload).digest("hex")},path=refFilePath(this.#root,ref);try{await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,payload,{flag:"wx",mode:384})}catch(error){throw this.#ownedBytes-=size,await rm2(path,{force:!0}),error}return this.#pending.set(ref.refId,{bytes:size,createdAtMs:this.#now()}),ref}async handle(control){let pending=this.#pending.get(control.refId);pending!==void 0&&(this.#pending.delete(control.refId),this.#ownedBytes-=pending.bytes,control.type==="ref_nack"&&await rm2(refFilePath(this.#root,{refId:control.refId,generation:this.generation}),{force:!0}))}pendingIds(){return[...this.#pending.keys()]}overdue(){let deadline=this.#now()-TOOL_CHILD_LIMITS.refAckMs;return[...this.#pending].filter(([,ref])=>ref.createdAtMs<=deadline).map(([refId])=>refId)}async teardown(){this.#pending.clear(),this.#ownedBytes=0,await teardownRefGeneration(this.#root,this.generation)}},isMissingFile=error=>error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ENOTDIR");async function hashFile(path,signal){let hash=createHash("sha256");for await(let chunk of createReadStream(path)){if(signal?.aborted)return"cancelled";hash.update(chunk)}return hash.digest("hex")}var PayloadRefReader=class{#root;#generation;#budget;#send;#owned=new Map;#ownedBytes=0;constructor(options){this.#root=options.root,this.#generation=options.generation,this.#budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#send=options.send}async accept(ref,signal){let reason=await this.#verify(ref,signal);return reason!==void 0?(this.refuse(ref,reason),{ok:!1,reason}):(this.#owned.set(ref.refId,ref),this.#ownedBytes+=ref.bytes,this.#send({type:"ref_ack",refId:ref.refId}),{ok:!0})}refuse(ref,reason){this.#owned.has(ref.refId)||this.#send({type:"ref_nack",refId:ref.refId,reason})}async consume(refId){let ref=this.#owned.get(refId);if(ref===void 0)throw new PayloadRefError("ref_not_owned",`ref ${refId} is not owned by this side`);let path=refFilePath(this.#root,ref),bytes=await readFile(path);return await rm2(path,{force:!0}),this.#owned.delete(refId),this.#ownedBytes-=ref.bytes,bytes}ownedIds(){return[...this.#owned.keys()]}async#verify(ref,signal){if(signal?.aborted)return"cancelled";if(ref.generation!==this.#generation||!isRefId(ref.refId)||this.#owned.has(ref.refId))return"foreign";if(this.#ownedBytes+ref.bytes>this.#budget)return"budget";let path=refFilePath(this.#root,ref);try{if((await stat(path)).size!==ref.bytes)return"corrupt";let digest=await hashFile(path,signal);return digest==="cancelled"?"cancelled":digest===ref.sha256?void 0:"corrupt"}catch(error){if(isMissingFile(error))return"missing";throw error}}};async function packPayload(value,writer){let normalized=value===void 0?null:value,json=JSON.stringify(normalized);return json===void 0||Buffer.byteLength(json,"utf8")<=TOOL_CHILD_LIMITS.REF_THRESHOLD?{inline:!0,value:normalized}:{inline:!1,ref:await writer.create(Buffer.from(json,"utf8"))}}async function unpackPayload(ref,reader,signal){let acceptance=await reader.accept(ref,signal);if(!acceptance.ok)throw new PayloadRefError("ref_rejected",`ref ${ref.refId} was refused (${acceptance.reason})`,acceptance.reason);let bytes=await reader.consume(ref.refId);return JSON.parse(Buffer.from(bytes.buffer,bytes.byteOffset,bytes.byteLength).toString("utf8"))}var ChildHostCalls=class{#channel;#admissions=new Map;#pending=new Map;#refs;#next=0;constructor(channel,refs){this.#channel=channel,this.#refs=refs}load(jobId){let admission=this.#admissions.get(jobId);return{active:admission?.active??0,waiting:admission?.waiting??0}}async call(jobId,target,signal){let label=target.name??target.kind;if(signal.aborted)throw new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);let callId=`h${++this.#next}`,packed=target.args===void 0||this.#refs===void 0?{inline:!0,value:target.args}:await packPayload(target.args,this.#refs.writer),frame={type:"host_call",callId,jobId,kind:target.kind,...target.name===void 0?{}:{name:target.name},...packed.inline?packed.value===void 0?{}:{args:packed.value}:{argsRef:packed.ref}};if(signal.aborted)throw this.#releaseUnsent(frame),new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);return new Promise((resolve,reject)=>{let decision=this.#admission(jobId).submit(callId);if(decision.state==="refused"){this.#forgetIdle(jobId),this.#releaseUnsent(frame),reject(new ToolChildJobError(decision.frame.code,`${label}: host call ${callId} refused`));return}let pending={frame,resolve,reject,sent:!1};this.#pending.set(callId,pending),signal.addEventListener("abort",()=>this.#settle(callId,call=>{call.sent||this.#releaseUnsent(call.frame),call.reject(new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`))}),{once:!0}),decision.state==="active"&&this.#send(pending)})}handle(frame){if(frame.type==="host_reply"){let{valueRef}=frame;return this.#settle(frame.callId,call=>{frame.error!==void 0?call.reject(new ToolChildJobError("host_call_failed",frame.error)):valueRef===void 0?call.resolve(frame.value??null):this.#refs===void 0?call.reject(new ToolChildJobError("host_call_failed","a valueRef reply on a side that reads no refs")):unpackPayload(valueRef,this.#refs.reader).then(call.resolve,error=>call.reject(new ToolChildJobError("host_call_failed",error instanceof Error?error.message:String(error))))}),!0}return frame.type==="host_call_refused"?(this.#settle(frame.callId,call=>call.reject(new ToolChildJobError(frame.code,`host call ${frame.callId} refused by the server`))),!0):!1}close(){for(let callId of[...this.#pending.keys()])this.#settle(callId,call=>call.reject(new ToolChildJobError("tool_child_exited","the channel closed")))}#admission(jobId){let admission=this.#admissions.get(jobId);return admission===void 0&&(admission=new HostCallAdmission,this.#admissions.set(jobId,admission)),admission}#forgetIdle(jobId){let admission=this.#admissions.get(jobId);admission!==void 0&&admission.active===0&&admission.waiting===0&&this.#admissions.delete(jobId)}#send(call){call.sent=!0,this.#channel.send(call.frame)}#releaseUnsent(frame){frame.argsRef!==void 0&&this.#refs?.writer.handle({type:"ref_nack",refId:frame.argsRef.refId,reason:"cancelled"})}#settle(callId,apply){let call=this.#pending.get(callId);if(call===void 0)return;this.#pending.delete(callId);let{jobId}=call.frame,promoted=this.#admissions.get(jobId)?.settle(callId);if(this.#forgetIdle(jobId),apply(call),promoted!==void 0){let next=this.#pending.get(promoted);next!==void 0&&this.#send(next)}}};var JobUpdates=class{#jobId;#channel;#writer;#window;#nextSeq=0;#acked=0;#waiters=[];#ended=!1;#tail=Promise.resolve();constructor(options){this.#jobId=options.jobId,this.#channel=options.channel,this.#writer=options.writer,this.#window=options.window??TOOL_CHILD_LIMITS.updatesInFlight}update(value){let sent=this.#tail.then(()=>this.#send(value));return this.#tail=sent.catch(()=>{}),sent}async#send(value){for(;!this.#ended&&this.#nextSeq-this.#acked>=this.#window;)await new Promise(resolve=>this.#waiters.push(resolve));if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let packed=this.#writer===void 0?{inline:!0,value}:await packPayload(value,this.#writer);if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let seq=++this.#nextSeq;this.#channel.send(packed.inline?{type:"update",jobId:this.#jobId,seq,...packed.value===void 0?{}:{value:packed.value}}:{type:"update",jobId:this.#jobId,seq,valueRef:packed.ref})}acked(seq){seq<=this.#acked||(this.#acked=Math.min(seq,this.#nextSeq),this.#wake())}end(){this.#ended=!0,this.#wake()}#wake(){for(let resolve of this.#waiters.splice(0))resolve()}};var BarrierClock=class _BarrierClock{constructor(buffer){if(buffer.byteLength%Int32Array.BYTES_PER_ELEMENT!==0)throw new Error("barrier clock buffer is misaligned");let length=buffer.byteLength/Int32Array.BYTES_PER_ELEMENT;if(length<5||(length-1)%4!==0)throw new Error("barrier clock buffer has no slots");this.buffer=buffer,this.cells=new Int32Array(buffer),this.slots=(length-1)/4}static create(slots=256){if(!Number.isInteger(slots)||slots<1)throw new Error(`barrier clock needs at least one slot, got ${slots}`);return new _BarrierClock(new SharedArrayBuffer((1+slots*4)*Int32Array.BYTES_PER_ELEMENT))}tick(){return Atomics.add(this.cells,0,1)+1}claimSlot(){for(let slot=0;slot<this.slots;slot++)if(Atomics.compareExchange(this.cells,this.index(slot,3),0,1)===0)return Atomics.store(this.cells,this.index(slot,0),0),Atomics.store(this.cells,this.index(slot,1),0),Atomics.store(this.cells,this.index(slot,2),0),slot}releaseSlot(slot){Atomics.store(this.cells,this.index(slot,3),0)}recordAck(slot){let tick=this.tick();return Atomics.store(this.cells,this.index(slot,0),tick),Atomics.notify(this.cells,this.index(slot,0)),tick}recordInvoke(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=this.tick();return Atomics.store(this.cells,this.index(slot,1),invokeTick),Atomics.add(this.cells,this.index(slot,2),1),{ackTick:ackTick===0?null:ackTick,invokeTick}}waitForAck(slot,timeoutMs=Number.POSITIVE_INFINITY){let at=this.index(slot,0);for(;Atomics.load(this.cells,at)===0;)if(Atomics.wait(this.cells,at,0,timeoutMs)==="timed-out")return"timed-out";return"acked"}read(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=Atomics.load(this.cells,this.index(slot,1));return{ackTick:ackTick===0?null:ackTick,invokeTick:invokeTick===0?null:invokeTick,invocations:Atomics.load(this.cells,this.index(slot,2))}}index(slot,field){if(!Number.isInteger(slot)||slot<0||slot>=this.slots)throw new Error(`no barrier slot ${slot}`);return 1+slot*4+field}};function proofIsOrdered(proof){return proof.ackTick!==null&&proof.ackTick<proof.invokeTick}import{randomUUID}from"node:crypto";import{existsSync,readdirSync,rmSync,watch}from"node:fs";import{writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var PREFIX="SENPI_TOOL_CHILD_TEST_",TEST_CONTROL_DIR_ENV=`${PREFIX}CONTROL_DIR`;function readTestControls(env){let dir=env[TEST_CONTROL_DIR_ENV],value=name=>{let raw=env[`${PREFIX}${name}`];return raw===void 0||raw===""||raw==="0"?void 0:raw};return{enabled:name=>value(name)!==void 0,value,released:file=>dir===void 0?Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)):waitForFile(dir,file),watchPrefix:(prefix,onFile)=>dir===void 0?{ready:Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)),close:()=>{}}:watchPrefix(dir,prefix,onFile)}}function watchPrefix(dir,prefix,onFile){let seen=new Set,report=name=>{!name.startsWith(prefix)||seen.has(name)||(seen.add(name),onFile(name))},sentinel=`.watch-${process.pid}-${randomUUID()}`,resend,live=!1,markReady=()=>{},failReady=()=>{},ready=new Promise((resolve,reject)=>{markReady=resolve,failReady=reject}),watcher=watch(dir,(_event,name)=>{if(name!==null){if(name===sentinel){live=!0,clearTimeout(resend),rmSync(join2(dir,sentinel),{force:!0});for(let existing of readdirSync(dir))report(existing);markReady();return}existsSync(join2(dir,name))&&report(name)}}),touch=()=>{live||writeFile2(join2(dir,sentinel),String(Date.now())).then(()=>{live||(resend=setTimeout(touch,50))},error=>failReady(error))};return touch(),{ready,close:()=>{live=!0,clearTimeout(resend),watcher.close(),rmSync(join2(dir,sentinel),{force:!0})}}}function waitForFile(dir,file){let path=join2(dir,file),sentinel=join2(dir,`.watch-${process.pid}-${randomUUID()}`);return new Promise((resolve,reject)=>{let done=!1,resend,finish=()=>{done||(done=!0,clearTimeout(resend),watcher.close(),rmSync(sentinel,{force:!0}),resolve())},watcher=watch(dir,(_event,name)=>{if(existsSync(path)){finish();return}name!==null&&join2(dir,name)===sentinel&&clearTimeout(resend)}),touch=()=>{done||writeFile2(sentinel,String(Date.now())).then(()=>{done||(existsSync(path)?finish():resend=setTimeout(touch,50))},error=>{done||(done=!0,watcher.close(),reject(error))})};touch()})}var WindowsJobError=class extends Error{constructor(step,win32Error){super(`tool_child_job_assign_failed: ${step} failed (win32 error ${win32Error})`),this.code="tool_child_job_assign_failed",this.name="WindowsJobError",this.win32Error=win32Error}};function extendedLimitInformation(){let info=new Uint8Array(144);return new DataView(info.buffer).setUint32(16,10240,!0),info}var WindowsJob=class _WindowsJob{constructor(kernel,handle){this.closed=!1,this.kernel=kernel,this.handle=handle}static create(kernel){let handle=kernel.CreateJobObjectW(null,null);if(!handle)throw new WindowsJobError("CreateJobObjectW",kernel.GetLastError());let info=extendedLimitInformation();if(kernel.SetInformationJobObject(handle,9,info,info.byteLength)===0){let error=kernel.GetLastError();throw kernel.CloseHandle(handle),new WindowsJobError("SetInformationJobObject",error)}return new _WindowsJob(kernel,handle)}assign(pid){let process2=this.kernel.OpenProcess(4353,0,pid);if(!process2)throw new WindowsJobError("OpenProcess",this.kernel.GetLastError());try{if(this.kernel.AssignProcessToJobObject(this.handle,process2)===0)throw new WindowsJobError("AssignProcessToJobObject",this.kernel.GetLastError());let inJob=new Uint8Array(4);if(this.kernel.IsProcessInJob(process2,this.handle,inJob)===0||new DataView(inJob.buffer).getInt32(0,!0)===0)throw new WindowsJobError("IsProcessInJob",this.kernel.GetLastError())}finally{this.kernel.CloseHandle(process2)}}memberPids(){let list=new Uint8Array(8200);if(this.kernel.QueryInformationJobObject(this.handle,3,list,list.byteLength,null)===0)return[];let view=new DataView(list.buffer),count=Math.min(view.getUint32(4,!0),1024);return Array.from({length:count},(_,index)=>Number(view.getBigUint64(8+index*8,!0)))}terminate(exitCode=1){this.closed||this.kernel.TerminateJobObject(this.handle,exitCode)}close(){this.closed||(this.closed=!0,this.kernel.CloseHandle(this.handle))}};function loadKernel32Job(){if(process.platform!=="win32")return;let ffi=process.getBuiltinModule("bun:ffi");if(ffi===void 0)return;let lib=ffi.dlopen("kernel32.dll",{CreateJobObjectW:{args:["ptr","ptr"],returns:"ptr"},SetInformationJobObject:{args:["ptr","i32","ptr","u32"],returns:"i32"},QueryInformationJobObject:{args:["ptr","i32","ptr","u32","ptr"],returns:"i32"},OpenProcess:{args:["u32","i32","u32"],returns:"ptr"},AssignProcessToJobObject:{args:["ptr","ptr"],returns:"i32"},IsProcessInJob:{args:["ptr","ptr","ptr"],returns:"i32"},TerminateJobObject:{args:["ptr","u32"],returns:"i32"},CloseHandle:{args:["ptr"],returns:"i32"},GetLastError:{args:[],returns:"u32"},GetCurrentProcess:{args:[],returns:"ptr"}}),call=(name,...args)=>{let fn=lib.symbols[name];if(fn===void 0)throw new Error(`kernel32 has no ${name}`);return fn(...args.map(arg=>arg instanceof Uint8Array?ffi.ptr(arg):arg))};return{CreateJobObjectW:()=>call("CreateJobObjectW",null,null),SetInformationJobObject:(job,infoClass,info,length)=>Number(call("SetInformationJobObject",job,infoClass,info,length)),QueryInformationJobObject:(job,infoClass,info,length)=>Number(call("QueryInformationJobObject",job,infoClass,info,length,null)),OpenProcess:(access,inherit,pid)=>call("OpenProcess",access,inherit,pid),AssignProcessToJobObject:(job,process2)=>Number(call("AssignProcessToJobObject",job,process2)),IsProcessInJob:(process2,job,result)=>Number(call("IsProcessInJob",process2,job,result)),TerminateJobObject:(job,exitCode)=>Number(call("TerminateJobObject",job,exitCode)),CloseHandle:handle=>Number(call("CloseHandle",handle)),GetLastError:()=>Number(call("GetLastError")),GetCurrentProcess:()=>call("GetCurrentProcess")}}var defaultInJob;function currentProcessInJob(kernel){if(kernel!==void 0)return queryInJob(kernel);if(defaultInJob===void 0){let loaded=loadKernel32Job();defaultInJob=loaded===void 0?!1:queryInJob(loaded)}return defaultInJob}function queryInJob(kernel){let result=new Uint8Array(4);return kernel.IsProcessInJob(kernel.GetCurrentProcess(),null,result)!==0&&new DataView(result.buffer).getInt32(0,!0)!==0}var FINISHED_SLOT_STATES=256,LaunchGateError=class extends Error{constructor(code,message){super(`${code}: ${message}`),this.name="LaunchGateError",this.code=code}},LaunchGate=class{#channel;#slots=new Map;#finished=new Map;#controls;#next=0;constructor(channel,clock=BarrierClock.create(),env=process.env,creatorInJob=currentProcessInJob){this.#channel=channel,this.clock=clock,this.#controls=readTestControls(env),this.#creatorInJob=creatorInJob}#creatorInJob;started(launchId,pid,breakaway=!1){this.#slots.has(launchId)&&this.#channel.send({type:"command_started",launchId,pid,startedAtMs:Date.now(),creatorInJob:this.#creatorInJob(),breakaway})}get skipsAckWait(){return this.#controls.enabled("SKIP_ACK_WAIT")}request(request){let slot=this.clock.claimSlot();if(slot===void 0)throw new LaunchGateError("tool_child_launch_capacity",`${this.clock.slots} launches in flight`);let launchId=`L${process.pid}-${++this.#next}`,ack,acked=new Promise(resolve=>{ack=resolve});return this.#slots.set(launchId,{slot,ack,lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request}),this.#controls.enabled("STOP_AFTER_SPAWN")&&process.kill(process.pid,"SIGSTOP"),{launchId,slot,acked}}adopt(launchId,slot,request){this.#slots.set(launchId,{slot,ack:()=>{},lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request})}handleWorker(message){message.kind==="launch"?this.adopt(message.launchId,message.slot,message.request):message.kind==="invoking"?this.invoking(message.launchId):message.kind==="started"?this.started(message.launchId,message.pid,message.breakaway):this.done(message.launchId,{...message.exitCode===void 0?{}:{exitCode:message.exitCode},...message.signal===void 0?{}:{signal:message.signal}})}handle(message){if(message.type==="launch_ack"){let entry=this.#slots.get(message.launchId);return entry!==void 0&&(this.clock.recordAck(entry.slot),entry.ack()),!0}if(message.type==="slot_query"){let entry=this.#slots.get(message.launchId),state=entry===void 0?this.#finished.get(message.launchId)??{ackTick:null,invokeTick:null,invocations:0}:this.clock.read(entry.slot);return this.#channel.send({type:"slot_state",launchId:message.launchId,...state}),!0}return!1}invokeNow(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)throw new LaunchGateError("tool_child_launch_unknown",launchId);this.clock.recordInvoke(entry.slot),this.invoking(launchId)}invoking(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)return;let state=this.clock.read(entry.slot),invokeTick=state.invokeTick;if(invokeTick===null)return;let send=()=>this.#channel.send({type:"launch_proof",launchId,ackTick:state.ackTick,invokeTick}),hold=this.#controls.value("HOLD_LAUNCH_PROOF");if(hold!==void 0&&(hold!=="detached"||entry.lifetime==="detached")){this.#controls.released(`release-proof-${launchId}`).then(send);return}send()}endJobGroups(jobId){let ended=[];for(let[launchId,{request}]of this.#slots)if(!(request.jobId!==jobId||request.lifetime!=="owned"||request.containment!=="own-group")&&!(request.pgid===void 0||request.pgid<=1))try{process.kill(-request.pgid,"SIGKILL"),ended.push({launchId,pgid:request.pgid})}catch{}for(let{launchId}of ended)this.done(launchId,{signal:"SIGKILL"});return ended.map(({pgid})=>pgid)}done(launchId,outcome){let entry=this.#slots.get(launchId);entry!==void 0&&(this.#slots.delete(launchId),this.#finished.set(launchId,this.clock.read(entry.slot)),this.#finished.size>FINISHED_SLOT_STATES&&this.#finished.delete(this.#finished.keys().next().value??""),this.clock.releaseSlot(entry.slot),this.#channel.send({type:"launch_done",launchId,...outcome.exitCode===void 0?{}:{exitCode:outcome.exitCode},...outcome.signal===void 0?{}:{signal:outcome.signal}}))}};import{mkdir as mkdir3,readdir as readdir2,readFile as readFile3,rm as rm4,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname3,join as join4}from"node:path";import{appendFile,mkdir as mkdir2,open,readFile as readFile2,rm as rm3}from"node:fs/promises";import{dirname as dirname2,join as join3}from"node:path";function generationLedgerPath(dir,generation){return join3(dir,`g${generation}`,"descendants.ledger")}var DescendantsLedger=class{#path;#durableDir=!1;#entries=new Map;constructor(path){this.#path=path}get path(){return this.#path}entries(){return[...this.#entries.values()]}async append(entry){if(!this.#durableDir){let directory=dirname2(this.#path);await mkdir2(directory,{recursive:!0,mode:448}),await(await open(this.#path,"a",384)).close(),await syncDirectory(directory),await syncDirectory(dirname2(directory)),this.#durableDir=!0}let handle=await open(this.#path,"a",384);try{await handle.write(`${JSON.stringify(entry)}
|
|
2
|
+
import{Text,truncateToWidth,visibleWidth}from"./chunk-4PMRUR4L.js";import{rotateLogIfNeeded}from"./chunk-LPYBKMPT.js";import{getShellConfig}from"./chunk-ZJUL5ODW.js";import{engineTrustAction}from"./chunk-R7J5TEYK.js";import{redactSecrets}from"./chunk-62OVOJPI.js";import{HOST_CALL_KINDS,TOOL_CHILD_LIMITS,connectChannel,isRefId,isStaleExtensionContextError}from"./chunk-IHES3JES.js";import{APP_NAME,envValue,getAgentDir}from"./chunk-SODMQEHO.js";import{typebox_exports}from"./chunk-MIENF2YK.js";import{TOOL_CHILD_LEDGER_ENV,TOOL_CHILD_REENTRY_ENV,TOOL_CHILD_REFS_ROOT_ENV,rememberToolChildReentry,scrubToolChildEnv,toolChildReentry}from"./chunk-OXNWERO4.js";import{BACKGROUND_START_GRACE_MS,DEFAULT_COLS,DEFAULT_MAX_SESSIONS,DEFAULT_ROWS,FOREGROUND_ENV_OVERRIDES,KILLED_SESSION_EXIT_GRACE_MS,SecretOutputRedactor,TERMINAL_BASH_TOOL,TERMINAL_INPUT_TOOL,TERMINAL_KILL_TOOL,TERMINAL_OUTPUT_TOOL,TERMINAL_RESIZE_TOOL,decodeUtf8,encodeKeys,encodeUtf8,loadPty,safeRegExp,utf8ByteLength}from"./chunk-5GCZFK4X.js";import{processIsRunning,processStartTimeMs,readProcessStartTime,sameProcessStartMs}from"./chunk-O5RYI3IW.js";import{adoptedEngineTrust}from"./chunk-RFFMEA4B.js";var ToolChildJobError=class extends Error{constructor(code,message){super(message),this.code=code,this.name="ToolChildJobError"}};var WakeAdmissionError=class extends Error{constructor(bytes){super(`wake_too_large: ${bytes} bytes exceeds the ${TOOL_CHILD_LIMITS.wakePendingBytes}-byte pending budget`),this.code="wake_too_large",this.name="WakeAdmissionError"}},WakeAdmission=class{#pending=new Map;#blocked=[];#pendingBytes=0;get pending(){return this.#pending.size}get blocked(){return this.#blocked.length}send(wakeId,bytes){return bytes>TOOL_CHILD_LIMITS.wakePendingBytes?Promise.reject(new WakeAdmissionError(bytes)):this.#blocked.length===0&&this.#fits(bytes)?(this.#admit(wakeId,bytes),Promise.resolve()):new Promise(release=>{this.#blocked.push({wakeId,bytes,release})})}ack(wakeId){let bytes=this.#pending.get(wakeId);if(bytes!==void 0){this.#pending.delete(wakeId),this.#pendingBytes-=bytes;for(let next=this.#blocked[0];next!==void 0&&this.#fits(next.bytes);next=this.#blocked[0])this.#blocked.shift(),this.#admit(next.wakeId,next.bytes),next.release()}}#fits(bytes){return this.#pending.size<TOOL_CHILD_LIMITS.wakePending&&this.#pendingBytes+bytes<=TOOL_CHILD_LIMITS.wakePendingBytes}#admit(wakeId,bytes){this.#pending.set(wakeId,bytes),this.#pendingBytes+=bytes}};function hostCallCapacity(){return TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE+TOOL_CHILD_LIMITS.HOST_CALL_WAITING}var HostCallAdmission=class{#active=new Set;#waiting=[];get active(){return this.#active.size}get waiting(){return this.#waiting.length}submit(callId){return this.#active.has(callId)||this.#waiting.includes(callId)?refuse(callId,"host_call_duplicate"):this.#active.size<TOOL_CHILD_LIMITS.HOST_CALL_ACTIVE&&this.#waiting.length===0?(this.#active.add(callId),{state:"active"}):this.#active.size+this.#waiting.length>=hostCallCapacity()?refuse(callId,"host_call_capacity"):(this.#waiting.push(callId),{state:"waiting"})}settle(callId){if(!this.#active.delete(callId)){let index=this.#waiting.indexOf(callId);index>=0&&this.#waiting.splice(index,1);return}let next=this.#waiting.shift();return next!==void 0&&this.#active.add(next),next}};function refuse(callId,code){return{state:"refused",frame:{type:"host_call_refused",callId,code}}}import{createHash,randomBytes}from"node:crypto";import{createReadStream}from"node:fs";import{mkdir,readFile,rm as rm2,stat,writeFile}from"node:fs/promises";import{dirname}from"node:path";import{readdir,rm}from"node:fs/promises";import{join}from"node:path";function refGenerationDir(root,generation){return join(root,`gen-${generation}`)}function refFilePath(root,ref){if(!isRefId(ref.refId))throw new Error(`invalid ref id: ${JSON.stringify(ref.refId)}`);return join(refGenerationDir(root,ref.generation),"refs",ref.refId)}async function teardownRefGeneration(root,generation){await rm(refGenerationDir(root,generation),{recursive:!0,force:!0})}var PayloadRefError=class extends Error{constructor(code,message,reason){super(`${code}: ${message}`),this.name="PayloadRefError",this.code=code,this.reason=reason}},PayloadRefWriter=class{#root;#now;#pending=new Map;#ownedBytes=0;constructor(options){this.generation=options.generation,this.budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#root=options.root,this.#now=options.now??Date.now}get ownedBytes(){return this.#ownedBytes}async create(payload){let size=payload.byteLength;if(this.#ownedBytes+size>this.budget)throw new PayloadRefError("ref_budget_exceeded",`${size} bytes on top of ${this.#ownedBytes} owned exceeds ${this.budget}`);this.#ownedBytes+=size;let ref={refId:randomBytes(12).toString("hex"),generation:this.generation,bytes:size,sha256:createHash("sha256").update(payload).digest("hex")},path=refFilePath(this.#root,ref);try{await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,payload,{flag:"wx",mode:384})}catch(error){throw this.#ownedBytes-=size,await rm2(path,{force:!0}),error}return this.#pending.set(ref.refId,{bytes:size,createdAtMs:this.#now()}),ref}async handle(control){let pending=this.#pending.get(control.refId);pending!==void 0&&(this.#pending.delete(control.refId),this.#ownedBytes-=pending.bytes,control.type==="ref_nack"&&await rm2(refFilePath(this.#root,{refId:control.refId,generation:this.generation}),{force:!0}))}pendingIds(){return[...this.#pending.keys()]}overdue(){let deadline=this.#now()-TOOL_CHILD_LIMITS.refAckMs;return[...this.#pending].filter(([,ref])=>ref.createdAtMs<=deadline).map(([refId])=>refId)}async teardown(){this.#pending.clear(),this.#ownedBytes=0,await teardownRefGeneration(this.#root,this.generation)}},isMissingFile=error=>error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ENOTDIR");async function hashFile(path,signal){let hash=createHash("sha256");for await(let chunk of createReadStream(path)){if(signal?.aborted)return"cancelled";hash.update(chunk)}return hash.digest("hex")}var PayloadRefReader=class{#root;#generation;#budget;#send;#owned=new Map;#ownedBytes=0;constructor(options){this.#root=options.root,this.#generation=options.generation,this.#budget=options.budget??TOOL_CHILD_LIMITS.refsBudget,this.#send=options.send}async accept(ref,signal){let reason=await this.#verify(ref,signal);return reason!==void 0?(this.refuse(ref,reason),{ok:!1,reason}):(this.#owned.set(ref.refId,ref),this.#ownedBytes+=ref.bytes,this.#send({type:"ref_ack",refId:ref.refId}),{ok:!0})}refuse(ref,reason){this.#owned.has(ref.refId)||this.#send({type:"ref_nack",refId:ref.refId,reason})}async consume(refId){let ref=this.#owned.get(refId);if(ref===void 0)throw new PayloadRefError("ref_not_owned",`ref ${refId} is not owned by this side`);let path=refFilePath(this.#root,ref),bytes=await readFile(path);return await rm2(path,{force:!0}),this.#owned.delete(refId),this.#ownedBytes-=ref.bytes,bytes}ownedIds(){return[...this.#owned.keys()]}async#verify(ref,signal){if(signal?.aborted)return"cancelled";if(ref.generation!==this.#generation||!isRefId(ref.refId)||this.#owned.has(ref.refId))return"foreign";if(this.#ownedBytes+ref.bytes>this.#budget)return"budget";let path=refFilePath(this.#root,ref);try{if((await stat(path)).size!==ref.bytes)return"corrupt";let digest=await hashFile(path,signal);return digest==="cancelled"?"cancelled":digest===ref.sha256?void 0:"corrupt"}catch(error){if(isMissingFile(error))return"missing";throw error}}};async function packPayload(value,writer){let normalized=value===void 0?null:value,json=JSON.stringify(normalized);return json===void 0||Buffer.byteLength(json,"utf8")<=TOOL_CHILD_LIMITS.REF_THRESHOLD?{inline:!0,value:normalized}:{inline:!1,ref:await writer.create(Buffer.from(json,"utf8"))}}async function unpackPayload(ref,reader,signal){let acceptance=await reader.accept(ref,signal);if(!acceptance.ok)throw new PayloadRefError("ref_rejected",`ref ${ref.refId} was refused (${acceptance.reason})`,acceptance.reason);let bytes=await reader.consume(ref.refId);return JSON.parse(Buffer.from(bytes.buffer,bytes.byteOffset,bytes.byteLength).toString("utf8"))}var ChildHostCalls=class{#channel;#admissions=new Map;#pending=new Map;#refs;#next=0;constructor(channel,refs){this.#channel=channel,this.#refs=refs}load(jobId){let admission=this.#admissions.get(jobId);return{active:admission?.active??0,waiting:admission?.waiting??0}}async call(jobId,target,signal){let label=target.name??target.kind;if(signal.aborted)throw new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);let callId=`h${++this.#next}`,packed=target.args===void 0||this.#refs===void 0?{inline:!0,value:target.args}:await packPayload(target.args,this.#refs.writer),frame={type:"host_call",callId,jobId,kind:target.kind,...target.name===void 0?{}:{name:target.name},...packed.inline?packed.value===void 0?{}:{args:packed.value}:{argsRef:packed.ref}};if(signal.aborted)throw this.#releaseUnsent(frame),new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`);return new Promise((resolve,reject)=>{let decision=this.#admission(jobId).submit(callId);if(decision.state==="refused"){this.#forgetIdle(jobId),this.#releaseUnsent(frame),reject(new ToolChildJobError(decision.frame.code,`${label}: host call ${callId} refused`));return}let pending={frame,resolve,reject,sent:!1};this.#pending.set(callId,pending),signal.addEventListener("abort",()=>this.#settle(callId,call=>{call.sent||this.#releaseUnsent(call.frame),call.reject(new ToolChildJobError("tool_child_cancelled",`${label}: job cancelled`))}),{once:!0}),decision.state==="active"&&this.#send(pending)})}handle(frame){if(frame.type==="host_reply"){let{valueRef}=frame;return this.#settle(frame.callId,call=>{frame.error!==void 0?call.reject(new ToolChildJobError("host_call_failed",frame.error)):valueRef===void 0?call.resolve(frame.value??null):this.#refs===void 0?call.reject(new ToolChildJobError("host_call_failed","a valueRef reply on a side that reads no refs")):unpackPayload(valueRef,this.#refs.reader).then(call.resolve,error=>call.reject(new ToolChildJobError("host_call_failed",error instanceof Error?error.message:String(error))))}),!0}return frame.type==="host_call_refused"?(this.#settle(frame.callId,call=>call.reject(new ToolChildJobError(frame.code,`host call ${frame.callId} refused by the server`))),!0):!1}close(){for(let callId of[...this.#pending.keys()])this.#settle(callId,call=>call.reject(new ToolChildJobError("tool_child_exited","the channel closed")))}#admission(jobId){let admission=this.#admissions.get(jobId);return admission===void 0&&(admission=new HostCallAdmission,this.#admissions.set(jobId,admission)),admission}#forgetIdle(jobId){let admission=this.#admissions.get(jobId);admission!==void 0&&admission.active===0&&admission.waiting===0&&this.#admissions.delete(jobId)}#send(call){call.sent=!0,this.#channel.send(call.frame)}#releaseUnsent(frame){frame.argsRef!==void 0&&this.#refs?.writer.handle({type:"ref_nack",refId:frame.argsRef.refId,reason:"cancelled"})}#settle(callId,apply){let call=this.#pending.get(callId);if(call===void 0)return;this.#pending.delete(callId);let{jobId}=call.frame,promoted=this.#admissions.get(jobId)?.settle(callId);if(this.#forgetIdle(jobId),apply(call),promoted!==void 0){let next=this.#pending.get(promoted);next!==void 0&&this.#send(next)}}};var JobUpdates=class{#jobId;#channel;#writer;#window;#nextSeq=0;#acked=0;#waiters=[];#ended=!1;#tail=Promise.resolve();constructor(options){this.#jobId=options.jobId,this.#channel=options.channel,this.#writer=options.writer,this.#window=options.window??TOOL_CHILD_LIMITS.updatesInFlight}update(value){let sent=this.#tail.then(()=>this.#send(value));return this.#tail=sent.catch(()=>{}),sent}async#send(value){for(;!this.#ended&&this.#nextSeq-this.#acked>=this.#window;)await new Promise(resolve=>this.#waiters.push(resolve));if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let packed=this.#writer===void 0?{inline:!0,value}:await packPayload(value,this.#writer);if(this.#ended)throw new Error(`update after job ${this.#jobId} ended`);let seq=++this.#nextSeq;this.#channel.send(packed.inline?{type:"update",jobId:this.#jobId,seq,...packed.value===void 0?{}:{value:packed.value}}:{type:"update",jobId:this.#jobId,seq,valueRef:packed.ref})}acked(seq){seq<=this.#acked||(this.#acked=Math.min(seq,this.#nextSeq),this.#wake())}end(){this.#ended=!0,this.#wake()}#wake(){for(let resolve of this.#waiters.splice(0))resolve()}};var BarrierClock=class _BarrierClock{constructor(buffer){if(buffer.byteLength%Int32Array.BYTES_PER_ELEMENT!==0)throw new Error("barrier clock buffer is misaligned");let length=buffer.byteLength/Int32Array.BYTES_PER_ELEMENT;if(length<5||(length-1)%4!==0)throw new Error("barrier clock buffer has no slots");this.buffer=buffer,this.cells=new Int32Array(buffer),this.slots=(length-1)/4}static create(slots=256){if(!Number.isInteger(slots)||slots<1)throw new Error(`barrier clock needs at least one slot, got ${slots}`);return new _BarrierClock(new SharedArrayBuffer((1+slots*4)*Int32Array.BYTES_PER_ELEMENT))}tick(){return Atomics.add(this.cells,0,1)+1}claimSlot(){for(let slot=0;slot<this.slots;slot++)if(Atomics.compareExchange(this.cells,this.index(slot,3),0,1)===0)return Atomics.store(this.cells,this.index(slot,0),0),Atomics.store(this.cells,this.index(slot,1),0),Atomics.store(this.cells,this.index(slot,2),0),slot}releaseSlot(slot){Atomics.store(this.cells,this.index(slot,3),0)}recordAck(slot){let tick=this.tick();return Atomics.store(this.cells,this.index(slot,0),tick),Atomics.notify(this.cells,this.index(slot,0)),tick}recordInvoke(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=this.tick();return Atomics.store(this.cells,this.index(slot,1),invokeTick),Atomics.add(this.cells,this.index(slot,2),1),{ackTick:ackTick===0?null:ackTick,invokeTick}}waitForAck(slot,timeoutMs=Number.POSITIVE_INFINITY){let at=this.index(slot,0);for(;Atomics.load(this.cells,at)===0;)if(Atomics.wait(this.cells,at,0,timeoutMs)==="timed-out")return"timed-out";return"acked"}read(slot){let ackTick=Atomics.load(this.cells,this.index(slot,0)),invokeTick=Atomics.load(this.cells,this.index(slot,1));return{ackTick:ackTick===0?null:ackTick,invokeTick:invokeTick===0?null:invokeTick,invocations:Atomics.load(this.cells,this.index(slot,2))}}index(slot,field){if(!Number.isInteger(slot)||slot<0||slot>=this.slots)throw new Error(`no barrier slot ${slot}`);return 1+slot*4+field}};function proofIsOrdered(proof){return proof.ackTick!==null&&proof.ackTick<proof.invokeTick}import{randomUUID}from"node:crypto";import{existsSync,readdirSync,rmSync,watch}from"node:fs";import{writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var PREFIX="SENPI_TOOL_CHILD_TEST_",TEST_CONTROL_DIR_ENV=`${PREFIX}CONTROL_DIR`;function readTestControls(env){let dir=env[TEST_CONTROL_DIR_ENV],value=name=>{let raw=env[`${PREFIX}${name}`];return raw===void 0||raw===""||raw==="0"?void 0:raw};return{enabled:name=>value(name)!==void 0,value,released:file=>dir===void 0?Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)):waitForFile(dir,file),watchPrefix:(prefix,onFile)=>dir===void 0?{ready:Promise.reject(new Error(`${TEST_CONTROL_DIR_ENV} is not set`)),close:()=>{}}:watchPrefix(dir,prefix,onFile)}}function watchPrefix(dir,prefix,onFile){let seen=new Set,report=name=>{!name.startsWith(prefix)||seen.has(name)||(seen.add(name),onFile(name))},sentinel=`.watch-${process.pid}-${randomUUID()}`,resend,live=!1,markReady=()=>{},failReady=()=>{},ready=new Promise((resolve,reject)=>{markReady=resolve,failReady=reject}),watcher=watch(dir,(_event,name)=>{if(name!==null){if(name===sentinel){live=!0,clearTimeout(resend),rmSync(join2(dir,sentinel),{force:!0});for(let existing of readdirSync(dir))report(existing);markReady();return}existsSync(join2(dir,name))&&report(name)}}),touch=()=>{live||writeFile2(join2(dir,sentinel),String(Date.now())).then(()=>{live||(resend=setTimeout(touch,50))},error=>failReady(error))};return touch(),{ready,close:()=>{live=!0,clearTimeout(resend),watcher.close(),rmSync(join2(dir,sentinel),{force:!0})}}}function waitForFile(dir,file){let path=join2(dir,file),sentinel=join2(dir,`.watch-${process.pid}-${randomUUID()}`);return new Promise((resolve,reject)=>{let done=!1,resend,finish=()=>{done||(done=!0,clearTimeout(resend),watcher.close(),rmSync(sentinel,{force:!0}),resolve())},watcher=watch(dir,(_event,name)=>{if(existsSync(path)){finish();return}name!==null&&join2(dir,name)===sentinel&&clearTimeout(resend)}),touch=()=>{done||writeFile2(sentinel,String(Date.now())).then(()=>{done||(existsSync(path)?finish():resend=setTimeout(touch,50))},error=>{done||(done=!0,watcher.close(),reject(error))})};touch()})}var WindowsJobError=class extends Error{constructor(step,win32Error){super(`tool_child_job_assign_failed: ${step} failed (win32 error ${win32Error})`),this.code="tool_child_job_assign_failed",this.name="WindowsJobError",this.win32Error=win32Error}};function extendedLimitInformation(){let info=new Uint8Array(144);return new DataView(info.buffer).setUint32(16,10240,!0),info}var WindowsJob=class _WindowsJob{constructor(kernel,handle){this.closed=!1,this.kernel=kernel,this.handle=handle}static create(kernel){let handle=kernel.CreateJobObjectW(null,null);if(!handle)throw new WindowsJobError("CreateJobObjectW",kernel.GetLastError());let info=extendedLimitInformation();if(kernel.SetInformationJobObject(handle,9,info,info.byteLength)===0){let error=kernel.GetLastError();throw kernel.CloseHandle(handle),new WindowsJobError("SetInformationJobObject",error)}return new _WindowsJob(kernel,handle)}assign(pid){let process2=this.kernel.OpenProcess(4353,0,pid);if(!process2)throw new WindowsJobError("OpenProcess",this.kernel.GetLastError());try{if(this.kernel.AssignProcessToJobObject(this.handle,process2)===0)throw new WindowsJobError("AssignProcessToJobObject",this.kernel.GetLastError());let inJob=new Uint8Array(4);if(this.kernel.IsProcessInJob(process2,this.handle,inJob)===0||new DataView(inJob.buffer).getInt32(0,!0)===0)throw new WindowsJobError("IsProcessInJob",this.kernel.GetLastError())}finally{this.kernel.CloseHandle(process2)}}memberPids(){let list=new Uint8Array(8200);if(this.kernel.QueryInformationJobObject(this.handle,3,list,list.byteLength,null)===0)return[];let view=new DataView(list.buffer),count=Math.min(view.getUint32(4,!0),1024);return Array.from({length:count},(_,index)=>Number(view.getBigUint64(8+index*8,!0)))}terminate(exitCode=1){this.closed||this.kernel.TerminateJobObject(this.handle,exitCode)}close(){this.closed||(this.closed=!0,this.kernel.CloseHandle(this.handle))}};function loadKernel32Job(){if(process.platform!=="win32")return;let ffi=process.getBuiltinModule("bun:ffi");if(ffi===void 0)return;let lib=ffi.dlopen("kernel32.dll",{CreateJobObjectW:{args:["ptr","ptr"],returns:"ptr"},SetInformationJobObject:{args:["ptr","i32","ptr","u32"],returns:"i32"},QueryInformationJobObject:{args:["ptr","i32","ptr","u32","ptr"],returns:"i32"},OpenProcess:{args:["u32","i32","u32"],returns:"ptr"},AssignProcessToJobObject:{args:["ptr","ptr"],returns:"i32"},IsProcessInJob:{args:["ptr","ptr","ptr"],returns:"i32"},TerminateJobObject:{args:["ptr","u32"],returns:"i32"},CloseHandle:{args:["ptr"],returns:"i32"},GetLastError:{args:[],returns:"u32"},GetCurrentProcess:{args:[],returns:"ptr"}}),call=(name,...args)=>{let fn=lib.symbols[name];if(fn===void 0)throw new Error(`kernel32 has no ${name}`);return fn(...args.map(arg=>arg instanceof Uint8Array?ffi.ptr(arg):arg))};return{CreateJobObjectW:()=>call("CreateJobObjectW",null,null),SetInformationJobObject:(job,infoClass,info,length)=>Number(call("SetInformationJobObject",job,infoClass,info,length)),QueryInformationJobObject:(job,infoClass,info,length)=>Number(call("QueryInformationJobObject",job,infoClass,info,length,null)),OpenProcess:(access,inherit,pid)=>call("OpenProcess",access,inherit,pid),AssignProcessToJobObject:(job,process2)=>Number(call("AssignProcessToJobObject",job,process2)),IsProcessInJob:(process2,job,result)=>Number(call("IsProcessInJob",process2,job,result)),TerminateJobObject:(job,exitCode)=>Number(call("TerminateJobObject",job,exitCode)),CloseHandle:handle=>Number(call("CloseHandle",handle)),GetLastError:()=>Number(call("GetLastError")),GetCurrentProcess:()=>call("GetCurrentProcess")}}var defaultInJob;function currentProcessInJob(kernel){if(kernel!==void 0)return queryInJob(kernel);if(defaultInJob===void 0){let loaded=loadKernel32Job();defaultInJob=loaded===void 0?!1:queryInJob(loaded)}return defaultInJob}function queryInJob(kernel){let result=new Uint8Array(4);return kernel.IsProcessInJob(kernel.GetCurrentProcess(),null,result)!==0&&new DataView(result.buffer).getInt32(0,!0)!==0}var FINISHED_SLOT_STATES=256,LaunchGateError=class extends Error{constructor(code,message){super(`${code}: ${message}`),this.name="LaunchGateError",this.code=code}},LaunchGate=class{#channel;#slots=new Map;#finished=new Map;#controls;#next=0;constructor(channel,clock=BarrierClock.create(),env=process.env,creatorInJob=currentProcessInJob){this.#channel=channel,this.clock=clock,this.#controls=readTestControls(env),this.#creatorInJob=creatorInJob}#creatorInJob;started(launchId,pid,breakaway=!1){this.#slots.has(launchId)&&this.#channel.send({type:"command_started",launchId,pid,startedAtMs:Date.now(),creatorInJob:this.#creatorInJob(),breakaway})}get skipsAckWait(){return this.#controls.enabled("SKIP_ACK_WAIT")}request(request){let slot=this.clock.claimSlot();if(slot===void 0)throw new LaunchGateError("tool_child_launch_capacity",`${this.clock.slots} launches in flight`);let launchId=`L${process.pid}-${++this.#next}`,ack,acked=new Promise(resolve=>{ack=resolve});return this.#slots.set(launchId,{slot,ack,lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request}),this.#controls.enabled("STOP_AFTER_SPAWN")&&process.kill(process.pid,"SIGSTOP"),{launchId,slot,acked}}adopt(launchId,slot,request){this.#slots.set(launchId,{slot,ack:()=>{},lifetime:request.lifetime,request}),this.#channel.send({type:"launch",launchId,...request})}handleWorker(message){message.kind==="launch"?this.adopt(message.launchId,message.slot,message.request):message.kind==="invoking"?this.invoking(message.launchId):message.kind==="started"?this.started(message.launchId,message.pid,message.breakaway):this.done(message.launchId,{...message.exitCode===void 0?{}:{exitCode:message.exitCode},...message.signal===void 0?{}:{signal:message.signal}})}handle(message){if(message.type==="launch_ack"){let entry=this.#slots.get(message.launchId);return entry!==void 0&&(this.clock.recordAck(entry.slot),entry.ack()),!0}if(message.type==="slot_query"){let entry=this.#slots.get(message.launchId),state=entry===void 0?this.#finished.get(message.launchId)??{ackTick:null,invokeTick:null,invocations:0}:this.clock.read(entry.slot);return this.#channel.send({type:"slot_state",launchId:message.launchId,...state}),!0}return!1}invokeNow(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)throw new LaunchGateError("tool_child_launch_unknown",launchId);this.clock.recordInvoke(entry.slot),this.invoking(launchId)}invoking(launchId){let entry=this.#slots.get(launchId);if(entry===void 0)return;let state=this.clock.read(entry.slot),invokeTick=state.invokeTick;if(invokeTick===null)return;let send=()=>this.#channel.send({type:"launch_proof",launchId,ackTick:state.ackTick,invokeTick}),hold=this.#controls.value("HOLD_LAUNCH_PROOF");if(hold!==void 0&&(hold!=="detached"||entry.lifetime==="detached")){this.#controls.released(`release-proof-${launchId}`).then(send);return}send()}endJobGroups(jobId){let ended=[];for(let[launchId,{request}]of this.#slots)if(!(request.jobId!==jobId||request.lifetime!=="owned"||request.containment!=="own-group")&&!(request.pgid===void 0||request.pgid<=1))try{process.kill(-request.pgid,"SIGKILL"),ended.push({launchId,pgid:request.pgid})}catch{}for(let{launchId}of ended)this.done(launchId,{signal:"SIGKILL"});return ended.map(({pgid})=>pgid)}done(launchId,outcome){let entry=this.#slots.get(launchId);entry!==void 0&&(this.#slots.delete(launchId),this.#finished.set(launchId,this.clock.read(entry.slot)),this.#finished.size>FINISHED_SLOT_STATES&&this.#finished.delete(this.#finished.keys().next().value??""),this.clock.releaseSlot(entry.slot),this.#channel.send({type:"launch_done",launchId,...outcome.exitCode===void 0?{}:{exitCode:outcome.exitCode},...outcome.signal===void 0?{}:{signal:outcome.signal}}))}};import{mkdir as mkdir3,readdir as readdir2,readFile as readFile3,rm as rm4,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname3,join as join4}from"node:path";import{appendFile,mkdir as mkdir2,open,readFile as readFile2,rm as rm3}from"node:fs/promises";import{dirname as dirname2,join as join3}from"node:path";function generationLedgerPath(dir,generation){return join3(dir,`g${generation}`,"descendants.ledger")}var DescendantsLedger=class{#path;#durableDir=!1;#entries=new Map;constructor(path){this.#path=path}get path(){return this.#path}entries(){return[...this.#entries.values()]}async append(entry){if(!this.#durableDir){let directory=dirname2(this.#path);await mkdir2(directory,{recursive:!0,mode:448}),await(await open(this.#path,"a",384)).close(),await syncDirectory(directory),await syncDirectory(dirname2(directory)),this.#durableDir=!0}let handle=await open(this.#path,"a",384);try{await handle.write(`${JSON.stringify(entry)}
|
|
3
3
|
`),await handle.datasync()}finally{await handle.close()}this.#entries.set(entry.launchId,entry)}static async readPersisted(path){let text;try{text=await readFile2(path,"utf8")}catch{return[]}let entries=[];for(let line of text.split(`
|
|
4
4
|
`))if(line.trim()!=="")try{entries.push(JSON.parse(line))}catch{}return entries}async remove(){this.#entries.clear(),await rm3(this.#path,{force:!0})}};async function syncDirectory(directory){if(process.platform==="win32")return;let handle=await open(directory,"r");try{await handle.sync()}finally{await handle.close()}}var LaunchLog=class{#path;#chain=Promise.resolve();#failedWrites=0;constructor(path){this.#path=path}get path(){return this.#path}get failedWrites(){return this.#failedWrites}settled(){return this.#chain}record(record){let line=`${JSON.stringify({atMs:Date.now(),...record})}
|
|
5
5
|
`;return this.#chain=this.#chain.then(async()=>{try{await mkdir2(dirname2(this.#path),{recursive:!0,mode:448}),await appendFile(this.#path,line,{mode:384})}catch{this.#failedWrites+=1}}),this.#chain}};import{execFile}from"node:child_process";async function classifyGroup(group,ownGroup,probes){if(group.lifetime==="detached")return"detached";if(ownGroup===void 0||group.pgid===ownGroup||group.pgid<=1)return"own-group";if(!probes.groupHasMembers(group.pgid))return"empty";if(!probes.isAlive(group.pgid))return"sweep";let observed=await probes.startOf(group.pgid).catch(()=>{}),recorded=group.leaderStart===void 0?void 0:processStartTimeMs(group.leaderStart);return sameProcessStartMs(recorded,observed===void 0?void 0:processStartTimeMs(observed))?"sweep":"leader-reused"}async function sweepGroups(groups,options,probes=defaultGroupProbes){let ownGroup=await probes.ownGroup(),verdicts=await Promise.all(groups.map(async group=>({group,verdict:await classifyGroup(group,ownGroup,probes)}))),targets=verdicts.filter(entry=>entry.verdict==="sweep").map(entry=>entry.group.pgid);for(let pgid of targets)probes.signalGroup(pgid,"SIGTERM");let remaining=await drain(targets,options.graceMs,options.pollMs??25,probes);for(let pgid of remaining)probes.signalGroup(pgid,"SIGKILL");return remaining=await drain(remaining,options.killWaitMs,options.pollMs??25,probes),verdicts.map(({group,verdict})=>({launchId:group.launchId,pgid:group.pgid,verdict,...verdict==="sweep"?{survived:remaining.includes(group.pgid)}:{}}))}async function drain(pgids,budgetMs,pollMs,probes){let remaining=pgids.filter(pgid=>probes.groupHasMembers(pgid));for(let waited=0;remaining.length>0&&waited<budgetMs;waited+=pollMs)await probes.wait(pollMs),remaining=remaining.filter(pgid=>probes.groupHasMembers(pgid));return remaining}function processGroupOf(pid){return process.platform==="win32"?Promise.resolve(void 0):new Promise(resolve=>{execFile("ps",["-o","pgid=","-p",String(pid)],{timeout:2e3},(error,stdout)=>{let text=String(stdout).trim();resolve(error===null&&/^\d+$/u.test(text)?Number(text):void 0)})})}function groupHasMembers(pgid){try{return process.kill(-pgid,0),!0}catch(error){return error instanceof Error&&"code"in error&&error.code==="EPERM"}}var defaultGroupProbes={groupHasMembers,isAlive:processIsRunning,startOf:pid=>readProcessStartTime(pid),ownGroup:()=>processGroupOf(process.pid),signalGroup:(pgid,signal)=>{try{process.kill(-pgid,signal)}catch{}},wait:ms=>new Promise(resolve=>setTimeout(resolve,ms))};var SWEEP_TIMING={graceMs:500,killWaitMs:1e3};async function sweepLedger(path){let groups=(await DescendantsLedger.readPersisted(path)).flatMap(entry=>entry.pgid===void 0?[]:[{launchId:entry.launchId,pgid:entry.pgid,leaderStart:entry.leaderStart,lifetime:entry.lifetime}]);return groups.length===0?[]:sweepGroups(groups,SWEEP_TIMING)}var GENERATION_CHILD_FILE="child.pid";async function recordGenerationChild(dir,generation,pid){let generationDir=dirname3(generationLedgerPath(dir,generation));await mkdir3(generationDir,{recursive:!0,mode:448}),await writeFile3(join4(generationDir,GENERATION_CHILD_FILE),String(pid),{mode:384})}async function childAlive(file){let pid=Number(await readFile3(file,"utf8").catch(()=>""));if(!Number.isSafeInteger(pid)||pid<=1)return!1;try{return process.kill(pid,0),!0}catch(error){return Reflect.get(Object(error),"code")==="EPERM"}}async function sweepStaleGenerations(dir){let names=await readdir2(dir).catch(()=>[]),outcomes=[];for(let name of names){let generation=/^g(\d+)$/.exec(name)?.[1];generation!==void 0&&(await childAlive(join4(dir,name,GENERATION_CHILD_FILE))||(outcomes.push(...await sweepLedger(generationLedgerPath(dir,Number(generation)))),await rm4(join4(dir,name),{recursive:!0,force:!0})))}return outcomes}var TOOL_CHILD_GENERATION_ENV="SENPI_TOOL_CHILD_GENERATION",TOOL_CHILD_PROTOCOL_VERSION=2,NEVER_CANCELLED=new AbortController().signal;async function runToolChild(options){let env={...options.env??process.env},exit=options.exit??(code=>process.exit(code)),generation=Number(env[TOOL_CHILD_GENERATION_ENV]);(!Number.isSafeInteger(generation)||generation<0)&&(process.stderr.write(`tool-child: invalid generation
|
|
6
|
-
`),exit(70));let channel=await connectChannel(env),controls=readTestControls(env);controls.enabled("EXIT_ON_START")&&exit(1),rememberToolChildReentry(env[TOOL_CHILD_REENTRY_ENV]),options.env===void 0&&scrubToolChildEnv(process.env);let running=new Map,streams=new Map,gate=new LaunchGate(channel),refsRoot=env[TOOL_CHILD_REFS_ROOT_ENV],refs=refsRoot===void 0?void 0:{writer:new PayloadRefWriter({root:refsRoot,generation}),reader:new PayloadRefReader({root:refsRoot,generation,send:control=>channel.send(control)})},hostCalls=new ChildHostCalls(channel,refs),wakes=new WakeAdmission,wakeSeq=0,session={generation,wake:async(source,value)=>{let wakeId=`w${++wakeSeq}`,bytes=Buffer.byteLength(JSON.stringify(value??null));await wakes.send(wakeId,bytes),channel.send({type:"wake",wakeId,source,bytes,value})}},readerBlocked=!1,shutdownRequested=!1;channel.onMessage(message=>{if(controls.enabled("BLOCK_READER")&&!readerBlocked&&(readerBlocked=!0,Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,3e4)),!gate.handle(message)&&!hostCalls.handle(message)){if(message.type==="ref_ack"||message.type==="ref_nack"){refs?.writer.handle(message);return}switch(message.type){case"ping":channel.send({type:"pong",seq:message.seq});return;case"job":controls.value("EXIT_MID_JOB")===message.kind&&exit(1),runJob(channel,gate,hostCalls,refs,options.handlers,running,streams,message,session);return;case"wake_ack":wakes.ack(message.wakeId);return;case"update_ack":streams.get(message.jobId)?.acked(message.seq);return;case"cancel":if(controls.enabled("IGNORE_CANCEL"))return;running.get(message.jobId)?.abort(),channel.send({type:"cancel_ack",jobId:message.jobId});return;case"shutdown":shutdownRequested=!0,channel.close();return;default:return}}}),controls.enabled("HANG_BEFORE_READY")||channel.send({type:"hello",generation,pid:process.pid,protocol:TOOL_CHILD_PROTOCOL_VERSION,jobKinds:Object.keys(options.handlers).sort()}),controls.enabled("STOP_SELF")&&process.kill(process.pid,"SIGSTOP"),await channel.closed,hostCalls.close();for(let controller of running.values())controller.abort();shutdownRequested||await orphanedByHost(env),exit(0)}function readJobArgs(ref,reader,signal){return reader===void 0?Promise.reject(new ToolChildJobError("tool_child_refs_unavailable","a job sent its arguments by reference, but this child reads no references")):unpackPayload(ref,reader,signal)}async function runJob(channel,gate,hostCalls,refs,handlers,running,streams,job,session){let refReader=refs?.reader,handler=handlers[job.kind];if((handler===void 0||running.has(job.jobId))&&job.argsRef!==void 0&&refReader?.refuse(job.argsRef,"cancelled"),handler===void 0){channel.send({type:"job_error",jobId:job.jobId,code:"tool_child_unknown_kind",message:`no handler for ${job.kind}`});return}if(running.has(job.jobId)){channel.send({type:"job_refused",jobId:job.jobId,code:"tool_child_duplicate_job"});return}let controller=new AbortController;running.set(job.jobId,controller);try{let hostCall=(target,options)=>hostCalls.call(job.jobId,target,options?.survivesCancel===!0?NEVER_CANCELLED:controller.signal),args=job.argsRef===void 0?job.args:await readJobArgs(job.argsRef,refReader,controller.signal),stream=new JobUpdates({jobId:job.jobId,channel,...refs===void 0?{}:{writer:refs.writer}});streams.set(job.jobId,stream);let update=value2=>stream.update(value2),value=await handler(args,{jobId:job.jobId,signal:controller.signal,channel,gate,hostCall,update,generation:session.generation,wake:session.wake});channel.send({type:"result",jobId:job.jobId,value:value??null})}catch(error){let code=error instanceof ToolChildJobError?error.code:controller.signal.aborted?"tool_child_cancelled":"tool_child_job_failed";channel.send({type:"job_error",jobId:job.jobId,code,message:error instanceof Error?error.message:String(error)})}finally{running.delete(job.jobId),streams.get(job.jobId)?.end(),streams.delete(job.jobId)}}async function orphanedByHost(env){let ledger=env[TOOL_CHILD_LEDGER_ENV];if(ledger!==void 0&&await sweepLedger(ledger).catch(()=>[]),process.platform!=="win32")try{process.kill(-process.pid,"SIGKILL")}catch{}}import{realpathSync,statSync}from"node:fs";import{isAbsolute,relative,sep}from"node:path";import{extname}from"node:path";import{fileURLToPath}from"node:url";import realWorkerThreads,{parentPort,Worker}from"node:worker_threads";function goShimScript(fd){return[`IFS= read -r _go <&${fd} || exit 127`,`command -v "$0" >/dev/null 2>&1 || { printf 'ENOENT\\n' >&${fd}; exit 127; }`,`exec "$0" "$@" ${fd}<&-`].join("; ")}function controlFd(callerStdio){return Math.max(3,callerStdio.length)}function withControlPipe(callerStdio,fd,pad,pipe){let stdio=[...callerStdio];for(;stdio.length<fd;)stdio.push(pad);return stdio.push(pipe),stdio}function isLaunchMessage(value){return typeof value=="object"&&value!==null&&"kind"in value&&(value.kind==="launch"||value.kind==="invoking"||value.kind==="started"||value.kind==="done")}function startGatedWorker(gate,file,jobId,options={}){let workerData={...options.workerData,barrierClock:gate.clock.buffer,jobId,reentry:toolChildReentry()},worker=new Worker(file,{...options,workerData});return worker.on("message",message=>{isLaunchMessage(message)&&gate.handleWorker(message)}),worker}function siblingWorkerUrl(sourceSpecifier,callerUrl){let extension=extname(fileURLToPath(callerUrl));return new URL(sourceSpecifier.replace(/\.ts$/,extension),callerUrl)}var MODULE_JOB_KIND="module",TOOL_CHILD_MODULE_ROOTS_ENV="SENPI_TOOL_CHILD_MODULE_ROOTS";function parseModuleJobArgs(value){if(typeof value!="object"||value===null)throw new ToolChildJobError("module_job_invalid","args must be an object");let modulePath=Reflect.get(value,"modulePath"),exportName=Reflect.get(value,"export");if(typeof modulePath!="string"||!isAbsolute(modulePath))throw new ToolChildJobError("module_job_invalid","modulePath must be an absolute path");if(typeof exportName!="string"||exportName.length===0)throw new ToolChildJobError("module_job_invalid","export must be a non-empty string");return{modulePath,export:exportName,args:Reflect.get(value,"args")}}function parseModuleRoots(env){let raw=env[TOOL_CHILD_MODULE_ROOTS_ENV];if(raw===void 0||raw==="")return[];let parsed=JSON.parse(raw);if(!Array.isArray(parsed)||!parsed.every(root=>typeof root=="string"&&isAbsolute(root)))throw new ToolChildJobError("module_job_invalid",`${TOOL_CHILD_MODULE_ROOTS_ENV} must be a JSON array of absolute paths`);return parsed}function realpathOrUndefined(path){try{return realpathSync(path)}catch{return}}function containedModulePath(modulePath,roots){let resolved=realpathOrUndefined(modulePath);if(resolved===void 0)throw new ToolChildJobError("offload_module_unavailable",`${modulePath} does not exist`);for(let root of roots){let realRoot=realpathOrUndefined(root);if(realRoot===void 0)continue;if(resolved===realRoot&&statSync(resolved).isFile())return resolved;let inside=relative(realRoot,resolved);if(inside!==""&&!inside.startsWith(`..${sep}`)&&inside!==".."&&!isAbsolute(inside))return resolved}throw new ToolChildJobError("module_job_outside_roots",`${modulePath} is not inside an installed extension directory`)}var MODULE_CANCEL_GRACE_MS=2e3;function createModuleJobHandler(env={...process.env}){return async(value,context)=>{let job=parseModuleJobArgs(value),modulePath=containedModulePath(job.modulePath,parseModuleRoots(env)),worker=startGatedWorker(context.gate,siblingWorkerUrl("./module-job-worker.ts",import.meta.url),context.jobId,{workerData:{modulePath,exportName:job.export,args:job.args}}),cancelled=!1,graceTimer,locks=new JobFileLocks(context),abort=()=>{cancelled=!0,worker.postMessage({kind:"cancel"}),graceTimer=setTimeout(()=>{worker.terminate()},MODULE_CANCEL_GRACE_MS)};context.signal.addEventListener("abort",abort,{once:!0});try{let outcome=new Promise((resolve,reject)=>{worker.on("message",message=>{if(typeof message!="object"||message===null)return;let kind=Reflect.get(message,"kind");if(kind==="host_call"){forwardHostCall(worker,context,locks,message);return}kind==="module_result"?resolve(Reflect.get(message,"value")):kind==="module_error"&&reject(new ToolChildJobError(String(Reflect.get(message,"code")),String(Reflect.get(message,"message"))))}),worker.once("error",error=>reject(new ToolChildJobError("module_job_failed",error instanceof Error?error.message:String(error)))),worker.once("exit",code=>reject(new ToolChildJobError("module_job_failed",`worker exited (${code})`)))});try{return await outcome}catch(error){throw cancelled?new ToolChildJobError("tool_child_cancelled","the job was cancelled"):error}}finally{context.signal.removeEventListener("abort",abort),clearTimeout(graceTimer),await worker.terminate(),cancelled&&context.gate.endJobGroups(context.jobId),await locks.releaseAll()}}}var JobFileLocks=class{#context;#held=new Set;#closed=!1;constructor(context){this.#context=context}granted(lockId){return this.#closed?(this.#unlock(lockId),!1):(this.#held.add(lockId),!0)}released(lockId){this.#held.delete(lockId)}async releaseAll(){this.#closed=!0;let held=[...this.#held];this.#held.clear(),await Promise.allSettled(held.map(lockId=>this.#unlock(lockId)))}#unlock(lockId){return this.#context.hostCall({kind:"unlock_file",args:{lockId}},{survivesCancel:!0})}};function forwardHostCall(worker,context,locks,message){let callId=Reflect.get(message,"callId"),kind=Reflect.get(message,"hostKind"),name=Reflect.get(message,"name");if(typeof callId!="string"||!isHostCallKind(kind))return;let args=Reflect.get(message,"args"),lockCall=kind==="lock_file"||kind==="unlock_file";context.hostCall({kind,...typeof name=="string"?{name}:{},...args===void 0?{}:{args}},{survivesCancel:lockCall}).then(value=>{let lockId=typeof value=="object"&&value!==null?Reflect.get(value,"lockId"):void 0;if(!(kind==="lock_file"&&typeof lockId=="string"&&!locks.granted(lockId))){if(kind==="unlock_file"){let released=typeof args=="object"&&args!==null?Reflect.get(args,"lockId"):void 0;typeof released=="string"&&locks.released(released)}worker.postMessage({kind:"host_reply",callId,value})}},error=>worker.postMessage({kind:"host_reply",callId,error:error instanceof Error?error.message:String(error),code:error instanceof ToolChildJobError?error.code:"host_call_failed"}))}function isHostCallKind(value){return typeof value=="string"&&HOST_CALL_KINDS.some(kind=>kind===value)}var DEFAULT_MAX_LINES=2e3,DEFAULT_MAX_BYTES=51200;function splitLinesForCounting(content){if(content.length===0)return[];let lines=content.split(`
|
|
6
|
+
`),exit(70));let channel=await connectChannel(env),controls=readTestControls(env);controls.enabled("EXIT_ON_START")&&exit(1),rememberToolChildReentry(env[TOOL_CHILD_REENTRY_ENV]),options.env===void 0&&scrubToolChildEnv(process.env);let running=new Map,streams=new Map,gate=new LaunchGate(channel),refsRoot=env[TOOL_CHILD_REFS_ROOT_ENV],refs=refsRoot===void 0?void 0:{writer:new PayloadRefWriter({root:refsRoot,generation}),reader:new PayloadRefReader({root:refsRoot,generation,send:control=>channel.send(control)})},hostCalls=new ChildHostCalls(channel,refs),wakes=new WakeAdmission,wakeSeq=0,session={generation,wake:async(source,value)=>{let wakeId=`w${++wakeSeq}`,bytes=Buffer.byteLength(JSON.stringify(value??null));await wakes.send(wakeId,bytes),channel.send({type:"wake",wakeId,source,bytes,value})}},readerBlocked=!1,shutdownRequested=!1;channel.onMessage(message=>{if(controls.enabled("BLOCK_READER")&&!readerBlocked&&(readerBlocked=!0,Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,3e4)),!gate.handle(message)&&!hostCalls.handle(message)){if(message.type==="ref_ack"||message.type==="ref_nack"){refs?.writer.handle(message);return}switch(message.type){case"ping":channel.send({type:"pong",seq:message.seq});return;case"job":controls.value("EXIT_MID_JOB")===message.kind&&exit(1),runJob(channel,gate,hostCalls,refs,options.handlers,running,streams,message,session);return;case"wake_ack":wakes.ack(message.wakeId);return;case"update_ack":streams.get(message.jobId)?.acked(message.seq);return;case"cancel":if(controls.enabled("IGNORE_CANCEL"))return;running.get(message.jobId)?.abort(),channel.send({type:"cancel_ack",jobId:message.jobId});return;case"shutdown":shutdownRequested=!0,channel.close();return;default:return}}}),controls.enabled("HANG_BEFORE_READY")||channel.send({type:"hello",generation,pid:process.pid,protocol:TOOL_CHILD_PROTOCOL_VERSION,jobKinds:Object.keys(options.handlers).sort()}),controls.enabled("STOP_SELF")&&process.kill(process.pid,"SIGSTOP"),await channel.closed,hostCalls.close();for(let controller of running.values())controller.abort();shutdownRequested||await orphanedByHost(env),exit(0)}function readJobArgs(ref,reader,signal){return reader===void 0?Promise.reject(new ToolChildJobError("tool_child_refs_unavailable","a job sent its arguments by reference, but this child reads no references")):unpackPayload(ref,reader,signal)}async function runJob(channel,gate,hostCalls,refs,handlers,running,streams,job,session){let refReader=refs?.reader,handler=handlers[job.kind];if((handler===void 0||running.has(job.jobId))&&job.argsRef!==void 0&&refReader?.refuse(job.argsRef,"cancelled"),handler===void 0){channel.send({type:"job_error",jobId:job.jobId,code:"tool_child_unknown_kind",message:`no handler for ${job.kind}`});return}if(running.has(job.jobId)){channel.send({type:"job_refused",jobId:job.jobId,code:"tool_child_duplicate_job"});return}let controller=new AbortController;running.set(job.jobId,controller);try{let hostCall=(target,options)=>hostCalls.call(job.jobId,target,options?.survivesCancel===!0?NEVER_CANCELLED:controller.signal),args=job.argsRef===void 0?job.args:await readJobArgs(job.argsRef,refReader,controller.signal),stream=new JobUpdates({jobId:job.jobId,channel,...refs===void 0?{}:{writer:refs.writer}});streams.set(job.jobId,stream);let update=value2=>stream.update(value2),value=await handler(args,{jobId:job.jobId,signal:controller.signal,channel,gate,hostCall,update,generation:session.generation,wake:session.wake});channel.send({type:"result",jobId:job.jobId,value:value??null})}catch(error){let code=error instanceof ToolChildJobError?error.code:controller.signal.aborted?"tool_child_cancelled":"tool_child_job_failed";channel.send({type:"job_error",jobId:job.jobId,code,message:error instanceof Error?error.message:String(error)})}finally{running.delete(job.jobId),streams.get(job.jobId)?.end(),streams.delete(job.jobId)}}async function orphanedByHost(env){let ledger=env[TOOL_CHILD_LEDGER_ENV];if(ledger!==void 0&&await sweepLedger(ledger).catch(()=>[]),process.platform!=="win32")try{process.kill(-process.pid,"SIGKILL")}catch{}}import{realpathSync,statSync}from"node:fs";import{isAbsolute,relative,sep}from"node:path";import{extname}from"node:path";import{fileURLToPath}from"node:url";import realWorkerThreads,{parentPort,Worker}from"node:worker_threads";function goShimScript(fd){return[`IFS= read -r _go <&${fd} || exit 127`,`command -v "$0" >/dev/null 2>&1 || { printf 'ENOENT\\n' >&${fd}; exit 127; }`,`exec "$0" "$@" ${fd}<&-`].join("; ")}function controlFd(callerStdio){return Math.max(3,callerStdio.length)}function withControlPipe(callerStdio,fd,pad,pipe){let stdio=[...callerStdio];for(;stdio.length<fd;)stdio.push(pad);return stdio.push(pipe),stdio}function isLaunchMessage(value){return typeof value=="object"&&value!==null&&"kind"in value&&(value.kind==="launch"||value.kind==="invoking"||value.kind==="started"||value.kind==="done")}function startGatedWorker(gate,file,jobId,options={}){let workerData={...options.workerData,barrierClock:gate.clock.buffer,jobId,reentry:toolChildReentry()},worker=new Worker(file,{...options,workerData});return worker.on("message",message=>{isLaunchMessage(message)&&gate.handleWorker(message)}),worker}function siblingWorkerUrl(sourceSpecifier,callerUrl){let extension=extname(fileURLToPath(callerUrl));return new URL(sourceSpecifier.replace(/\.ts$/,extension),callerUrl)}var MODULE_JOB_KIND="module",TOOL_CHILD_MODULE_ROOTS_ENV="SENPI_TOOL_CHILD_MODULE_ROOTS";function parseModuleJobArgs(value){if(typeof value!="object"||value===null)throw new ToolChildJobError("module_job_invalid","args must be an object");let modulePath=Reflect.get(value,"modulePath"),exportName=Reflect.get(value,"export");if(typeof modulePath!="string"||!isAbsolute(modulePath))throw new ToolChildJobError("module_job_invalid","modulePath must be an absolute path");if(typeof exportName!="string"||exportName.length===0)throw new ToolChildJobError("module_job_invalid","export must be a non-empty string");return{modulePath,export:exportName,args:Reflect.get(value,"args")}}function parseModuleRoots(env){let raw=env[TOOL_CHILD_MODULE_ROOTS_ENV];if(raw===void 0||raw==="")return[];let parsed=JSON.parse(raw);if(!Array.isArray(parsed)||!parsed.every(root=>typeof root=="string"&&isAbsolute(root)))throw new ToolChildJobError("module_job_invalid",`${TOOL_CHILD_MODULE_ROOTS_ENV} must be a JSON array of absolute paths`);return parsed}function realpathOrUndefined(path){try{return realpathSync(path)}catch{return}}function containedModulePath(modulePath,roots){let resolved=realpathOrUndefined(modulePath);if(resolved===void 0)throw new ToolChildJobError("offload_module_unavailable",`${modulePath} does not exist`);for(let root of roots){let realRoot=realpathOrUndefined(root);if(realRoot===void 0)continue;if(resolved===realRoot&&statSync(resolved).isFile())return resolved;let inside=relative(realRoot,resolved);if(inside!==""&&!inside.startsWith(`..${sep}`)&&inside!==".."&&!isAbsolute(inside))return resolved}throw new ToolChildJobError("module_job_outside_roots",`${modulePath} is not inside an installed extension directory`)}var MODULE_CANCEL_GRACE_MS=2e3;function createModuleJobHandler(env={...process.env}){return async(value,context)=>{let job=parseModuleJobArgs(value),modulePath=containedModulePath(job.modulePath,parseModuleRoots(env)),worker=startGatedWorker(context.gate,siblingWorkerUrl("./module-job-worker.ts",import.meta.url),context.jobId,{workerData:{modulePath,exportName:job.export,args:job.args}}),cancelled=!1,graceTimer,locks=new JobFileLocks(context),abort=()=>{cancelled=!0,worker.postMessage({kind:"cancel"}),graceTimer=setTimeout(()=>{worker.terminate()},MODULE_CANCEL_GRACE_MS)};context.signal.addEventListener("abort",abort,{once:!0});try{let outcome=new Promise((resolve,reject)=>{worker.on("message",message=>{if(typeof message!="object"||message===null)return;let kind=Reflect.get(message,"kind");if(kind==="host_call"){forwardHostCall(worker,context,locks,message);return}kind==="module_result"?resolve(Reflect.get(message,"value")):kind==="module_error"&&reject(new ToolChildJobError(String(Reflect.get(message,"code")),String(Reflect.get(message,"message"))))}),worker.once("error",error=>reject(new ToolChildJobError("module_job_failed",error instanceof Error?error.message:String(error)))),worker.once("exit",code=>reject(new ToolChildJobError("module_job_failed",`worker exited (${code})`)))});try{return await outcome}catch(error){throw cancelled?new ToolChildJobError("tool_child_cancelled","the job was cancelled"):error}}finally{context.signal.removeEventListener("abort",abort),clearTimeout(graceTimer),await worker.terminate(),cancelled&&context.gate.endJobGroups(context.jobId),await locks.releaseAll()}}}var JobFileLocks=class{#context;#held=new Set;#closed=!1;constructor(context){this.#context=context}granted(lockId){return this.#closed?(this.#unlock(lockId),!1):(this.#held.add(lockId),!0)}released(lockId){this.#held.delete(lockId)}async releaseAll(){this.#closed=!0;let held=[...this.#held];this.#held.clear(),await Promise.allSettled(held.map(lockId=>this.#unlock(lockId)))}#unlock(lockId){return this.#context.hostCall({kind:"unlock_file",args:{lockId}},{survivesCancel:!0})}};function forwardHostCall(worker,context,locks,message){let callId=Reflect.get(message,"callId"),kind=Reflect.get(message,"hostKind"),name=Reflect.get(message,"name");if(typeof callId!="string"||!isHostCallKind(kind))return;let args=Reflect.get(message,"args"),lockCall=kind==="lock_file"||kind==="unlock_file";context.hostCall({kind,...typeof name=="string"?{name}:{},...args===void 0?{}:{args}},{survivesCancel:lockCall}).then(value=>{let lockId=typeof value=="object"&&value!==null?Reflect.get(value,"lockId"):void 0;if(!(kind==="lock_file"&&typeof lockId=="string"&&!locks.granted(lockId))){if(kind==="unlock_file"){let released=typeof args=="object"&&args!==null?Reflect.get(args,"lockId"):void 0;typeof released=="string"&&locks.released(released)}worker.postMessage({kind:"host_reply",callId,value})}},error=>worker.postMessage({kind:"host_reply",callId,error:error instanceof Error?error.message:String(error),code:error instanceof ToolChildJobError?error.code:"host_call_failed"}))}function isHostCallKind(value){return typeof value=="string"&&HOST_CALL_KINDS.some(kind=>kind===value)}var DEFAULT_MAX_LINES=2e3,DEFAULT_MAX_BYTES=50*1024,GREP_MAX_LINE_LENGTH=500;function splitLinesForCounting(content){if(content.length===0)return[];let lines=content.split(`
|
|
7
7
|
`);return content.endsWith(`
|
|
8
|
-
`)&&lines.pop(),lines}function formatSize(bytes){return bytes<1024?`${bytes}B`:bytes<1024*1024?`${(bytes/1024).toFixed(1)}KB`:`${(bytes/(1024*1024)).toFixed(1)}MB`}function truncateHead(content,options={}){let maxLines=options.maxLines??
|
|
9
|
-
`),finalOutputBytes=
|
|
10
|
-
`),finalOutputBytes=
|
|
8
|
+
`)&&lines.pop(),lines}function formatSize(bytes){return bytes<1024?`${bytes}B`:bytes<1024*1024?`${(bytes/1024).toFixed(1)}KB`:`${(bytes/(1024*1024)).toFixed(1)}MB`}function truncateHead(content,options={}){let maxLines=options.maxLines??DEFAULT_MAX_LINES,maxBytes=options.maxBytes??DEFAULT_MAX_BYTES,totalBytes=utf8ByteLength(content),lines=splitLinesForCounting(content),totalLines=lines.length;if(totalLines<=maxLines&&totalBytes<=maxBytes)return{content,truncated:!1,truncatedBy:null,totalLines,totalBytes,outputLines:totalLines,outputBytes:totalBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes};if(utf8ByteLength(lines[0])>maxBytes)return{content:"",truncated:!0,truncatedBy:"bytes",totalLines,totalBytes,outputLines:0,outputBytes:0,lastLinePartial:!1,firstLineExceedsLimit:!0,maxLines,maxBytes};let outputLinesArr=[],outputBytesCount=0,truncatedBy="lines";for(let i=0;i<lines.length&&i<maxLines;i++){let line=lines[i],lineBytes=utf8ByteLength(line)+(i>0?1:0);if(outputBytesCount+lineBytes>maxBytes){truncatedBy="bytes";break}outputLinesArr.push(line),outputBytesCount+=lineBytes}outputLinesArr.length>=maxLines&&outputBytesCount<=maxBytes&&(truncatedBy="lines");let outputContent=outputLinesArr.join(`
|
|
9
|
+
`),finalOutputBytes=utf8ByteLength(outputContent);return{content:outputContent,truncated:!0,truncatedBy,totalLines,totalBytes,outputLines:outputLinesArr.length,outputBytes:finalOutputBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes}}function truncateTail(content,options={}){let maxLines=options.maxLines??DEFAULT_MAX_LINES,maxBytes=options.maxBytes??DEFAULT_MAX_BYTES,totalBytes=utf8ByteLength(content),lines=splitLinesForCounting(content),totalLines=lines.length;if(totalLines<=maxLines&&totalBytes<=maxBytes)return{content,truncated:!1,truncatedBy:null,totalLines,totalBytes,outputLines:totalLines,outputBytes:totalBytes,lastLinePartial:!1,firstLineExceedsLimit:!1,maxLines,maxBytes};let outputLinesArr=[],outputBytesCount=0,truncatedBy="lines",lastLinePartial=!1;for(let i=lines.length-1;i>=0&&outputLinesArr.length<maxLines;i--){let line=lines[i],lineBytes=utf8ByteLength(line)+(outputLinesArr.length>0?1:0);if(outputBytesCount+lineBytes>maxBytes){if(truncatedBy="bytes",outputLinesArr.length===0){let truncatedLine=truncateStringToBytesFromEnd(line,maxBytes);outputLinesArr.unshift(truncatedLine),outputBytesCount=utf8ByteLength(truncatedLine),lastLinePartial=!0}break}outputLinesArr.unshift(line),outputBytesCount+=lineBytes}outputLinesArr.length>=maxLines&&outputBytesCount<=maxBytes&&(truncatedBy="lines");let outputContent=outputLinesArr.join(`
|
|
10
|
+
`),finalOutputBytes=utf8ByteLength(outputContent);return{content:outputContent,truncated:!0,truncatedBy,totalLines,totalBytes,outputLines:outputLinesArr.length,outputBytes:finalOutputBytes,lastLinePartial,firstLineExceedsLimit:!1,maxLines,maxBytes}}function truncateStringToBytesFromEnd(str,maxBytes){let buf=encodeUtf8(str);if(buf.length<=maxBytes)return str;let start=buf.length-maxBytes;for(;start<buf.length&&(buf[start]&192)===128;)start++;return decodeUtf8(buf.slice(start))}function truncateLine(line,maxChars=GREP_MAX_LINE_LENGTH){return line.length<=maxChars?{text:line,wasTruncated:!1}:{text:`${line.slice(0,maxChars)}... [truncated]`,wasTruncated:!0}}import{closeSync,fchmodSync,mkdirSync,openSync,writeSync}from"node:fs";import{dirname as dirname4,join as join5}from"node:path";var DEFAULT_MAX_BYTES2=5*1024*1024,MAX_STRING_LENGTH=200,DEBUG_PREFIX=`[${APP_NAME}-session]`,BLOCKED_KEY=/^(?:__proto__|constructor|prototype|headers?|env(?:ironment)?|authorization|credential(?:s)?|password|secret|token|api_?key|client_?secret)$/i,ALLOWED_DATA_KEY=/^(?:action|attemptId|disposition|stage|error|mode|count|willRetry|deferAdmission|delivered|restored|cause|accepted|skipped|rejectionCause|reason|durationMs|kind|retryable|phase|op|bytes|generation|requestId|tokens|tokensBefore|tokensAfter|contextWindow|attempt|aborted|sessionId|role|provider|model|source|actor|from|to|duringTurn|persistDefault|extension|handlerEvent|queuedId|ageMs|seat|until|shared|toolCallId|parentToolCallId|toolName|thresholdMs|elapsedMs|queueDepth|queueHead)$/,SENSITIVE_TEXT=/((?:authorization\s*[:=]\s*(?:bearer|basic)\s+)|(?:bearer\s+)|(?:[?&](?:api[_-]?key|token|secret|password|auth(?:orization)?)=))[^\s&,"'}\]]+/gi;function createSessionLogger(agentDir,options={}){if(typeof agentDir!="string"||agentDir.length===0)return{debug:()=>{},info:()=>{},warn:()=>{}};let filePath=join5(agentDir,"logs","session.log"),maxBytes=validMaxBytes(options.maxBytes),reportedWriteFailure=!1;function log(level,event,data){try{let line=formatLine(level,event,options.context?{...options.context(),...data}:data);options.sink?.(line),writeLine(filePath,line,maxBytes),(options.mirrorToStderr??envValue("SESSION_DEBUG")==="1")&&console.error(DEBUG_PREFIX,line)}catch(error){reportedWriteFailure||(reportedWriteFailure=!0,console.error("Unable to write session log",error))}}return{debug:(event,data)=>log("debug",event,data),info:(event,data)=>log("info",event,data),warn:(event,data)=>log("warn",event,data)}}function validMaxBytes(value){return typeof value=="number"&&Number.isFinite(value)&&value>0?Math.floor(value):DEFAULT_MAX_BYTES2}function formatLine(level,event,data){let entry={ts:new Date().toISOString(),level,event:safeText(event)};if(data!==void 0){for(let[key,value]of Object.entries(data))if(ALLOWED_DATA_KEY.test(key)&&!BLOCKED_KEY.test(key)){let safeValue=serializeValue(value);safeValue!==void 0&&(entry[key]=safeValue)}}return JSON.stringify(entry)}function writeLine(filePath,line,maxBytes){mkdirSync(dirname4(filePath),{recursive:!0,mode:448});let text=`${line}
|
|
11
11
|
`;rotateLogIfNeeded(filePath,Buffer.byteLength(text),maxBytes);let descriptor=openSync(filePath,"a",384);try{writeSync(descriptor,text),fchmodSync(descriptor,384)}finally{closeSync(descriptor)}}function serializeValue(value){if(typeof value=="string")return safeText(value);if(typeof value=="number"||typeof value=="boolean"||value===null)return value;if(typeof value=="bigint")return value.toString()}function safeText(value){let redacted=value.replace(SENSITIVE_TEXT,"$1[redacted]");return redacted.length<=MAX_STRING_LENGTH?redacted:`${redacted.slice(0,MAX_STRING_LENGTH-3)}...`}var PRIVATE_KEY_MARKER="[REDACTED private key]",LABEL=String.raw`((?:[A-Z0-9]+ )*PRIVATE KEY(?: BLOCK)?)`,BEGIN=new RegExp(`-----BEGIN ${LABEL}-----`),END=new RegExp(`-----END ${LABEL}-----`),BODY=/^[A-Za-z0-9+/]{16,}={0,2}$/,PREFIXED_BODY_MIN=60,UPPER=/[A-Z]/,LOWER=/[a-z]/,BODY_CONTINUED=/^(?:[A-Za-z0-9+/]+={0,2}|=[A-Za-z0-9+/]{4})$/,ARMOR_HEADER=/^[A-Za-z][A-Za-z0-9-]*: \S/,BASE64_RUN=/[A-Za-z0-9+/]{40,}/,MAX_HELD_LINES=512;function isBase64Char(code){return code>=65&&code<=90||code>=97&&code<=122||code>=48&&code<=57||code===43||code===47}function prefixShape(prefix){return prefix.trim().replace(/\d+/g,"0")}function bodyParts(line){let trimmed=line.trim(),start=trimmed.length,pad=0;for(;start>0&&pad<2&&trimmed[start-1]==="=";)start--,pad++;let runEnd=start;for(;start>0&&isBase64Char(trimmed.charCodeAt(start-1));)start--;if(start!==runEnd)return pad===0&&runEnd-start===4&&trimmed[start-1]==="="&&start--,{shape:prefixShape(trimmed.slice(0,start)),token:trimmed.slice(start)}}function startsBody(parts){let{shape,token:token2}=parts;return shape.length>0&&token2.length<PREFIXED_BODY_MIN?!1:BODY.test(token2)&&UPPER.test(token2)&&LOWER.test(token2)}function keyLike(line,shape){let trimmed=line.trim();if(trimmed.length===0||BODY_CONTINUED.test(trimmed)||ARMOR_HEADER.test(trimmed)||BASE64_RUN.test(trimmed))return!0;if(shape.length===0)return!1;if(prefixShape(trimmed)===shape)return!0;let parts=bodyParts(trimmed);return parts!==void 0&&parts.shape===shape&&BODY_CONTINUED.test(parts.token)}function startsWithEnd(line){let end=END.exec(line);if(!end)return!1;let begin=BEGIN.exec(line);return!begin||end.index<begin.index}var PrivateKeyLineFilter=class{#block;#blockShape="";#blockCrossedGap=!1;#gapBeforeHeld=!1;#held=[];#heldShape="";push(line){if(this.#block===void 0){let parts=bodyParts(line);if(parts&&this.#held.length>0&&parts.shape===this.#heldShape&&BODY_CONTINUED.test(parts.token))return this.#hold(line);if(parts&&startsBody(parts)){let out2=this.#releaseHeld();return this.#heldShape=parts.shape,out2.push(...this.#hold(line)),out2}}let out=[];this.#block===void 0&&startsWithEnd(line)?this.#held=[]:out.push(...this.#releaseHeld());let trimmed=line.trim();trimmed!==""&&!ARMOR_HEADER.test(trimmed)&&(this.#gapBeforeHeld=!1);let kept=this.#scan(line);return kept!==void 0&&out.push(kept),out}cut(){return this.#block!==void 0&&(this.#blockCrossedGap=!0),this.#gapBeforeHeld=!0,this.#held.length===0?[]:(this.#held=[],[PRIVATE_KEY_MARKER])}finish(){let out=this.#releaseHeld();return this.#block=void 0,this.#blockCrossedGap=!1,this.#gapBeforeHeld=!1,out}#hold(line){return this.#held.push(line),this.#held.length>MAX_HELD_LINES?[this.#held.shift()]:[]}#releaseHeld(){let held=this.#held;return this.#held=[],held.length===0?[]:this.#gapBeforeHeld?[PRIVATE_KEY_MARKER]:held}#scan(line){let rest=line,kept="",touched=!1,marked=!1;for(;;){if(this.#block!==void 0){touched=!0;let close=`-----END ${this.#block}-----`,at=rest.indexOf(close);if(at!==-1){this.#closeBlock(),rest=rest.slice(at+close.length);continue}if(this.#blockCrossedGap&&!keyLike(rest,this.#blockShape)){this.#closeBlock();continue}break}let begin=BEGIN.exec(rest),end=END.exec(rest);if(end&&(!begin||end.index<begin.index)){kept+=PRIVATE_KEY_MARKER,touched=marked=!0,rest=rest.slice(end.index+end[0].length);continue}if(begin){kept+=rest.slice(0,begin.index)+PRIVATE_KEY_MARKER,touched=marked=!0,this.#block=begin[1],this.#blockShape=prefixShape(rest.slice(0,begin.index)),rest=rest.slice(begin.index+begin[0].length);continue}kept+=rest;break}return touched?marked||kept.trim().length>0?kept:void 0:line}#closeBlock(){this.#block=void 0,this.#blockCrossedGap=!1}};var secretOutputObfuscator=()=>new SecretOutputRedactor,JobWidgetSourceRedactor=class{#keys=new PrivateKeyLineFilter;#obfuscator;#stream;#partial="";constructor(obfuscator){this.#obfuscator=obfuscator}push(line){return this.#obfuscate(this.#keys.push(line))}cut(){return this.#obfuscate(this.#keys.cut())}finish(){let out=this.#obfuscate(this.#keys.finish());return this.#stream&&(this.#partial+=this.#stream.finish(),this.#stream=void 0),this.#partial.length>0&&out.push(redactSecrets(this.#partial)),this.#partial="",out}#obfuscate(lines){if(!this.#obfuscator)return lines.map(line=>redactSecrets(line));if(lines.length===0)return[];this.#stream??=this.#obfuscator();let stream=this.#stream,out=[];for(let line of lines){let parts=(this.#partial+stream.push(`${line}
|
|
12
12
|
`)).split(`
|
|
13
13
|
`);this.#partial=parts.pop()??"";for(let part of parts)out.push(redactSecrets(part))}return out}};function createWidgetRedactor(obfuscate){let source=()=>new JobWidgetSourceRedactor(obfuscate);return{source,text:text=>{let lines=source(),out=text.split(`
|
|
@@ -32,7 +32,7 @@ import{Text,truncateToWidth,visibleWidth}from"./chunk-4PMRUR4L.js";import{rotate
|
|
|
32
32
|
`));lastBreak>=0&&(this.#partialAfterCr=combined[lastBreak]==="\r");let raw=combined.replace(/\r\n?/g,`
|
|
33
33
|
`).split(`
|
|
34
34
|
`);this.#partial=(raw.pop()??"").slice(0,4096*2),(flush||!chunk.open)&&this.#partial.length>0&&(raw.push(this.#partial),this.#partial="");let clean=raw.map(sanitizeLine),redactor=this.#redactor;return{lines:(redactor?[...skipped?redactor.cut():[],...clean.flatMap(line=>redactor.push(line)),...flush||!chunk.open?redactor.finish():[]]:clean).map(line=>line.slice(0,4096)),open:chunk.open,end:chunk.end}}get progress(){if(!this.#partialAfterCr||this.#partial.length===0)return;let line=sanitizeLine(this.#partial.replace(UNFINISHED_ESCAPE,"")).slice(0,4096).replace(OPEN_TOKEN_TAIL,"").trim();return line.length>0?line:void 0}};function ruleReadsSource(from,id){return from==="*"?!0:from.endsWith("*")?id.startsWith(from.slice(0,-1)):from===id}function ruleFields(rule){let fields=[];for(let group of new Set(patternGroupNames(rule.match)))group!==rule.key&&fields.push({field:group,text:group===rule.text,count:!1});return rule.count!==void 0&&fields.push({field:rule.count,text:!1,count:!0}),fields}function aggNeedsValue(agg){return agg!=="count"&&agg!=="rate"}function fieldFeeds(spec){let fields=new Map;for(let rule of spec.rules)for(let{field,text,count}of ruleFields(rule)){let feed=fields.get(field)??{value:!1,text:!1,keyGroups:new Set};feed.value||=!text&&!count,feed.text||=text,rule.key!==void 0&&feed.keyGroups.add(rule.key),fields.set(field,feed)}return fields}function keyedFields(spec){let keyed=new Set;for(let rule of spec?.rules??[])if(rule.key!==void 0)for(let{field}of ruleFields(rule))keyed.add(field);return keyed}function pinnedKeys(spec){let pinned=new Map,pin=ref=>{if(ref?.key===void 0)return;let keys=pinned.get(ref.field)??new Set;keys.add(ref.key),pinned.set(ref.field,keys)};pin(spec?.headline);for(let block of spec?.blocks??[])if(block.kind==="spark")pin(block);else if(block.kind==="meter")pin(block),typeof block.total!="number"&&pin(block.total);else if(block.kind==="stat")for(let item of block.items)pin(item);return pinned}var NUMBER_PREFIX=/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?/,SUFFIX_SCALE={k:1e3,K:1e3,M:1e6,G:1e9},WRITTEN_NUMBER=/\d[\d,_]*(?:\.\d+)?[kKMG]?/g;function parseWidgetValue(text){let first=text.charCodeAt(0);if(first>=48&&first<=57&&!/[xXbBoO]/.test(text.charAt(1))){let plain2=Number(text);if(Number.isFinite(plain2))return plain2}let compact=text.trim().replace(/[,_]/g,""),match=NUMBER_PREFIX.exec(compact);return match?Number.parseFloat(match[0])*(SUFFIX_SCALE[compact.charAt(match[0].length)]??1):Number.NaN}function statedNumbers(texts){let stated=new Set;for(let text of texts)for(let match of text.matchAll(WRITTEN_NUMBER))stated.add(parseWidgetValue(match[0]));return stated}function compileRule(rule,groups){let captures=[];return groups.forEach((field,index)=>{field!==rule.key&&captures.push({index,field,text:field===rule.text})}),{key:rule.key===void 0?-1:groups.indexOf(rule.key),captures,count:rule.count,scale:rule.scale??1}}function compileSourceMatcher(spec,matcher,sourceId){let byPattern=new Map;for(let rule of spec.rules){if(!ruleReadsSource(rule.from,sourceId))continue;let rules=byPattern.get(rule.match);rules?rules.push(rule):byPattern.set(rule.match,[rule])}if(byPattern.size===0)return;let patterns=[...byPattern.keys()],compiled=compilePatterns(matcher,patterns);return{compiled,rules:patterns.map((pattern,index)=>(byPattern.get(pattern)??[]).map(rule=>compileRule(rule,compiled.groupNames[index])))}}function applyMatches(entry,lines,t,store){let matched=new Set;for(let hit of entry.compiled.matchLines(lines)){matched.add(hit.line);let line=lines[hit.line];for(let rule of entry.rules[hit.pattern]){let keySpan=rule.key<0?void 0:hit.spans[rule.key],key=keySpan?line.slice(keySpan.start,keySpan.end).trim():"";for(let capture of rule.captures){let span=hit.spans[capture.index];if(!span)continue;let captured=line.slice(span.start,span.end),value=capture.text?Number.NaN:parseWidgetValue(captured)*rule.scale;Number.isFinite(value)?store.push(capture.field,key,{value,text:void 0,line,t}):store.push(capture.field,key,{value:void 0,text:captured.trim(),line,t})}rule.count!==void 0&&store.push(rule.count,key,{value:void 0,text:void 0,line,t})}}return matched}var SAMPLE_HEAD_LINES=30,SAMPLE_TAIL_LINES=60,MAX_STAGE_CHARS=200;function newSourceStats(id,label){return{id,label,size:0,lines:0,head:[],tail:[],lastActiveAt:0,recent:[]}}function recordLines(stats,lines,t){let fresh=0,tailFrom=0;for(let index=0;index<lines.length;index++)lines[index].trim().length!==0&&(fresh+=1,stats.head.length<SAMPLE_HEAD_LINES&&(stats.head.push(lines[index]),tailFrom=index+1));if(fresh===0)return!1;let newest=[];for(let index=lines.length-1;index>=tailFrom&&newest.length<SAMPLE_TAIL_LINES;index--)lines[index].trim().length>0&&newest.push(lines[index]);return newest.length>0?(stats.lastLine=newest[0],newest.reverse(),stats.tail=[...stats.tail,...newest].slice(-SAMPLE_TAIL_LINES)):stats.lastLine=stats.head.at(-1),stats.lines+=fresh,stats.lastActiveAt=t,stats.recent.push({t,n:fresh}),trimWindow(stats.recent,t),!0}function latestLine(all){let best,bestIsPipe=!1;for(let stats of all){if(!stats.lastLine)continue;let isPipe=/(?:^|:)pipe:/.test(stats.id);(!best||isPipe&&!bestIsPipe||isPipe===bestIsPipe&&stats.lastActiveAt>=best.lastActiveAt)&&(best=stats,bestIsPipe=isPipe)}return best?.lastLine?truncateText(best.lastLine.trim(),MAX_STAGE_CHARS):void 0}function sourceSample(stats){return{id:stats.id,label:stats.label,size:stats.size,lines:stats.lines,head:stats.head.slice(),tail:stats.tail.slice()}}function sampleLines(samples){return samples.map(sample=>({id:sample.id,lines:[...sample.head,...sample.tail]}))}var JOB_WIDGET_AGGS=["last","first","min","max","mean","sum","count","rate","delta","change"];var FIELD_NAME=/^[a-z][a-z0-9_]{0,23}$/,GROUP_NAME=/^[A-Za-z_][A-Za-z0-9_]{0,31}$/,SOURCE_ID=/^(?:\*|[A-Za-z0-9_:.-]{1,64}\*?)$/;var SPARK_POINTS=48,MAX_BAR_ITEMS=16,MAX_GRID_CELLS=48,MAX_TEXT_CHARS=200,TREND_AGGS=new Set(["last","min","max"]);function buildValue(ref,ctx){let series=ctx.store.series(ref.field,ref.key),value=aggregateSeries(series,ref.agg,ctx.now,ctx.startTime),unit=ref.agg==="change"?"%":ref.unit,text=value===void 0?MISSING_VALUE_TEXT:formatWidgetNumber(value,unit,ref.digits),trend=ref.better&&TREND_AGGS.has(ref.agg)&&series.values>=2?formatWidgetTrend(series.first,series.last,ref.better,ref.unit):void 0;return{text,value,...trend?{trend}:{}}}function buildHeadline(ref,ctx){let{text,value,trend}=buildValue(ref,ctx);if(value!==void 0)return{text,...ref.label?{label:ref.label}:{},...trend?{trend}:{}}}function buildBlock(block,ctx){switch(block.kind){case"spark":return buildSpark(block,ctx);case"bars":{let entries=ctx.store.keys(block.field,MAX_BAR_ITEMS),unit=block.agg==="change"?"%":block.unit,values=entries.map(([,series])=>aggregateSeries(series,block.agg,ctx.now,ctx.startTime)??0),labels=keyLabels(entries.map(([key])=>key)),items=entries.map(([key],index)=>({key:labels[index]||key||block.label,value:values[index],text:formatWidgetNumber(values[index],unit)})),peak=Math.max(0,...values);return{kind:"bars",label:block.label,items,max:block.max??(peak>0?peak:1)}}case"meter":{let series=ctx.store.series(block.field,block.key),value=aggregateSeries(series,block.agg,ctx.now,ctx.startTime)??0,total=typeof block.total=="number"?block.total:buildValue(block.total,ctx).value??0,fraction=total>0?Math.min(1,Math.max(0,value/total)):0,text=`${formatWidgetNumber(value)}/${formatWidgetNumber(total,meterUnit(block.unit,total))}`;return{kind:"meter",label:block.label,value:fraction,text}}case"stat":return{kind:"stat",items:block.items.map(item=>{let{text,trend}=buildValue(item,ctx);return{label:item.label,text,...trend?{trend}:{}}})};case"grid":{let entries=ctx.store.keys(block.field,MAX_GRID_CELLS),labels=keyLabels(entries.map(([key])=>key));return{kind:"grid",label:block.label,cells:entries.map(([key,series],index)=>{let raw=series.text??(series.values>0?formatWidgetNumber(series.last):series.line?.trim()??""),text=truncateText(raw,MAX_TEXT_CHARS);return{key:labels[index]||key||block.label,tone:gridTone(block.tones,text),text}})}}case"text":{let series=ctx.store.series(block.field);return{kind:"text",text:truncateText(series.text??series.line?.trim()??"",MAX_TEXT_CHARS)}}}}function meterUnit(unit,total){if(!unit)return;let match=/^\s*(?:\/|out of\b|of\b)?\s*([^\s/]+)\s*(.*)$/i.exec(unit);return!match||!new Set([String(total),formatWidgetNumber(total)]).has(match[1].replaceAll(",",""))?unit:match[2].trim()||void 0}function buildSpark(block,ctx){let series=ctx.store.series(block.field,block.key),ring=series.ring.length>240?series.ring.slice(-240):series.ring,values=downsample(ring,SPARK_POINTS).map(point=>point.v),marks=block.target===void 0?void 0:[{value:block.target,label:block.targetLabel??`target ${formatWidgetNumber(block.target,block.unit)}`}],{min,max}=sparkDomain([...values,...(marks??[]).map(mark=>mark.value)],block.min,block.max);return{kind:"spark",label:block.label,values,min,max,...marks?{marks}:{},last:series.values>0?formatWidgetNumber(series.last,block.unit):MISSING_VALUE_TEXT}}function sparkDomain(bounds,specMin,specMax){let min=0,max=1;if(bounds.length>0){let lo=Math.min(...bounds),hi=Math.max(...bounds),pad=hi>lo?(hi-lo)*.1:Math.max(1,Math.abs(hi)*.05);min=lo>=0?Math.max(0,lo-pad):lo-pad,max=hi+pad}return min=specMin??min,max=specMax??max,max<=min&&(max=min+1),{min,max}}function hasData(block){switch(block.kind){case"text":return block.text.length>0;case"bars":return block.items.length>0;case"grid":return block.cells.length>0;case"spark":return block.values.length>0;case"meter":case"stat":return!0}}function keyLabels(keys){if(keys.length===0||!keys.every(key=>key.includes("/")))return keys.slice();let short=keys.map(key=>key.slice(key.lastIndexOf("/")+1));return short.every(label=>label.length>0)&&new Set(short).size===short.length?short:keys.slice()}function gridTone(tones,text){let lower=text.toLowerCase();for(let[status,tone]of Object.entries(tones))if(lower.includes(status.toLowerCase()))return tone;return"neutral"}var MAX_MATCH_LINES=2e3,JobWidgetRuntime=class{#matcher;#startTime;#now;#redactSource;#readers=new Map;#stats=new Map;#matchers=new Map;#store;#lastMatchAt;#lastLineAt;#unmatchedLines=0;#lastUnmatchedLine;#progress;constructor(options){this.spec=options.spec,this.#matcher=options.matcher,this.#startTime=options.startTime,this.#now=options.now??Date.now,this.#redactSource=options.redactSource,this.#store=new FieldStore(keyedFields(options.spec),pinnedKeys(options.spec))}get unmatchedLines(){return this.#unmatchedLines}get lastMatchAt(){return this.#lastMatchAt}get totalLines(){let total=0;for(let stats of this.#stats.values())total+=stats.lines;return total}get linesPerSecond(){let recent=[...this.#stats.values()].flatMap(stats=>stats.recent);return windowRate(recent,this.#now(),this.#startTime)}ingest(sources,flush){let t=this.#now(),changed=!1;for(let source of sources){let reader=this.#readers.get(source.id);(!reader||reader.source!==source)&&(reader=new SourceLineReader(source,this.#redactSource?.()),this.#readers.set(source.id,reader));let{lines,end}=reader.read(flush),progress=reader.progress;if(progress!==void 0){let once=this.#redactSource?.(),text=once?[...once.push(progress),...once.finish()].join(" "):progress;this.#progress=truncateText(text.trim(),MAX_STAGE_CHARS)}else lines.length>0&&(this.#progress=void 0);let stats=this.#stats.get(source.id);stats||(stats=newSourceStats(source.id,source.label),this.#stats.set(source.id,stats)),stats.size=end,lines.length!==0&&(changed=!0,recordLines(stats,lines,t)&&(this.#lastLineAt=t),this.#matchLines(source.id,lines,t))}return changed}#sourceMatcher(id){let known=this.#matchers.get(id);if(known!==void 0)return known??void 0;let entry=this.spec?compileSourceMatcher(this.spec,this.#matcher,id):void 0;return this.#matchers.set(id,entry??null),entry}#matchLines(sourceId,lines,t){let entry=this.#sourceMatcher(sourceId);if(!entry)return;let window=lines.length>MAX_MATCH_LINES?lines.slice(-MAX_MATCH_LINES):lines,matched=applyMatches(entry,window,t,this.#store),lastMatched=matched.size>0?Math.max(...matched):-1;lastMatched>=0&&(this.#lastMatchAt=t);let unmatched=0;for(let index=lastMatched+1;index<window.length;index++)window[index].trim().length>0&&(unmatched+=1);this.#unmatchedLines=lastMatched>=0?unmatched:this.#unmatchedLines+unmatched;for(let index=window.length-1;index>=0;index--){let line=window[index].trim();if(!(matched.has(index)||line.length===0)){this.#lastUnmatchedLine=truncateText(line,MAX_STAGE_CHARS);break}}}samples(){return[...this.#stats.values()].filter(stats=>stats.lines>0).sort((a,b)=>b.lines-a.lines).map(sourceSample)}derive(context){let now=this.#now(),updatedAtMs=this.#lastMatchAt??this.#lastLineAt??this.#startTime,lineStage=context.lineStage===!0,spec=this.spec;if(!spec){let stage2=context.stage??(lineStage?this.#progress??latestLine(this.#stats.values()):void 0),title=truncateText(context.label.replace(/\s+/g," ").trim(),48);return{state:context.authoring?"pending":"fallback",view:{title,...stage2?{stage:stage2}:{},blocks:[],lines:this.totalLines},updatedAtMs}}let ctx={store:this.#store,now,startTime:this.#startTime},headline=spec.headline?buildHeadline(spec.headline,ctx):void 0,stage=(spec.stage?this.#specStage(spec.stage):void 0)??context.stage??(lineStage?this.#progress??this.#lastUnmatchedLine:void 0);return{state:context.settled?"done":"live",view:{title:spec.title,...headline?{headline}:{},...stage?{stage}:{},blocks:spec.blocks.map(block=>buildBlock(block,ctx)).filter(hasData)},updatedAtMs}}#specStage(field){let series=this.#store.series(field),text=(series.text??series.line)?.trim();return text?truncateText(text,MAX_STAGE_CHARS):void 0}};var JobWidgetJob=class{#matcher;#redact;#asked;#authoring;#skippedAtMs;constructor(input,matcher,redact){this.settled=!1,this.#asked=!1,this.#authoring=!1,this.id=input.id,this.kind=input.kind,this.startTime=input.startedAtMs??Date.now(),this.sources=input.sources,this.brief={...input.brief,kind:input.kind},this.#matcher=matcher,this.#redact=redact,this.runtime=this.#newRuntime(void 0)}#newRuntime(spec){return new JobWidgetRuntime({spec,matcher:this.#matcher,startTime:this.startTime,redactSource:()=>this.#redact.source()})}ingest(){this.runtime.ingest(this.sources,this.settled)}requestStarted(){this.#asked=!0,this.#authoring=!0}requestSettled(outcome){this.#authoring=!1,outcome.kind==="installed"?(this.runtime=this.#newRuntime(outcome.spec),this.ingest()):outcome.kind==="skipped"&&!this.runtime.spec&&(this.#skippedAtMs=Date.now())}entry(){if(this.#skippedAtMs!==void 0)return{id:this.id,kind:this.kind,state:"skipped",updatedAtMs:this.#skippedAtMs};if(!this.#asked)return;let brief=this.brief,derived=this.runtime.derive({label:this.#redact.text(brief.intent??brief.task??brief.command??this.id),...brief.stage===void 0?{}:{stage:this.#redact.text(brief.stage)},lineStage:this.kind==="bash",authoring:this.#authoring,settled:this.settled});return{id:this.id,kind:this.kind,state:derived.state,view:derived.view,updatedAtMs:derived.updatedAtMs}}};var JOB_WIDGET_REQUEST_LIMITS={authorAfterMs:15e3,minLines:3,maxRequestsPerJob:3,maxInFlight:2,maxPerHour:30,driftLines:200,driftStaleMs:9e4,noModelRetryMs:3e4},REQUEST_WINDOW_MS=3600*1e3;function newAuthoringState(){return{requests:0,inFlight:!1,stopped:!1,specHadWatch:!1}}function reauthorReason(job,state,now,limits){let{brief,runtime}=job;if(brief.watch&&!state.specHadWatch)return`the subagent now says what to watch: ${brief.watch}`;if(runtime.unmatchedLines<limits.driftLines)return;let newest=runtime.lastMatchAt;if(!(newest!==void 0&&now-newest<=limits.driftStaleMs))return`no rule matched the last ${runtime.unmatchedLines} lines`}function planRequest(job,state,now,limits){if(state.inFlight||state.stopped||state.requests>=limits.maxRequestsPerJob||now-job.startTime<limits.authorAfterMs)return;let{brief,runtime}=job;if(brief.kind==="task"&&!brief.watch)return;let skipped=state.skippedWatch;if(!(skipped!==void 0&&(brief.kind==="bash"||skipped===brief.watch))){if(runtime.spec){let reason=reauthorReason(job,state,now,limits);return reason?{previous:{spec:runtime.spec,reason}}:void 0}return runtime.samples().some(sample=>sample.lines>=limits.minLines)?{}:void 0}}var TOOLS_SOURCE_ID="tools";function dryRun(spec,compiled,samples,numeric,errors){let seen=!1,matches=0,marked=new Set,numbers=new Set,words=new Map;for(let sample of samples)if(sample.lines.some(line=>line.trim().length>0)){seen=!0;for(let hit of compiled.matchLines(sample.lines)){let rule=spec.rules[hit.pattern];if(!ruleReadsSource(rule.from,sample.id))continue;matches+=1;let line=sample.lines[hit.line];sample.id===TOOLS_SOURCE_ID&&line.startsWith("\xBB ")&&marked.add(hit.pattern),compiled.groupNames[hit.pattern].forEach((field,position)=>{let span=hit.spans[position];if(field===rule.key||field===rule.text||span===void 0)return;let captured=line.slice(span.start,span.end);Number.isFinite(parseWidgetValue(captured))?numbers.add(field):words.has(field)||words.set(field,captured)})}}seen&&matches===0&&errors.push("no rule matches any sample line; copy the exact text of lines that carry the numbers");for(let index of marked)errors.push(`rules[${index}]: matches \`${"\xBB "}<tool> <intent>\` lines, which mark the subagent's tool calls, not its output; read the result lines below them, or skip if none show progress`);for(let[field,where]of numeric){let word=words.get(field);word===void 0||numbers.has(field)||errors.push(`${where}: field "${field}" needs numbers, but its group captured "${truncateText(word,40)}" in the samples; capture only the digits`)}}function checkStatedNumbers(spec,samples,brief,errors){let stated=statedNumbers([brief,...samples.flatMap(sample=>sample.lines)]);spec.blocks.forEach((block,index)=>{let where=`blocks[${index}] (${block.kind})`;block.kind==="meter"&&typeof block.total=="number"&&!stated.has(block.total)?errors.push(`${where}.total: ${block.total} appears nowhere in the job or its output; read the total from a line (a value ref) or show the value as a stat`):block.kind==="spark"&&block.target!==void 0&&!stated.has(block.target)&&errors.push(`${where}.target: ${block.target} appears nowhere in the job or its output; set a target only when the job states one`)})}var JOB_WIDGET_TONES=["success","error","warning","pending","info","muted","neutral"];function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function readList(value,where,errors,min,max){if(!Array.isArray(value)){errors.push(`${where}: expected an array`);return}if(value.length<min||value.length>max){errors.push(`${where}: expected ${min}\u2013${max} entries, got ${value.length}`);return}return value}function readString(value,where,errors,options={}){if(value==null){options.required&&errors.push(`${where}: required`);return}if(typeof value!="string"){errors.push(`${where}: expected a string`);return}let trimmed=value.trim();if(trimmed.length===0){options.required&&errors.push(`${where}: must not be empty`);return}if(options.max!==void 0&&trimmed.length>options.max){errors.push(`${where}: at most ${options.max} characters`);return}return options.cut===void 0?trimmed:truncateText(trimmed,options.cut)}function readNumber(value,where,errors){if(value!=null){if(typeof value!="number"||!Number.isFinite(value)){errors.push(`${where}: expected a finite number`);return}return value}}function readFieldName(value,where,errors){let name=readString(value,where,errors,{required:!0});if(name!==void 0&&!FIELD_NAME.test(name)){errors.push(`${where}: "${name}" must match ${FIELD_NAME.source}`);return}return name}function readAgg(value,where,errors,fallback){if(value==null&&fallback!==void 0)return fallback;let agg=JOB_WIDGET_AGGS.find(candidate=>candidate===value);return agg===void 0&&errors.push(`${where}: expected one of ${JOB_WIDGET_AGGS.join(", ")}`),agg}function readBetter(value,where,errors){if(value!=null){if(value==="higher"||value==="lower")return value;errors.push(`${where}: expected "higher" or "lower"`)}}function readTone(value,where,errors){let tone=JOB_WIDGET_TONES.find(candidate=>candidate===value);return tone===void 0&&errors.push(`${where}: expected one of ${JOB_WIDGET_TONES.join(", ")}`),tone}function optional(value,name){return value===void 0?{}:{[name]:value}}function parseValueRef(value,where,errors,defaultAgg){if(!isRecord(value)){errors.push(`${where}: expected an object`);return}let field=readFieldName(value.field,`${where}.field`,errors),key=readString(value.key,`${where}.key`,errors,{max:120}),agg=readAgg(value.agg,`${where}.agg`,errors,defaultAgg),unit=readString(value.unit,`${where}.unit`,errors,{cut:12}),digits=readNumber(value.digits,`${where}.digits`,errors);digits!==void 0&&(!Number.isInteger(digits)||digits<0||digits>4)&&errors.push(`${where}.digits: expected an integer 0\u20134`);let better=readBetter(value.better,`${where}.better`,errors);if(!(field===void 0||agg===void 0))return{field,agg,...key!==void 0?{key}:{},...unit!==void 0?{unit}:{},...digits!==void 0?{digits}:{},...better!==void 0?{better}:{}}}function repairRuleGroups(match,key,text){let groups=new Set(patternGroupNames(match)),wrap=text!==void 0&&FIELD_NAME.test(text)&&groups.size===0,keyGroup=key!==void 0&&groups.has(key)?key:void 0,textGroup=text!==void 0&&(wrap||groups.has(text))?text:void 0;return{match:wrap?`(?P<${text}>${match})`:match,...keyGroup!==void 0?{key:keyGroup}:{},...textGroup!==void 0?{text:textGroup}:{}}}function readMeterTotal(raw){let whole=typeof raw=="string"?Number(raw):raw;return isRecord(whole)?{kind:"ref",value:whole}:typeof whole=="number"&&!Number.isNaN(whole)?{kind:"number",value:whole}:{kind:"unknown"}}var DEFAULT_BLOCK_AGG="last";function parseBlock(value,where,errors){if(!isRecord(value)){errors.push(`${where}: expected an object`);return}let before=errors.length,block=parseBlockKind(value,where,errors);return errors.length===before?block:void 0}function parseBlockKind(value,where,errors){let label=()=>readString(value.label,`${where}.label`,errors,{cut:48,required:!0})??"",unit=()=>optional(readString(value.unit,`${where}.unit`,errors,{cut:12}),"unit"),field=()=>readFieldName(value.field,`${where}.field`,errors)??"",key=()=>optional(readString(value.key,`${where}.key`,errors,{max:120}),"key"),better=()=>optional(readBetter(value.better,`${where}.better`,errors),"better"),agg=()=>readAgg(value.agg,`${where}.agg`,errors,DEFAULT_BLOCK_AGG)??DEFAULT_BLOCK_AGG;switch(value.kind){case"spark":return{kind:"spark",field:field(),label:label(),...key(),...unit(),...better(),...optional(readNumber(value.target,`${where}.target`,errors),"target"),...optional(readString(value.targetLabel,`${where}.targetLabel`,errors,{cut:48}),"targetLabel"),...optional(readNumber(value.min,`${where}.min`,errors),"min"),...optional(readNumber(value.max,`${where}.max`,errors),"max")};case"bars":return{kind:"bars",field:field(),agg:agg(),label:label(),...unit(),...optional(readNumber(value.max,`${where}.max`,errors),"max"),...better()};case"meter":return parseMeter(value,where,errors,{field,agg,label,key,unit});case"stat":return{kind:"stat",items:parseStatItems(value.items,`${where}.items`,errors)};case"grid":return{kind:"grid",field:field(),label:label(),tones:parseTones(value.tones,where,errors)};case"text":return{kind:"text",field:field()};default:errors.push(`${where}.kind: expected spark, bars, meter, stat, grid or text`);return}}function parseMeter(value,where,errors,read){let whole=readMeterTotal(value.total);if(whole.kind==="unknown"){let ref=parseValueRef(value,where,errors,DEFAULT_BLOCK_AGG);return ref&&{kind:"stat",items:[{...ref,label:read.label()}]}}let total;return whole.kind==="number"?!Number.isFinite(whole.value)||whole.value<=0?errors.push(`${where}.total: expected a positive number`):total=whole.value:total=parseValueRef(whole.value,`${where}.total`,errors),{kind:"meter",field:read.field(),agg:read.agg(),total:total??1,label:read.label(),...read.key(),...read.unit()}}function parseStatItems(value,where,errors){let items=[];return readList(value,where,errors,1,4)?.forEach((item,index)=>{let itemWhere=`${where}[${index}]`,ref=parseValueRef(item,itemWhere,errors),label=isRecord(item)?readString(item.label,`${itemWhere}.label`,errors,{cut:48,required:!0}):void 0;ref&&label!==void 0&&items.push({...ref,label})}),items}function parseTones(value,where,errors){let tones={};if(!isRecord(value))return errors.push(`${where}.tones: expected an object of status substring \u2192 tone`),tones;let entries=Object.entries(value);entries.length>12&&errors.push(`${where}.tones: at most ${12} entries`);for(let[status,raw]of entries.slice(0,12)){let tone=readTone(raw,`${where}.tones.${status}`,errors);tone!==void 0&&(tones[status]=tone)}return tones}function parseSpec(value,errors){if(!isRecord(value)){errors.push("spec: expected an object");return}let title=readString(value.title,"title",errors,{cut:48,required:!0}),rules=readList(value.rules,"rules",errors,1,12)?.map((rule,index)=>parseRule(rule,`rules[${index}]`,errors)),blocks=readList(value.blocks,"blocks",errors,1,4)?.map((block,index)=>parseBlock(block,`blocks[${index}]`,errors)),headline=value.headline===void 0?void 0:parseHeadline(value.headline,errors),stage=value.stage===void 0?void 0:readFieldName(value.stage,"stage",errors);if(errors.length>0||title===void 0||!rules||!blocks)return;let presentRules=rules.filter(rule=>rule!==void 0),presentBlocks=blocks.filter(block=>block!==void 0);if(!(presentRules.length!==rules.length||presentBlocks.length!==blocks.length))return{title,rules:presentRules,blocks:presentBlocks,...headline?{headline}:{},...stage?{stage}:{}}}function parseHeadline(value,errors){let ref=parseValueRef(value,"headline",errors),label=isRecord(value)?readString(value.label,"headline.label",errors,{cut:48}):void 0;if(ref)return label?{...ref,label}:ref}function parseRule(value,where,errors){if(!isRecord(value)){errors.push(`${where}: expected an object`);return}let from=readString(value.from,`${where}.from`,errors,{required:!0});from!==void 0&&!SOURCE_ID.test(from)&&errors.push(`${where}.from: invalid source id "${from}"`);let match=readString(value.match,`${where}.match`,errors,{required:!0,max:400}),group=name=>{let raw=readString(value[name],`${where}.${name}`,errors);return raw!==void 0&&!GROUP_NAME.test(raw)&&errors.push(`${where}.${name}: invalid group name "${raw}"`),raw},key=group("key"),text=group("text"),count=value.count===void 0?void 0:readFieldName(value.count,`${where}.count`,errors),scale=readNumber(value.scale,`${where}.scale`,errors);if(!(from===void 0||match===void 0))return{from,...repairRuleGroups(match,key,text),...count!==void 0?{count}:{},...scale!==void 0?{scale}:{}}}function jobWidgetSkip(value){if(!isRecord(value)||typeof value.skip!="string")return;let reason=value.skip.trim();return reason.length>0?reason:void 0}function validateJobWidgetSpec(value,options){let errors=[],spec=parseSpec(value,errors);if(!spec)return{ok:!1,errors};let numeric=checkReferences(spec,errors),compiled;try{compiled=compilePatterns(options.matcher,spec.rules.map(rule=>rule.match))}catch(error){if(!(error instanceof MatcherCompileError))throw error;errors.push(`rules[${error.pattern}].match: ${error.reason}`)}return compiled&&options.samples&&errors.length===0&&(dryRun(spec,compiled,options.samples,numeric,errors),options.brief!==void 0&&checkStatedNumbers(spec,options.samples,options.brief,errors)),errors.length>0?{ok:!1,errors}:{ok:!0,spec}}function checkReferences(spec,errors){let feeds=fieldFeeds(spec),numeric=new Map,checkField=(where,field,agg,key)=>{let feed=feeds.get(field);if(!feed){errors.push(`${where}: unknown field "${field}"; no rule has a group (?P<${field}>\u2026) or count "${field}"`);return}key!==void 0&&feed.keyGroups.has(key)&&errors.push(`${where}.key: "${key}" is the name of the key group; set one of its values (one model, one job) or omit \`key\``),!(agg===void 0||!aggNeedsValue(agg))&&(feed.value?numeric.has(field)||numeric.set(field,where):errors.push(`${where}: agg "${agg}" needs numbers, but field "${field}" only counts matches or keeps text`))},checkRef=(where,ref)=>checkField(where,ref.field,ref.agg,ref.key),needsKey=(where,field,kind)=>{feeds.get(field)?.keyGroups.size===0&&errors.push(`${where}: ${kind} need a rule with \`key\``)};return spec.rules.forEach((rule,index)=>{let where=`rules[${index}]`;rule.text!==void 0&&rule.text===rule.key&&errors.push(`${where}.text: the key group is not a field`);for(let group of patternGroupNames(rule.match))group!==rule.key&&!FIELD_NAME.test(group)&&errors.push(`${where}.match: group "${group}" names a field, so it must match ${FIELD_NAME.source}`);ruleFields(rule).length===0&&errors.push(`${where}: feeds no field; name a group (?P<field>\u2026) besides the key, or set \`count\``)}),spec.headline&&checkRef("headline",spec.headline),spec.stage&&checkField("stage",spec.stage,void 0),spec.blocks.forEach((block,index)=>{let where=`blocks[${index}] (${block.kind})`;switch(block.kind){case"spark":checkField(where,block.field,"last",block.key);break;case"bars":checkField(where,block.field,block.agg),needsKey(where,block.field,"bars");break;case"meter":checkField(where,block.field,block.agg,block.key),typeof block.total!="number"&&checkRef(`${where}.total`,block.total);break;case"stat":block.items.forEach((item,itemIndex)=>checkRef(`${where}.items[${itemIndex}]`,item));break;case"grid":checkField(where,block.field,void 0),needsKey(where,block.field,"grids");break;case"text":checkField(where,block.field,void 0);break}}),numeric}var ROUNDS=2;function statedText(brief){return[brief.command,brief.task,brief.intent,brief.watch,brief.stage].filter(Boolean).join(`
|
|
35
|
-
`)}var JobWidgetRequestController=class{#author;#matcher;#now;#limits;#redact;#states=new Map;#aborts=new Map;#sent=[];#inFlight=0;#noModelUntil=Number.NEGATIVE_INFINITY;constructor(options){this.#author=options.author,this.#matcher=options.matcher,this.#now=options.now??Date.now,this.#limits={...JOB_WIDGET_REQUEST_LIMITS,...options.limits},this.#redact=createWidgetRedactor(options.obfuscate)}configure(options){this.#limits={...JOB_WIDGET_REQUEST_LIMITS,...options.limits},this.#redact=createWidgetRedactor(options.obfuscate)}get inFlight(){return this.#inFlight}maybeRequest(job){let now=this.#now();if(now<this.#noModelUntil||this.#inFlight>=this.#limits.maxInFlight||!this.#windowHasRoom(now))return;let state=this.#states.get(job.id);state||(state=newAuthoringState(),this.#states.set(job.id,state));let plan=planRequest(job,state,now,this.#limits);return plan?this.#run(job,state,plan):void 0}forget(jobId){this.#aborts.get(jobId)?.abort(),this.#aborts.delete(jobId),this.#states.delete(jobId)}dispose(){for(let controller of this.#aborts.values())controller.abort();this.#aborts.clear(),this.#states.clear()}#windowHasRoom(now){for(;this.#sent.length>0&&now-(this.#sent[0]??now)>=REQUEST_WINDOW_MS;)this.#sent.shift();return this.#sent.length<this.#limits.maxPerHour}#canSend(state){return state.requests<this.#limits.maxRequestsPerJob&&this.#windowHasRoom(this.#now())}async#run(job,state,plan){let controller=new AbortController;this.#aborts.set(job.id,controller),state.inFlight=!0,this.#inFlight+=1;try{return await this.#rounds(job,state,plan,controller.signal)}catch(error){return controller.signal.aborted?{kind:"aborted"}:{kind:"failed",error}}finally{this.#inFlight-=1,state.inFlight=!1,this.#aborts.get(job.id)===controller&&this.#aborts.delete(job.id)}}async#rounds(job,state,plan,signal){let raw={jobId:job.id,brief:job.brief,sources:job.runtime.samples(),previous:plan.previous},base=redactAuthorRequest(raw,this.#redact),validation={matcher:this.#matcher,samples:sampleLines(base.sources),brief:statedText(base.brief)},rejected,errors=[];for(let round=0;round<ROUNDS&&this.#canSend(state);round++){state.requests+=1;let sentAt=this.#now();this.#sent.push(sentAt);let request=rejected?redactAuthorRequest({...raw,rejected},this.#redact):base,answer=await this.#author(request,signal);if(signal.aborted)return{kind:"aborted"};if(answer===void 0){state.requests-=1;let slot=this.#sent.indexOf(sentAt);return slot!==-1&&this.#sent.splice(slot,1),this.#noModelUntil=this.#now()+this.#limits.noModelRetryMs,{kind:"unavailable"}}let skip=jobWidgetSkip(answer);if(skip!==void 0)return state.skippedWatch=job.brief.watch??"",{kind:"skipped",reason:skip};let checked=validateJobWidgetSpec(answer,validation);if(checked.ok)return state.specHadWatch=!!job.brief.watch,{kind:"installed",spec:checked.spec};errors=checked.errors,rejected={answer:JSON.stringify(answer),errors}}return job.runtime.spec||(state.stopped=!0),{kind:"rejected",errors}}};var VOCABULARY_KEYS=new Set(["kind","tone"]);function redactStrings(value,redact){return typeof value=="string"?redact(value):Array.isArray(value)?value.map(item=>redactStrings(item,redact)):typeof value!="object"||value===null?value:Object.fromEntries(Object.entries(value).map(([key,field])=>[key,VOCABULARY_KEYS.has(key)?field:redactStrings(field,redact)]))}function redactEntry(entry,redact){return entry.view===void 0?entry:{...entry,view:redactStrings(entry.view,redact)}}function redactJobWidgetState(state,redact){return{...state,jobs:state.jobs.map(entry=>redactEntry(entry,redact))}}var PUBLISH_INTERVAL_MS=1e3;function displayKey(state){return JSON.stringify(state.jobs.map(({updatedAtMs:_updatedAtMs,...shown})=>shown))}var EMPTY_KEY="[]",JobWidgetStatePublisher=class{#send;#redact;#sentKey=EMPTY_KEY;#sentAt;#latest;#timer;#disposed=!1;constructor(send,redact){this.#send=send,this.#redact=redact}redacted(state){return redactJobWidgetState(state,this.#redact)}offer(state){if(this.#disposed||(this.#latest=state,this.#timer!==void 0))return;let wait=this.#sentAt===void 0?0:this.#sentAt+PUBLISH_INTERVAL_MS-Date.now();if(wait<=0){this.#flush();return}this.#timer=setTimeout(()=>{this.#timer=void 0,this.#flush()},wait),this.#timer.unref?.()}reset(){this.#sentKey=""}dispose(){this.#disposed=!0,clearTimeout(this.#timer),this.#timer=void 0}#flush(){if(!this.#latest)return;let state=this.redacted(this.#latest),key=displayKey(state);key!==this.#sentKey&&(this.#sentKey=key,this.#sentAt=Date.now(),this.#send(state))}};var INGEST_MIN_INTERVAL_MS=250,REFRESH_INTERVAL_MS=1e3,INERT_HANDLE={notify:()=>{},update:()=>{},settle:()=>{},dispose:()=>{}},JobWidgetRegistry=class{#matcher;#redact={text:text=>this.#currentRedact.text(text),source:()=>this.#currentRedact.source()};#currentRedact;#controller;#publisher;#jobs=new Map;#ticker;#ingestTimer;#lastRefreshAt=Number.NEGATIVE_INFINITY;#disposed=!1;constructor(options){this.sessionId=options.sessionId,this.#matcher=options.matcher??defaultLineMatcher,this.#currentRedact=createWidgetRedactor(options.obfuscate),this.#controller=new JobWidgetRequestController({author:options.author,matcher:this.#matcher,...options.limits===void 0?{}:{limits:options.limits},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}}),this.#publisher=new JobWidgetStatePublisher(options.publish,this.#redact.text)}add(input){if(this.#disposed)return INERT_HANDLE;let previous=this.#jobs.get(input.id);previous&&this.#forget(previous);let job=new JobWidgetJob(input,this.#matcher,this.#redact);this.#jobs.set(job.id,job),this.#refresh(job),this.#ensureTicker();let live=()=>this.#jobs.get(job.id)===job;return{notify:()=>{live()&&!job.settled&&this.#scheduleRefresh()},update:brief=>{live()&&(job.brief={...brief,kind:job.kind},this.#scheduleRefresh())},settle:()=>{live()&&this.#settle(job)},dispose:()=>{live()&&this.#forget(job)}}}state(){return this.#publisher.redacted(this.snapshot())}snapshot(){let jobs=[];for(let job of this.#jobs.values()){let entry=job.entry();entry&&jobs.push(entry)}return{v:1,sessionId:this.sessionId,jobs}}configure(options){this.#currentRedact=createWidgetRedactor(options.obfuscate),this.#controller.configure(options)}republish(){this.#publisher.reset(),this.#publish()}dispose(){this.#disposed=!0,this.#stopTicker(),clearTimeout(this.#ingestTimer),this.#ingestTimer=void 0,this.#controller.dispose(),this.#publisher.dispose(),this.#jobs.clear()}#scheduleRefresh(){if(this.#disposed||this.#ingestTimer!==void 0)return;let wait=Math.max(0,this.#lastRefreshAt+INGEST_MIN_INTERVAL_MS-Date.now());this.#ingestTimer=setTimeout(()=>{this.#ingestTimer=void 0,this.#refreshAll()},wait),this.#ingestTimer.unref?.()}#refreshAll(){if(!this.#disposed){this.#lastRefreshAt=Date.now();for(let job of this.#jobs.values())job.settled||this.#refresh(job);this.#publish()}}#refresh(job){if(job.ingest(),job.settled)return;let pending=this.#controller.maybeRequest(job);pending&&(job.requestStarted(),pending.then(outcome=>{this.#disposed||this.#jobs.get(job.id)!==job||(job.requestSettled(outcome),this.#publish())}))}#settle(job){job.settled=!0,job.ingest(),this.#publish(),this.#stopTickerWhenIdle()}#forget(job){this.#jobs.delete(job.id),this.#controller.forget(job.id),this.#publish(),this.#stopTickerWhenIdle()}#publish(){this.#disposed||this.#publisher.offer(this.snapshot())}#ensureTicker(){this.#ticker===void 0&&(this.#ticker=setInterval(()=>this.#refreshAll(),REFRESH_INTERVAL_MS),this.#ticker.unref?.())}#stopTickerWhenIdle(){for(let job of this.#jobs.values())if(!job.settled)return;this.#stopTicker()}#stopTicker(){clearInterval(this.#ticker),this.#ticker=void 0}};var sessions=new Map,sessionListeners=new Set,hostResolver;function onJobWidgetSessionChange(listener){return sessionListeners.add(listener),()=>{sessionListeners.delete(listener)}}function notifySessionChange(sessionId,open2){for(let listener of[...sessionListeners])listener(sessionId,open2)}function openJobWidgetSession(sessionId,options){let existing=sessions.get(sessionId);if(existing){existing.author=options.author,existing.publish=options.publish,existing.registry.configure({limits:{authorAfterMs:options.authorAfterMs},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}}),existing.registry.republish();return}let slot={author:options.author,publish:options.publish,registry:new JobWidgetRegistry({sessionId,author:(request,signal)=>slot.author(request,signal),publish:state=>slot.publish?.(state),limits:{authorAfterMs:options.authorAfterMs},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}})};sessions.set(sessionId,slot),notifySessionChange(sessionId,!0)}function resendJobWidgetState(sessionId){let registry=sessions.get(sessionId)?.registry;registry&®istry.snapshot().jobs.length>0&®istry.republish()}function parkJobWidgetSession(sessionId){let slot=sessions.get(sessionId);slot&&(slot.publish=void 0)}function closeJobWidgetSession(sessionId){let slot=sessions.get(sessionId);slot&&(slot.registry.dispose(),sessions.delete(sessionId),notifySessionChange(sessionId,!1))}function registerJobWidgetSource(registration){let{sessionId,...input}=registration;return sessions.get(sessionId)?.registry.add(input)}function getJobWidgetState(sessionId){return sessions.get(sessionId)?.registry.state()}function setJobWidgetAuthorResolver(resolver){return hostResolver=resolver,()=>{hostResolver===resolver&&(hostResolver=void 0)}}function jobWidgetHostResolver(){return hostResolver}function truncateToVisualLines(text,maxVisualLines,width,paddingX=0,keep="end"){if(!text)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var TerminalManager=class{constructor(options={}){this.runtimes=new Map,this.monitorIds=new Map,this.exited=new Set,this.reservations=0,this.maxSessions=options.maxSessions??DEFAULT_MAX_SESSIONS,this.scrollback=options.scrollback,options.idScope!==void 0&&(this.idScope=options.idScope)}get size(){return this.runtimes.size}get activeSize(){return this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations}reserve(){if(this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations>=this.maxSessions)return null;this.reservations+=1;let released=!1;return()=>{released||(released=!0,this.reservations-=1)}}async create(command,options){let pty=await loadPty(),release=this.reserve();if(!release)throw new pty.SessionRegistryCapacityError(this.maxSessions);this.registry??=new pty.SessionRegistry({maxSessions:this.maxSessions,...this.idScope===void 0?{}:{idScope:this.idScope}});let registry=this.registry,runtimeOptions={...options,scrollback:this.scrollback},{TerminalRuntimeSession}=await import("./runtime-session-VO3X4OE3.js"),runtime=new TerminalRuntimeSession(command,runtimeOptions),entry;try{entry=await registry.create({command,session:runtime.session})}catch(error){throw release(),runtime.dispose(),runtime.session.kill(),error}return this.runtimes.set(entry.id,runtime),runtime.session.onExit(()=>{this.exited.add(entry.id)}),release(),this.reconcileRuntimes(),{id:entry.id,runtime}}get(id){let registry=this.registry;return!registry||!registry.get(id)?null:this.runtimes.get(id)??null}bindMonitorId(monitorId,sessionId){this.monitorIds.set(monitorId,sessionId)}monitorIdOf(runtimeId){for(let[monitorId,sessionId]of this.monitorIds)if(sessionId===runtimeId)return monitorId}resolveId(idOrMonitorId){if(idOrMonitorId.startsWith("mon_"))return this.monitorIds.get(idOrMonitorId);let registry=this.registry;if(registry)return registry.get(idOrMonitorId)?idOrMonitorId:void 0}list(){let registry=this.registry;if(!registry)return[];let result=[];for(let entry of registry.list()){let runtime=this.runtimes.get(entry.id);runtime&&result.push({id:entry.id,runtime})}return result}async stop(id){let registry=this.registry;if(!registry)return!1;let stopped=await registry.stop(id);return this.reconcileRuntimes(),stopped}async teardown(){let registry=this.registry;registry&&await registry.teardown(),this.registry=void 0;for(let runtime of this.runtimes.values())runtime.dispose();this.runtimes.clear(),this.exited.clear(),this.monitorIds.clear()}reconcileRuntimes(){let registry=this.registry;if(!registry)return;let liveIds=new Set(registry.list().map(entry=>entry.id));for(let[id,runtime]of this.runtimes)if(!liveIds.has(id)){runtime.dispose(),this.runtimes.delete(id),this.exited.delete(id);for(let[monitorId,sessionId]of this.monitorIds)sessionId===id&&this.monitorIds.delete(monitorId)}}};var token=code=>new RegExp(`(?<![A-Za-z0-9_])${code}(?![A-Za-z0-9_])`,"u"),SHELL_TRUST_PATTERNS=[["UNABLE_TO_GET_ISSUER_CERT_LOCALLY",token("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")],["UNABLE_TO_GET_ISSUER_CERT",token("UNABLE_TO_GET_ISSUER_CERT")],["UNABLE_TO_VERIFY_LEAF_SIGNATURE",token("UNABLE_TO_VERIFY_LEAF_SIGNATURE")],["SELF_SIGNED_CERT_IN_CHAIN",token("SELF_SIGNED_CERT_IN_CHAIN")],["DEPTH_ZERO_SELF_SIGNED_CERT",token("DEPTH_ZERO_SELF_SIGNED_CERT")],["CERT_UNTRUSTED",token("CERT_UNTRUSTED")],["unable-to-verify-the-first-certificate",/unable to verify the first certificate/iu],["unable-to-get-local-issuer-certificate",/unable to get local issuer certificate/iu],["unable-to-get-issuer-certificate",/unable to get issuer certificate/iu],["self-signed-certificate-in-certificate-chain",/self[- ]signed certificate in certificate chain/iu],["self-signed-certificate",/self[- ]signed certificate/iu],["certificate-not-trusted",/certificate not trusted/iu]];function annotateShellTrust({exitCode,output}){let marker=adoptedEngineTrust();if(marker?.automatic!=="fallback"||marker.fallbackReason===null||exitCode===null||exitCode===0)return;let reason=marker.fallbackReason,action=engineTrustAction(reason),status={code:"trust-import-degraded",reason,action:action.id},pattern=SHELL_TRUST_PATTERNS.find(([,matcher])=>matcher.test(output))?.[0];return pattern===void 0?{trust:{status},text:void 0}:{trust:{status,hint:{code:"tls-verify-text-in-output",heuristic:!0,pattern}},text:`omo: certificate import is degraded (${reason}), so some TLS connections may fail. This command's output contains text that looks like a certificate verification error; omo has not confirmed the cause. To diagnose: ${action.text}`}}function modelOnlyText(text){return{type:"text",text,audience:"model"}}function isModelOnlyText(part){return typeof part=="object"&&part!==null&&"type"in part&&part.type==="text"&&"audience"in part&&part.audience==="model"}var TERMINAL_TOOL_MAX_LINES=2e3,TERMINAL_TOOL_MAX_BYTES=50*1024,OSC_PATTERN=/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,CSI_PATTERN=/\x1b\[[0-?]*[ -/]*[@-~]/g,DESIGNATE_AND_SINGLE_PATTERN=/\x1b(?:[()#%*+][0-9A-Za-z]|[0-9<=>@-Z\\-_])/g,C0_CONTROL_PATTERN=/[\x00-\x07\x0b\x0c\x0e-\x1f\x7f]/g;function stripEscapeSequences(text){return text.replace(OSC_PATTERN,"").replace(CSI_PATTERN,"").replace(DESIGNATE_AND_SINGLE_PATTERN,"").replace(C0_CONTROL_PATTERN,"")}function collapseRedraws(line){let cells=[],cursor=0;for(let ch of line)ch==="\r"?cursor=0:ch==="\b"?cursor>0&&(cursor-=1):(cells[cursor]=ch,cursor+=1);return cells.join("")}function sanitizeTerminalOutput(raw){return stripEscapeSequences(raw).replace(/\r\n/g,`
|
|
35
|
+
`)}var JobWidgetRequestController=class{#author;#matcher;#now;#limits;#redact;#states=new Map;#aborts=new Map;#sent=[];#inFlight=0;#noModelUntil=Number.NEGATIVE_INFINITY;constructor(options){this.#author=options.author,this.#matcher=options.matcher,this.#now=options.now??Date.now,this.#limits={...JOB_WIDGET_REQUEST_LIMITS,...options.limits},this.#redact=createWidgetRedactor(options.obfuscate)}configure(options){this.#limits={...JOB_WIDGET_REQUEST_LIMITS,...options.limits},this.#redact=createWidgetRedactor(options.obfuscate)}get inFlight(){return this.#inFlight}maybeRequest(job){let now=this.#now();if(now<this.#noModelUntil||this.#inFlight>=this.#limits.maxInFlight||!this.#windowHasRoom(now))return;let state=this.#states.get(job.id);state||(state=newAuthoringState(),this.#states.set(job.id,state));let plan=planRequest(job,state,now,this.#limits);return plan?this.#run(job,state,plan):void 0}forget(jobId){this.#aborts.get(jobId)?.abort(),this.#aborts.delete(jobId),this.#states.delete(jobId)}dispose(){for(let controller of this.#aborts.values())controller.abort();this.#aborts.clear(),this.#states.clear()}#windowHasRoom(now){for(;this.#sent.length>0&&now-(this.#sent[0]??now)>=REQUEST_WINDOW_MS;)this.#sent.shift();return this.#sent.length<this.#limits.maxPerHour}#canSend(state){return state.requests<this.#limits.maxRequestsPerJob&&this.#windowHasRoom(this.#now())}async#run(job,state,plan){let controller=new AbortController;this.#aborts.set(job.id,controller),state.inFlight=!0,this.#inFlight+=1;try{return await this.#rounds(job,state,plan,controller.signal)}catch(error){return controller.signal.aborted?{kind:"aborted"}:{kind:"failed",error}}finally{this.#inFlight-=1,state.inFlight=!1,this.#aborts.get(job.id)===controller&&this.#aborts.delete(job.id)}}async#rounds(job,state,plan,signal){let raw={jobId:job.id,brief:job.brief,sources:job.runtime.samples(),previous:plan.previous},base=redactAuthorRequest(raw,this.#redact),validation={matcher:this.#matcher,samples:sampleLines(base.sources),brief:statedText(base.brief)},rejected,errors=[];for(let round=0;round<ROUNDS&&this.#canSend(state);round++){state.requests+=1;let sentAt=this.#now();this.#sent.push(sentAt);let request=rejected?redactAuthorRequest({...raw,rejected},this.#redact):base,answer=await this.#author(request,signal);if(signal.aborted)return{kind:"aborted"};if(answer===void 0){state.requests-=1;let slot=this.#sent.indexOf(sentAt);return slot!==-1&&this.#sent.splice(slot,1),this.#noModelUntil=this.#now()+this.#limits.noModelRetryMs,{kind:"unavailable"}}let skip=jobWidgetSkip(answer);if(skip!==void 0)return state.skippedWatch=job.brief.watch??"",{kind:"skipped",reason:skip};let checked=validateJobWidgetSpec(answer,validation);if(checked.ok)return state.specHadWatch=!!job.brief.watch,{kind:"installed",spec:checked.spec};errors=checked.errors,rejected={answer:JSON.stringify(answer),errors}}return job.runtime.spec||(state.stopped=!0),{kind:"rejected",errors}}};var VOCABULARY_KEYS=new Set(["kind","tone"]);function redactStrings(value,redact){return typeof value=="string"?redact(value):Array.isArray(value)?value.map(item=>redactStrings(item,redact)):typeof value!="object"||value===null?value:Object.fromEntries(Object.entries(value).map(([key,field])=>[key,VOCABULARY_KEYS.has(key)?field:redactStrings(field,redact)]))}function redactEntry(entry,redact){return entry.view===void 0?entry:{...entry,view:redactStrings(entry.view,redact)}}function redactJobWidgetState(state,redact){return{...state,jobs:state.jobs.map(entry=>redactEntry(entry,redact))}}var PUBLISH_INTERVAL_MS=1e3;function displayKey(state){return JSON.stringify(state.jobs.map(({updatedAtMs:_updatedAtMs,...shown})=>shown))}var EMPTY_KEY="[]",JobWidgetStatePublisher=class{#send;#redact;#sentKey=EMPTY_KEY;#sentAt;#latest;#timer;#disposed=!1;constructor(send,redact){this.#send=send,this.#redact=redact}redacted(state){return redactJobWidgetState(state,this.#redact)}offer(state){if(this.#disposed||(this.#latest=state,this.#timer!==void 0))return;let wait=this.#sentAt===void 0?0:this.#sentAt+PUBLISH_INTERVAL_MS-Date.now();if(wait<=0){this.#flush();return}this.#timer=setTimeout(()=>{this.#timer=void 0,this.#flush()},wait),this.#timer.unref?.()}reset(){this.#sentKey=""}dispose(){this.#disposed=!0,clearTimeout(this.#timer),this.#timer=void 0}#flush(){if(!this.#latest)return;let state=this.redacted(this.#latest),key=displayKey(state);key!==this.#sentKey&&(this.#sentKey=key,this.#sentAt=Date.now(),this.#send(state))}};var INGEST_MIN_INTERVAL_MS=250,REFRESH_INTERVAL_MS=1e3,INERT_HANDLE={notify:()=>{},update:()=>{},settle:()=>{},dispose:()=>{}},JobWidgetRegistry=class{#matcher;#redact={text:text=>this.#currentRedact.text(text),source:()=>this.#currentRedact.source()};#currentRedact;#controller;#publisher;#jobs=new Map;#ticker;#ingestTimer;#lastRefreshAt=Number.NEGATIVE_INFINITY;#disposed=!1;constructor(options){this.sessionId=options.sessionId,this.#matcher=options.matcher??defaultLineMatcher,this.#currentRedact=createWidgetRedactor(options.obfuscate),this.#controller=new JobWidgetRequestController({author:options.author,matcher:this.#matcher,...options.limits===void 0?{}:{limits:options.limits},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}}),this.#publisher=new JobWidgetStatePublisher(options.publish,this.#redact.text)}add(input){if(this.#disposed)return INERT_HANDLE;let previous=this.#jobs.get(input.id);previous&&this.#forget(previous);let job=new JobWidgetJob(input,this.#matcher,this.#redact);this.#jobs.set(job.id,job),this.#refresh(job),this.#ensureTicker();let live=()=>this.#jobs.get(job.id)===job;return{notify:()=>{live()&&!job.settled&&this.#scheduleRefresh()},update:brief=>{live()&&(job.brief={...brief,kind:job.kind},this.#scheduleRefresh())},settle:()=>{live()&&this.#settle(job)},dispose:()=>{live()&&this.#forget(job)}}}state(){return this.#publisher.redacted(this.snapshot())}snapshot(){let jobs=[];for(let job of this.#jobs.values()){let entry=job.entry();entry&&jobs.push(entry)}return{v:1,sessionId:this.sessionId,jobs}}configure(options){this.#currentRedact=createWidgetRedactor(options.obfuscate),this.#controller.configure(options)}republish(){this.#publisher.reset(),this.#publish()}dispose(){this.#disposed=!0,this.#stopTicker(),clearTimeout(this.#ingestTimer),this.#ingestTimer=void 0,this.#controller.dispose(),this.#publisher.dispose(),this.#jobs.clear()}#scheduleRefresh(){if(this.#disposed||this.#ingestTimer!==void 0)return;let wait=Math.max(0,this.#lastRefreshAt+INGEST_MIN_INTERVAL_MS-Date.now());this.#ingestTimer=setTimeout(()=>{this.#ingestTimer=void 0,this.#refreshAll()},wait),this.#ingestTimer.unref?.()}#refreshAll(){if(!this.#disposed){this.#lastRefreshAt=Date.now();for(let job of this.#jobs.values())job.settled||this.#refresh(job);this.#publish()}}#refresh(job){if(job.ingest(),job.settled)return;let pending=this.#controller.maybeRequest(job);pending&&(job.requestStarted(),pending.then(outcome=>{this.#disposed||this.#jobs.get(job.id)!==job||(job.requestSettled(outcome),this.#publish())}))}#settle(job){job.settled=!0,job.ingest(),this.#publish(),this.#stopTickerWhenIdle()}#forget(job){this.#jobs.delete(job.id),this.#controller.forget(job.id),this.#publish(),this.#stopTickerWhenIdle()}#publish(){this.#disposed||this.#publisher.offer(this.snapshot())}#ensureTicker(){this.#ticker===void 0&&(this.#ticker=setInterval(()=>this.#refreshAll(),REFRESH_INTERVAL_MS),this.#ticker.unref?.())}#stopTickerWhenIdle(){for(let job of this.#jobs.values())if(!job.settled)return;this.#stopTicker()}#stopTicker(){clearInterval(this.#ticker),this.#ticker=void 0}};var sessions=new Map,sessionListeners=new Set,hostResolver;function onJobWidgetSessionChange(listener){return sessionListeners.add(listener),()=>{sessionListeners.delete(listener)}}function notifySessionChange(sessionId,open2){for(let listener of[...sessionListeners])listener(sessionId,open2)}function openJobWidgetSession(sessionId,options){let existing=sessions.get(sessionId);if(existing){existing.author=options.author,existing.publish=options.publish,existing.registry.configure({limits:{authorAfterMs:options.authorAfterMs},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}}),existing.registry.republish();return}let slot={author:options.author,publish:options.publish,registry:new JobWidgetRegistry({sessionId,author:(request,signal)=>slot.author(request,signal),publish:state=>slot.publish?.(state),limits:{authorAfterMs:options.authorAfterMs},...options.obfuscate===void 0?{}:{obfuscate:options.obfuscate}})};sessions.set(sessionId,slot),notifySessionChange(sessionId,!0)}function resendJobWidgetState(sessionId){let registry=sessions.get(sessionId)?.registry;registry&®istry.snapshot().jobs.length>0&®istry.republish()}function parkJobWidgetSession(sessionId){let slot=sessions.get(sessionId);slot&&(slot.publish=void 0)}function closeJobWidgetSession(sessionId){let slot=sessions.get(sessionId);slot&&(slot.registry.dispose(),sessions.delete(sessionId),notifySessionChange(sessionId,!1))}function registerJobWidgetSource(registration){let{sessionId,...input}=registration;return sessions.get(sessionId)?.registry.add(input)}function getJobWidgetState(sessionId){return sessions.get(sessionId)?.registry.state()}function setJobWidgetAuthorResolver(resolver){return hostResolver=resolver,()=>{hostResolver===resolver&&(hostResolver=void 0)}}function jobWidgetHostResolver(){return hostResolver}function truncateToVisualLines(text,maxVisualLines,width,paddingX=0,keep="end"){if(!text)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var TerminalManager=class{constructor(options={}){this.runtimes=new Map,this.monitorIds=new Map,this.exited=new Set,this.reservations=0,this.maxSessions=options.maxSessions??DEFAULT_MAX_SESSIONS,this.scrollback=options.scrollback,options.idScope!==void 0&&(this.idScope=options.idScope)}get size(){return this.runtimes.size}get activeSize(){return this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations}reserve(){if(this.reconcileRuntimes(),this.runtimes.size-this.exited.size+this.reservations>=this.maxSessions)return null;this.reservations+=1;let released=!1;return()=>{released||(released=!0,this.reservations-=1)}}async create(command,options){let pty=await loadPty(),release=this.reserve();if(!release)throw new pty.SessionRegistryCapacityError(this.maxSessions);this.registry??=new pty.SessionRegistry({maxSessions:this.maxSessions,...this.idScope===void 0?{}:{idScope:this.idScope}});let registry=this.registry,runtimeOptions={...options,scrollback:this.scrollback},{TerminalRuntimeSession}=await import("./runtime-session-KKHEYZOH.js"),runtime=new TerminalRuntimeSession(command,runtimeOptions),entry;try{entry=await registry.create({command,session:runtime.session})}catch(error){throw release(),runtime.dispose(),runtime.session.kill(),error}return this.runtimes.set(entry.id,runtime),runtime.session.onExit(()=>{this.exited.add(entry.id)}),release(),this.reconcileRuntimes(),{id:entry.id,runtime}}get(id){let registry=this.registry;return!registry||!registry.get(id)?null:this.runtimes.get(id)??null}bindMonitorId(monitorId,sessionId){this.monitorIds.set(monitorId,sessionId)}monitorIdOf(runtimeId){for(let[monitorId,sessionId]of this.monitorIds)if(sessionId===runtimeId)return monitorId}resolveId(idOrMonitorId){if(idOrMonitorId.startsWith("mon_"))return this.monitorIds.get(idOrMonitorId);let registry=this.registry;if(registry)return registry.get(idOrMonitorId)?idOrMonitorId:void 0}list(){let registry=this.registry;if(!registry)return[];let result=[];for(let entry of registry.list()){let runtime=this.runtimes.get(entry.id);runtime&&result.push({id:entry.id,runtime})}return result}async stop(id){let registry=this.registry;if(!registry)return!1;let stopped=await registry.stop(id);return this.reconcileRuntimes(),stopped}async teardown(){let registry=this.registry;registry&&await registry.teardown(),this.registry=void 0;for(let runtime of this.runtimes.values())runtime.dispose();this.runtimes.clear(),this.exited.clear(),this.monitorIds.clear()}reconcileRuntimes(){let registry=this.registry;if(!registry)return;let liveIds=new Set(registry.list().map(entry=>entry.id));for(let[id,runtime]of this.runtimes)if(!liveIds.has(id)){runtime.dispose(),this.runtimes.delete(id),this.exited.delete(id);for(let[monitorId,sessionId]of this.monitorIds)sessionId===id&&this.monitorIds.delete(monitorId)}}};var token=code=>new RegExp(`(?<![A-Za-z0-9_])${code}(?![A-Za-z0-9_])`,"u"),SHELL_TRUST_PATTERNS=[["UNABLE_TO_GET_ISSUER_CERT_LOCALLY",token("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")],["UNABLE_TO_GET_ISSUER_CERT",token("UNABLE_TO_GET_ISSUER_CERT")],["UNABLE_TO_VERIFY_LEAF_SIGNATURE",token("UNABLE_TO_VERIFY_LEAF_SIGNATURE")],["SELF_SIGNED_CERT_IN_CHAIN",token("SELF_SIGNED_CERT_IN_CHAIN")],["DEPTH_ZERO_SELF_SIGNED_CERT",token("DEPTH_ZERO_SELF_SIGNED_CERT")],["CERT_UNTRUSTED",token("CERT_UNTRUSTED")],["unable-to-verify-the-first-certificate",/unable to verify the first certificate/iu],["unable-to-get-local-issuer-certificate",/unable to get local issuer certificate/iu],["unable-to-get-issuer-certificate",/unable to get issuer certificate/iu],["self-signed-certificate-in-certificate-chain",/self[- ]signed certificate in certificate chain/iu],["self-signed-certificate",/self[- ]signed certificate/iu],["certificate-not-trusted",/certificate not trusted/iu]];function annotateShellTrust({exitCode,output}){let marker=adoptedEngineTrust();if(marker?.automatic!=="fallback"||marker.fallbackReason===null||exitCode===null||exitCode===0)return;let reason=marker.fallbackReason,action=engineTrustAction(reason),status={code:"trust-import-degraded",reason,action:action.id},pattern=SHELL_TRUST_PATTERNS.find(([,matcher])=>matcher.test(output))?.[0];return pattern===void 0?{trust:{status},text:void 0}:{trust:{status,hint:{code:"tls-verify-text-in-output",heuristic:!0,pattern}},text:`omo: certificate import is degraded (${reason}), so some TLS connections may fail. This command's output contains text that looks like a certificate verification error; omo has not confirmed the cause. To diagnose: ${action.text}`}}function modelOnlyText(text){return{type:"text",text,audience:"model"}}function isModelOnlyText(part){return typeof part=="object"&&part!==null&&"type"in part&&part.type==="text"&&"audience"in part&&part.audience==="model"}var TERMINAL_TOOL_MAX_LINES=2e3,TERMINAL_TOOL_MAX_BYTES=50*1024,OSC_PATTERN=/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g,CSI_PATTERN=/\x1b\[[0-?]*[ -/]*[@-~]/g,DESIGNATE_AND_SINGLE_PATTERN=/\x1b(?:[()#%*+][0-9A-Za-z]|[0-9<=>@-Z\\-_])/g,C0_CONTROL_PATTERN=/[\x00-\x07\x0b\x0c\x0e-\x1f\x7f]/g;function stripEscapeSequences(text){return text.replace(OSC_PATTERN,"").replace(CSI_PATTERN,"").replace(DESIGNATE_AND_SINGLE_PATTERN,"").replace(C0_CONTROL_PATTERN,"")}function collapseRedraws(line){let cells=[],cursor=0;for(let ch of line)ch==="\r"?cursor=0:ch==="\b"?cursor>0&&(cursor-=1):(cells[cursor]=ch,cursor+=1);return cells.join("")}function sanitizeTerminalOutput(raw){return stripEscapeSequences(raw).replace(/\r\n/g,`
|
|
36
36
|
`).split(`
|
|
37
37
|
`).map(collapseRedraws).join(`
|
|
38
38
|
`)}function formatTerminalToolOutput(raw){let sanitized=sanitizeTerminalOutput(raw).trimEnd(),truncation=truncateTail(sanitized,{maxLines:TERMINAL_TOOL_MAX_LINES,maxBytes:TERMINAL_TOOL_MAX_BYTES});if(!truncation.truncated)return{text:sanitized,body:sanitized,truncated:!1,truncation};let marker=truncation.lastLinePartial?`[Showing last ${formatSize(truncation.outputBytes)} of a single line; earlier output dropped]`:`[Showing lines ${truncation.totalLines-truncation.outputLines+1}-${truncation.totalLines} of ${truncation.totalLines}; earlier output dropped]`;return{text:`${truncation.content}
|
|
@@ -41,11 +41,11 @@ ${marker}`,body:truncation.content,marker,truncated:!0,truncation}}function spli
|
|
|
41
41
|
`)){if(afterNotice&&index===cursor)parts.push(modelOnlyText(notice));else if(index>cursor&&text[index-1]===`
|
|
42
42
|
`)parts.push({type:"text",text:text.slice(cursor,index-1)},modelOnlyText(notice));else continue;cursor=end<text.length?end+1:end,afterNotice=end<text.length}}return parts.length===0?[{type:"text",text}]:((cursor<text.length||text[text.length-1]===`
|
|
43
43
|
`)&&parts.push({type:"text",text:text.slice(cursor)}),parts)}function withTerminalContext(callback,retire){try{return callback()}catch(error){if(!isStaleExtensionContextError(error))throw error;retire();return}}async function spawnCommandSession(ctx,request){let shell=getShellConfig(ctx.shellPath),useStdin=shell.commandTransport==="stdin",args=useStdin?[...shell.args]:[...shell.args,request.command],launch=ctx.launchBarrier?.wrap(shell.shell,args)??{command:shell.shell,args},created=await ctx.manager.create(shell.shell,{command:launch.command,args:[...launch.args],cwd:request.cwd??ctx.cwd,env:{...ctx.getEnv(),...request.envOverrides},cols:request.cols,rows:request.rows,timeoutMs:request.timeoutMs,redactSecretsInOutput:ctx.redactSecretsInOutput});if(ctx.launchBarrier!==void 0){let session=created.runtime.session;try{await ctx.launchBarrier.release({pid:session.pid,write:data=>session.write(data),onExit:listener=>session.onExit(()=>listener(session.exitResult?.exitCode??null))})}catch(error){throw await ctx.manager.stop(created.id),error}}return useStdin&&created.runtime.session.write(`${request.command}
|
|
44
|
-
`),created}function describeExit(runtime){let exit=runtime.exitResult;return exit?exit.timedOut?"timed_out":exit.cancelled?"killed":exit.exitCode===0?"completed":exit.exitCode!==null?`exited_${exit.exitCode}`:exit.signal?`signal_${exit.signal}`:"exited":null}var NON_INTERACTIVE_MODES=new Set(["print","json"]),TERMINAL_NOTIFICATION_CUSTOM_TYPE="senpi-terminal:notification",NOTICE_TAIL_MAX_CHARS=2e3;function getTerminalNotificationDelivery(deps,customType=TERMINAL_NOTIFICATION_CUSTOM_TYPE){let mode=deps.getMode();if(mode==="off")return;let ctx=deps.getContext();if(!(!ctx||NON_INTERACTIVE_MODES.has(ctx.mode)||!ctx.model))return{send:(content,options)=>deps.sendMessage({customType,content,display:!1,...options?.details===void 0?{}:{details:options.details}},{triggerTurn:!0,deliverAs:mode==="wake"||options?.forceWake===!0?"steer":"followUp"})}}function minutes(count){return`${count} minute${count===1?"":"s"}`}function killCall(id){return`kill_bash({ bash_id: "${id}" })`}function describeBackgroundAge(event){let label=event.command===void 0||event.command===event.description?event.description:`${event.description}: ${event.command}`,session=`Background terminal session ${event.id} (${label})`;if(event.kind==="reaped")return`${session} was stopped automatically after ${minutes(event.autoReapMinutes??event.ageMinutes)} (auto-reap).`;if(event.kind==="reap_failed")return`${session} is still running: auto-reap at ${minutes(event.autoReapMinutes??event.ageMinutes)} failed (${event.reason??"unknown reason"}) and will not retry; stop it with ${killCall(event.id)} if it is no longer needed.`;let reap=event.autoReapMinutes===null?"Nothing stops it automatically":`Auto-reap stops it at ${minutes(event.autoReapMinutes)}`;return`${session} has been running for ${minutes(event.ageMinutes)}. ${reap}; stop it now with ${killCall(event.id)} if it is no longer needed.`}function buildNotice(id,runtime,trustText){let reaped=runtime.autoReapedAfterMinutes,reapText=reaped===void 0?"":` It was stopped automatically after ${minutes(reaped)} (auto-reap: the auto_reap_minutes parameter or the terminal.backgroundAutoReapMinutes setting).`,status=describeExit(runtime)??"exited",code=runtime.exitResult?.exitCode,codeText=code==null?"":` (exit code ${code})`,tail=sanitizeTerminalOutput(runtime.fullOutput()).trimEnd(),tailSection="";if(tail.length>0){let truncated=tail.length>NOTICE_TAIL_MAX_CHARS,shown=truncated?tail.slice(tail.length-NOTICE_TAIL_MAX_CHARS):tail,note=truncated?`
|
|
44
|
+
`),created}function describeExit(runtime){let exit=runtime.exitResult;return exit?exit.timedOut?"timed_out":exit.cancelled?"killed":exit.exitCode===0?"completed":exit.exitCode!==null?`exited_${exit.exitCode}`:exit.signal?`signal_${exit.signal}`:"exited":null}var NON_INTERACTIVE_MODES=new Set(["print","json"]),TERMINAL_NOTIFICATION_CUSTOM_TYPE="senpi-terminal:notification",NOTICE_TAIL_MAX_CHARS=2e3;function getTerminalNotificationDelivery(deps,customType=TERMINAL_NOTIFICATION_CUSTOM_TYPE){let mode=deps.getMode();if(mode==="off")return;let ctx=deps.getContext();if(!(!ctx||NON_INTERACTIVE_MODES.has(ctx.mode)||!ctx.model))return{send:(content,options)=>deps.sendMessage({customType,content,display:!1,...options?.details===void 0?{}:{details:options.details}},options?.nextTurn===!0?{triggerTurn:!1,deliverAs:"nextTurn"}:{triggerTurn:!0,deliverAs:mode==="wake"||options?.forceWake===!0?"steer":"followUp"})}}function minutes(count){return`${count} minute${count===1?"":"s"}`}function killCall(id){return`kill_bash({ bash_id: "${id}" })`}function describeBackgroundAge(event){let label=event.command===void 0||event.command===event.description?event.description:`${event.description}: ${event.command}`,session=`Background terminal session ${event.id} (${label})`;if(event.kind==="reaped")return`${session} was stopped automatically after ${minutes(event.autoReapMinutes??event.ageMinutes)} (auto-reap).`;if(event.kind==="reap_failed")return`${session} is still running: auto-reap at ${minutes(event.autoReapMinutes??event.ageMinutes)} failed (${event.reason??"unknown reason"}) and will not retry; stop it with ${killCall(event.id)} if it is no longer needed.`;let reap=event.autoReapMinutes===null?"Nothing stops it automatically":`Auto-reap stops it at ${minutes(event.autoReapMinutes)}`;return`${session} has been running for ${minutes(event.ageMinutes)}. ${reap}; stop it now with ${killCall(event.id)} if it is no longer needed.`}function buildNotice(id,runtime,trustText){let reaped=runtime.autoReapedAfterMinutes,reapText=reaped===void 0?"":` It was stopped automatically after ${minutes(reaped)} (auto-reap: the auto_reap_minutes parameter or the terminal.backgroundAutoReapMinutes setting).`,status=describeExit(runtime)??"exited",code=runtime.exitResult?.exitCode,codeText=code==null?"":` (exit code ${code})`,tail=sanitizeTerminalOutput(runtime.fullOutput()).trimEnd(),tailSection="";if(tail.length>0){let truncated=tail.length>NOTICE_TAIL_MAX_CHARS,shown=truncated?tail.slice(tail.length-NOTICE_TAIL_MAX_CHARS):tail,note=truncated?`
|
|
45
45
|
[Final output truncated to the last ${NOTICE_TAIL_MAX_CHARS} chars; the full history is still peekable.]`:"";tailSection=`
|
|
46
46
|
Final output:
|
|
47
47
|
${shown}${note}`}let trustSection=trustText===void 0?"":`
|
|
48
|
-
${trustText}`;return`<system-reminder>Background terminal session ${id} finished: ${status}${codeText}.${reapText}${tailSection}${trustSection}</system-reminder>`}var TerminalNotifier=class{constructor(deps){this.notified=new Set,this.retired=!1,this.deps=deps}notifyCompletion(id,runtime){this.retired||this.notified.has(id)||withTerminalContext(()=>this.deliverCompletion(id,runtime),()=>this.retire())}notifyAge(event){this.retired||this.notified.has(event.id)||withTerminalContext(()=>getTerminalNotificationDelivery(this.deps)?.send(`<system-reminder>${describeBackgroundAge(event)}</system-reminder>`,{details:{backgroundAge:event}}),()=>this.retire())}retire(){this.retired=!0,this.notified.clear()}deliverCompletion(id,runtime){let delivery=getTerminalNotificationDelivery(this.deps);if(!delivery)return;this.notified.add(id);let annotation=annotateShellTrust({exitCode:runtime.exitResult?.exitCode??null,output:runtime.fullOutput()});delivery.send(buildNotice(id,runtime,annotation?.text),annotation===void 0?void 0:{details:{trust:annotation.trust}})}};function stallThresholdMs(timeoutSeconds){return typeof timeoutSeconds!="number"||!Number.isFinite(timeoutSeconds)||timeoutSeconds<=0?3e4:Math.max(1,Math.min(3e4,Math.trunc(timeoutSeconds*1e3)))}function queueEntryLabel(event){let toolCallId=event.toolCallId;return typeof toolCallId=="string"?`${event.type}:${toolCallId}`:event.type}function watchForStall(thresholdMs,onStall){let startedAt=Date.now(),timer=setTimeout(()=>onStall(Date.now()-startedAt),thresholdMs);return timer.unref?.(),{stop:()=>clearTimeout(timer)}}var PendingQueueLedger=class{constructor(){this.nextId=0,this.entries=new Map}track(label,run){let id=this.nextId++;this.entries.set(id,{label,enqueuedAt:Date.now()});let release=()=>{this.entries.delete(id)};return(...args)=>{let result;try{result=run(...args)}catch(error){throw release(),error}return result instanceof Promise?result.then(release,release):release(),result}}snapshot(){let head=this.entries.values().next().value;return head===void 0?{queueDepth:0}:{queueDepth:this.entries.size,queueHead:head.label,ageMs:Date.now()-head.enqueuedAt}}};function resolveTerminalId(manager,id){return manager.resolveId?.(id)??id}function textResult(text,extra){return{content:[{type:"text",text}],details:extra?.details,isError:extra?.isError}}function errorResult(text){return{content:[{type:"text",text}],details:void 0,isError:!0}}function noticedResult(text,notices,extra){return{content:splitModelOnlyNotices(text,notices),details:extra?.details,isError:extra?.isError}}var MINUTE_MS=6e4,MAX_TIMER_MS=2147483647;function resolveAutoReapMinutes(requested,configured){let value=requested??configured;if(value===void 0||!Number.isFinite(value))return;let minutes2=Math.trunc(value);return minutes2>=1?minutes2:void 0}function backgroundStart(input,configuredMinutes,startedAtMs){return{description:input.description??input.command,command:input.command,startedAtMs,autoReapMinutes:resolveAutoReapMinutes(input.auto_reap_minutes,configuredMinutes)}}function reapedView(runtime,minutes2){return{exitResult:runtime.exitResult,autoReapedAfterMinutes:minutes2,fullOutput:()=>runtime.fullOutput()}}function trackBackgroundSession(ctx,id,runtime,start){ctx.onBackgroundStart?.(id,start.description,start.startedAtMs,start.command,start.autoReapMinutes);let minutes2=start.autoReapMinutes,reapedAfterMinutes,reaping,timer,reap=async age=>{let failure=await ctx.manager.stop(id).then(stopped=>stopped?runtime.exited?void 0:"the session was still running after the stop (TERM, then KILL)":`the terminal manager has no session ${id} to stop`,error=>error instanceof Error?error.message:String(error));if(failure===void 0){reapedAfterMinutes=age;return}(ctx.sessionLogger??createSessionLogger(getAgentDir())).warn("bash_auto_reap_failed",{bash_id:id,autoReapMinutes:age,error:failure}),runtime.exited||ctx.onBackgroundReapFailed?.(id,age,failure)},arm=deadlineMs=>{timer=setTimeout(()=>{if(timer=void 0,!(runtime.exited||minutes2===void 0)){if(Date.now()<deadlineMs){arm(deadlineMs);return}reaping=Promise.resolve().then(()=>reap(minutes2))}},Math.min(Math.max(0,deadlineMs-Date.now()),MAX_TIMER_MS)),timer.unref?.()};minutes2!==void 0&&!runtime.exited&&arm(start.startedAtMs+minutes2*MINUTE_MS),!(minutes2===void 0&&!ctx.onBackgroundExit)&&runtime.session.onExit(()=>{timer!==void 0&&clearTimeout(timer),timer=void 0;let report=()=>ctx.onBackgroundExit?.(id,reapedAfterMinutes===void 0?runtime:reapedView(runtime,reapedAfterMinutes));reaping===void 0?report():reaping.then(report)})}function createForegroundDetachGate(options){let cancelled=!1,committed=!1,timer,resolveDetached,detached=new Promise(resolve=>{resolveDetached=resolve}),clearDeadline=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)},linearize=()=>{if(cancelled||committed||options.runtime.exited||options.signal?.aborted)return;let exitedAtGate=!1,unsubscribeExit=options.runtime.session.onExit(()=>{committed||(exitedAtGate=!0)});if(cancelled||options.runtime.exited||exitedAtGate||options.signal?.aborted){unsubscribeExit();return}committed=!0,options.removeAbortListener(),unsubscribeExit(),resolveDetached()};return timer=setTimeout(()=>queueMicrotask(linearize),options.delayMs),{detached,cancel(){cancelled=!0,clearDeadline()}}}function resolveForegroundWindowSeconds(env){let parsed=Number.parseFloat(env.PI_BASH_FOREGROUND_SECONDS??"");return!Number.isFinite(parsed)||parsed<=0?60:parsed}var SHELL_WRAPPER=/^(?:env\s+(?:[\w.]+=[^\s]*\s+)*)?(?:\/(?:usr\/)?bin\/)?(?:ba|z|da|k)?sh\s+-[a-z]*c\s+/i,POWER_MANAGEMENT=/\b(?:pmset|systemsetup|caffeinate|displaysleep|disksleep)\b/,SLEEP_CALL=/(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+(\d+(?:\.\d+)?)/g,PURE=/^sleep\s+\d+(?:\.\d+)?$/,LEADING=/^\(?\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*(?:[;&|]|$)/,LOOP=/\b(?:while|until|for)\b[\s\S]*?(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+\d/,TRAILING=/[;&|]\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*\)?\s*$/;function unwrap(command){let current=command.trim();for(let depth=0;depth<3;depth+=1){let stripped=current.replace(SHELL_WRAPPER,"");if(stripped===current)break;current=stripped.trim();let quote=current[0];(quote==="'"||quote==='"')&¤t.endsWith(quote)&¤t.length>1&&(current=current.slice(1,-1).trim())}return current}function longestSleepSeconds(command){SLEEP_CALL.lastIndex=0;let longest;for(let match of command.matchAll(SLEEP_CALL)){let seconds=Number.parseFloat(match[1]??"");Number.isFinite(seconds)&&(longest===void 0||seconds>longest)&&(longest=seconds)}return longest}function classifySleepWait(command){if(POWER_MANAGEMENT.test(command))return;let unwrapped=unwrap(command),seconds=longestSleepSeconds(unwrapped);if(seconds!==void 0){if(LOOP.test(unwrapped))return seconds>=2?{kind:"sleep-wait",rule:"R3",seconds}:void 0;if(!(seconds<10)){if(PURE.test(unwrapped))return{kind:"sleep-wait",rule:"R1",seconds};if(LEADING.test(unwrapped))return{kind:"sleep-wait",rule:"R2",seconds};if(TRAILING.test(unwrapped))return{kind:"sleep-wait",rule:"R4",seconds}}}}var ptyBashSchema=typebox_exports.Object({command:typebox_exports.String({description:"Shell command to execute in a PTY-backed session."}),timeout:typebox_exports.Optional(typebox_exports.Number({description:"Process kill deadline in seconds (default 1800). Foreground blocking stops at the ~60s window: a command still running then auto-detaches to a live background session instead of being killed. Ignored for run_in_background sessions (they live until exit or kill_bash)."})),description:typebox_exports.Optional(typebox_exports.String({description:"Short human-readable label for this command."})),run_in_background:typebox_exports.Optional(typebox_exports.Boolean({description:"Run as a persistent background session: returns a bash_id immediately (read with bash_output, steer with bash_input, stop with kill_bash). A plain & job dies with the call's PTY hangup (native backend), and nohup at best leaves an untracked orphan (no bash_id, no log) that the call's timeout still group-kills. This flag is the only reliable way a job outlives the call."})),auto_reap_minutes:typebox_exports.Optional(typebox_exports.Number({description:"Background sessions only: stop this session (TERM, then KILL to its process group) once it has run this many minutes. Defaults to the terminal.backgroundAutoReapMinutes setting, which is off; 0 turns it off for this call."})),cols:typebox_exports.Optional(typebox_exports.Number({description:"PTY width in columns (default 120)."})),rows:typebox_exports.Optional(typebox_exports.Number({description:"PTY height in rows (default 40)."}))});function resolveDimension(value,fallback){return value===void 0||!Number.isFinite(value)||value<1?fallback:Math.trunc(value)}function delay(ms){return new Promise(resolve=>setTimeout(resolve,ms))}var MAX_TIMEOUT_MS=2147483647,BASH_UPDATE_THROTTLE_MS=100;function createThrottledEmitter(emit,throttleMs=BASH_UPDATE_THROTTLE_MS){let timer,dirty=!1,lastEmissionAt,emitIfDirty=()=>{dirty&&(dirty=!1,lastEmissionAt=Date.now(),emit())},clearTimer=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)};return{schedule(){if(dirty=!0,timer!==void 0)return;let elapsed=lastEmissionAt===void 0?throttleMs:Date.now()-lastEmissionAt;if(elapsed>=throttleMs){emitIfDirty();return}timer=setTimeout(()=>{timer=void 0,emitIfDirty()},throttleMs-elapsed)},flush(){clearTimer(),emitIfDirty()},dispose(){clearTimer(),dirty=!1,lastEmissionAt=void 0}}}var defaultSessionLogger;async function spawnReportingStall(ctx,request,toolCallId,execCtx){let thresholdMs=stallThresholdMs(request.timeoutMs===void 0?void 0:request.timeoutMs/1e3),watch2=watchForStall(thresholdMs,elapsedMs=>{let logger=ctx.sessionLogger??(defaultSessionLogger??=createSessionLogger(getAgentDir())),sessionId=(execCtx??ctx.getSessionContext?.())?.sessionManager?.getSessionId();logger.warn("bash_spawn_stalled",{toolCallId,toolName:TERMINAL_BASH_TOOL,...sessionId===void 0?{}:{sessionId},thresholdMs,elapsedMs})});try{return await spawnCommandSession(sessionSpawnContext(ctx),request)}finally{watch2.stop()}}function sessionSpawnContext(ctx){return{...ctx,getEnv:()=>({...ctx.getEnv(),PI_SESSION_CWD:void 0,PI_GOAL_STORE_FILE:void 0,OMO_BROWSER_ENGINE:void 0})}}function sessionEnvOverrides(ctx,execCtx){let session=execCtx??ctx.getSessionContext?.();if(!session?.sessionManager)return{};let env={...session.sessionEnv};env.PI_SESSION_ID=session.sessionManager.getSessionId(),session.cwd&&(env.PI_SESSION_CWD=session.cwd),session.goalStoreFile&&(env.PI_GOAL_STORE_FILE=session.goalStoreFile);let sessionFile=session.sessionManager.getSessionFile();return sessionFile&&(env.PI_SESSION_FILE=sessionFile),session.model&&(env.PI_PROVIDER=session.model.provider,env.PI_MODEL=session.model.id),session.thinkingLevel&&(env.PI_REASONING_LEVEL=session.thinkingLevel),session.browserEngine&&(env.OMO_BROWSER_ENGINE=session.browserEngine),env}function raceExitWithKillGrace(runtime,signal,timeoutMs){return new Promise((resolve,reject)=>{let settled=!1,abortGraceTimer,timeoutGraceTimer,armAbortGrace,settle=finish=>{settled||(settled=!0,abortGraceTimer&&clearTimeout(abortGraceTimer),timeoutGraceTimer&&clearTimeout(timeoutGraceTimer),signal&&armAbortGrace&&signal.removeEventListener("abort",armAbortGrace),finish())};if(runtime.session.waitExit().then(()=>settle(()=>resolve("exited")),error=>settle(()=>reject(error instanceof Error?error:new Error(String(error))))),timeoutMs!==void 0){let timeoutGraceDeadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;timeoutGraceDeadlineMs<=MAX_TIMEOUT_MS&&(timeoutGraceTimer=setTimeout(()=>settle(()=>resolve("timeout_grace")),timeoutGraceDeadlineMs))}signal&&(armAbortGrace=()=>{abortGraceTimer??=setTimeout(()=>settle(()=>resolve("abort_grace")),KILLED_SESSION_EXIT_GRACE_MS)},signal.aborted?armAbortGrace():signal.addEventListener("abort",armAbortGrace,{once:!0}))})}function resolveAutoDetachDelayMs(ctx,input,sleepWait){if(ctx.timeoutAction==="kill")return;let windowSeconds=sleepWait?Math.min(5,resolveForegroundWindowSeconds(process.env)):resolveForegroundWindowSeconds(process.env);if(!((input.timeout!==void 0&&Number.isFinite(input.timeout)?input.timeout:1/0)<=windowSeconds))return Math.max(0,Math.trunc(windowSeconds*1e3))}function scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt){if(timeoutMs===void 0)return;let deadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;if(!Number.isFinite(deadlineMs)||deadlineMs>MAX_TIMEOUT_MS||runtime.exited)return;let remainingMs=Math.max(0,deadlineMs-(Date.now()-startedAt)),timer,unsubscribeExit,clearSweep=()=>{timer!==void 0&&clearTimeout(timer),timer=void 0,unsubscribeExit?.(),unsubscribeExit=void 0};if(unsubscribeExit=runtime.session.onExit(clearSweep),runtime.exited){clearSweep();return}timer=setTimeout(()=>{clearSweep(),runtime.exited||ctx.manager.stop(id).catch(()=>{})},remainingMs)}async function runForeground(ctx,input,cols,rows,signal,cwd,onUpdate,toolCallId,execCtx){if(signal?.aborted)return errorResult("Command aborted");let timeoutMs=input.timeout!==void 0?Math.trunc(input.timeout*1e3):void 0,{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,timeoutMs,cwd,envOverrides:{...sessionEnvOverrides(ctx,execCtx),...FOREGROUND_ENV_OVERRIDES}},toolCallId,execCtx),startedAt=Date.now(),activity=`running ${input.command.slice(0,80)}`,updateEmitter=onUpdate?createThrottledEmitter(()=>{let text=formatTerminalToolOutput(runtime.fullOutput()).body.slice(-2e3);onUpdate?.({content:[{type:"text",text}],details:{progress:{activity,startedAt}}})}):void 0;onUpdate?.({content:[],details:void 0});let unsubscribeOutput=onUpdate?runtime.onOutput(()=>updateEmitter?.schedule()):void 0,sleepWait=classifySleepWait(input.command),detachDelayMs=resolveAutoDetachDelayMs(ctx,input,sleepWait),outcome;if(detachDelayMs===void 0){let onAbort=()=>runtime.session.kill("SIGKILL");signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));try{outcome=await raceExitWithKillGrace(runtime,signal,timeoutMs)}finally{signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}else{let abortGate=new AbortController,onAbort=()=>{runtime.session.kill("SIGKILL"),abortGate.abort()};signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));let detachGate=createForegroundDetachGate({runtime,signal,delayMs:detachDelayMs,removeAbortListener:()=>signal?.removeEventListener("abort",onAbort)});try{outcome=await Promise.race([raceExitWithKillGrace(runtime,abortGate.signal,timeoutMs),detachGate.detached.then(()=>"detached")])}finally{detachGate.cancel(),signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}if(outcome==="detached"){scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt),trackBackgroundSession(ctx,id,runtime,backgroundStart(input,ctx.backgroundAutoReapMinutes,startedAt));let delta=runtime.readDelta(),partialOutput=formatTerminalToolOutput(delta.text).text||"(no output yet)",timeoutNote=input.timeout!==void 0&&Number.isFinite(input.timeout)?`not killed; the original ${input.timeout}s timeout still applies`:"not killed; it will run until exit or kill_bash",guidance=sleepWait?`This command is a wait (${sleepWait.seconds}s sleep), so it detached immediately; the wait continues in the background. Do nothing and end your turn: completion will be reported automatically with exit status and output tail. Do NOT poll bash_output({ bash_id: "${id}" }) for it. When you are waiting for a pattern in a command's output, launch it with monitor({ command, filter }) instead so matching lines arrive as events. Use kill_bash({ bash_id: "${id}" }) to stop this session.`:`Continue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`;return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).
|
|
48
|
+
${trustText}`,interrupted=runtime.stoppedByInterrupt,ended=interrupted===void 0?`finished: ${status}${codeText}.`:`was stopped when turn ${interrupted.turnId} was interrupted (${status}${codeText}).`;return`<system-reminder>Background terminal session ${id} ${ended}${reapText}${tailSection}${trustSection}</system-reminder>`}var TerminalNotifier=class{constructor(deps){this.notified=new Set,this.retired=!1,this.deps=deps}notifyCompletion(id,runtime){this.retired||this.notified.has(id)||withTerminalContext(()=>this.deliverCompletion(id,runtime),()=>this.retire())}notifyAge(event){this.retired||this.notified.has(event.id)||withTerminalContext(()=>getTerminalNotificationDelivery(this.deps)?.send(`<system-reminder>${describeBackgroundAge(event)}</system-reminder>`,{details:{backgroundAge:event}}),()=>this.retire())}retire(){this.retired=!0,this.notified.clear()}deliverCompletion(id,runtime){let delivery=getTerminalNotificationDelivery(this.deps);if(!delivery)return;this.notified.add(id);let annotation=annotateShellTrust({exitCode:runtime.exitResult?.exitCode??null,output:runtime.fullOutput()});delivery.send(buildNotice(id,runtime,annotation?.text),{...runtime.stoppedByInterrupt===void 0?{}:{nextTurn:!0},...annotation===void 0?{}:{details:{trust:annotation.trust}}})}};function stallThresholdMs(timeoutSeconds){return typeof timeoutSeconds!="number"||!Number.isFinite(timeoutSeconds)||timeoutSeconds<=0?3e4:Math.max(1,Math.min(3e4,Math.trunc(timeoutSeconds*1e3)))}function queueEntryLabel(event){let toolCallId=event.toolCallId;return typeof toolCallId=="string"?`${event.type}:${toolCallId}`:event.type}function watchForStall(thresholdMs,onStall){let startedAt=Date.now(),timer=setTimeout(()=>onStall(Date.now()-startedAt),thresholdMs);return timer.unref?.(),{stop:()=>clearTimeout(timer)}}var PendingQueueLedger=class{constructor(){this.nextId=0,this.entries=new Map}track(label,run){let id=this.nextId++;this.entries.set(id,{label,enqueuedAt:Date.now()});let release=()=>{this.entries.delete(id)};return(...args)=>{let result;try{result=run(...args)}catch(error){throw release(),error}return result instanceof Promise?result.then(release,release):release(),result}}snapshot(){let head=this.entries.values().next().value;return head===void 0?{queueDepth:0}:{queueDepth:this.entries.size,queueHead:head.label,ageMs:Date.now()-head.enqueuedAt}}};function resolveTerminalId(manager,id){return manager.resolveId?.(id)??id}function textResult(text,extra){return{content:[{type:"text",text}],details:extra?.details,isError:extra?.isError}}function errorResult(text){return{content:[{type:"text",text}],details:void 0,isError:!0}}function noticedResult(text,notices,extra){return{content:splitModelOnlyNotices(text,notices),details:extra?.details,isError:extra?.isError}}var MINUTE_MS=6e4,MAX_TIMER_MS=2147483647;function resolveAutoReapMinutes(requested,configured){let value=requested??configured;if(value===void 0||!Number.isFinite(value))return;let minutes2=Math.trunc(value);return minutes2>=1?minutes2:void 0}function backgroundStart(input,configuredMinutes,startedAtMs){return{description:input.description??input.command,command:input.command,startedAtMs,autoReapMinutes:resolveAutoReapMinutes(input.auto_reap_minutes,configuredMinutes)}}function reapedView(runtime,minutes2){return{exitResult:runtime.exitResult,autoReapedAfterMinutes:minutes2,fullOutput:()=>runtime.fullOutput()}}function trackBackgroundSession(ctx,id,runtime,start){ctx.onBackgroundStart?.(id,start.description,start.startedAtMs,start.command,start.autoReapMinutes);let minutes2=start.autoReapMinutes,reapedAfterMinutes,reaping,timer,reap=async age=>{let failure=await ctx.manager.stop(id).then(stopped=>stopped?runtime.exited?void 0:"the session was still running after the stop (TERM, then KILL)":`the terminal manager has no session ${id} to stop`,error=>error instanceof Error?error.message:String(error));if(failure===void 0){reapedAfterMinutes=age;return}(ctx.sessionLogger??createSessionLogger(getAgentDir())).warn("bash_auto_reap_failed",{bash_id:id,autoReapMinutes:age,error:failure}),runtime.exited||ctx.onBackgroundReapFailed?.(id,age,failure)},arm=deadlineMs=>{timer=setTimeout(()=>{if(timer=void 0,!(runtime.exited||minutes2===void 0)){if(Date.now()<deadlineMs){arm(deadlineMs);return}reaping=Promise.resolve().then(()=>reap(minutes2))}},Math.min(Math.max(0,deadlineMs-Date.now()),MAX_TIMER_MS)),timer.unref?.()};minutes2!==void 0&&!runtime.exited&&arm(start.startedAtMs+minutes2*MINUTE_MS),!(minutes2===void 0&&!ctx.onBackgroundExit)&&runtime.session.onExit(()=>{timer!==void 0&&clearTimeout(timer),timer=void 0;let report=()=>ctx.onBackgroundExit?.(id,reapedAfterMinutes===void 0?runtime:reapedView(runtime,reapedAfterMinutes));reaping===void 0?report():reaping.then(report)})}function createForegroundDetachGate(options){let cancelled=!1,committed=!1,timer,resolveDetached,detached=new Promise(resolve=>{resolveDetached=resolve}),clearDeadline=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)},linearize=()=>{if(cancelled||committed||options.runtime.exited||options.signal?.aborted)return;let exitedAtGate=!1,unsubscribeExit=options.runtime.session.onExit(()=>{committed||(exitedAtGate=!0)});if(cancelled||options.runtime.exited||exitedAtGate||options.signal?.aborted){unsubscribeExit();return}committed=!0,options.removeAbortListener(),unsubscribeExit(),resolveDetached()};return timer=setTimeout(()=>queueMicrotask(linearize),options.delayMs),{detached,cancel(){cancelled=!0,clearDeadline()}}}function resolveForegroundWindowSeconds(env){let parsed=Number.parseFloat(env.PI_BASH_FOREGROUND_SECONDS??"");return!Number.isFinite(parsed)||parsed<=0?60:parsed}var SHELL_WRAPPER=/^(?:env\s+(?:[\w.]+=[^\s]*\s+)*)?(?:\/(?:usr\/)?bin\/)?(?:ba|z|da|k)?sh\s+-[a-z]*c\s+/i,POWER_MANAGEMENT=/\b(?:pmset|systemsetup|caffeinate|displaysleep|disksleep)\b/,SLEEP_CALL=/(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+(\d+(?:\.\d+)?)/g,PURE=/^sleep\s+\d+(?:\.\d+)?$/,LEADING=/^\(?\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*(?:[;&|]|$)/,LOOP=/\b(?:while|until|for)\b[\s\S]*?(?<![\w.\-/])(?:\/(?:usr\/)?bin\/)?sleep\s+\d/,TRAILING=/[;&|]\s*(?:\/(?:usr\/)?bin\/)?sleep\s+\d+(?:\.\d+)?\s*\)?\s*$/;function unwrap(command){let current=command.trim();for(let depth=0;depth<3;depth+=1){let stripped=current.replace(SHELL_WRAPPER,"");if(stripped===current)break;current=stripped.trim();let quote=current[0];(quote==="'"||quote==='"')&¤t.endsWith(quote)&¤t.length>1&&(current=current.slice(1,-1).trim())}return current}function longestSleepSeconds(command){SLEEP_CALL.lastIndex=0;let longest;for(let match of command.matchAll(SLEEP_CALL)){let seconds=Number.parseFloat(match[1]??"");Number.isFinite(seconds)&&(longest===void 0||seconds>longest)&&(longest=seconds)}return longest}function classifySleepWait(command){if(POWER_MANAGEMENT.test(command))return;let unwrapped=unwrap(command),seconds=longestSleepSeconds(unwrapped);if(seconds!==void 0){if(LOOP.test(unwrapped))return seconds>=2?{kind:"sleep-wait",rule:"R3",seconds}:void 0;if(!(seconds<10)){if(PURE.test(unwrapped))return{kind:"sleep-wait",rule:"R1",seconds};if(LEADING.test(unwrapped))return{kind:"sleep-wait",rule:"R2",seconds};if(TRAILING.test(unwrapped))return{kind:"sleep-wait",rule:"R4",seconds}}}}var ptyBashSchema=typebox_exports.Object({command:typebox_exports.String({description:"Shell command to execute in a PTY-backed session."}),timeout:typebox_exports.Optional(typebox_exports.Number({description:"Process kill deadline in seconds (default 1800). Foreground blocking stops at the ~60s window: a command still running then auto-detaches to a live background session instead of being killed. Ignored for run_in_background sessions (they live until exit or kill_bash)."})),description:typebox_exports.Optional(typebox_exports.String({description:"Short human-readable label for this command."})),run_in_background:typebox_exports.Optional(typebox_exports.Boolean({description:"Run as a persistent background session: returns a bash_id immediately (read with bash_output, steer with bash_input, stop with kill_bash). A plain & job dies with the call's PTY hangup (native backend), and nohup at best leaves an untracked orphan (no bash_id, no log) that the call's timeout still group-kills. This flag is the only reliable way a job outlives the call."})),auto_reap_minutes:typebox_exports.Optional(typebox_exports.Number({description:"Background sessions only: stop this session (TERM, then KILL to its process group) once it has run this many minutes. Defaults to the terminal.backgroundAutoReapMinutes setting, which is off; 0 turns it off for this call."})),cols:typebox_exports.Optional(typebox_exports.Number({description:"PTY width in columns (default 120)."})),rows:typebox_exports.Optional(typebox_exports.Number({description:"PTY height in rows (default 40)."}))});function resolveDimension(value,fallback){return value===void 0||!Number.isFinite(value)||value<1?fallback:Math.trunc(value)}function delay(ms){return new Promise(resolve=>setTimeout(resolve,ms))}var MAX_TIMEOUT_MS=2147483647,BASH_UPDATE_THROTTLE_MS=100;function createThrottledEmitter(emit,throttleMs=BASH_UPDATE_THROTTLE_MS){let timer,dirty=!1,lastEmissionAt,emitIfDirty=()=>{dirty&&(dirty=!1,lastEmissionAt=Date.now(),emit())},clearTimer=()=>{timer!==void 0&&(clearTimeout(timer),timer=void 0)};return{schedule(){if(dirty=!0,timer!==void 0)return;let elapsed=lastEmissionAt===void 0?throttleMs:Date.now()-lastEmissionAt;if(elapsed>=throttleMs){emitIfDirty();return}timer=setTimeout(()=>{timer=void 0,emitIfDirty()},throttleMs-elapsed)},flush(){clearTimer(),emitIfDirty()},dispose(){clearTimer(),dirty=!1,lastEmissionAt=void 0}}}var defaultSessionLogger;async function spawnReportingStall(ctx,request,toolCallId,execCtx){let thresholdMs=stallThresholdMs(request.timeoutMs===void 0?void 0:request.timeoutMs/1e3),watch2=watchForStall(thresholdMs,elapsedMs=>{let logger=ctx.sessionLogger??(defaultSessionLogger??=createSessionLogger(getAgentDir())),sessionId=(execCtx??ctx.getSessionContext?.())?.sessionManager?.getSessionId();logger.warn("bash_spawn_stalled",{toolCallId,toolName:TERMINAL_BASH_TOOL,...sessionId===void 0?{}:{sessionId},thresholdMs,elapsedMs})});try{return await spawnCommandSession(sessionSpawnContext(ctx),request)}finally{watch2.stop()}}function sessionSpawnContext(ctx){return{...ctx,getEnv:()=>({...ctx.getEnv(),PI_SESSION_CWD:void 0,PI_GOAL_STORE_FILE:void 0,OMO_BROWSER_ENGINE:void 0})}}function sessionEnvOverrides(ctx,execCtx){let session=execCtx??ctx.getSessionContext?.();if(!session?.sessionManager)return{};let env={...session.sessionEnv};env.PI_SESSION_ID=session.sessionManager.getSessionId(),session.cwd&&(env.PI_SESSION_CWD=session.cwd),session.goalStoreFile&&(env.PI_GOAL_STORE_FILE=session.goalStoreFile);let sessionFile=session.sessionManager.getSessionFile();return sessionFile&&(env.PI_SESSION_FILE=sessionFile),session.model&&(env.PI_PROVIDER=session.model.provider,env.PI_MODEL=session.model.id),session.thinkingLevel&&(env.PI_REASONING_LEVEL=session.thinkingLevel),session.browserEngine&&(env.OMO_BROWSER_ENGINE=session.browserEngine),env}function raceExitWithKillGrace(runtime,signal,timeoutMs){return new Promise((resolve,reject)=>{let settled=!1,abortGraceTimer,timeoutGraceTimer,armAbortGrace,settle=finish=>{settled||(settled=!0,abortGraceTimer&&clearTimeout(abortGraceTimer),timeoutGraceTimer&&clearTimeout(timeoutGraceTimer),signal&&armAbortGrace&&signal.removeEventListener("abort",armAbortGrace),finish())};if(runtime.session.waitExit().then(()=>settle(()=>resolve("exited")),error=>settle(()=>reject(error instanceof Error?error:new Error(String(error))))),timeoutMs!==void 0){let timeoutGraceDeadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;timeoutGraceDeadlineMs<=MAX_TIMEOUT_MS&&(timeoutGraceTimer=setTimeout(()=>settle(()=>resolve("timeout_grace")),timeoutGraceDeadlineMs))}signal&&(armAbortGrace=()=>{abortGraceTimer??=setTimeout(()=>settle(()=>resolve("abort_grace")),KILLED_SESSION_EXIT_GRACE_MS)},signal.aborted?armAbortGrace():signal.addEventListener("abort",armAbortGrace,{once:!0}))})}function resolveAutoDetachDelayMs(ctx,input,sleepWait){if(ctx.timeoutAction==="kill")return;let windowSeconds=sleepWait?Math.min(5,resolveForegroundWindowSeconds(process.env)):resolveForegroundWindowSeconds(process.env);if(!((input.timeout!==void 0&&Number.isFinite(input.timeout)?input.timeout:1/0)<=windowSeconds))return Math.max(0,Math.trunc(windowSeconds*1e3))}function scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt){if(timeoutMs===void 0)return;let deadlineMs=timeoutMs+KILLED_SESSION_EXIT_GRACE_MS;if(!Number.isFinite(deadlineMs)||deadlineMs>MAX_TIMEOUT_MS||runtime.exited)return;let remainingMs=Math.max(0,deadlineMs-(Date.now()-startedAt)),timer,unsubscribeExit,clearSweep=()=>{timer!==void 0&&clearTimeout(timer),timer=void 0,unsubscribeExit?.(),unsubscribeExit=void 0};if(unsubscribeExit=runtime.session.onExit(clearSweep),runtime.exited){clearSweep();return}timer=setTimeout(()=>{clearSweep(),runtime.exited||ctx.manager.stop(id).catch(()=>{})},remainingMs)}async function runForeground(ctx,input,cols,rows,signal,cwd,onUpdate,toolCallId,execCtx){if(signal?.aborted)return errorResult("Command aborted");let timeoutMs=input.timeout!==void 0?Math.trunc(input.timeout*1e3):void 0,{id,runtime}=await spawnReportingStall(ctx,{command:input.command,cols,rows,timeoutMs,cwd,envOverrides:{...sessionEnvOverrides(ctx,execCtx),...FOREGROUND_ENV_OVERRIDES}},toolCallId,execCtx),startedAt=Date.now(),activity=`running ${input.command.slice(0,80)}`,updateEmitter=onUpdate?createThrottledEmitter(()=>{let text=formatTerminalToolOutput(runtime.fullOutput()).body.slice(-2e3);onUpdate?.({content:[{type:"text",text}],details:{progress:{activity,startedAt}}})}):void 0;onUpdate?.({content:[],details:void 0});let unsubscribeOutput=onUpdate?runtime.onOutput(()=>updateEmitter?.schedule()):void 0,sleepWait=classifySleepWait(input.command),detachDelayMs=resolveAutoDetachDelayMs(ctx,input,sleepWait),outcome;if(detachDelayMs===void 0){let onAbort=()=>runtime.session.kill("SIGKILL");signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));try{outcome=await raceExitWithKillGrace(runtime,signal,timeoutMs)}finally{signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}else{let abortGate=new AbortController,onAbort=()=>{runtime.session.kill("SIGKILL"),abortGate.abort()};signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort,{once:!0}));let detachGate=createForegroundDetachGate({runtime,signal,delayMs:detachDelayMs,removeAbortListener:()=>signal?.removeEventListener("abort",onAbort)});try{outcome=await Promise.race([raceExitWithKillGrace(runtime,abortGate.signal,timeoutMs),detachGate.detached.then(()=>"detached")])}finally{detachGate.cancel(),signal?.removeEventListener("abort",onAbort),unsubscribeOutput?.(),updateEmitter?.flush(),updateEmitter?.dispose()}}if(outcome==="detached"){scheduleDetachedSweep(ctx,id,runtime,timeoutMs,startedAt),trackBackgroundSession(ctx,id,runtime,backgroundStart(input,ctx.backgroundAutoReapMinutes,startedAt));let delta=runtime.readDelta(),partialOutput=formatTerminalToolOutput(delta.text).text||"(no output yet)",timeoutNote=input.timeout!==void 0&&Number.isFinite(input.timeout)?`not killed; the original ${input.timeout}s timeout still applies`:"not killed; it will run until exit or kill_bash",guidance=sleepWait?`This command is a wait (${sleepWait.seconds}s sleep), so it detached immediately; the wait continues in the background. Do nothing and end your turn: completion will be reported automatically with exit status and output tail. Do NOT poll bash_output({ bash_id: "${id}" }) for it. When you are waiting for a pattern in a command's output, launch it with monitor({ command, filter }) instead so matching lines arrive as events. Use kill_bash({ bash_id: "${id}" }) to stop this session.`:`Continue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`;return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).
|
|
49
49
|
|
|
50
50
|
Partial output:
|
|
51
51
|
${partialOutput}
|
|
@@ -70,4 +70,4 @@ ${early}`:"";return textResult(`${header}${backendNote}${earlyBlock}`,{details:{
|
|
|
70
70
|
`:"";if(input.view==="screen")return textResult(`${prefix}${statusLine(runtime)}
|
|
71
71
|
${screenView(runtime)}`,extra);let delta=runtime.readDelta(),formatted=formatTerminalToolOutput(applyFilter(delta.text,input.filter)),droppedNotice=delta.droppedChars>0?`[${delta.droppedChars} earlier chars dropped]`:void 0,dropped=droppedNotice===void 0?"":`${droppedNotice}
|
|
72
72
|
`;return noticedResult(`${prefix}${statusLine(runtime)}
|
|
73
|
-
${dropped}${formatted.text||"(no new output)"}`,[droppedNotice,formatted.marker],extra)},renderCall:renderBashOutputCall,renderResult:renderBashOutputResult}}var bashResizeSchema=typebox_exports.Object({bash_id:typebox_exports.String({description:"Session id returned by a run_in_background bash call."}),cols:typebox_exports.Number({description:"New PTY width in columns."}),rows:typebox_exports.Number({description:"New PTY height in rows."})});function valid(value){return Number.isFinite(value)&&value>=1}function createBashResizeTool(ctx){return{name:TERMINAL_RESIZE_TOOL,label:"bash_resize",description:"Resize a live background bash session's PTY (cols x rows) so full-screen TUIs reflow. No-ops with a note under the pipe fallback.",exposure:"search",allowLazyActivation:!0,searchKeywords:["resize","pty size","cols","rows","terminal size"],parameters:bashResizeSchema,async execute(_toolCallId,input,_signal){let sessionId=resolveTerminalId(ctx.manager,input.bash_id),runtime=ctx.manager.get(sessionId);if(!runtime)return errorResult(`No terminal session found with id: ${input.bash_id}`);if(runtime.exited)return errorResult(`Session ${input.bash_id} is not running; cannot resize.`);if(!valid(input.cols)||!valid(input.rows))return errorResult("cols and rows must be finite integers >= 1.");let cols=Math.trunc(input.cols),rows=Math.trunc(input.rows),result=runtime.session.resize(cols,rows);return runtime.resizeScreen(cols,rows),result.ok?textResult(`Resized ${input.bash_id} to ${cols}x${rows}.`):textResult(`Resize note for ${input.bash_id}: ${result.note}`)}}}import{mkdir as mkdir4,rm as rm5}from"node:fs/promises";import{isAbsolute as isAbsolute2,join as join6}from"node:path";function terminalStateDir(ctx){if(ctx!==void 0&&NON_INTERACTIVE_MODES.has(ctx.mode))return;let sessionDir=ctx?.sessionManager?.getSessionDir?.();if(!(sessionDir===void 0||sessionDir.length===0||!isAbsolute2(sessionDir)))return join6(sessionDir,"extensions","terminal")}function monitorStateDir(terminalDir,monitorId){return join6(terminalDir,"state",monitorId)}async function ensureMonitorStateDir(terminalDir,monitorId){let dir=monitorStateDir(terminalDir,monitorId);return await mkdir4(dir,{recursive:!0,mode:448}),dir}async function removeMonitorStateDir(terminalDir,monitorId){await rm5(monitorStateDir(terminalDir,monitorId),{recursive:!0,force:!0})}var killBashSchema=typebox_exports.Object({bash_id:typebox_exports.Optional(typebox_exports.String({description:"Session id to tree-kill."})),all:typebox_exports.Optional(typebox_exports.Boolean({description:"Tree-kill every live background session."}))});function createKillBashTool(ctx){return{name:TERMINAL_KILL_TOOL,label:"kill_bash",description:"Terminate a background bash session (or all of them) and its process tree cleanly.",promptSnippet:"Tree-kill a background bash session (or all) with no orphans",parameters:killBashSchema,async execute(_toolCallId,input,_signal){let terminalDir=terminalStateDir(ctx.getSessionContext?.()),dropStateDir=async monitorId2=>{terminalDir!==void 0&&monitorId2!==void 0&&await removeMonitorStateDir(terminalDir,monitorId2)};if(input.all){let terminalCount=ctx.manager.size,monitorIds=(ctx.monitorRegistry?.snapshot()??[]).map(entry=>entry.monitorId),fileCount=await ctx.monitorRegistry?.stopAllFiles()??0,rpcCount=ctx.monitorRegistry?.stopAllRpc()??0;await ctx.manager.teardown();for(let monitorId2 of monitorIds)await dropStateDir(monitorId2);return textResult(`Killed ${terminalCount+fileCount+rpcCount} session(s).`)}if(!input.bash_id)return errorResult("Provide `bash_id` or set `all:true`.");let sessionId=resolveTerminalId(ctx.manager,input.bash_id),monitorId=input.bash_id.startsWith("mon_")?input.bash_id:ctx.manager.monitorIdOf?.(sessionId);return await ctx.monitorRegistry?.stopFile(sessionId)||ctx.monitorRegistry?.stopRpc(sessionId)?(await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):ctx.manager.get(sessionId)?(await ctx.manager.stop(sessionId),await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):errorResult(`No terminal session found with id: ${input.bash_id}`)}}}var TERMINAL_CHILD_JOB_KINDS={bash:"terminal.bash",output:"terminal.output",input:"terminal.input",resize:"terminal.resize",kill:"terminal.kill"};function childTerminalIdScope(generation){return`c${generation}`}var CHILD_SESSION_ID=/_c(\d+)_\d+$/;function isChildSessionId(id){return CHILD_SESSION_ID.test(id)}function childGenerationOf(id){let generation=CHILD_SESSION_ID.exec(id)?.[1];return generation===void 0?void 0:Number(generation)}function optionalMinutes(value){return typeof value=="number"&&Number.isFinite(value)&&value>=1?Math.trunc(value):void 0}function parseBackgroundWake(value){if(typeof value!="object"||value===null)return;let event=Reflect.get(value,"event"),id=Reflect.get(value,"id");if(!(typeof id!="string"||!isChildSessionId(id))){if(event==="background_start"){let description=Reflect.get(value,"description"),startedAtMs=Reflect.get(value,"startedAtMs");if(typeof description!="string"||typeof startedAtMs!="number")return;let command=Reflect.get(value,"command"),autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes"));return{event,id,description,startedAtMs,...typeof command=="string"?{command}:{},...autoReapMinutes===void 0?{}:{autoReapMinutes}}}if(event==="background_reap_failed"){let autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes")),reason=Reflect.get(value,"reason");return autoReapMinutes===void 0||typeof reason!="string"?void 0:{event,id,autoReapMinutes,reason}}if(event==="background_exit"){let output=Reflect.get(value,"output"),exit=Reflect.get(value,"exit");if(typeof output!="string"||exit!==null&&typeof exit!="object")return;let autoReapedAfterMinutes=optionalMinutes(Reflect.get(value,"autoReapedAfterMinutes"));return{event,id,exit,output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}}}function exitView(exit,output,autoReapedAfterMinutes){return{exitResult:exit,fullOutput:()=>output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}function bashIdOf(value){if(typeof value!="object"||value===null)return;let id=value.bash_id;return typeof id=="string"?id:void 0}function lostSessionResult(id,generation){return{content:[{type:"text",text:`bash_id ${id} is lost: the session's tool child (generation ${generation}) exited, which ended this session and every process it started. Start a new session with bash.`}],details:{bash_id:id,lost:!0,generation}}}function terminalChildJob(ctx,kind){return{kind,...kind===TERMINAL_CHILD_JOB_KINDS.bash?backgroundRelay(ctx):{},...kind===TERMINAL_CHILD_JOB_KINDS.bash?{}:{placement:params=>{let id=bashIdOf(params);return id===void 0?kind===TERMINAL_CHILD_JOB_KINDS.kill?"both":"child":isChildSessionId(id)?"child":"server"}},result:(params,value,generation)=>{if(kind===TERMINAL_CHILD_JOB_KINDS.bash)return value;let id=bashIdOf(params),startedOn=id===void 0?void 0:childGenerationOf(id);return id===void 0||startedOn===void 0||startedOn===generation?value:lostSessionResult(id,startedOn)},args:(params,toolCallId,execCtx)=>{let env={};for(let[name,value]of Object.entries(ctx.getEnv()))typeof value=="string"&&(env[name]=value);return{params,toolCallId,cwd:execCtx.cwd??ctx.cwd,env:{...env,...sessionEnvOverrides(ctx,execCtx)},...ctx.shellPath===void 0?{}:{shellPath:ctx.shellPath},defaultCols:ctx.defaultCols,defaultRows:ctx.defaultRows,redactSecretsInOutput:ctx.redactSecretsInOutput===!0,...ctx.timeoutAction===void 0?{}:{timeoutAction:ctx.timeoutAction},...ctx.backgroundAutoReapMinutes===void 0?{}:{backgroundAutoReapMinutes:ctx.backgroundAutoReapMinutes}}}}}function backgroundRelay(ctx){let running=new Map;return{wake:(value,generation)=>{let wake=parseBackgroundWake(value);if(wake!==void 0){if(wake.event==="background_start"){running.set(wake.id,generation),ctx.onBackgroundStart?.(wake.id,wake.description,wake.startedAtMs,wake.command,wake.autoReapMinutes);return}if(wake.event==="background_reap_failed"){ctx.onBackgroundReapFailed?.(wake.id,wake.autoReapMinutes,wake.reason);return}running.delete(wake.id),ctx.onBackgroundExit?.(wake.id,exitView(wake.exit,wake.output,wake.autoReapedAfterMinutes))}},childExited:generation=>{for(let[id,startedOn]of running)startedOn===generation&&(running.delete(id),ctx.onBackgroundExit?.(id,exitView({exitCode:null,signal:null,timedOut:!1,cancelled:!0},`The session's tool child (generation ${generation}) exited, which ended this session and every process it started.`)))}}}export{ToolChildJobError,HostCallAdmission,PayloadRefWriter,PayloadRefReader,packPayload,unpackPayload,proofIsOrdered,TEST_CONTROL_DIR_ENV,readTestControls,WindowsJobError,WindowsJob,loadKernel32Job,generationLedgerPath,DescendantsLedger,LaunchLog,sweepGroups,defaultGroupProbes,recordGenerationChild,sweepStaleGenerations,TOOL_CHILD_GENERATION_ENV,TOOL_CHILD_PROTOCOL_VERSION,runToolChild,goShimScript,controlFd,withControlPipe,MODULE_JOB_KIND,TOOL_CHILD_MODULE_ROOTS_ENV,createModuleJobHandler,TerminalManager,annotateShellTrust,withTerminalContext,modelOnlyText,isModelOnlyText,DEFAULT_MAX_LINES,DEFAULT_MAX_BYTES,formatSize,truncateHead,truncateTail,truncateLine,sanitizeTerminalOutput,spawnCommandSession,describeExit,NOTICE_TAIL_MAX_CHARS,getTerminalNotificationDelivery,describeBackgroundAge,TerminalNotifier,createSessionLogger,queueEntryLabel,watchForStall,PendingQueueLedger,resolveTerminalId,textResult,errorResult,resolveForegroundWindowSeconds,createPtyBashTool,createBashInputTool,secretOutputObfuscator,truncateText,JOB_WIDGET_AGGS,JOB_WIDGET_TONES,onJobWidgetSessionChange,openJobWidgetSession,resendJobWidgetState,parkJobWidgetSession,closeJobWidgetSession,registerJobWidgetSource,getJobWidgetState,setJobWidgetAuthorResolver,jobWidgetHostResolver,truncateToVisualLines,jobWidgetLineStyle,cutPlain,formatJobWidgetLine,renderMonitorCall,createBashOutputTool,createBashResizeTool,terminalStateDir,ensureMonitorStateDir,removeMonitorStateDir,createKillBashTool,TERMINAL_CHILD_JOB_KINDS,childTerminalIdScope,terminalChildJob};
|
|
73
|
+
${dropped}${formatted.text||"(no new output)"}`,[droppedNotice,formatted.marker],extra)},renderCall:renderBashOutputCall,renderResult:renderBashOutputResult}}var bashResizeSchema=typebox_exports.Object({bash_id:typebox_exports.String({description:"Session id returned by a run_in_background bash call."}),cols:typebox_exports.Number({description:"New PTY width in columns."}),rows:typebox_exports.Number({description:"New PTY height in rows."})});function valid(value){return Number.isFinite(value)&&value>=1}function createBashResizeTool(ctx){return{name:TERMINAL_RESIZE_TOOL,label:"bash_resize",description:"Resize a live background bash session's PTY (cols x rows) so full-screen TUIs reflow. No-ops with a note under the pipe fallback.",exposure:"search",allowLazyActivation:!0,searchKeywords:["resize","pty size","cols","rows","terminal size"],parameters:bashResizeSchema,async execute(_toolCallId,input,_signal){let sessionId=resolveTerminalId(ctx.manager,input.bash_id),runtime=ctx.manager.get(sessionId);if(!runtime)return errorResult(`No terminal session found with id: ${input.bash_id}`);if(runtime.exited)return errorResult(`Session ${input.bash_id} is not running; cannot resize.`);if(!valid(input.cols)||!valid(input.rows))return errorResult("cols and rows must be finite integers >= 1.");let cols=Math.trunc(input.cols),rows=Math.trunc(input.rows),result=runtime.session.resize(cols,rows);return runtime.resizeScreen(cols,rows),result.ok?textResult(`Resized ${input.bash_id} to ${cols}x${rows}.`):textResult(`Resize note for ${input.bash_id}: ${result.note}`)}}}import{mkdir as mkdir4,rm as rm5}from"node:fs/promises";import{isAbsolute as isAbsolute2,join as join6}from"node:path";function terminalStateDir(ctx){if(ctx!==void 0&&NON_INTERACTIVE_MODES.has(ctx.mode))return;let sessionDir=ctx?.sessionManager?.getSessionDir?.();if(!(sessionDir===void 0||sessionDir.length===0||!isAbsolute2(sessionDir)))return join6(sessionDir,"extensions","terminal")}function monitorStateDir(terminalDir,monitorId){return join6(terminalDir,"state",monitorId)}async function ensureMonitorStateDir(terminalDir,monitorId){let dir=monitorStateDir(terminalDir,monitorId);return await mkdir4(dir,{recursive:!0,mode:448}),dir}async function removeMonitorStateDir(terminalDir,monitorId){await rm5(monitorStateDir(terminalDir,monitorId),{recursive:!0,force:!0})}var killBashSchema=typebox_exports.Object({bash_id:typebox_exports.Optional(typebox_exports.String({description:"Session id to tree-kill."})),all:typebox_exports.Optional(typebox_exports.Boolean({description:"Tree-kill every live background session."}))});function createKillBashTool(ctx){return{name:TERMINAL_KILL_TOOL,label:"kill_bash",description:"Terminate a background bash session (or all of them) and its process tree cleanly.",promptSnippet:"Tree-kill a background bash session (or all) with no orphans",parameters:killBashSchema,async execute(_toolCallId,input,_signal){let terminalDir=terminalStateDir(ctx.getSessionContext?.()),dropStateDir=async monitorId2=>{terminalDir!==void 0&&monitorId2!==void 0&&await removeMonitorStateDir(terminalDir,monitorId2)};if(input.all){let terminalCount=ctx.manager.size,monitorIds=(ctx.monitorRegistry?.snapshot()??[]).map(entry=>entry.monitorId),fileCount=await ctx.monitorRegistry?.stopAllFiles()??0,rpcCount=ctx.monitorRegistry?.stopAllRpc()??0;await ctx.manager.teardown();for(let monitorId2 of monitorIds)await dropStateDir(monitorId2);return textResult(`Killed ${terminalCount+fileCount+rpcCount} session(s).`)}if(!input.bash_id)return errorResult("Provide `bash_id` or set `all:true`.");let sessionId=resolveTerminalId(ctx.manager,input.bash_id),monitorId=input.bash_id.startsWith("mon_")?input.bash_id:ctx.manager.monitorIdOf?.(sessionId);return await ctx.monitorRegistry?.stopFile(sessionId)||ctx.monitorRegistry?.stopRpc(sessionId)?(await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):ctx.manager.get(sessionId)?(await ctx.manager.stop(sessionId),await dropStateDir(monitorId),textResult(`Killed ${input.bash_id}.`)):errorResult(`No terminal session found with id: ${input.bash_id}`)}}}var TERMINAL_CHILD_JOB_KINDS={bash:"terminal.bash",output:"terminal.output",input:"terminal.input",resize:"terminal.resize",kill:"terminal.kill"};function childTerminalIdScope(generation){return`c${generation}`}var CHILD_SESSION_ID=/_c(\d+)_\d+$/;function isChildSessionId(id){return CHILD_SESSION_ID.test(id)}function childGenerationOf(id){let generation=CHILD_SESSION_ID.exec(id)?.[1];return generation===void 0?void 0:Number(generation)}function optionalMinutes(value){return typeof value=="number"&&Number.isFinite(value)&&value>=1?Math.trunc(value):void 0}function parseBackgroundWake(value){if(typeof value!="object"||value===null)return;let event=Reflect.get(value,"event"),id=Reflect.get(value,"id");if(!(typeof id!="string"||!isChildSessionId(id))){if(event==="background_start"){let description=Reflect.get(value,"description"),startedAtMs=Reflect.get(value,"startedAtMs");if(typeof description!="string"||typeof startedAtMs!="number")return;let command=Reflect.get(value,"command"),autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes"));return{event,id,description,startedAtMs,...typeof command=="string"?{command}:{},...autoReapMinutes===void 0?{}:{autoReapMinutes}}}if(event==="background_reap_failed"){let autoReapMinutes=optionalMinutes(Reflect.get(value,"autoReapMinutes")),reason=Reflect.get(value,"reason");return autoReapMinutes===void 0||typeof reason!="string"?void 0:{event,id,autoReapMinutes,reason}}if(event==="background_exit"){let output=Reflect.get(value,"output"),exit=Reflect.get(value,"exit");if(typeof output!="string"||exit!==null&&typeof exit!="object")return;let autoReapedAfterMinutes=optionalMinutes(Reflect.get(value,"autoReapedAfterMinutes"));return{event,id,exit,output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}}}function exitView(exit,output,autoReapedAfterMinutes){return{exitResult:exit,fullOutput:()=>output,...autoReapedAfterMinutes===void 0?{}:{autoReapedAfterMinutes}}}function bashIdOf(value){if(typeof value!="object"||value===null)return;let id=value.bash_id;return typeof id=="string"?id:void 0}function lostSessionResult(id,generation){return{content:[{type:"text",text:`bash_id ${id} is lost: the session's tool child (generation ${generation}) exited, which ended this session and every process it started. Start a new session with bash.`}],details:{bash_id:id,lost:!0,generation}}}function terminalChildJob(ctx,kind){return{kind,...kind===TERMINAL_CHILD_JOB_KINDS.bash?backgroundRelay(ctx):{},...kind===TERMINAL_CHILD_JOB_KINDS.bash?{}:{placement:params=>{let id=bashIdOf(params);return id===void 0?kind===TERMINAL_CHILD_JOB_KINDS.kill?"both":"child":isChildSessionId(id)?"child":"server"}},result:(params,value,generation)=>{if(kind===TERMINAL_CHILD_JOB_KINDS.bash)return value;let id=bashIdOf(params),startedOn=id===void 0?void 0:childGenerationOf(id);return id===void 0||startedOn===void 0||startedOn===generation?value:lostSessionResult(id,startedOn)},args:(params,toolCallId,execCtx)=>{let env={};for(let[name,value]of Object.entries(ctx.getEnv()))typeof value=="string"&&(env[name]=value);return{params,toolCallId,cwd:execCtx.cwd??ctx.cwd,env:{...env,...sessionEnvOverrides(ctx,execCtx)},...ctx.shellPath===void 0?{}:{shellPath:ctx.shellPath},defaultCols:ctx.defaultCols,defaultRows:ctx.defaultRows,redactSecretsInOutput:ctx.redactSecretsInOutput===!0,...ctx.timeoutAction===void 0?{}:{timeoutAction:ctx.timeoutAction},...ctx.backgroundAutoReapMinutes===void 0?{}:{backgroundAutoReapMinutes:ctx.backgroundAutoReapMinutes}}}}}function backgroundRelay(ctx){let running=new Map;return{wake:(value,generation)=>{let wake=parseBackgroundWake(value);if(wake!==void 0){if(wake.event==="background_start"){running.set(wake.id,generation),ctx.onBackgroundStart?.(wake.id,wake.description,wake.startedAtMs,wake.command,wake.autoReapMinutes);return}if(wake.event==="background_reap_failed"){ctx.onBackgroundReapFailed?.(wake.id,wake.autoReapMinutes,wake.reason);return}running.delete(wake.id),ctx.onBackgroundExit?.(wake.id,exitView(wake.exit,wake.output,wake.autoReapedAfterMinutes))}},childExited:generation=>{for(let[id,startedOn]of running)startedOn===generation&&(running.delete(id),ctx.onBackgroundExit?.(id,exitView({exitCode:null,signal:null,timedOut:!1,cancelled:!0},`The session's tool child (generation ${generation}) exited, which ended this session and every process it started.`)))}}}export{ToolChildJobError,HostCallAdmission,PayloadRefWriter,PayloadRefReader,packPayload,unpackPayload,proofIsOrdered,TEST_CONTROL_DIR_ENV,readTestControls,WindowsJobError,WindowsJob,loadKernel32Job,generationLedgerPath,DescendantsLedger,LaunchLog,sweepGroups,defaultGroupProbes,recordGenerationChild,sweepStaleGenerations,TOOL_CHILD_GENERATION_ENV,TOOL_CHILD_PROTOCOL_VERSION,runToolChild,goShimScript,controlFd,withControlPipe,MODULE_JOB_KIND,TOOL_CHILD_MODULE_ROOTS_ENV,createModuleJobHandler,TerminalManager,annotateShellTrust,withTerminalContext,modelOnlyText,isModelOnlyText,DEFAULT_MAX_LINES,DEFAULT_MAX_BYTES,GREP_MAX_LINE_LENGTH,formatSize,truncateHead,truncateTail,truncateLine,sanitizeTerminalOutput,spawnCommandSession,describeExit,NOTICE_TAIL_MAX_CHARS,getTerminalNotificationDelivery,describeBackgroundAge,TerminalNotifier,createSessionLogger,queueEntryLabel,watchForStall,PendingQueueLedger,resolveTerminalId,textResult,errorResult,resolveForegroundWindowSeconds,createPtyBashTool,createBashInputTool,secretOutputObfuscator,truncateText,JOB_WIDGET_AGGS,JOB_WIDGET_TONES,onJobWidgetSessionChange,openJobWidgetSession,resendJobWidgetState,parkJobWidgetSession,closeJobWidgetSession,registerJobWidgetSource,getJobWidgetState,setJobWidgetAuthorResolver,jobWidgetHostResolver,truncateToVisualLines,jobWidgetLineStyle,cutPlain,formatJobWidgetLine,renderMonitorCall,createBashOutputTool,createBashResizeTool,terminalStateDir,ensureMonitorStateDir,removeMonitorStateDir,createKillBashTool,TERMINAL_CHILD_JOB_KINDS,childTerminalIdScope,terminalChildJob};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{appendDebugLogEntry}from"./chunk-EUCZC2RF.js";import{isRecoverableInspectorVmImportError}from"./chunk-
|
|
2
|
+
import{appendDebugLogEntry}from"./chunk-EUCZC2RF.js";import{isRecoverableInspectorVmImportError}from"./chunk-TEXE4HT6.js";import{hasModeCrashHandler}from"./chunk-ZFIC2DZV.js";import{isStaleExtensionContextError}from"./chunk-IHES3JES.js";function containStaleExtensionError(error,origin){if(!isStaleExtensionContextError(error))return!1;try{appendDebugLogEntry(`contained stale extension ctx (${origin})`,error.stack??error.message)}catch{}return!0}var installed=!1;function installStaleExtensionContainment(){installed||(installed=!0,process.on("uncaughtException",(error,origin)=>{containStaleExtensionError(error,origin??"uncaughtException")||hasModeCrashHandler("uncaughtException")||isRecoverableInspectorVmImportError(error,origin??"uncaughtException")||(console.error(error),process.exit(1))}))}export{containStaleExtensionError,installStaleExtensionContainment};
|