@robota-sdk/agent-subagent-runner 3.0.0-beta.82 → 3.0.0-beta.84

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/README.md CHANGED
@@ -1,26 +1,33 @@
1
1
  # @robota-sdk/agent-subagent-runner
2
2
 
3
- Child-process subagent runner for the Robota SDK. Runs subagents in isolated child processes with IPC, worktree isolation, and log streaming.
3
+ Child-process subagent runner for the Robota SDK. It runs each subagent in its own Node.js child
4
+ process, talks to it over a typed IPC protocol, and can wrap each job in worktree isolation and stream
5
+ its logs to disk.
4
6
 
5
7
  ## Installation
6
8
 
7
9
  ```bash
8
- pnpm add @robota-sdk/agent-subagent-runner
10
+ npm install @robota-sdk/agent-subagent-runner
9
11
  ```
10
12
 
11
13
  ## Overview
12
14
 
13
- This package is an optional add-on for `@robota-sdk/agent-framework`. It enables spawning subagents in separate Node.js child processes, giving each subagent full process isolation while maintaining structured IPC communication back to the parent session.
15
+ This package is an optional add-on for `@robota-sdk/agent-framework`. Without it, subagents run
16
+ in-process; with it, each subagent gets process isolation while reporting back to the parent session
17
+ over structured IPC.
14
18
 
15
19
  ```
16
- agent-cli
20
+ composition root (e.g. agent-cli)
17
21
  └── createChildProcessSubagentRunnerFactory()
18
22
  └── ChildProcessSubagentRunner ← this package
19
- ├── fork() ← Node.js child_process.fork
23
+ ├── spawn() ← a copy of the running artifact in worker mode
20
24
  ├── IPC messages ← TSubagentWorkerParentMessage / TSubagentWorkerChildMessage
21
- └── worktree isolation ← via agent-executor
25
+ └── worktree isolation ← via agent-executor, with an injected worktree adapter
22
26
  ```
23
27
 
28
+ The runner composes nothing itself. The composition root supplies how to start a copy of itself
29
+ (`workerEntry`), the tool factory and provider registry the child uses, and the worktree adapter.
30
+
24
31
  ## Usage
25
32
 
26
33
  ```typescript
@@ -40,13 +47,13 @@ declare const providerConfig: IProviderDefinitionConfig;
40
47
  // The concrete worktree adapter (git/fs I/O) is owned and injected by the composition root.
41
48
  declare const worktreeAdapter: ISubagentWorktreeAdapter;
42
49
 
43
- // ARCH-021: YOUR product's surface, built at the CHILD's execution root. This package composes
44
- // nothing — an optional parameter falling back to defaults is exactly the defect the port removes.
50
+ // Your product's tool surface, built at the CHILD's execution root. This package composes nothing:
51
+ // there is no default tool set or provider registry to fall back to.
45
52
  declare const createMyTools: (context: { readonly cwd: string }) => IToolWithEventService[];
46
53
  declare const myProviderDefinitions: readonly IProviderDefinition[];
47
54
 
48
- // DIST-006: your entry IS the worker. Dispatch before starting your app, so a subagent child
49
- // re-enters here instead of booting the whole product.
55
+ // Your entry is the worker. Dispatch before starting your app, so a subagent child re-enters here
56
+ // instead of booting the whole product.
50
57
  if (isSubagentWorkerModeArgv(process.argv)) {
51
58
  runSubagentWorkerMain({
52
59
  createTools: createMyTools,
@@ -60,12 +67,13 @@ const factory = createChildProcessSubagentRunnerFactory({
60
67
  // nothing, because `process.execPath` is the binary and re-executing it re-enters its entry.
61
68
  workerEntry: { execPath: process.execPath, args: [process.argv[1] ?? ''] },
62
69
  providerConfig,
70
+ providerDefinitions: myProviderDefinitions, // required: a job whose provider is not here is refused
63
71
  logsDir: '.robota/logs',
64
72
  worktreeAdapter, // required: no concrete git default — inject the port at the composition root
65
73
  });
66
74
  ```
67
75
 
68
- Pass `factory` to `createAgentRuntime({ subagentRunnerFactory: factory })`.
76
+ Pass `factory` as the `subagentRunnerFactory` option of `agent-framework`'s `createAgentRuntime`.
69
77
 
70
78
  ## API
71
79
 
@@ -75,7 +83,7 @@ Pass `factory` to `createAgentRuntime({ subagentRunnerFactory: factory })`.
75
83
  | -------------------------------------------------- | --------------------------------------------------------------------------- |
76
84
  | `createChildProcessSubagentRunnerFactory(options)` | Returns a `TSubagentRunnerFactory` that spawns subagents in child processes |
77
85
  | `isSubagentWorkerModeArgv(argv)` | True when this process was started as a subagent worker |
78
- | `runSubagentWorkerMain()` | Enters worker mode; refuses loudly (exit 2) without an IPC channel |
86
+ | `runSubagentWorkerMain(composition)` | Enters worker mode; refuses loudly (exit 2) without an IPC channel |
79
87
 
80
88
  ### Classes
81
89
 
@@ -85,16 +93,27 @@ Pass `factory` to `createAgentRuntime({ subagentRunnerFactory: factory })`.
85
93
 
86
94
  ### Types
87
95
 
88
- | Export | Description |
89
- | ------------------------------------ | ---------------------------------------------------------- |
90
- | `IChildProcessSubagentRunnerOptions` | Options for `createChildProcessSubagentRunnerFactory` |
91
- | `ISubagentWorkerEntry` | How to spawn a copy of the running artifact in worker mode |
92
- | `ISubagentWorkerStartPayload` | IPC payload sent from parent to worker on start |
93
- | `TSubagentWorkerParentMessage` | Union of all messages the parent sends to the worker |
94
- | `TSubagentWorkerChildMessage` | Union of all messages the worker sends to the parent |
95
- | `TSubagentWorkerWireValue` | Serializable value type used in IPC messages |
96
+ | Export | Description |
97
+ | ------------------------------------ | -------------------------------------------------------------------------------- |
98
+ | `IChildProcessSubagentRunnerOptions` | Options for `createChildProcessSubagentRunnerFactory` |
99
+ | `ISubagentWorkerEntry` | How to spawn a copy of the running artifact in worker mode |
100
+ | `ISubagentWorkerComposition` | What the product composes in the child: tools, provider registry, optional ports |
101
+ | `ISubagentWorkerStartPayload` | IPC payload sent from parent to worker on start |
102
+ | `TSubagentWorkerParentMessage` | Union of all messages the parent sends to the worker |
103
+ | `TSubagentWorkerChildMessage` | Union of all messages the worker sends to the parent |
104
+ | `TSubagentWorkerWireValue` | Serializable value type used in IPC messages |
105
+
106
+ ### Type guards and wire helpers
107
+
108
+ | Export | Description |
109
+ | ------------------------------------------------------------------------------- | ------------------------------------------------------ |
110
+ | `isSubagentWorkerParentMessage` | Narrows to `TSubagentWorkerParentMessage` |
111
+ | `isSubagentWorkerChildMessage` | Narrows to `TSubagentWorkerChildMessage` |
112
+ | `SUBAGENT_WORKER_MODE_FLAG` | The argv flag that puts an entry into worker mode |
113
+ | `encodeAgentDefinition` / `decodeAgentDefinitionDto` / `restoreAgentDefinition` | JSON-safe wire form of the subagent's agent definition |
114
+ | `encodeParentContext` / `decodeParentContextDto` / `restoreParentContext` | JSON-safe wire form of the parent's loaded context |
96
115
 
97
- ### Forked session records
116
+ ## Forked session records
98
117
 
99
118
  If a job includes `resumeSessionId`, the composition root must provide
100
119
  `ISubagentWorkerComposition.openSessionStore`. The worker opens that store for the parent request's
@@ -102,17 +121,16 @@ If a job includes `resumeSessionId`, the composition root must provide
102
121
  completed turn is persisted back into the fork record. Only the ID crosses IPC; the conversation does
103
122
  not. Jobs without `resumeSessionId` remain transient.
104
123
 
105
- ### Type Guards
106
-
107
- | Export | Description |
108
- | ------------------------------- | ----------------------------------------- |
109
- | `isSubagentWorkerParentMessage` | Narrows to `TSubagentWorkerParentMessage` |
110
- | `isSubagentWorkerChildMessage` | Narrows to `TSubagentWorkerChildMessage` |
111
-
112
124
  ## Dependencies
113
125
 
114
- - `@robota-sdk/agent-executor` — worktree isolation and background task primitives
115
- - `@robota-sdk/agent-framework` — runtime types (`ISubagentRunner`, `TSubagentRunnerFactory`)
126
+ - `@robota-sdk/agent-executor` — `ISubagentRunner`, worktree isolation, and background task primitives
127
+ - `@robota-sdk/agent-framework` — `TSubagentRunnerFactory` and session assembly for the worker
128
+ - `@robota-sdk/agent-core` — provider and tool types
129
+ - `@robota-sdk/agent-interface-execution` — subagent job contracts
130
+ - `@robota-sdk/agent-process` — process-tree termination
131
+
132
+ See [docs/SPEC.md](./docs/SPEC.md) for the package contract: required composition, IPC validation, and
133
+ how the provider connection is checked across the process boundary.
116
134
 
117
135
  ## License
118
136
 
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:child_process"),t=require("node:fs"),n=require("node:path"),r=require("@robota-sdk/agent-executor"),i=require("@robota-sdk/agent-process"),a=require("@robota-sdk/agent-core"),o=require("@robota-sdk/agent-framework");function s(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function c(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const l={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},u={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ee(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function te(e){return d(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function ne(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&(0,a.isModelEffort)(t);case`string[]`:return ee(t);case`file-entry[]`:return Array.isArray(t)&&t.every(te)}}function f(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function p(e,t,n){if(!d(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!ne(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:f(t,n)}}function m(e){return f(e,l)}function h(e){return p(`agentDefinition`,e,l)}function g(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function _(e){return f(e,u)}function v(e){return p(`parentContext`,e,u)}function y(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function b(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function x(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function S(e,t,n,i,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if((0,a.findProviderDefinition)(s,c)===void 0)throw new r.BackgroundTaskError(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let l=T(n.providerConfig,t,e,s),u=(0,r.connectionEnvironmentNames)(l,s),d=(0,r.findConnectionEnvironmentDivergence)(u,i,o);if(d!==void 0)throw new r.BackgroundTaskError(`validation`,`The subagent's environment sets ${d} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:l,connectionCheck:(0,r.sealConnectionEnvironment)(u,o)}}function re(e,t,n){let r=ie(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:m(C(r,e)),parentConfig:s(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:_(c(t.context)),...n.connection??S(e,t,n,process.env,process.env),permissionMode:t.permissionMode,...b(t),...n.logsDir?{logsDir:n.logsDir}:{}};return x(t).then(e=>({...i,...e}))}function ie(e,t,n,i){let a=t?.(e)??n?.find(t=>t.name===e)??i?.find(t=>t.name===e);if(!a)throw new r.BackgroundTaskError(`validation`,`Unknown agent type: ${e}`);return a}function C(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function w(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function T(e,t,n,r){let i=e??t.config.provider,o=(0,a.findProviderDefinition)(r,i.name)?.defaults??{},s=i.baseURL??o.baseURL,c=i.options??o.options,l=w(i,o.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...l,...s===void 0?{}:{baseURL:s},...i.timeout===void 0?{}:{timeout:i.timeout},...c===void 0?{}:{options:c}}}function E(e){return typeof e==`object`&&!!e}function ae(e){if(!E(e)||!D(e,`nonce`)||!D(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function D(e,t){return typeof e[t]==`string`}function O(e,t){return D(e,t)}function oe(e,t){return D(e,t)}function se(e,t){return e[t]===void 0||typeof e[t]==`string`}function ce(e){if(e.usage===void 0)return!0;let t=e.usage;return E(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function k(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function A(e){return!E(e)||!oe(e,`taskId`)||!E(e.request)||!O(e.request,`agentType`)||!O(e.request,`prompt`)||!O(e.request,`permissionPolicy`)||!O(e.request,`cwd`)||!se(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!E(e.worktree)||!D(e.worktree,`path`))||!h(e.agentDefinition).ok||!E(e.parentConfig)||!v(e.parentContext).ok||!E(e.providerProfile)||!D(e.providerProfile,`type`)||!D(e.providerProfile,`model`)?!1:ae(e.connectionCheck)}function j(e){if(!E(e)||!D(e,`type`))return!1;switch(e.type){case`start`:return A(e.payload);case`send`:return D(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}function M(e){if(!E(e)||!D(e,`type`))return!1;switch(e.type){case`ready`:return k(e);case`text_delta`:return D(e,`delta`);case`tool_start`:return D(e,`toolName`);case`tool_end`:return D(e,`toolName`)&&typeof e.success==`boolean`;case`result`:return D(e,`output`)&&ce(e);case`error`:return D(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const N=process.platform!==`win32`;function P(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const F=new WeakMap;function I(e){let t=e.stderr;if(!t)return;let n=(0,a.createBoundedOutput)({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});F.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function L(e){return(F.get(e)?.toString()??``).trim()}function R(e,t,n,i,a){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:i(new r.BackgroundTaskError(`runner`,e.message));break;case`cancelled`:i(new r.BackgroundTaskError(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:z(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;default:i(new r.BackgroundTaskError(`runner`,`Unhandled subagent worker message`))}}function z(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function B(e,t){return new Promise((n,i)=>{if(!e.connected){i(new r.BackgroundTaskError(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){i(e);return}n()})})}async function V(e,t){await(0,i.killProcessTree)(e.child,{graceMs:e.killGraceMs,processGroup:N,preKill:async()=>{e.child.connected&&(await B(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await P(e.child,e.killGraceMs))}})}function H(e){return new Promise((t,n)=>{new U(e,t,n).start()})}var U=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let i=e.handshakeBudgetMs;this.handshakeBudgetMs=i!==void 0&&i>0?i:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=G(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(V(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new r.BackgroundTaskError(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:B(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!M(e)){this.rejectOnce(new r.BackgroundTaskError(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;R(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit)};onError=e=>{this.rejectOnce(new r.BackgroundTaskError(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new r.BackgroundTaskError(`crash`,K(e,t,L(this.options.runtime.child))))};resolveOnce=e=>{if(this.settled)return;this.settled=!0,this.clearTimers(),this.cleanup();let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(le(t.job,e,n))};rejectOnce=e=>{this.settled||(this.settled=!0,this.clearTimers(),this.cleanup(),this.reject(e))};clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function W(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(i){t||(t=!0,n(new r.BackgroundTaskError(`runner`,i??`Subagent job cancelled: ${e}`)))}}}function G(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{V(e,`Subagent worker timed out`),t(new r.BackgroundTaskError(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function le(e,t,n){let r=n(e);return{taskId:e.taskId,output:t.output,...r?{metadata:{transcriptPath:r,logPath:r}}:{},...t.usage?{usage:t.usage}:{}}}function K(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const q=`--__robota-subagent-worker`;function ue(e){return e.includes(q)}const de=process.platform!==`win32`;function fe(e){return t=>{let n=new J(t,e);return e.worktreeIsolation===!1?n:(0,r.createWorktreeSubagentRunner)({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var J=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;logsDir;constructor(e,t){this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??i.DEFAULT_KILL_GRACE_MS,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.logsDir=t.logsDir}start(t){let n=this.workerEntry,i={...process.env,...this.env??{}},a=S(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},process.env,i),o=(0,e.spawn)(n.execPath,[...n.execArgv??[],...n.args,q],{cwd:(0,r.subagentExecutionRoot)(t),env:i,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:de});I(o);let s={job:t,child:o,killGraceMs:this.killGraceMs},c=H({runtime:s,payload:this.createStartPayload(t,a),...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e)}),l=W(t.taskId);c.catch(()=>void 0);let u=Promise.race([c,l.promise]);u.catch(()=>void 0);let d=this.resolveTranscriptPath(t);return{taskId:t.taskId,...o.pid!==void 0&&{pid:o.pid},...d!==void 0&&{transcriptPath:d,logPath:d},result:u,cancel:async e=>{l.reject(e),await V(s,e)},send:async e=>{await B(o,{type:`send`,prompt:e})},...d!==void 0&&{readLog:async e=>pe(t.taskId,d,e)}}}createStartPayload(e,t){return re(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir}})}resolveTranscriptPath(e){if(this.logsDir)return(0,n.join)(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}};function pe(e,n,i){return(0,t.existsSync)(n)?(0,r.createBackgroundTaskLogPage)(e,(0,t.readFileSync)(n,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function me(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);(0,o.restoreSessionRecordIntoSession)(n,r,t)}}function he(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function ge(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const _e={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let Y=null,X=!1,Z=Promise.resolve();function Q(e){process.send&&process.send(e)}function $(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function ve(e){try{return(0,a.sumHistoryUsage)(e.getFullHistory())}catch{return}}async function ye(e,t){try{if(!(0,r.verifyConnectionEnvironment)(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await ge(e.sandboxProjection,t.sandboxFactories),i=(0,r.createProviderFromExactProfile)(e.providerProfile,e.request.model,t.providerDefinitions),a=e.logsDir?(0,o.createSubagentLogger)(e.request.parentSessionId,e.taskId,e.logsDir):void 0,s=he(e,t);Y=(0,o.createSubagentSession)({agentDefinition:g(e.agentDefinition),parentConfig:e.parentConfig,parentContext:y(e.parentContext),parentTools:t.createTools({cwd:(0,r.subagentExecutionRoot)(e),...n===void 0?{}:{sandboxClient:n},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:(0,r.subagentExecutionRoot)(e),provider:i,terminal:_e,sessionId:e.request.resumeSessionId??e.taskId,...s===void 0?{}:{sessionStore:s},...a?{sessionLogger:a}:{},permissionMode:e.permissionMode,...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors()},onTextDelta:e=>Q({type:`text_delta`,delta:e}),onToolExecution:be}),me(e,Y,s);let c=await Y.run(e.request.prompt);if(X){$({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let l=ve(Y);$({type:`result`,output:c,...l?{usage:l}:{}},0)}catch(e){if(X){$({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}$({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function be(e){if(e.type===`start`){Q({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Q({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function xe(e){if(Y===null){Q({type:`error`,message:`Subagent worker has not started`});return}Z=Z.then(async()=>{try{await Y?.run(e)}catch(e){Q({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function Se(e){X=!0,Y?.abort(),Q({type:`cancelled`,reason:e}),await Y?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Ce(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`robota: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function we(e){process.send===void 0&&(process.stderr.write(`robota: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
2
- `),process.exit(2)),process.on(`message`,t=>{if(!j(t)){Q({type:`error`,message:`Malformed subagent worker parent message`});return}switch(t.type){case`start`:Z=Z.then(()=>ye(t.payload,e));break;case`send`:xe(t.prompt);break;case`cancel`:Se(t.reason);break;default:Q({type:`error`,message:`Unhandled subagent worker parent message`})}}),process.on(`disconnect`,()=>{X=!0,Y?.abort(),Y?.shutdown({reason:`other`}).catch(()=>void 0)});let t=Ce(e);Q({type:`ready`,...t?{composedToolNames:t}:{}})}exports.ChildProcessSubagentRunner=J,exports.SUBAGENT_WORKER_MODE_FLAG=q,exports.createChildProcessSubagentRunnerFactory=fe,exports.decodeAgentDefinitionDto=h,exports.decodeParentContextDto=v,exports.encodeAgentDefinition=m,exports.encodeParentContext=_,exports.isSubagentWorkerChildMessage=M,exports.isSubagentWorkerModeArgv=ue,exports.isSubagentWorkerParentMessage=j,exports.restoreAgentDefinition=g,exports.restoreParentContext=y,exports.runSubagentWorkerMain=we;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:child_process"),t=require("node:fs"),n=require("node:path"),r=require("@robota-sdk/agent-executor"),i=require("@robota-sdk/agent-process"),a=require("@robota-sdk/agent-core"),o=require("@robota-sdk/agent-framework");function s(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function c(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const l={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},u={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function p(e){return d(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function m(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&(0,a.isModelEffort)(t);case`string[]`:return f(t);case`file-entry[]`:return Array.isArray(t)&&t.every(p)}}function h(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function g(e,t,n){if(!d(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!m(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:h(t,n)}}function _(e){return h(e,l)}function v(e){return g(`agentDefinition`,e,l)}function y(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function b(e){return h(e,u)}function x(e){return g(`parentContext`,e,u)}function S(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function ee(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function C(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function w(e,t,n,i,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if((0,a.findProviderDefinition)(s,c)===void 0)throw new r.BackgroundTaskError(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let l=E(n.providerConfig,t,e,s),u=(0,r.connectionEnvironmentNames)(l,s),d=(0,r.findConnectionEnvironmentDivergence)(u,i,o);if(d!==void 0)throw new r.BackgroundTaskError(`validation`,`The subagent's environment sets ${d} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:l,connectionCheck:(0,r.sealConnectionEnvironment)(u,o)}}function te(e,t,n){let r=ne(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:_(re(r,e)),parentConfig:s(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:b(c(t.context)),...n.connection??w(e,t,n,process.env,process.env),permissionMode:t.permissionMode,...ee(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return C(t).then(e=>({...i,...e}))}function ne(e,t,n,i){let a=t?.(e)??n?.find(t=>t.name===e)??i?.find(t=>t.name===e);if(!a)throw new r.BackgroundTaskError(`validation`,`Unknown agent type: ${e}`);return a}function re(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function T(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function E(e,t,n,r){let i=e??t.config.provider,o=(0,a.findProviderDefinition)(r,i.name)?.defaults??{},s=i.baseURL??o.baseURL,c=i.options??o.options,l=T(i,o.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...l,...s===void 0?{}:{baseURL:s},...i.timeout===void 0?{}:{timeout:i.timeout},...c===void 0?{}:{options:c}}}function D(e){return typeof e==`object`&&!!e}function ie(e){if(!D(e)||!O(e,`nonce`)||!O(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function O(e,t){return typeof e[t]==`string`}function k(e,t){return O(e,t)}function ae(e,t){return O(e,t)}function oe(e,t){return e[t]===void 0||typeof e[t]==`string`}function se(e){if(e.usage===void 0)return!0;let t=e.usage;return D(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function ce(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function le(e){return!D(e)||!ae(e,`taskId`)||!D(e.request)||!k(e.request,`agentType`)||!k(e.request,`prompt`)||!k(e.request,`permissionPolicy`)||!k(e.request,`cwd`)||!oe(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!D(e.worktree)||!O(e.worktree,`path`))||!v(e.agentDefinition).ok||!D(e.parentConfig)||!x(e.parentContext).ok||!D(e.providerProfile)||!O(e.providerProfile,`type`)||!O(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!D(e.parentSandboxSettings)?!1:ie(e.connectionCheck)}function A(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`start`:return le(e.payload);case`send`:return O(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return D(e.settings);case`permission_response`:return O(e,`requestId`)&&ue(e.result);default:return!1}}function ue(e){return typeof e==`boolean`||e===`allow-session`||e===`allow-project`}function j(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`ready`:return ce(e);case`text_delta`:return O(e,`delta`);case`tool_start`:return O(e,`toolName`);case`tool_end`:return O(e,`toolName`)&&typeof e.success==`boolean`;case`permission_request`:return O(e,`requestId`)&&O(e,`toolName`);case`result`:return O(e,`output`)&&se(e);case`error`:return O(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const de=process.platform!==`win32`;function fe(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const M=new WeakMap;function N(e){let t=e.stderr;if(!t)return;let n=(0,a.createBoundedOutput)({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});M.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function P(e){return(M.get(e)?.toString()??``).trim()}function F(e,t,n,i,a,o){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:i(new r.BackgroundTaskError(`runner`,e.message));break;case`cancelled`:i(new r.BackgroundTaskError(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:I(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;case`permission_request`:o?.(e);break;default:i(new r.BackgroundTaskError(`runner`,`Unhandled subagent worker message`))}}function I(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function L(e,t){return new Promise((n,i)=>{if(!e.connected){i(new r.BackgroundTaskError(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){i(e);return}n()})})}async function R(e,t){await(0,i.killProcessTree)(e.child,{graceMs:e.killGraceMs,processGroup:de,preKill:async()=>{e.child.connected&&(await L(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await fe(e.child,e.killGraceMs))}})}function z(e){return new Promise((t,n)=>{new B(e,t,n).start()})}var B=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;deniedToolCallCounts={"no-approver":0,"denied-by-person":0,"approver-error":0,cancelled:0};pendingPermissionRequests=new Map;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let i=e.handshakeBudgetMs;this.handshakeBudgetMs=i!==void 0&&i>0?i:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=pe(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(R(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new r.BackgroundTaskError(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:L(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!j(e)){this.rejectOnce(new r.BackgroundTaskError(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;F(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit,this.onPermissionRequest)};onPermissionRequest=e=>{let t=this.answerPermissionRequest(e).finally(()=>{this.pendingPermissionRequests.delete(e.requestId)});this.pendingPermissionRequests.set(e.requestId,t)};async answerPermissionRequest(e){let{reason:t,result:n}=await this.askApprover(e);t!==void 0&&(this.deniedToolCallCounts[t]+=1);let{child:r}=this.options.runtime;r.connected&&await L(r,{type:`permission_response`,requestId:e.requestId,result:n}).catch(()=>void 0)}async askApprover(e){let t=this.options.permissionApprover;if(t===void 0)return{reason:`no-approver`,result:!1};try{let n=await t(e.toolName,e.toolArgs??{},this.options.permissionAbort.signal);return n===!1?this.options.permissionAbort.signal.aborted?{reason:`cancelled`,result:!1}:{reason:`denied-by-person`,result:!1}:{result:n}}catch{return{reason:`approver-error`,result:!1}}}onError=e=>{this.rejectOnce(new r.BackgroundTaskError(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new r.BackgroundTaskError(`crash`,ge(e,t,P(this.options.runtime.child))))};resolveOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>{let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(me(t.job,e,n,this.deniedToolCallCounts))}))};rejectOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>this.reject(e)))};async settleAfterPendingPermissionRequests(e){this.options.permissionAbort.abort(),this.clearTimers(),this.cleanup(),await Promise.all(this.pendingPermissionRequests.values()),e()}clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function V(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(i){t||(t=!0,n(new r.BackgroundTaskError(`runner`,i??`Subagent job cancelled: ${e}`)))}}}function pe(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{R(e,`Subagent worker timed out`),t(new r.BackgroundTaskError(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function me(e,t,n,r){let i=n(e),a=he(r);return{taskId:e.taskId,output:t.output,...i?{metadata:{transcriptPath:i,logPath:i}}:{},...t.usage?{usage:t.usage}:{},...a?{deniedToolCalls:a}:{}}}function he(e){let t=Object.values(e).reduce((e,t)=>e+t,0);return t===0?void 0:{total:t,byReason:{...e}}}function ge(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const H=`--__robota-subagent-worker`;function _e(e){return e.includes(H)}const ve=process.platform!==`win32`;function ye(e){return t=>{let n=new U(t,e);return e.worktreeIsolation===!1?n:(0,r.createWorktreeSubagentRunner)({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var U=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;logsDir;parentSandboxSettings;watchParentSandboxSettings;constructor(e,t){this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??i.DEFAULT_KILL_GRACE_MS,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.logsDir=t.logsDir,this.parentSandboxSettings=t.parentSandboxSettings,this.watchParentSandboxSettings=t.watchParentSandboxSettings}start(t){let n=this.workerEntry,i={...process.env,...this.env??{}},a=w(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},process.env,i),o=(0,e.spawn)(n.execPath,[...n.execArgv??[],...n.args,H],{cwd:(0,r.subagentExecutionRoot)(t),env:i,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:ve});N(o),this.forwardSandboxSettingChanges(o);let s={job:t,child:o,killGraceMs:this.killGraceMs},c=this.createStartPayload(t,a),l=new AbortController,u=this.permissionApprover(t),d=z({runtime:s,payload:c,...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e),permissionAbort:l,...u===void 0?{}:{permissionApprover:u}}),f=V(t.taskId);d.catch(()=>void 0);let p=Promise.race([d,f.promise]);p.catch(()=>void 0);let m=this.resolveTranscriptPath(t);return{taskId:t.taskId,...o.pid!==void 0&&{pid:o.pid},...m!==void 0&&{transcriptPath:m,logPath:m},result:p,cancel:async e=>{l.abort(e),f.reject(e),await R(s,e)},send:async e=>{await L(o,{type:`send`,prompt:e})},...m!==void 0&&{readLog:async e=>be(t.taskId,m,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return te(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir},...n===void 0?{}:{parentSandboxSettings:n}})}forwardSandboxSettingChanges(e){let t=this.watchParentSandboxSettings?.(t=>{e.connected&&L(e,{type:`sandbox_settings`,settings:t}).catch(()=>void 0)});t!==void 0&&(e.once(`exit`,t),e.once(`error`,t))}resolveTranscriptPath(e){if(this.logsDir)return(0,n.join)(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}permissionApprover(e){let t=this.deps.permissionHandler;if(t===void 0)return;let n={kind:`background-agent`,label:e.request.agentType,taskId:e.taskId};return(e,r,i)=>t(e,r,{requester:n,signal:i})}};function be(e,n,i){return(0,t.existsSync)(n)?(0,r.createBackgroundTaskLogPage)(e,(0,t.readFileSync)(n,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function xe(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);(0,o.restoreSessionRecordIntoSession)(n,r,t)}}function Se(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function Ce(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const we={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let W=null,G=!1;const K=new Map;let Te=0,q,J,Y,X=Promise.resolve();function Z(e){process.send&&process.send(e)}function Q(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function Ee(e){try{return(0,a.sumHistoryUsage)(e.getFullHistory())}catch{return}}async function De(e,t){try{if(!(0,r.verifyConnectionEnvironment)(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await Ce(e.sandboxProjection,t.sandboxFactories),i=(0,r.createProviderFromExactProfile)(e.providerProfile,e.request.model,t.providerDefinitions),a=e.logsDir?(0,o.createSubagentLogger)(e.request.parentSessionId,e.taskId,e.logsDir):void 0,s=Se(e,t),c=q??e.parentSandboxSettings;J=n===void 0?t.createSandbox?.({cwd:(0,r.subagentExecutionRoot)(e),...c===void 0?{}:{parentSettings:c}}):void 0;let l=n??J?.client;W=(0,o.createSubagentSession)({agentDefinition:y(e.agentDefinition),parentConfig:e.parentConfig,parentContext:S(e.parentContext),parentTools:t.createTools({cwd:(0,r.subagentExecutionRoot)(e),...l===void 0?{}:{sandboxClient:l},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:(0,r.subagentExecutionRoot)(e),provider:i,terminal:we,sessionId:e.request.resumeSessionId??e.taskId,...s===void 0?{}:{sessionStore:s},...a?{sessionLogger:a}:{},permissionMode:e.permissionMode,...J?.commandSandbox===void 0?{}:{commandSandbox:J.commandSandbox},...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors()},onTextDelta:e=>Z({type:`text_delta`,delta:e}),onToolExecution:Ae,permissionHandler:Oe}),xe(e,W,s);let u=await W.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let d=Ee(W);Q({type:`result`,output:u,...d?{usage:d}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Oe(e,t){let n=`perm_${++Te}`;return new Promise(r=>{K.set(n,r),Z({type:`permission_request`,requestId:n,toolName:e,toolArgs:t})})}function ke(e,t){let n=K.get(e);n!==void 0&&(K.delete(e),n(t))}function Ae(e){if(e.type===`start`){Z({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Z({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function $(e){if(W===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await W?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function je(e){G=!0,W?.abort(),Z({type:`cancelled`,reason:e}),await W?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Me(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`robota: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function Ne(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),W?.abort()}}function Pe(e){process.send===void 0&&(process.stderr.write(`robota: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
2
+ `),process.exit(2)),process.on(`message`,t=>{if(!A(t)){Z({type:`error`,message:`Malformed subagent worker parent message`});return}switch(t.type){case`start`:X=X.then(()=>De(t.payload,e));break;case`send`:$(t.prompt);break;case`cancel`:je(t.reason);break;case`sandbox_settings`:Ne(t.settings);break;case`permission_response`:ke(t.requestId,t.result);break;default:Z({type:`error`,message:`Unhandled subagent worker parent message`})}}),process.on(`disconnect`,()=>{G=!0,W?.abort(),W?.shutdown({reason:`other`}).catch(()=>void 0)});let t=Me(e);Z({type:`ready`,...t?{composedToolNames:t}:{}})}exports.ChildProcessSubagentRunner=U,exports.SUBAGENT_WORKER_MODE_FLAG=H,exports.createChildProcessSubagentRunnerFactory=ye,exports.decodeAgentDefinitionDto=v,exports.decodeParentContextDto=x,exports.encodeAgentDefinition=_,exports.encodeParentContext=b,exports.isSubagentWorkerChildMessage=j,exports.isSubagentWorkerModeArgv=_e,exports.isSubagentWorkerParentMessage=A,exports.restoreAgentDefinition=y,exports.restoreParentContext=S,exports.runSubagentWorkerMain=Pe;
@@ -1,6 +1,6 @@
1
1
  import { IConnectionEnvironmentCheck, ISubagentJobHandle, ISubagentJobStart, ISubagentRunner, ISubagentWorktreeAdapter } from "@robota-sdk/agent-executor";
2
2
  import { IHookTypeExecutor, IProviderDefinition, IProviderDefinitionConfig, ISessionUsageTotals, IToolWithEventService, TPermissionMode, TToolArgs } from "@robota-sdk/agent-core";
3
- import { IAgentDefinition, IInProcessSubagentRunnerDeps, IResolvedConfig, ISubagentParentContext, TSubagentRunnerFactory, restoreSessionRecordIntoSession } from "@robota-sdk/agent-framework";
3
+ import { IAgentDefinition, IInProcessSubagentRunnerDeps, IResolvedConfig, ISubagentOptions, ISubagentParentContext, TSubagentRunnerFactory, restoreSessionRecordIntoSession } from "@robota-sdk/agent-framework";
4
4
  import { ISerializableProviderProfile, ISubagentSpawnRequest } from "@robota-sdk/agent-interface-execution";
5
5
  //#region src/worker-entry.d.ts
6
6
  /**
@@ -42,104 +42,6 @@ interface ISubagentWorkerEntry {
42
42
  /** True when this process was started as a subagent worker. */
43
43
  declare function isSubagentWorkerModeArgv(argv: readonly string[]): boolean;
44
44
  //#endregion
45
- //#region src/child-process-subagent-runner.d.ts
46
- interface IChildProcessSubagentRunnerOptions {
47
- /**
48
- * DIST-006: how to start a copy of the running artifact in subagent-worker mode, stated by the
49
- * composition root. It replaced `workerPath`, which asked this package to locate a file whose
50
- * location is a property of the packaging step — a question no library can answer, and one that
51
- * was answered wrongly twice.
52
- */
53
- workerEntry: ISubagentWorkerEntry;
54
- providerConfig?: IProviderDefinitionConfig;
55
- /**
56
- * The parent's provider registry. Its defaults complete the connection the child is given, and
57
- * each definition names the environment its client reads. Required: a job whose provider has no
58
- * definition here is refused, because its connection cannot be checked.
59
- */
60
- providerDefinitions: readonly IProviderDefinition[];
61
- killGraceMs?: number;
62
- /**
63
- * How long a spawned worker may take to signal `ready` before the runner gives up. Injectable so
64
- * the branch is reachable in a test; without that it is a fix that ships untested.
65
- */
66
- handshakeBudgetMs?: number;
67
- env?: NodeJS.ProcessEnv;
68
- worktreeIsolation?: boolean;
69
- worktreeAdapter: ISubagentWorktreeAdapter;
70
- logsDir?: string;
71
- }
72
- declare function createChildProcessSubagentRunnerFactory(options: IChildProcessSubagentRunnerOptions): TSubagentRunnerFactory;
73
- declare class ChildProcessSubagentRunner implements ISubagentRunner {
74
- private readonly deps;
75
- private readonly workerEntry;
76
- private readonly killGraceMs;
77
- private readonly handshakeBudgetMs?;
78
- private readonly providerConfig?;
79
- private readonly providerDefinitions;
80
- private readonly env?;
81
- private readonly logsDir?;
82
- constructor(deps: IInProcessSubagentRunnerDeps, options: IChildProcessSubagentRunnerOptions);
83
- start(job: ISubagentJobStart): ISubagentJobHandle;
84
- /**
85
- * The payload the child is started with. The builder lives in
86
- * `child-process-subagent-projection.ts` (CLI-1994 moved it there so the ARCH-044 key-set test
87
- * pins the code that produces it); review of ARCH-033/ARCH-034 is the reason it is a named
88
- * producer at all — both fields were declared on the wire type, read by the worker, and set by
89
- * nothing, because this was the only production site that constructs a payload and no test
90
- * reached it.
91
- */
92
- private createStartPayload;
93
- private resolveTranscriptPath;
94
- }
95
- //#endregion
96
- //#region src/subagent-worker-start-dto.d.ts
97
- /**
98
- * The parent's loaded-context RUNTIME model (`ILoadedContext`, which the framework barrel does not
99
- * export). Named here for the encoder/restore signatures only — the wire DTO below never references it.
100
- */
101
- type TParentContextModel = IInProcessSubagentRunnerDeps['context'];
102
- interface ISubagentWorkerAgentDefinitionDto {
103
- readonly name: string;
104
- readonly description: string;
105
- readonly systemPrompt: string;
106
- readonly model?: string;
107
- readonly effort?: IAgentDefinition['effort'];
108
- readonly role?: string;
109
- readonly maxTurns?: number;
110
- readonly tools?: readonly string[];
111
- readonly disallowedTools?: readonly string[];
112
- }
113
- interface ISubagentWorkerContextFileEntryDto {
114
- readonly filePath: string;
115
- readonly content: string;
116
- readonly contentHash: string;
117
- }
118
- interface ISubagentWorkerParentContextDto {
119
- readonly agentsMd: string;
120
- readonly projectNotesMd: string;
121
- readonly memoryMd?: string;
122
- readonly taskContext?: string;
123
- readonly compactInstructions?: string;
124
- readonly agentsFileEntries?: readonly ISubagentWorkerContextFileEntryDto[];
125
- readonly projectNotesFileEntries?: readonly ISubagentWorkerContextFileEntryDto[];
126
- }
127
- type TDtoDecodeResult<TDto> = {
128
- readonly ok: true;
129
- readonly value: TDto;
130
- } | {
131
- readonly ok: false;
132
- readonly reason: string;
133
- };
134
- declare function encodeAgentDefinition(definition: IAgentDefinition): ISubagentWorkerAgentDefinitionDto;
135
- declare function decodeAgentDefinitionDto(value: unknown): TDtoDecodeResult<ISubagentWorkerAgentDefinitionDto>;
136
- /** Explicit restore in the worker: the DTO's fields are the runtime model's, copied, not aliased. */
137
- declare function restoreAgentDefinition(dto: ISubagentWorkerAgentDefinitionDto): IAgentDefinition;
138
- /** Accepts the issue #2317 projection (or anything wider, structurally); only declared fields cross. */
139
- declare function encodeParentContext(context: ISubagentParentContext): ISubagentWorkerParentContextDto;
140
- declare function decodeParentContextDto(value: unknown): TDtoDecodeResult<ISubagentWorkerParentContextDto>;
141
- declare function restoreParentContext(dto: ISubagentWorkerParentContextDto): TParentContextModel;
142
- //#endregion
143
45
  //#region src/worker-composition.d.ts
144
46
  /**
145
47
  * The session record store a fork job's `resumeSessionId` names a record in, typed FROM the one
@@ -252,6 +154,34 @@ interface ISubagentWorkerComposition {
252
154
  readonly openSessionStore?: (context: {
253
155
  readonly cwd: string;
254
156
  }) => TResumeSessionStore;
157
+ /**
158
+ * A sandbox the child composes itself at its execution root, rather than restoring one from a
159
+ * snapshot: the OS sandbox is a function of the root and its settings, and the settings cross as
160
+ * data (`parentSettings`, the parent's as they stood at spawn) where a live handle cannot.
161
+ *
162
+ * The worker builds it once and hands the SAME instance to `createTools` (as `sandboxClient`) and to
163
+ * the session (as `commandSandbox`), so the approval a confined command gets comes from the instance
164
+ * the command runs under. Absent ⇒ the child's session approves no command on a sandbox's say-so.
165
+ */
166
+ readonly createSandbox?: (context: {
167
+ readonly cwd: string;
168
+ /** The parent's sandbox settings at spawn, when its composition root sent them. */
169
+ readonly parentSettings?: TParentSandboxSettings;
170
+ }) => ISubagentComposedSandbox | undefined;
171
+ }
172
+ /** A composition root's sandbox settings, as plain data that crosses the process boundary. */
173
+ type TParentSandboxSettings = Readonly<Record<string, unknown>>;
174
+ /** A sandbox the child composed itself: the client its tools run under and the approval it gives. */
175
+ interface ISubagentComposedSandbox {
176
+ readonly client: TProjectedSandboxClient;
177
+ readonly commandSandbox?: ISubagentOptions['commandSandbox'];
178
+ /**
179
+ * Take the parent's settings after a change it made while this child runs (`/sandbox`), so the
180
+ * next command is confined and approved as the parent's would be. Throws on settings it cannot
181
+ * read: the worker then aborts the run and ends it with that error, rather than run on settings the
182
+ * user has replaced.
183
+ */
184
+ readonly applyParentSettings?: (settings: TParentSandboxSettings) => void;
255
185
  }
256
186
  /**
257
187
  * Rebuilds a sandbox client of ONE type from a snapshot reference the parent produced.
@@ -284,6 +214,128 @@ interface ISandboxProjection {
284
214
  readonly snapshotId: string;
285
215
  }
286
216
  //#endregion
217
+ //#region src/child-process-subagent-runner.d.ts
218
+ interface IChildProcessSubagentRunnerOptions {
219
+ /**
220
+ * DIST-006: how to start a copy of the running artifact in subagent-worker mode, stated by the
221
+ * composition root. It replaced `workerPath`, which asked this package to locate a file whose
222
+ * location is a property of the packaging step — a question no library can answer, and one that
223
+ * was answered wrongly twice.
224
+ */
225
+ workerEntry: ISubagentWorkerEntry;
226
+ providerConfig?: IProviderDefinitionConfig;
227
+ /**
228
+ * The parent's provider registry. Its defaults complete the connection the child is given, and
229
+ * each definition names the environment its client reads. Required: a job whose provider has no
230
+ * definition here is refused, because its connection cannot be checked.
231
+ */
232
+ providerDefinitions: readonly IProviderDefinition[];
233
+ killGraceMs?: number;
234
+ /**
235
+ * How long a spawned worker may take to signal `ready` before the runner gives up. Injectable so
236
+ * the branch is reachable in a test; without that it is a fix that ships untested.
237
+ */
238
+ handshakeBudgetMs?: number;
239
+ env?: NodeJS.ProcessEnv;
240
+ worktreeIsolation?: boolean;
241
+ worktreeAdapter: ISubagentWorktreeAdapter;
242
+ logsDir?: string;
243
+ /**
244
+ * The parent's sandbox settings as they stand now, read at EACH spawn: a setting the user changed
245
+ * this session (`/sandbox`) lives on the parent's live client, not in the files a child would read.
246
+ * The child's `createSandbox` receives the value. Absent ⇒ the child reads its root's settings.
247
+ */
248
+ parentSandboxSettings?: () => TParentSandboxSettings | undefined;
249
+ /**
250
+ * Be told the parent's sandbox settings after each change (`/sandbox`); returns the way to stop.
251
+ * The runner forwards each change to every running child, so a child started before the change
252
+ * follows it too.
253
+ */
254
+ watchParentSandboxSettings?: (listener: (settings: TParentSandboxSettings) => void) => () => void;
255
+ }
256
+ declare function createChildProcessSubagentRunnerFactory(options: IChildProcessSubagentRunnerOptions): TSubagentRunnerFactory;
257
+ declare class ChildProcessSubagentRunner implements ISubagentRunner {
258
+ private readonly deps;
259
+ private readonly workerEntry;
260
+ private readonly killGraceMs;
261
+ private readonly handshakeBudgetMs?;
262
+ private readonly providerConfig?;
263
+ private readonly providerDefinitions;
264
+ private readonly env?;
265
+ private readonly logsDir?;
266
+ private readonly parentSandboxSettings?;
267
+ private readonly watchParentSandboxSettings?;
268
+ constructor(deps: IInProcessSubagentRunnerDeps, options: IChildProcessSubagentRunnerOptions);
269
+ start(job: ISubagentJobStart): ISubagentJobHandle;
270
+ /**
271
+ * The payload the child is started with. The builder lives in
272
+ * `child-process-subagent-projection.ts` (CLI-1994 moved it there so the ARCH-044 key-set test
273
+ * pins the code that produces it); review of ARCH-033/ARCH-034 is the reason it is a named
274
+ * producer at all — both fields were declared on the wire type, read by the worker, and set by
275
+ * nothing, because this was the only production site that constructs a payload and no test
276
+ * reached it.
277
+ */
278
+ private createStartPayload;
279
+ private forwardSandboxSettingChanges;
280
+ private resolveTranscriptPath;
281
+ /**
282
+ * Issue #3288 §1: how this job's child gets a human's yes/no — the parent session's own approver
283
+ * (`deps.permissionHandler`, the exact function the in-process runner already hands its own child
284
+ * session), bound to a `requester` identity that names this task so a surface can say "Background
285
+ * agent X wants to …" instead of an unattributed prompt. `undefined` when the parent session has no
286
+ * approver at all (print mode / a truly headless run): the result controller then denies every
287
+ * request from the child immediately, the same fail-closed default the enforcer applies with none.
288
+ */
289
+ private permissionApprover;
290
+ }
291
+ //#endregion
292
+ //#region src/subagent-worker-start-dto.d.ts
293
+ /**
294
+ * The parent's loaded-context RUNTIME model (`ILoadedContext`, which the framework barrel does not
295
+ * export). Named here for the encoder/restore signatures only — the wire DTO below never references it.
296
+ */
297
+ type TParentContextModel = IInProcessSubagentRunnerDeps['context'];
298
+ interface ISubagentWorkerAgentDefinitionDto {
299
+ readonly name: string;
300
+ readonly description: string;
301
+ readonly systemPrompt: string;
302
+ readonly model?: string;
303
+ readonly effort?: IAgentDefinition['effort'];
304
+ readonly role?: string;
305
+ readonly maxTurns?: number;
306
+ readonly tools?: readonly string[];
307
+ readonly disallowedTools?: readonly string[];
308
+ }
309
+ interface ISubagentWorkerContextFileEntryDto {
310
+ readonly filePath: string;
311
+ readonly content: string;
312
+ readonly contentHash: string;
313
+ }
314
+ interface ISubagentWorkerParentContextDto {
315
+ readonly agentsMd: string;
316
+ readonly projectNotesMd: string;
317
+ readonly memoryMd?: string;
318
+ readonly taskContext?: string;
319
+ readonly compactInstructions?: string;
320
+ readonly agentsFileEntries?: readonly ISubagentWorkerContextFileEntryDto[];
321
+ readonly projectNotesFileEntries?: readonly ISubagentWorkerContextFileEntryDto[];
322
+ }
323
+ type TDtoDecodeResult<TDto> = {
324
+ readonly ok: true;
325
+ readonly value: TDto;
326
+ } | {
327
+ readonly ok: false;
328
+ readonly reason: string;
329
+ };
330
+ declare function encodeAgentDefinition(definition: IAgentDefinition): ISubagentWorkerAgentDefinitionDto;
331
+ declare function decodeAgentDefinitionDto(value: unknown): TDtoDecodeResult<ISubagentWorkerAgentDefinitionDto>;
332
+ /** Explicit restore in the worker: the DTO's fields are the runtime model's, copied, not aliased. */
333
+ declare function restoreAgentDefinition(dto: ISubagentWorkerAgentDefinitionDto): IAgentDefinition;
334
+ /** Accepts the issue #2317 projection (or anything wider, structurally); only declared fields cross. */
335
+ declare function encodeParentContext(context: ISubagentParentContext): ISubagentWorkerParentContextDto;
336
+ declare function decodeParentContextDto(value: unknown): TDtoDecodeResult<ISubagentWorkerParentContextDto>;
337
+ declare function restoreParentContext(dto: ISubagentWorkerParentContextDto): TParentContextModel;
338
+ //#endregion
287
339
  //#region src/child-process-subagent-ipc.d.ts
288
340
  type TSubagentWorkerWireValue = string | number | boolean | null | undefined | object;
289
341
  /** ARCH-044: the four config members the child reads. See `projectParentConfig`. */
@@ -358,6 +410,12 @@ interface ISubagentWorkerStartPayload {
358
410
  sessionTiers?: {
359
411
  readonly includeGoalTool?: boolean;
360
412
  };
413
+ /**
414
+ * The parent's sandbox settings as they stand at spawn, including a change made this session.
415
+ * Opaque here: the composition root produced it and its `createSandbox` reads it, so the child
416
+ * confines and approves as the parent does now, not as its root's settings files say.
417
+ */
418
+ parentSandboxSettings?: TParentSandboxSettings;
361
419
  permissionMode?: TPermissionMode;
362
420
  logsDir?: string;
363
421
  }
@@ -373,7 +431,28 @@ interface ISubagentWorkerCancelMessage {
373
431
  type: 'cancel';
374
432
  reason?: string;
375
433
  }
376
- type TSubagentWorkerParentMessage = ISubagentWorkerStartMessage | ISubagentWorkerSendMessage | ISubagentWorkerCancelMessage;
434
+ /** The parent's sandbox settings changed while the child runs (`/sandbox`); the child follows. */
435
+ interface ISubagentWorkerSandboxSettingsMessage {
436
+ type: 'sandbox_settings';
437
+ settings: TParentSandboxSettings;
438
+ }
439
+ /**
440
+ * Issue #3288 §1: the three-way answer a permission ask can receive — the same shape
441
+ * `@robota-sdk/agent-session`'s `TPermissionResult` allows, inlined here so this wire module does not
442
+ * need that package as a dependency for one literal union.
443
+ */
444
+ type TSubagentWorkerPermissionResult = boolean | 'allow-session' | 'allow-project';
445
+ /**
446
+ * Issue #3288 §1: the parent's answer to a `permission_request` the child raised, correlated by
447
+ * `requestId`. `false` when the parent has no approver attached (print mode) — the fail-closed
448
+ * default, not a special case the child has to know about.
449
+ */
450
+ interface ISubagentWorkerPermissionResponseMessage {
451
+ type: 'permission_response';
452
+ requestId: string;
453
+ result: TSubagentWorkerPermissionResult;
454
+ }
455
+ type TSubagentWorkerParentMessage = ISubagentWorkerStartMessage | ISubagentWorkerSendMessage | ISubagentWorkerCancelMessage | ISubagentWorkerSandboxSettingsMessage | ISubagentWorkerPermissionResponseMessage;
377
456
  interface ISubagentWorkerReadyMessage {
378
457
  type: 'ready';
379
458
  /**
@@ -400,6 +479,17 @@ interface ISubagentWorkerToolEndMessage {
400
479
  toolName: string;
401
480
  success: boolean;
402
481
  }
482
+ /**
483
+ * Issue #3288 §1: a tool call inside the child needs a human's approval. `requestId` correlates this
484
+ * with the parent's eventual `permission_response`; the child parks the call until it arrives (or
485
+ * until its own turn is cancelled, which the enforcer's existing signal race already denies).
486
+ */
487
+ interface ISubagentWorkerPermissionRequestMessage {
488
+ type: 'permission_request';
489
+ requestId: string;
490
+ toolName: string;
491
+ toolArgs?: TToolArgs;
492
+ }
403
493
  interface ISubagentWorkerResultMessage {
404
494
  type: 'result';
405
495
  output: string;
@@ -414,7 +504,7 @@ interface ISubagentWorkerCancelledMessage {
414
504
  type: 'cancelled';
415
505
  reason?: string;
416
506
  }
417
- type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
507
+ type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerPermissionRequestMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
418
508
  declare function isSubagentWorkerParentMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerParentMessage;
419
509
  declare function isSubagentWorkerChildMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerChildMessage;
420
510
  //#endregion
@@ -432,5 +522,5 @@ declare function isSubagentWorkerChildMessage(value: TSubagentWorkerWireValue):
432
522
  */
433
523
  declare function runSubagentWorkerMain(composition: ISubagentWorkerComposition): void;
434
524
  //#endregion
435
- export { ChildProcessSubagentRunner, type IChildProcessSubagentRunnerOptions, type ISubagentWorkerAgentDefinitionDto, type ISubagentWorkerComposition, type ISubagentWorkerContextFileEntryDto, type ISubagentWorkerEntry, type ISubagentWorkerParentContextDto, type ISubagentWorkerStartPayload, SUBAGENT_WORKER_MODE_FLAG, type TResumeSessionStore, type TSubagentWorkerChildMessage, type TSubagentWorkerParentMessage, type TSubagentWorkerWireValue, createChildProcessSubagentRunnerFactory, decodeAgentDefinitionDto, decodeParentContextDto, encodeAgentDefinition, encodeParentContext, isSubagentWorkerChildMessage, isSubagentWorkerModeArgv, isSubagentWorkerParentMessage, restoreAgentDefinition, restoreParentContext, runSubagentWorkerMain };
525
+ export { ChildProcessSubagentRunner, type IChildProcessSubagentRunnerOptions, type ISubagentComposedSandbox, type ISubagentWorkerAgentDefinitionDto, type ISubagentWorkerComposition, type ISubagentWorkerContextFileEntryDto, type ISubagentWorkerEntry, type ISubagentWorkerParentContextDto, type ISubagentWorkerStartPayload, SUBAGENT_WORKER_MODE_FLAG, type TParentSandboxSettings, type TResumeSessionStore, type TSubagentWorkerChildMessage, type TSubagentWorkerParentMessage, type TSubagentWorkerWireValue, createChildProcessSubagentRunnerFactory, decodeAgentDefinitionDto, decodeParentContextDto, encodeAgentDefinition, encodeParentContext, isSubagentWorkerChildMessage, isSubagentWorkerModeArgv, isSubagentWorkerParentMessage, restoreAgentDefinition, restoreParentContext, runSubagentWorkerMain };
436
526
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/worker-entry.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/worker-composition.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;UCMxB;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;EACb;EACA,iBAAiB;EACjB;;iBAGc,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAU9B;mBATF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAWX,MAAM,KAAK,oBAAoB;;;;;;;;;UAsFvB;UAWA;;;;;;;;KClLL,sBAAsB;UAEV;WACN;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA,6BAA6B;WAC7B,mCAAmC;;KAmClC,iBAAiB;WAChB;WAAmB,OAAO;;WAAoB;WAAoB;;iBAmE/D,sBACd,YAAY,mBACX;iBAOa,yBACd,iBACC,iBAAiB;;iBASJ,uBAAuB,KAAK,oCAAoC;;iBAgBhE,oBACd,SAAS,yBACR;iBAOa,uBACd,iBACC,iBAAiB;iBAIJ,qBAAqB,KAAK,kCAAkC;;;;;;;;;KCrMhE,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,gCAAgC;;;;;;;;;EAShC,YAAY;aACD;;;;;;;;;;;;;;aAcA;;eAEE;;;;;;;;;;aAUF,gBAAgB;MACvB;;;;;;WAOK,8BAA8B;;;;;;;;;;;;;;;;;;;;;WAsB9B,mBAAmB,SAAS,eAAe;;;;;;;;;;;;;;WAe3C,oBAAoB;aAAoB;QAAkB;;;;;;;;KASzD,yBAAyB,uBAAuB,QAAQ;;;;;;;;;;;;;KAcxD;;;;;;;UAQK;WACN;WACA;;;;KCxIC;;UAKK;WACN;aAAqB;;WACrB,aAAa;WACb,mBAAmB;WACnB,QAAQ;;UAGF;EACf;EACA,SAAS;;;;;;;;;;EAUT;aAAsB;aAAuB;;;EAE7C,iBAAiB;;;;;;;;;;;EAWjB,cAAc;;;;;;;EAOd,eAAe;EACf,iBAAiB;;;;;EAKjB,iBAAiB;;;;;;;;;;;;EAYjB,oBAAoB;;;;;;;EAOpB;aAA0B;;EAC1B,iBAAiB;EACjB;;UAGe;EACf;EACA,SAAS;;UAGM;EACf;EACA;;UAGe;EACf;EACA;;KAGU,+BACV,8BAA8B,6BAA6B;UAE5C;EACf;;;;;;;;;EASA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA;;UAGe;EACf;EACA;;EAEA,QAAQ;;UAGO;EACf;EACA;;UAGe;EACf;EACA;;KAGU,8BACR,8BACA,kCACA,kCACA,gCACA,+BACA,8BACA;iBA+GY,8BACd,OAAO,2BACN,SAAS;iBAcI,6BACd,OAAO,2BACN,SAAS;;;;;;;;;;;;;;iBCpCI,sBAAsB,aAAa"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/worker-entry.ts","../../src/worker-composition.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;;;;;;;KC3B7B,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,gCAAgC;;;;;;;;;EAShC,YAAY;aACD;;;;;;;;;;;;;;aAcA;;eAEE;;;;;;;;;;aAUF,gBAAgB;MACvB;;;;;;WAOK,8BAA8B;;;;;;;;;;;;;;;;;;;;;WAsB9B,mBAAmB,SAAS,eAAe;;;;;;;;;;;;;;WAe3C,oBAAoB;aAAoB;QAAkB;;;;;;;;;;WAW1D,iBAAiB;aACf;;aAEA,iBAAiB;QACtB;;;KAII,yBAAyB,SAAS;;UAG7B;WACN,QAAQ;WACR,iBAAiB;;;;;;;WAOjB,uBAAuB,UAAU;;;;;;;;KAShC,yBAAyB,uBAAuB,QAAQ;;;;;;;;;;;;;KAcxD;;;;;;;UAQK;WACN;WACA;;;;UCzHM;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;EACb;EACA,iBAAiB;EACjB;;;;;;EAMA,8BAA8B;;;;;;EAM9B,8BAA8B,WAAW,UAAU;;iBAGrC,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAY9B;mBAXF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAaX,MAAM,KAAK,oBAAoB;;;;;;;;;UAoGvB;UAaA;UAYA;;;;;;;;;UAaA;;;;;;;;KC3PL,sBAAsB;UAEV;WACN;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA,6BAA6B;WAC7B,mCAAmC;;KAmClC,iBAAiB;WAChB;WAAmB,OAAO;;WAAoB;WAAoB;;iBAmE/D,sBACd,YAAY,mBACX;iBAOa,yBACd,iBACC,iBAAiB;;iBASJ,uBAAuB,KAAK,oCAAoC;;iBAgBhE,oBACd,SAAS,yBACR;iBAOa,uBACd,iBACC,iBAAiB;iBAIJ,qBAAqB,KAAK,kCAAkC;;;KClMhE;;UAKK;WACN;aAAqB;;WACrB,aAAa;WACb,mBAAmB;WACnB,QAAQ;;UAGF;EACf;EACA,SAAS;;;;;;;;;;EAUT;aAAsB;aAAuB;;;EAE7C,iBAAiB;;;;;;;;;;;EAWjB,cAAc;;;;;;;EAOd,eAAe;EACf,iBAAiB;;;;;EAKjB,iBAAiB;;;;;;;;;;;;EAYjB,oBAAoB;;;;;;;EAOpB;aAA0B;;;;;;;EAM1B,wBAAwB;EACxB,iBAAiB;EACjB;;UAGe;EACf;EACA,SAAS;;UAGM;EACf;EACA;;UAGe;EACf;EACA;;;UAIe;EACf;EACA,UAAU;;;;;;;KAQA;;;;;;UAOK;EACf;EACA;EACA,QAAQ;;KAGE,+BACR,8BACA,6BACA,+BACA,wCACA;UAEa;EACf;;;;;;;;;EASA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA;;;;;;;UAQe;EACf;EACA;EACA;EACA,WAAW;;UAGI;EACf;EACA;;EAEA,QAAQ;;UAGO;EACf;EACA;;UAGe;EACf;EACA;;KAGU,8BACR,8BACA,kCACA,kCACA,gCACA,0CACA,+BACA,8BACA;iBAkHY,8BACd,OAAO,2BACN,SAAS;iBAuBI,6BACd,OAAO,2BACN,SAAS;;;;;;;;;;;;;;iBCNI,sBAAsB,aAAa"}