@namzu/sdk 32.0.0 → 33.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/dist/authorization/gate.d.ts +1 -1
  3. package/dist/authorization/gate.js +1 -1
  4. package/dist/connector/index.d.ts +1 -1
  5. package/dist/connector/index.d.ts.map +1 -1
  6. package/dist/connector/index.js +1 -1
  7. package/dist/connector/index.js.map +1 -1
  8. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  9. package/dist/connector/mcp/adapter.js +71 -16
  10. package/dist/connector/mcp/adapter.js.map +1 -1
  11. package/dist/connector/mcp/client.d.ts.map +1 -1
  12. package/dist/connector/mcp/client.js +3 -2
  13. package/dist/connector/mcp/client.js.map +1 -1
  14. package/dist/connector/mcp/http-redirect.d.ts +17 -0
  15. package/dist/connector/mcp/http-redirect.d.ts.map +1 -0
  16. package/dist/connector/mcp/http-redirect.js +31 -0
  17. package/dist/connector/mcp/http-redirect.js.map +1 -0
  18. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  19. package/dist/connector/mcp/http-sse.js +5 -0
  20. package/dist/connector/mcp/http-sse.js.map +1 -1
  21. package/dist/connector/mcp/image-admission.d.ts +16 -0
  22. package/dist/connector/mcp/image-admission.d.ts.map +1 -0
  23. package/dist/connector/mcp/image-admission.js +288 -0
  24. package/dist/connector/mcp/image-admission.js.map +1 -0
  25. package/dist/connector/mcp/stdio.d.ts +13 -0
  26. package/dist/connector/mcp/stdio.d.ts.map +1 -1
  27. package/dist/connector/mcp/stdio.js +66 -23
  28. package/dist/connector/mcp/stdio.js.map +1 -1
  29. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  30. package/dist/connector/mcp/streamable-http.js +3 -0
  31. package/dist/connector/mcp/streamable-http.js.map +1 -1
  32. package/dist/constants/tools/index.js +1 -1
  33. package/dist/constants/tools/index.js.map +1 -1
  34. package/dist/execution/base.d.ts +13 -0
  35. package/dist/execution/base.d.ts.map +1 -1
  36. package/dist/execution/base.js +103 -8
  37. package/dist/execution/base.js.map +1 -1
  38. package/dist/execution/errors.d.ts +12 -0
  39. package/dist/execution/errors.d.ts.map +1 -0
  40. package/dist/execution/errors.js +21 -0
  41. package/dist/execution/errors.js.map +1 -0
  42. package/dist/execution/factory.d.ts.map +1 -1
  43. package/dist/execution/factory.js +1 -0
  44. package/dist/execution/factory.js.map +1 -1
  45. package/dist/execution/hybrid.d.ts +5 -0
  46. package/dist/execution/hybrid.d.ts.map +1 -1
  47. package/dist/execution/hybrid.js +36 -16
  48. package/dist/execution/hybrid.js.map +1 -1
  49. package/dist/execution/index.d.ts +1 -0
  50. package/dist/execution/index.d.ts.map +1 -1
  51. package/dist/execution/index.js +1 -0
  52. package/dist/execution/index.js.map +1 -1
  53. package/dist/execution/local.d.ts +13 -0
  54. package/dist/execution/local.d.ts.map +1 -1
  55. package/dist/execution/local.js +145 -19
  56. package/dist/execution/local.js.map +1 -1
  57. package/dist/execution/output.d.ts +27 -0
  58. package/dist/execution/output.d.ts.map +1 -0
  59. package/dist/execution/output.js +105 -0
  60. package/dist/execution/output.js.map +1 -0
  61. package/dist/execution/remote.d.ts +26 -2
  62. package/dist/execution/remote.d.ts.map +1 -1
  63. package/dist/execution/remote.js +86 -15
  64. package/dist/execution/remote.js.map +1 -1
  65. package/dist/plugin/lifecycle.d.ts.map +1 -1
  66. package/dist/plugin/lifecycle.js +9 -3
  67. package/dist/plugin/lifecycle.js.map +1 -1
  68. package/dist/process/kill-tree.d.ts +11 -13
  69. package/dist/process/kill-tree.d.ts.map +1 -1
  70. package/dist/process/kill-tree.js +11 -13
  71. package/dist/process/kill-tree.js.map +1 -1
  72. package/dist/provider/fallback.d.ts.map +1 -1
  73. package/dist/provider/fallback.js +31 -0
  74. package/dist/provider/fallback.js.map +1 -1
  75. package/dist/provider/idle-timeout.d.ts.map +1 -1
  76. package/dist/provider/idle-timeout.js +5 -0
  77. package/dist/provider/idle-timeout.js.map +1 -1
  78. package/dist/provider/retry.d.ts.map +1 -1
  79. package/dist/provider/retry.js +5 -0
  80. package/dist/provider/retry.js.map +1 -1
  81. package/dist/public-runtime.d.ts +2 -2
  82. package/dist/public-runtime.d.ts.map +1 -1
  83. package/dist/public-runtime.js +2 -2
  84. package/dist/public-runtime.js.map +1 -1
  85. package/dist/registry/tool/execute.d.ts +7 -1
  86. package/dist/registry/tool/execute.d.ts.map +1 -1
  87. package/dist/registry/tool/execute.js +201 -54
  88. package/dist/registry/tool/execute.js.map +1 -1
  89. package/dist/run/command-gate.d.ts.map +1 -1
  90. package/dist/run/command-gate.js +11 -0
  91. package/dist/run/command-gate.js.map +1 -1
  92. package/dist/run/workspace-fingerprint.d.ts +4 -4
  93. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  94. package/dist/run/workspace-fingerprint.js +6 -4
  95. package/dist/run/workspace-fingerprint.js.map +1 -1
  96. package/dist/runtime/bidi/index.d.ts +1 -1
  97. package/dist/runtime/bidi/index.d.ts.map +1 -1
  98. package/dist/runtime/bidi/index.js +1 -1
  99. package/dist/runtime/bidi/index.js.map +1 -1
  100. package/dist/runtime/bidi/session.d.ts +19 -0
  101. package/dist/runtime/bidi/session.d.ts.map +1 -1
  102. package/dist/runtime/bidi/session.js +150 -26
  103. package/dist/runtime/bidi/session.js.map +1 -1
  104. package/dist/runtime/query/executor.d.ts +43 -1
  105. package/dist/runtime/query/executor.d.ts.map +1 -1
  106. package/dist/runtime/query/executor.js +626 -161
  107. package/dist/runtime/query/executor.js.map +1 -1
  108. package/dist/runtime/query/index.d.ts.map +1 -1
  109. package/dist/runtime/query/index.js +46 -4
  110. package/dist/runtime/query/index.js.map +1 -1
  111. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  112. package/dist/runtime/query/iteration/phases/tool-review.js +84 -22
  113. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  114. package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
  115. package/dist/runtime/query/request-rich-content.js +33 -13
  116. package/dist/runtime/query/request-rich-content.js.map +1 -1
  117. package/dist/runtime/query/resume-pending.d.ts +5 -1
  118. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  119. package/dist/runtime/query/resume-pending.js +66 -1
  120. package/dist/runtime/query/resume-pending.js.map +1 -1
  121. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  122. package/dist/runtime/query/tool-output-budget.js +45 -16
  123. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  124. package/dist/runtime/query/tooling.d.ts +6 -0
  125. package/dist/runtime/query/tooling.d.ts.map +1 -1
  126. package/dist/runtime/query/tooling.js +4 -0
  127. package/dist/runtime/query/tooling.js.map +1 -1
  128. package/dist/sandbox/provider/local.d.ts.map +1 -1
  129. package/dist/sandbox/provider/local.js +193 -41
  130. package/dist/sandbox/provider/local.js.map +1 -1
  131. package/dist/scheduler/delegating.d.ts +2 -1
  132. package/dist/scheduler/delegating.d.ts.map +1 -1
  133. package/dist/scheduler/delegating.js +6 -5
  134. package/dist/scheduler/delegating.js.map +1 -1
  135. package/dist/scheduler/local.d.ts +2 -1
  136. package/dist/scheduler/local.d.ts.map +1 -1
  137. package/dist/scheduler/local.js +2 -2
  138. package/dist/scheduler/local.js.map +1 -1
  139. package/dist/session/workspace/driver.d.ts +12 -4
  140. package/dist/session/workspace/driver.d.ts.map +1 -1
  141. package/dist/session/workspace/git-worktree.d.ts +17 -3
  142. package/dist/session/workspace/git-worktree.d.ts.map +1 -1
  143. package/dist/session/workspace/git-worktree.js +153 -34
  144. package/dist/session/workspace/git-worktree.js.map +1 -1
  145. package/dist/skills/registry.d.ts +15 -0
  146. package/dist/skills/registry.d.ts.map +1 -1
  147. package/dist/skills/registry.js +33 -0
  148. package/dist/skills/registry.js.map +1 -1
  149. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  150. package/dist/tools/builtins/computer-use.js +39 -2
  151. package/dist/tools/builtins/computer-use.js.map +1 -1
  152. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  153. package/dist/tools/builtins/run-code.js +9 -11
  154. package/dist/tools/builtins/run-code.js.map +1 -1
  155. package/dist/tools/builtins/skill.d.ts +2 -1
  156. package/dist/tools/builtins/skill.d.ts.map +1 -1
  157. package/dist/tools/builtins/skill.js +250 -6
  158. package/dist/tools/builtins/skill.js.map +1 -1
  159. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  160. package/dist/tools/coordinator/agent.js +100 -30
  161. package/dist/tools/coordinator/agent.js.map +1 -1
  162. package/dist/types/agent/manager.d.ts +1 -1
  163. package/dist/types/agent/manager.d.ts.map +1 -1
  164. package/dist/types/agent/scheduler.d.ts +10 -1
  165. package/dist/types/agent/scheduler.d.ts.map +1 -1
  166. package/dist/types/authorization/index.d.ts +12 -12
  167. package/dist/types/bidi/index.d.ts +19 -2
  168. package/dist/types/bidi/index.d.ts.map +1 -1
  169. package/dist/types/computer-use/index.d.ts +18 -0
  170. package/dist/types/computer-use/index.d.ts.map +1 -1
  171. package/dist/types/connector/execution-context.d.ts +3 -1
  172. package/dist/types/connector/execution-context.d.ts.map +1 -1
  173. package/dist/types/execution/index.d.ts +43 -1
  174. package/dist/types/execution/index.d.ts.map +1 -1
  175. package/dist/types/hitl/index.d.ts +11 -0
  176. package/dist/types/hitl/index.d.ts.map +1 -1
  177. package/dist/types/hitl/index.js.map +1 -1
  178. package/dist/types/message/index.d.ts +1 -1
  179. package/dist/types/message/index.d.ts.map +1 -1
  180. package/dist/types/message/index.js +2 -1
  181. package/dist/types/message/index.js.map +1 -1
  182. package/dist/types/plugin/index.d.ts +14 -1
  183. package/dist/types/plugin/index.d.ts.map +1 -1
  184. package/dist/types/plugin/index.js +1 -0
  185. package/dist/types/plugin/index.js.map +1 -1
  186. package/dist/types/provider/interface.d.ts +14 -0
  187. package/dist/types/provider/interface.d.ts.map +1 -1
  188. package/dist/types/sandbox/index.d.ts +15 -10
  189. package/dist/types/sandbox/index.d.ts.map +1 -1
  190. package/dist/types/sandbox/index.js.map +1 -1
  191. package/dist/types/tool/index.d.ts +77 -6
  192. package/dist/types/tool/index.d.ts.map +1 -1
  193. package/dist/types/tool/index.js.map +1 -1
  194. package/dist/types/workspace/ref.d.ts +5 -0
  195. package/dist/types/workspace/ref.d.ts.map +1 -1
  196. package/dist/utils/abort.d.ts +8 -0
  197. package/dist/utils/abort.d.ts.map +1 -1
  198. package/dist/utils/abort.js +16 -0
  199. package/dist/utils/abort.js.map +1 -1
  200. package/package.json +4 -4
  201. package/src/authorization/gate.ts +1 -1
  202. package/src/connector/index.ts +2 -0
  203. package/src/connector/mcp/adapter.ts +82 -21
  204. package/src/connector/mcp/client.ts +2 -1
  205. package/src/connector/mcp/http-redirect.ts +32 -0
  206. package/src/connector/mcp/http-sse.ts +5 -0
  207. package/src/connector/mcp/image-admission.ts +272 -0
  208. package/src/connector/mcp/stdio.ts +63 -21
  209. package/src/connector/mcp/streamable-http.ts +3 -0
  210. package/src/constants/tools/index.ts +1 -1
  211. package/src/execution/base.ts +124 -7
  212. package/src/execution/errors.ts +24 -0
  213. package/src/execution/factory.ts +1 -0
  214. package/src/execution/hybrid.ts +47 -16
  215. package/src/execution/index.ts +1 -0
  216. package/src/execution/local.ts +164 -19
  217. package/src/execution/output.ts +104 -0
  218. package/src/execution/remote.ts +122 -17
  219. package/src/plugin/lifecycle.ts +9 -3
  220. package/src/process/kill-tree.ts +11 -13
  221. package/src/provider/fallback.ts +39 -0
  222. package/src/provider/idle-timeout.ts +8 -0
  223. package/src/provider/retry.ts +8 -0
  224. package/src/public-runtime.ts +7 -1
  225. package/src/registry/tool/execute.ts +230 -64
  226. package/src/run/command-gate.ts +12 -0
  227. package/src/run/workspace-fingerprint.ts +5 -4
  228. package/src/runtime/bidi/index.ts +1 -1
  229. package/src/runtime/bidi/session.ts +177 -28
  230. package/src/runtime/query/executor.ts +769 -163
  231. package/src/runtime/query/index.ts +53 -6
  232. package/src/runtime/query/iteration/phases/tool-review.ts +87 -23
  233. package/src/runtime/query/request-rich-content.ts +39 -14
  234. package/src/runtime/query/resume-pending.ts +83 -1
  235. package/src/runtime/query/tool-output-budget.ts +52 -17
  236. package/src/runtime/query/tooling.ts +10 -0
  237. package/src/sandbox/provider/local.ts +213 -45
  238. package/src/scheduler/delegating.ts +6 -5
  239. package/src/scheduler/local.ts +3 -2
  240. package/src/session/workspace/driver.ts +12 -4
  241. package/src/session/workspace/git-worktree.ts +173 -34
  242. package/src/skills/registry.ts +47 -0
  243. package/src/tools/builtins/computer-use.ts +45 -2
  244. package/src/tools/builtins/run-code.ts +9 -11
  245. package/src/tools/builtins/skill.ts +325 -7
  246. package/src/tools/coordinator/agent.ts +108 -33
  247. package/src/types/agent/manager.ts +1 -1
  248. package/src/types/agent/scheduler.ts +10 -1
  249. package/src/types/bidi/index.ts +19 -2
  250. package/src/types/computer-use/index.ts +19 -0
  251. package/src/types/connector/execution-context.ts +3 -0
  252. package/src/types/execution/index.ts +46 -1
  253. package/src/types/hitl/index.ts +11 -0
  254. package/src/types/message/index.ts +3 -2
  255. package/src/types/plugin/index.ts +15 -0
  256. package/src/types/provider/interface.ts +18 -0
  257. package/src/types/sandbox/index.ts +15 -10
  258. package/src/types/tool/index.ts +85 -6
  259. package/src/types/workspace/ref.ts +5 -0
  260. package/src/utils/abort.ts +18 -0
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ CommandExecutor,
2
3
  CommandOptions,
3
4
  CommandResult,
4
5
  ExecutionCapability,
@@ -9,29 +10,41 @@ import type {
9
10
  } from '../types/connector/index.js'
10
11
  import type { Logger } from '../utils/logger.js'
11
12
  import { BaseExecutionContext } from './base.js'
13
+ import { CommandCancellationUnsupportedError, RemoteExecutionBusyError } from './errors.js'
12
14
 
13
15
  export interface RemoteExecutionContextOptions {
14
16
  id: string
15
17
  target: RemoteTarget
16
18
  capabilities?: ExecutionCapability[]
19
+ /**
20
+ * Executes a command while preserving its argument boundaries at Namzu's
21
+ * remote seam. A downstream executor may still interpret `shell` according
22
+ * to its own target.
23
+ */
24
+ commandExecutor?: CommandExecutor
25
+ /** @deprecated Use `commandExecutor`. */
17
26
  commandHandler?: RemoteCommandHandler
18
27
  log?: Logger
19
28
  }
20
29
 
21
- export class RemoteExecutionContext extends BaseExecutionContext {
30
+ export class RemoteExecutionContext extends BaseExecutionContext implements CommandExecutor {
22
31
  readonly id: string
23
32
  readonly environment: ExecutionEnvironment = 'remote'
24
33
 
25
34
  private target: RemoteTarget
26
35
  private connected = false
27
36
  private capabilities: ExecutionCapability[]
37
+ private commandExecutor: CommandExecutor | undefined
28
38
  private commandHandler: RemoteCommandHandler | undefined
39
+ private lifecycleAdmissionsOpen = true
40
+ private readonly activeCommands = new Set<symbol>()
29
41
 
30
42
  constructor(options: RemoteExecutionContextOptions) {
31
43
  super(options.log)
32
44
  this.id = options.id
33
45
  this.target = options.target
34
46
  this.capabilities = options.capabilities ?? ['network']
47
+ this.commandExecutor = options.commandExecutor
35
48
  this.commandHandler = options.commandHandler
36
49
  }
37
50
 
@@ -43,18 +56,30 @@ export class RemoteExecutionContext extends BaseExecutionContext {
43
56
  })
44
57
  }
45
58
 
59
+ protected override onInitializationStarted(): void {
60
+ this.lifecycleAdmissionsOpen = false
61
+ }
62
+
63
+ protected override onInitializationCommitted(): void {
64
+ this.lifecycleAdmissionsOpen = true
65
+ }
66
+
67
+ protected override onTeardownRequested(): void {
68
+ this.lifecycleAdmissionsOpen = false
69
+ }
70
+
46
71
  protected async doTeardown(): Promise<void> {
47
- if (this.connected) {
48
- this.connected = false
49
- this.emit({
50
- type: 'remote_disconnected',
51
- contextId: this.id,
52
- host: this.target.host,
53
- })
54
- }
72
+ this.assertIdleForDisconnect()
73
+ await this.disconnect()
55
74
  }
56
75
 
57
76
  async connect(): Promise<void> {
77
+ if (!this.lifecycleAdmissionsOpen) {
78
+ throw new Error(
79
+ `Remote execution context "${this.id}" cannot connect until initialization commits after teardown or failed initialization.`,
80
+ )
81
+ }
82
+ if (this.connected) return
58
83
  this.connected = true
59
84
  this.emit({
60
85
  type: 'remote_connected',
@@ -70,6 +95,7 @@ export class RemoteExecutionContext extends BaseExecutionContext {
70
95
 
71
96
  async disconnect(): Promise<void> {
72
97
  if (!this.connected) return
98
+ this.assertIdleForDisconnect()
73
99
  this.connected = false
74
100
  this.emit({
75
101
  type: 'remote_disconnected',
@@ -100,20 +126,49 @@ export class RemoteExecutionContext extends BaseExecutionContext {
100
126
  return this.capabilities.includes(cap)
101
127
  }
102
128
 
129
+ setCommandExecutor(executor: CommandExecutor): void {
130
+ this.commandExecutor = executor
131
+ }
132
+
133
+ /** @deprecated Use `setCommandExecutor()`. */
103
134
  setCommandHandler(handler: RemoteCommandHandler): void {
104
135
  this.commandHandler = handler
105
136
  }
106
137
 
107
- async executeRemote(command: string, options?: CommandOptions): Promise<CommandResult> {
108
- if (!this.commandHandler) {
109
- throw new Error(
110
- `No remote command handler configured for context "${this.id}". Set one via setCommandHandler() before calling executeRemote().`,
138
+ async executeCommand(
139
+ command: string,
140
+ args: string[] = [],
141
+ options?: CommandOptions,
142
+ ): Promise<CommandResult> {
143
+ if (this.commandExecutor) {
144
+ const executor = this.admitCommand(
145
+ this.commandExecutor,
146
+ `No remote command executor configured for context "${this.id}". Set one via setCommandExecutor() before calling executeCommand().`,
111
147
  )
148
+ this.assertCancellationUnsupported(options?.signal)
149
+ return this.trackCommand(() => executor.executeCommand(command, args, options))
112
150
  }
113
- if (!this.connected) {
114
- throw new Error(`Remote context "${this.id}" is not connected. Call connect() first.`)
115
- }
116
- return this.commandHandler.executeRemote(command, options)
151
+
152
+ const handler = this.admitCommand(
153
+ this.commandHandler,
154
+ `No remote command executor configured for context "${this.id}". Set one via setCommandExecutor() before calling executeCommand().`,
155
+ )
156
+ this.assertCancellationUnsupported(options?.signal)
157
+ const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command
158
+ return this.trackCommand(() => handler.executeRemote(fullCommand, options))
159
+ }
160
+
161
+ /**
162
+ * @deprecated Use `executeCommand()` so command arguments retain their
163
+ * boundaries at Namzu's remote execution seam.
164
+ */
165
+ async executeRemote(command: string, options?: CommandOptions): Promise<CommandResult> {
166
+ const handler = this.admitCommand(
167
+ this.commandHandler,
168
+ `No remote command handler configured for context "${this.id}". Set one via setCommandHandler() before calling executeRemote().`,
169
+ )
170
+ this.assertCancellationUnsupported(options?.signal)
171
+ return this.trackCommand(() => handler.executeRemote(command, options))
117
172
  }
118
173
 
119
174
  toConfig(): RemoteExecutionContextConfig {
@@ -133,4 +188,54 @@ export class RemoteExecutionContext extends BaseExecutionContext {
133
188
  throw new Error(`Unsupported remote target type: "${target.type}"`)
134
189
  }
135
190
  }
191
+
192
+ private admitCommand<T>(implementation: T | undefined, missingMessage: string): T {
193
+ if (implementation === undefined) throw new Error(missingMessage)
194
+ if (!this.lifecycleAdmissionsOpen) {
195
+ throw new Error(
196
+ `Remote execution context "${this.id}" is initializing, tearing down, or torn down. Wait for initialization to commit before executing another command.`,
197
+ )
198
+ }
199
+ if (!this.connected) {
200
+ throw new Error(`Remote context "${this.id}" is not connected. Call connect() first.`)
201
+ }
202
+ return implementation
203
+ }
204
+
205
+ private assertCancellationUnsupported(signal: AbortSignal | undefined): void {
206
+ if (signal !== undefined) throw new CommandCancellationUnsupportedError(this.id)
207
+ }
208
+
209
+ private assertIdleForDisconnect(): void {
210
+ if (this.activeCommands.size > 0) {
211
+ throw new RemoteExecutionBusyError(this.id, this.activeCommands.size)
212
+ }
213
+ }
214
+
215
+ private trackCommand(invoke: () => Promise<CommandResult>): Promise<CommandResult> {
216
+ const ownership = Symbol('remote-command')
217
+ this.activeCommands.add(ownership)
218
+ const release = (): void => {
219
+ this.activeCommands.delete(ownership)
220
+ }
221
+
222
+ let operation: Promise<CommandResult>
223
+ try {
224
+ operation = Promise.resolve(invoke())
225
+ } catch (error) {
226
+ release()
227
+ return Promise.reject(error)
228
+ }
229
+
230
+ return operation.then(
231
+ (result) => {
232
+ release()
233
+ return result
234
+ },
235
+ (error: unknown) => {
236
+ release()
237
+ throw error
238
+ },
239
+ )
240
+ }
136
241
  }
@@ -711,6 +711,12 @@ export class PluginLifecycleManager {
711
711
  }
712
712
 
713
713
  const results: PluginHookResult[] = []
714
+ // Interrupt hooks are cleanup/notification observers. One extension's
715
+ // skip, error, retry, or timeout must not suppress the extensions that
716
+ // follow it, and none of those results can change the cancellation that
717
+ // already happened. Other hook events retain their existing flow-control
718
+ // semantics.
719
+ const observationalFanOut = event === 'run_interrupt'
714
720
 
715
721
  // Determine execution order: post_* hooks run backward (for cleanup semantics)
716
722
  const isPost = event.startsWith('post_')
@@ -830,16 +836,16 @@ export class PluginLifecycleManager {
830
836
 
831
837
  results.push(result)
832
838
 
833
- if (result.action === 'modify') {
839
+ if (!observationalFanOut && result.action === 'modify') {
834
840
  toolInputOverlay = result.input
835
841
  }
836
842
 
837
843
  // Handle flow control: check priority order: error > skip > retry > resume > modify > continue
838
844
  // Short-circuit on error or skip; return immediately on resume or retry
839
- if (result.action === 'error' || result.action === 'skip') {
845
+ if (!observationalFanOut && (result.action === 'error' || result.action === 'skip')) {
840
846
  break
841
847
  }
842
- if (result.action === 'retry') {
848
+ if (!observationalFanOut && result.action === 'retry') {
843
849
  break
844
850
  }
845
851
  }
@@ -10,23 +10,21 @@ import type { spawn } from 'node:child_process'
10
10
  * paid for by a bug where a cancelled command kept running, and a
11
11
  * near-copy would reproduce the bug in the copy.
12
12
  *
13
- * Every caller reaches a real command through `/bin/sh -c "cmd"`, and under
14
- * the local sandbox's `linux-namespace`/`macos-seatbelt` tiers that shell is
15
- * wrapped again (`unshare …`/`sandbox-exec -- /bin/sh -c "cmd"`). Either
16
- * way, `child.pid` names the OUTERMOST wrapper Node spawned, not `cmd` —
17
- * signalling only that pid, which is both what `child.kill()` does and what
18
- * `spawn`'s own `signal` option does internally on abort, reaps the wrapper
19
- * and leaves `cmd`, and anything it forked, running past both a cancel and a
20
- * timeout.
13
+ * Some callers reach a command through a shell or isolation wrapper; the
14
+ * local execution context can also spawn the authored executable directly.
15
+ * In every case, signalling only `child.pid` which is both what
16
+ * `child.kill()` does and what `spawn`'s own `signal`/`timeout` options do
17
+ * can reap that direct child while leaving a descendant running past both a
18
+ * cancel and a timeout.
21
19
  *
22
20
  * POSIX: the caller must spawn with `detached: true`, which makes the child
23
21
  * the leader of a new process group (pgid === pid) instead of joining this
24
22
  * Node process's own. A negative pid signals that whole group in one call.
25
- * Group membership is a host-kernel fact that a fork()'d descendant inherits
26
- * from its parent whether or not it or an ancestor such as `unshare --pid`
27
- * subsequently entered a new PID namespace, so this reaches `cmd` and its
28
- * descendants along with the wrapper itself even under the namespaced
29
- * isolation tiers.
23
+ * Group membership is a host-kernel fact that an ordinary forked descendant
24
+ * inherits from its parent, including under the namespaced isolation tiers.
25
+ * A process which deliberately starts a new session/process group can escape
26
+ * this boundary; this helper is process-group signalling, not a portable
27
+ * arbitrary-descendant ownership primitive.
30
28
  *
31
29
  * Windows has no process-group id to sign a kill with — `process.kill` with
32
30
  * a negative pid there either throws or silently does nothing, depending on
@@ -230,6 +230,40 @@ function memberReasoningEffortLevels(
230
230
  return member.provider.effortLevelsFor?.(model, thinking)
231
231
  }
232
232
 
233
+ /** Read one member's model-owned default using its routed model id. */
234
+ function memberReasoningEffortDefault(
235
+ member: ProviderChainMember,
236
+ requestModel: string,
237
+ thinking?: ThinkingConfig,
238
+ ): ReasoningEffort | undefined {
239
+ return member.provider.reasoningEffortDefaultFor?.(member.model ?? requestModel, thinking)
240
+ }
241
+
242
+ /**
243
+ * A fallback request has one unambiguous default only when every route agrees.
244
+ *
245
+ * Omitting effort lets whichever member serves the request choose its own
246
+ * default. Publishing the head's answer as the chain's answer can therefore
247
+ * make the same shortcut move in opposite directions after fallback. The
248
+ * agreed value must also survive the chain-wide exact menu.
249
+ */
250
+ function commonReasoningEffortDefault(
251
+ members: readonly ProviderChainMember[],
252
+ requestModel: string,
253
+ thinking?: ThinkingConfig,
254
+ ): ReasoningEffort | undefined {
255
+ const common = commonReasoningEffortLevels(members, requestModel, thinking)
256
+ if (common === undefined) return undefined
257
+ let agreed: ReasoningEffort | undefined
258
+ for (const member of members) {
259
+ const value = memberReasoningEffortDefault(member, requestModel, thinking)
260
+ if (value === undefined) return undefined
261
+ if (agreed !== undefined && value !== agreed) return undefined
262
+ agreed = value
263
+ }
264
+ return agreed !== undefined && common.includes(agreed) ? agreed : undefined
265
+ }
266
+
233
267
  /**
234
268
  * The levels one request may carry safely through every member it can reach.
235
269
  *
@@ -463,6 +497,11 @@ export function withProviderFallback(
463
497
  // answer when any member cannot enumerate its selected model.
464
498
  reasoningEffortLevelsFor: (model: string, thinking?: ThinkingConfig) =>
465
499
  commonReasoningEffortLevels(members, model, thinking),
500
+ // Present on the chain wrapper for the same reason the menu method is:
501
+ // `undefined` is the honest answer when a member cannot answer, defaults
502
+ // disagree, or the value is absent from the common exact menu.
503
+ reasoningEffortDefaultFor: (model: string, thinking?: ThinkingConfig) =>
504
+ commonReasoningEffortDefault(members, model, thinking),
466
505
  // Compatibility projection only. Existing consumers of the deprecated
467
506
  // member keep the head-only answer they had; new consumers use the
468
507
  // canonical chain-aware member above.
@@ -220,6 +220,14 @@ export function withStreamIdleTimeout(
220
220
  ) => provider.reasoningEffortLevelsFor?.(model, thinking),
221
221
  }
222
222
  : {}),
223
+ ...(provider.reasoningEffortDefaultFor
224
+ ? {
225
+ reasoningEffortDefaultFor: (
226
+ model: string,
227
+ thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
228
+ ) => provider.reasoningEffortDefaultFor?.(model, thinking),
229
+ }
230
+ : {}),
223
231
  ...(provider.effortLevelsFor
224
232
  ? {
225
233
  effortLevelsFor: (
@@ -275,6 +275,14 @@ export function withProviderRetry(
275
275
  ) => provider.reasoningEffortLevelsFor?.(model, thinking),
276
276
  }
277
277
  : {}),
278
+ ...(provider.reasoningEffortDefaultFor
279
+ ? {
280
+ reasoningEffortDefaultFor: (
281
+ model: string,
282
+ thinking?: Parameters<NonNullable<LLMProvider['reasoningEffortDefaultFor']>>[1],
283
+ ) => provider.reasoningEffortDefaultFor?.(model, thinking),
284
+ }
285
+ : {}),
278
286
  // Forwarded for the same reason `healthCheck` is, and both were
279
287
  // missing until something consumed them. A member this wrapper drops
280
288
  // does not fail — it reads as "this driver cannot answer", which is a
@@ -293,7 +293,11 @@ export {
293
293
  formatSteeringNote,
294
294
  } from './runtime/query/steering.js'
295
295
  export type { SteeringChannel } from './runtime/query/steering.js'
296
- export { createMockBidiProvider, startBidiRun } from './runtime/bidi/index.js'
296
+ export {
297
+ BidiSessionCloseTimeoutError,
298
+ createMockBidiProvider,
299
+ startBidiRun,
300
+ } from './runtime/bidi/index.js'
297
301
  export { PromptCache } from './runtime/query/prompt-cache.js'
298
302
  export {
299
303
  CheckpointManager,
@@ -672,6 +676,7 @@ export {
672
676
  export {
673
677
  BaseConnector,
674
678
  BaseExecutionContext,
679
+ CommandCancellationUnsupportedError,
675
680
  ConnectorManager,
676
681
  ConnectorRegistry,
677
682
  EnvironmentConnectorManager,
@@ -695,6 +700,7 @@ export {
695
700
  mcpToolResultToToolResult,
696
701
  mcpToolToToolDefinition,
697
702
  RemoteExecutionContext,
703
+ RemoteExecutionBusyError,
698
704
  ScopedConnectorRegistry,
699
705
  // The only transport in the tree that can RUN an `MCPServer`. It reached
700
706
  // `connector/mcp/index.ts` and stopped there, so the server was public