@qoder-ai/qoder-agent-sdk 1.0.4 → 1.0.6

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
@@ -21,27 +21,75 @@ Prerequisites:
21
21
  `zod` is a peer dependency used when you define MCP tool schemas. Keep it
22
22
  installed if your application uses SDK tools or MCP integration.
23
23
 
24
- ## CLI Behavior
24
+ ## Runtime Behavior
25
25
 
26
- The npm package does not publish a `qodercli` binary inside the tarball. During
26
+ The standard npm package keeps the existing process runtime behavior:
27
+ `query()` launches `qodercli` as a child process by default. During
27
28
  `npm install`, the postinstall script downloads the platform-specific CLI into
28
29
  `dist/_bundled`.
29
30
 
30
- If your environment blocks install scripts or network downloads, skip the
31
- bundled CLI download:
31
+ Packages built with the Worker runtime bundle bake that choice into the SDK:
32
+ their default `query()` transport is `WorkerTransport.default`, and install
33
+ does not download the process CLI unless `QODER_INSTALL_BUNDLED_CLI=1` is set.
34
+ Worker runtime assets can either be packaged into the tarball or downloaded by
35
+ postinstall, depending on the release pipeline.
36
+
37
+ You can still select a transport explicitly on the same `query()` entry:
38
+
39
+ ```ts
40
+ import {
41
+ qodercliAuth,
42
+ query,
43
+ WorkerTransport,
44
+ } from "@qoder-ai/qoder-agent-sdk";
45
+
46
+ const q = query({
47
+ prompt: "Summarize this repository.",
48
+ options: {
49
+ auth: qodercliAuth(),
50
+ transport: WorkerTransport.default,
51
+ },
52
+ });
53
+ ```
54
+
55
+ When the package includes `dist/_worker/qoder-worker-runtime.obf.mjs`, the
56
+ worker transport uses that embedded runtime; otherwise set
57
+ `QODER_WORKER_RUNTIME_PATH` or pass
58
+ `new WorkerTransport({ pathToQoderWorkerRuntime })`.
59
+
60
+ Worker-bundled packages include a `dist/runtime-manifest.json` that records the
61
+ default runtime and whether the Worker runtime is packaged or installed by
62
+ postinstall. Install-delivered packages can also pin the qodercli Worker runtime
63
+ archive URL in that manifest; the SDK package itself does not need to host a
64
+ copy of the archive. The presence of `dist/_worker` is used as an integrity
65
+ check after installation, not as the mode selector.
66
+
67
+ The packaged Worker runtime is built as a self-contained universal profile by
68
+ default. Runtime assets such as native keychain bindings, PTY bindings, image
69
+ processing bindings, devtools support, and ripgrep binaries are carried by the
70
+ SDK package instead of by the host product.
71
+
72
+ If your environment blocks install scripts or network downloads, skip postinstall
73
+ runtime downloads:
32
74
 
33
75
  ```bash
34
76
  QODER_SKIP_DOWNLOAD=1 npm install @qoder-ai/qoder-agent-sdk zod
35
77
  ```
36
78
 
37
- Then point the SDK at an existing `qodercli`:
79
+ `QODER_SKIP_DOWNLOAD` only affects install-time downloads. It does not change the
80
+ package's default runtime. Then point the process transport at an existing
81
+ `qodercli`, or point the worker transport at an existing runtime:
38
82
 
39
83
  ```bash
40
84
  export QODERCLI_PATH=/absolute/path/to/qodercli
85
+ # or
86
+ export QODER_WORKER_RUNTIME_PATH=/absolute/path/to/qoder-worker-runtime.obf.mjs
41
87
  ```
42
88
 
43
- You can also set the CLI path for a single query with
44
- `options.pathToQoderCLIExecutable`.
89
+ `query()` is the only query entry point. Standard packages default to process;
90
+ Worker-bundled packages default to Worker. Pass `transport: ProcessTransport.default`,
91
+ `transport: WorkerTransport.default`, or a custom transport provider when a
92
+ single call needs to override the package default.
45
93
 
46
94
  ## Authentication
47
95
 
@@ -50,10 +98,10 @@ Every SDK query needs an explicit authentication option.
50
98
  To reuse the local `qodercli` login state:
51
99
 
52
100
  ```ts
53
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
101
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
54
102
 
55
103
  const q = query({
56
- prompt: 'Summarize this repository.',
104
+ prompt: "Summarize this repository.",
57
105
  options: {
58
106
  auth: qodercliAuth(),
59
107
  cwd: process.cwd(),
@@ -81,10 +129,10 @@ export QODER_PERSONAL_ACCESS_TOKEN=your-token
81
129
  ```
82
130
 
83
131
  ```ts
84
- import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
132
+ import { accessTokenFromEnv, query } from "@qoder-ai/qoder-agent-sdk";
85
133
 
86
134
  const q = query({
87
- prompt: 'Summarize this repository.',
135
+ prompt: "Summarize this repository.",
88
136
  options: {
89
137
  auth: accessTokenFromEnv(),
90
138
  cwd: process.cwd(),
@@ -99,10 +147,10 @@ const q = query({
99
147
  Create `demo.mjs`:
100
148
 
101
149
  ```js
102
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
150
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
103
151
 
104
152
  const q = query({
105
- prompt: process.argv.slice(2).join(' ') || 'Explain what this project does.',
153
+ prompt: process.argv.slice(2).join(" ") || "Explain what this project does.",
106
154
  options: {
107
155
  auth: qodercliAuth(),
108
156
  cwd: process.cwd(),
@@ -130,25 +178,25 @@ node demo.mjs "List the important files in this repository."
130
178
  messages.
131
179
 
132
180
  ```js
133
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
181
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
134
182
 
135
183
  const q = query({
136
- prompt: 'Explain this repository.',
184
+ prompt: "Explain this repository.",
137
185
  options: {
138
186
  auth: qodercliAuth(),
139
187
  cwd: process.cwd(),
140
- systemPrompt: 'You are a helpful assistant.',
188
+ systemPrompt: "You are a helpful assistant.",
141
189
  maxTurns: 1,
142
190
  },
143
191
  });
144
192
 
145
193
  for await (const message of q) {
146
- if (message.type !== 'assistant') {
194
+ if (message.type !== "assistant") {
147
195
  continue;
148
196
  }
149
197
 
150
198
  for (const block of message.message.content) {
151
- if (block.type === 'text') {
199
+ if (block.type === "text") {
152
200
  console.log(block.text);
153
201
  }
154
202
  }
@@ -164,16 +212,16 @@ auto-approved, while unlisted tools continue through `permissionMode` and
164
212
  available toolset. To block tools, use `disallowedTools`.
165
213
 
166
214
  ```ts
167
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
215
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
168
216
 
169
217
  const q = query({
170
- prompt: 'Update the README introduction.',
218
+ prompt: "Update the README introduction.",
171
219
  options: {
172
220
  auth: qodercliAuth(),
173
221
  cwd: process.cwd(),
174
- allowedTools: ['Read', 'Edit'],
175
- disallowedTools: ['Bash'],
176
- permissionMode: 'acceptEdits',
222
+ allowedTools: ["Read", "Edit"],
223
+ disallowedTools: ["Bash"],
224
+ permissionMode: "acceptEdits",
177
225
  },
178
226
  });
179
227
  ```
@@ -181,22 +229,22 @@ const q = query({
181
229
  For application-specific approval flows, provide `canUseTool`:
182
230
 
183
231
  ```ts
184
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
232
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
185
233
 
186
234
  const q = query({
187
- prompt: 'Inspect the source code, but do not run shell commands.',
235
+ prompt: "Inspect the source code, but do not run shell commands.",
188
236
  options: {
189
237
  auth: qodercliAuth(),
190
238
  cwd: process.cwd(),
191
239
  canUseTool: async (toolName) => {
192
- if (toolName === 'Bash') {
240
+ if (toolName === "Bash") {
193
241
  return {
194
- behavior: 'deny',
195
- message: 'Shell commands are disabled here.',
242
+ behavior: "deny",
243
+ message: "Shell commands are disabled here.",
196
244
  };
197
245
  }
198
246
 
199
- return { behavior: 'allow' };
247
+ return { behavior: "allow" };
200
248
  },
201
249
  },
202
250
  });
@@ -207,13 +255,13 @@ const q = query({
207
255
  Use `cwd` to run the agent in a specific project directory:
208
256
 
209
257
  ```ts
210
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
258
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
211
259
 
212
260
  const q = query({
213
- prompt: 'Analyze this project.',
261
+ prompt: "Analyze this project.",
214
262
  options: {
215
263
  auth: qodercliAuth(),
216
- cwd: '/path/to/project',
264
+ cwd: "/path/to/project",
217
265
  },
218
266
  });
219
267
  ```
@@ -224,19 +272,19 @@ Use an async iterable prompt when you need a long-lived, bidirectional session
224
272
  instead of a single string prompt.
225
273
 
226
274
  ```ts
227
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
275
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
228
276
 
229
277
  function userMessage(text: string) {
230
278
  return {
231
- type: 'user',
232
- message: { role: 'user', content: [{ type: 'text', text }] },
279
+ type: "user",
280
+ message: { role: "user", content: [{ type: "text", text }] },
233
281
  parent_tool_use_id: null,
234
282
  };
235
283
  }
236
284
 
237
285
  async function* conversation() {
238
- yield userMessage('Inspect this project and summarize the main modules.');
239
- yield userMessage('Now list the files that are most likely to need tests.');
286
+ yield userMessage("Inspect this project and summarize the main modules.");
287
+ yield userMessage("Now list the files that are most likely to need review.");
240
288
  }
241
289
 
242
290
  const q = query({
@@ -265,33 +313,33 @@ SDK MCP servers. This avoids managing a separate MCP subprocess for simple
265
313
  application-local tools.
266
314
 
267
315
  ```ts
268
- import { createSdkMcpServer, qodercliAuth, query, tool } from '@qoder-ai/qoder-agent-sdk';
269
- import { z } from 'zod';
316
+ import {
317
+ createSdkMcpServer,
318
+ qodercliAuth,
319
+ query,
320
+ tool,
321
+ } from "@qoder-ai/qoder-agent-sdk";
322
+ import { z } from "zod";
270
323
 
271
324
  const server = createSdkMcpServer({
272
- name: 'my-tools',
273
- version: '1.0.0',
325
+ name: "my-tools",
326
+ version: "1.0.0",
274
327
  tools: [
275
- tool(
276
- 'greet',
277
- 'Greet a user.',
278
- { name: z.string() },
279
- async ({ name }) => ({
280
- content: [{ type: 'text', text: `Hello, ${name}!` }],
281
- }),
282
- ),
328
+ tool("greet", "Greet a user.", { name: z.string() }, async ({ name }) => ({
329
+ content: [{ type: "text", text: `Hello, ${name}!` }],
330
+ })),
283
331
  ],
284
332
  });
285
333
 
286
334
  const q = query({
287
- prompt: 'Greet Alice.',
335
+ prompt: "Greet Alice.",
288
336
  options: {
289
337
  auth: qodercliAuth(),
290
338
  cwd: process.cwd(),
291
339
  mcpServers: {
292
340
  tools: server,
293
341
  },
294
- allowedTools: ['mcp__tools__greet'],
342
+ allowedTools: ["mcp__tools__greet"],
295
343
  },
296
344
  });
297
345
  ```
@@ -303,26 +351,26 @@ They are useful for validation, policy checks, logging, and
303
351
  application-specific feedback.
304
352
 
305
353
  ```ts
306
- import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
307
- import type { HookCallback } from '@qoder-ai/qoder-agent-sdk';
354
+ import { qodercliAuth, query } from "@qoder-ai/qoder-agent-sdk";
355
+ import type { HookCallback } from "@qoder-ai/qoder-agent-sdk";
308
356
 
309
357
  const blockDeployScript: HookCallback = async (input) => {
310
- if (input.hook_event_name !== 'PreToolUse') {
358
+ if (input.hook_event_name !== "PreToolUse") {
311
359
  return {};
312
360
  }
313
361
 
314
- if (input.tool_name !== 'Bash') {
362
+ if (input.tool_name !== "Bash") {
315
363
  return {};
316
364
  }
317
365
 
318
366
  const toolInput = input.tool_input as { command?: unknown } | undefined;
319
- const command = String(toolInput?.command ?? '');
320
- if (command.includes('./deploy.sh')) {
367
+ const command = String(toolInput?.command ?? "");
368
+ if (command.includes("./deploy.sh")) {
321
369
  return {
322
370
  hookSpecificOutput: {
323
- hookEventName: 'PreToolUse',
324
- permissionDecision: 'deny',
325
- permissionDecisionReason: 'Deployment scripts require review.',
371
+ hookEventName: "PreToolUse",
372
+ permissionDecision: "deny",
373
+ permissionDecisionReason: "Deployment scripts require review.",
326
374
  },
327
375
  };
328
376
  }
@@ -331,14 +379,12 @@ const blockDeployScript: HookCallback = async (input) => {
331
379
  };
332
380
 
333
381
  const q = query({
334
- prompt: 'Review this project without deploying it.',
382
+ prompt: "Review this project without deploying it.",
335
383
  options: {
336
384
  auth: qodercliAuth(),
337
385
  cwd: process.cwd(),
338
386
  hooks: {
339
- PreToolUse: [
340
- { matcher: 'Bash', hooks: [blockDeployScript] },
341
- ],
387
+ PreToolUse: [{ matcher: "Bash", hooks: [blockDeployScript] }],
342
388
  },
343
389
  },
344
390
  });
@@ -353,12 +399,12 @@ import {
353
399
  ProtocolVersionMismatchError,
354
400
  qodercliAuth,
355
401
  query,
356
- } from '@qoder-ai/qoder-agent-sdk';
402
+ } from "@qoder-ai/qoder-agent-sdk";
357
403
 
358
404
  function errorCode(error: unknown): string | undefined {
359
- if (typeof error === 'object' && error !== null && 'code' in error) {
405
+ if (typeof error === "object" && error !== null && "code" in error) {
360
406
  const code = (error as { code?: unknown }).code;
361
- return typeof code === 'string' ? code : undefined;
407
+ return typeof code === "string" ? code : undefined;
362
408
  }
363
409
 
364
410
  return undefined;
@@ -366,7 +412,7 @@ function errorCode(error: unknown): string | undefined {
366
412
 
367
413
  try {
368
414
  const q = query({
369
- prompt: 'Hello Qoder',
415
+ prompt: "Hello Qoder",
370
416
  options: {
371
417
  auth: qodercliAuth(),
372
418
  cwd: process.cwd(),
@@ -377,14 +423,14 @@ try {
377
423
  console.log(message);
378
424
  }
379
425
  } catch (error) {
380
- if (errorCode(error) === 'auth_not_configured') {
381
- console.error('Configure options.auth before calling query().');
426
+ if (errorCode(error) === "auth_not_configured") {
427
+ console.error("Configure options.auth before calling query().");
382
428
  } else if (error instanceof ProtocolVersionMismatchError) {
383
- console.error('Upgrade qodercli or @qoder-ai/qoder-agent-sdk.');
429
+ console.error("Upgrade qodercli or @qoder-ai/qoder-agent-sdk.");
384
430
  } else if (error instanceof ModelPolicyTimeoutError) {
385
- console.error('Model policy resolution timed out.');
431
+ console.error("Model policy resolution timed out.");
386
432
  } else if (error instanceof AbortError) {
387
- console.error('The query was aborted.');
433
+ console.error("The query was aborted.");
388
434
  } else {
389
435
  console.error(error);
390
436
  }
@@ -1,9 +1,9 @@
1
- import{McpServer as G}from"@modelcontextprotocol/sdk/server/mcp.js";function Z(s){if(!s.name||typeof s.name!="string"||s.name.trim()==="")throw new Error("[createSdkMcpServer] Server name must be a non-empty string.");let e=new G({name:s.name,version:s.version??"1.0.0"},{capabilities:{tools:s.tools&&s.tools.length>0?{}:void 0}});if(s.tools&&s.tools.length>0)for(let t of s.tools){if(!t.name||typeof t.name!="string"||t.name.trim()==="")throw new Error(`[createSdkMcpServer] Tool name must be a non-empty string in server "${s.name}".`);if(!t.description||typeof t.description!="string")throw new Error(`[createSdkMcpServer] Tool "${t.name}" must have a non-empty description string.`);try{e.registerTool(t.name,{description:t.description,inputSchema:t.inputSchema,...t.annotations?{annotations:t.annotations}:{}},t.handler)}catch(o){throw o instanceof Error&&o.message.includes("already registered")?new Error(`[createSdkMcpServer] Duplicate tool name "${t.name}" in server "${s.name}". Each tool name must be unique within a server.`):o}}return{type:"sdk",name:s.name,instance:e}}function X(s,e,t,o,r){return{name:s,description:e,inputSchema:t,handler:o,annotations:r?.annotations}}var v=class{queue=[];readResolve;readReject;isDone=!1;errorValue;started=!1;returnCallback;constructor(e){this.returnCallback=e}[Symbol.asyncIterator](){if(this.started)throw new Error("Stream can only be iterated once");return this.started=!0,this}async next(){if(this.queue.length>0)return{done:!1,value:this.queue.shift()};if(this.isDone)return{done:!0,value:void 0};if(this.errorValue!==void 0)throw this.errorValue;return new Promise((e,t)=>{this.readResolve=e,this.readReject=t})}enqueue(e){if(!this.isDone)if(this.readResolve){let t=this.readResolve;this.readResolve=void 0,this.readReject=void 0,t({done:!1,value:e})}else this.queue.push(e)}done(){if(this.isDone=!0,this.readResolve){let e=this.readResolve;this.readResolve=void 0,this.readReject=void 0,e({done:!0,value:void 0})}}error(e){if(this.errorValue=e,this.readReject){let t=this.readReject;this.readResolve=void 0,this.readReject=void 0,t(e)}}async return(){return this.isDone=!0,this.returnCallback?.(),{done:!0,value:void 0}}async throw(e){return this.error(e),{done:!0,value:void 0}}};var Y=3e4,ee=3e4,M=class{options;ws=null;ready=!1;readyResolve;readyReject;readyPromise;messages=new v;keepAliveTimer;exitError;constructor(e){this.options=e,this.readyPromise=new Promise((t,o)=>{this.readyResolve=t,this.readyReject=o}),this.initialize()}initialize(){let e=new globalThis.WebSocket(this.options.url);this.ws=e;let t=setTimeout(()=>{if(!this.ready){let o=new Error("WebSocket connection timeout");this.readyReject?.(o),e.close()}},ee);e.onopen=()=>{clearTimeout(t),this.ready=!0,this.readyResolve?.(),this.options.authMessage&&e.send(JSON.stringify(this.options.authMessage)+`
1
+ import{McpServer as G}from"@modelcontextprotocol/sdk/server/mcp.js";function Z(s){if(!s.name||typeof s.name!="string"||s.name.trim()==="")throw new Error("[createSdkMcpServer] Server name must be a non-empty string.");let e=new G({name:s.name,version:s.version??"1.0.0"},{capabilities:{tools:s.tools&&s.tools.length>0?{}:void 0}});if(s.tools&&s.tools.length>0)for(let t of s.tools){if(!t.name||typeof t.name!="string"||t.name.trim()==="")throw new Error(`[createSdkMcpServer] Tool name must be a non-empty string in server "${s.name}".`);if(!t.description||typeof t.description!="string")throw new Error(`[createSdkMcpServer] Tool "${t.name}" must have a non-empty description string.`);try{e.registerTool(t.name,{description:t.description,inputSchema:t.inputSchema,...t.annotations?{annotations:t.annotations}:{}},t.handler)}catch(o){throw o instanceof Error&&o.message.includes("already registered")?new Error(`[createSdkMcpServer] Duplicate tool name "${t.name}" in server "${s.name}". Each tool name must be unique within a server.`):o}}return{type:"sdk",name:s.name,instance:e}}function X(s,e,t,o,r){return{name:s,description:e,inputSchema:t,handler:o,annotations:r?.annotations}}var v=class{queue=[];readResolve;readReject;isDone=!1;errorValue;started=!1;returnCallback;constructor(e){this.returnCallback=e}[Symbol.asyncIterator](){if(this.started)throw new Error("Stream can only be iterated once");return this.started=!0,this}async next(){if(this.queue.length>0)return{done:!1,value:this.queue.shift()};if(this.isDone)return{done:!0,value:void 0};if(this.errorValue!==void 0)throw this.errorValue;return new Promise((e,t)=>{this.readResolve=e,this.readReject=t})}enqueue(e){if(!this.isDone)if(this.readResolve){let t=this.readResolve;this.readResolve=void 0,this.readReject=void 0,t({done:!1,value:e})}else this.queue.push(e)}done(){if(this.isDone=!0,this.readResolve){let e=this.readResolve;this.readResolve=void 0,this.readReject=void 0,e({done:!0,value:void 0})}}error(e){if(this.errorValue=e,this.readReject){let t=this.readReject;this.readResolve=void 0,this.readReject=void 0,t(e)}}async return(){return this.isDone=!0,this.returnCallback?.(),{done:!0,value:void 0}}async throw(e){return this.error(e),{done:!0,value:void 0}}};var Y=3e4,ee=3e4,M=class{options;ws=null;ready=!1;readyResolve;readyReject;readyPromise;messages=new v;keepAliveTimer;exitError;initialized=!1;constructor(e){this.options=e,this.readyPromise=new Promise((t,o)=>{this.readyResolve=t,this.readyReject=o}),this.initialize()}initialize(){return this.initialized||(this.initialized=!0,this.open()),this.readyPromise}open(){let e=new globalThis.WebSocket(this.options.url);this.ws=e;let t=setTimeout(()=>{if(!this.ready){let o=new Error("WebSocket connection timeout");this.readyReject?.(o),e.close()}},ee);e.onopen=()=>{clearTimeout(t),this.ready=!0,this.readyResolve?.(),this.options.authMessage&&e.send(JSON.stringify(this.options.authMessage)+`
2
2
  `),this.keepAliveTimer=setInterval(()=>{e.readyState===WebSocket.OPEN&&e.send(JSON.stringify({type:"keep_alive"})+`
3
3
  `)},Y)},e.onmessage=o=>{let r=String(o.data).split(`
4
- `);for(let n of r)if(n.trim())try{let i=JSON.parse(n);this.messages.enqueue(i)}catch{}},e.onerror=()=>{let o=new Error("WebSocket connection error");this.exitError=o,this.readyReject?.(o),this.messages.done()},e.onclose=o=>{this.ready=!1,this.keepAliveTimer&&(clearInterval(this.keepAliveTimer),this.keepAliveTimer=void 0),o.code!==1e3&&o.code!==1001&&(this.exitError=new Error(`WebSocket closed abnormally: ${o.code} ${o.reason}`)),this.messages.done()},this.options.abortController?.signal.addEventListener("abort",()=>{this.close()})}async write(e){this.ready||await this.readyPromise,this.ws?.send(e)}close(){this.keepAliveTimer&&(clearInterval(this.keepAliveTimer),this.keepAliveTimer=void 0),this.ws&&(this.ws.close(1e3),this.ws=null),this.messages.done()}isReady(){return this.ready}async*readMessages(){if(yield*this.messages,this.exitError)throw this.exitError}endInput(){}};var k=class extends Error{constructor(e="Operation was aborted"){super(e),this.name="AbortError"}};var C=class extends Error{timeoutMs;constructor(e){super(`resolveModel did not return within ${e}ms. Increase resolveModelTimeoutMs or ensure the callback resolves faster.`),this.name="ModelPolicyTimeoutError",this.timeoutMs=e}},w=class extends Error{cliProtocolVersion;sdkProtocolVersion;constructor(e,t){super(`Wire protocol major mismatch: CLI announced "${e}" but this SDK was built for "${t}". Upgrade either qodercli or @qoder-ai/qoder-agent-sdk so the major versions align.`),this.name="ProtocolVersionMismatchError",this.cliProtocolVersion=e,this.sdkProtocolVersion=t}};var E="1.0.0";var q="ExitPlanMode";import*as B from"fs";function D(s,e,t,o){return new Promise((r,n)=>{if(!("id"in e&&e.id!==null)){try{t.onmessage?.(e)}catch(l){n(l);return}r({jsonrpc:"2.0"});return}let a=`${s}:${e.id}`;o.set(a,{resolve:r,reject:n}),t.onmessage?t.onmessage(e):(o.delete(a),n(new Error(`No message handler registered for MCP server "${s}"`)))})}function x(s,e,t){if("id"in e&&e.id!==null){let o=`${s}:${e.id}`,r=t.get(o);if(r)return r.resolve(e),t.delete(o),!0}return!1}function K(s,e,t){let o=0,r=`${s}:`,n=Array.from(t.entries());for(let i of n){let[a,l]=i;a.startsWith(r)&&(l.reject(e),t.delete(a),o++)}return o}function A(){return Math.random().toString(36).substring(2,15)}function j(s,e){let t="type"in e&&!("subtype"in e)?{...e,subtype:e.type}:e;return{type:"control_request",request_id:s,request:t}}function O(s,e){return{type:"control_response",response:{subtype:"success",request_id:s,response:e}}}function N(s,e,t){return{type:"control_response",response:{subtype:"error",request_id:s,error:e,...t?{code:t}:{}}}}function U(s){return typeof s=="object"&&s!==null&&s.type==="control_response"}function J(s){return typeof s=="object"&&s!==null&&s.type==="control_request"}function H(s){return typeof s=="object"&&s!==null&&(s.type==="control_cancel_request"||s.type==="control_cancel")}function P(s){if(typeof s!="object"||s===null)return;let e=s,t=e.subtype;if(typeof t=="string")return t;let o=e.type;return typeof o=="string"?o:void 0}function z(s){if(typeof s!="object"||s===null)return!1;let e=s.type;return e==="keepalive"||e==="keep_alive"}function $(s){return typeof s=="object"&&s!==null&&s.type==="streamlined_text"}function Q(s){return typeof s=="object"&&s!==null&&s.type==="streamlined_tool_use_summary"}function L(s){return typeof s=="object"&&s!==null&&s.type==="post_turn_summary"}function F(s){return typeof s=="object"&&s!==null&&s.type==="result"}var I=class s{static INITIALIZE_TIMEOUT_MS=12e4;transport;inputStream;pendingRequests=new Map;pendingInboundRequests=new Map;hooks;hookCallbacks=new Map;nextHookCallbackId=0;sdkMcpServers;sdkMcpTransports;pendingMcpResponses;isSingleTurn;canUseTool;abortController;jsonSchema;initConfig;onElicitation;onAuthExpired;fetchJobToken;diagnostics;controlRequestTimeoutMs;resolveModel;resolveModelTimeoutMs;initResponse;initializationPromise;resultMessage;readLoopPromise;closed=!1;authExpiredFired=!1;protocolHandshakeValidated=!1;firstResultReceived=!1;firstResultReceivedResolve;constructor(e,t,o,r,n,i,a,l,c,p,d,f,m,u,y,g,b){if(this.transport=e,this.isSingleTurn=t,this.canUseTool=o,this.hooks=r??{},this.abortController=n,this.sdkMcpServers=i??new Map,this.sdkMcpTransports=m??new Map,this.pendingMcpResponses=u??new Map,this.jsonSchema=a,this.initConfig=l??{},this.onElicitation=c,this.onAuthExpired=d,this.fetchJobToken=y,this.diagnostics=p,this.controlRequestTimeoutMs=f??6e4,this.resolveModel=g,this.resolveModelTimeoutMs=b??500,this.inputStream=new v(()=>{this.close().catch(()=>{})}),this.readLoopPromise=this.readMessages().catch(S=>{this.inputStream.error(S)}),this.initializationPromise=this.performInitialize(),this.initializationPromise.catch(()=>{}),this.abortController){let S=this.abortController.signal;S.aborted?this.close().catch(()=>{}):S.addEventListener("abort",()=>{this.close().catch(()=>{})},{once:!0})}}[Symbol.asyncIterator](){return this}async next(){return this.inputStream.next()}async return(){return await this.close(),{done:!0,value:void 0}}async throw(e){return await this.inputStream.throw(e),{done:!0,value:void 0}}async readMessages(){let e;try{for await(let t of this.transport.readMessages()){if(this.closed)break;if(U(t)){this.handleControlResponse(t);continue}if(J(t)){this.handleControlRequest(t).catch(r=>{this.diagnostics?.record("[QueryRunner] Error handling control request:",r)});continue}if(H(t)){this.handleControlCancelRequest(t);continue}if(z(t)||$(t)||Q(t)||L(t))continue;if(F(t)){let r=t;this.resultMessage=r,this.firstResultReceived=!0,this.firstResultReceivedResolve?.(),this.firstResultReceivedResolve=void 0,this.inputStream.enqueue(r),this.isSingleTurn&&this.transport.endInput();continue}let o=t;if(o.type==="system"&&o.subtype==="init")try{this.validateProtocolHandshake(o)}catch(r){throw this.inputStream.error(r),r}if(this.onAuthExpired&&!this.authExpiredFired){let r=!1;(o.type==="auth_status"&&o.error||o.type==="assistant"&&o.error==="authentication_failed")&&(r=!0),r&&(this.authExpiredFired=!0,Promise.resolve(this.onAuthExpired()).catch(i=>{this.diagnostics?.record("[QueryRunner] onAuthExpired callback threw:",i)}))}this.inputStream.enqueue(o)}}catch(t){e=t}finally{let t=e instanceof Error?e:new Error("Transport closed");this.firstResultReceivedResolve?.(),this.firstResultReceivedResolve=void 0;for(let[,o]of this.pendingRequests)o.reject(t);this.pendingRequests.clear(),e!==void 0?this.inputStream.error(e):this.inputStream.done()}}async request(e,t){let o=A(),r=j(o,e),n=t?.timeoutMs??this.controlRequestTimeoutMs;return new Promise((i,a)=>{let l=null,c=()=>{l&&(clearTimeout(l),l=null)};this.pendingRequests.set(o,{resolve:p=>{c(),i(p)},reject:p=>{c(),a(p)}}),n>0&&Number.isFinite(n)&&(l=setTimeout(()=>{if(this.pendingRequests.has(o)){this.pendingRequests.delete(o);try{this.transport.write(JSON.stringify({type:"control_cancel_request",request_id:o})+`
4
+ `);for(let n of r)if(n.trim())try{let i=JSON.parse(n);this.messages.enqueue(i)}catch{}},e.onerror=()=>{let o=new Error("WebSocket connection error");this.exitError=o,this.readyReject?.(o),this.messages.done()},e.onclose=o=>{this.ready=!1,this.keepAliveTimer&&(clearInterval(this.keepAliveTimer),this.keepAliveTimer=void 0),o.code!==1e3&&o.code!==1001&&(this.exitError=new Error(`WebSocket closed abnormally: ${o.code} ${o.reason}`)),this.messages.done()},this.options.abortController?.signal.addEventListener("abort",()=>{this.close()})}async write(e){this.ready||await this.readyPromise,this.ws?.send(e)}close(){this.keepAliveTimer&&(clearInterval(this.keepAliveTimer),this.keepAliveTimer=void 0),this.ws&&(this.ws.close(1e3),this.ws=null),this.messages.done()}isReady(){return this.ready}async*readMessages(){if(yield*this.messages,this.exitError)throw this.exitError}endInput(){}};var k=class extends Error{constructor(e="Operation was aborted"){super(e),this.name="AbortError"}};var C=class extends Error{timeoutMs;constructor(e){super(`resolveModel did not return within ${e}ms. Increase resolveModelTimeoutMs or ensure the callback resolves faster.`),this.name="ModelPolicyTimeoutError",this.timeoutMs=e}},w=class extends Error{cliProtocolVersion;sdkProtocolVersion;constructor(e,t){super(`Wire protocol major mismatch: CLI announced "${e}" but this SDK was built for "${t}". Upgrade either qodercli or @qoder-ai/qoder-agent-sdk so the major versions align.`),this.name="ProtocolVersionMismatchError",this.cliProtocolVersion=e,this.sdkProtocolVersion=t}};var E="1.0.0";var q="ExitPlanMode";import*as B from"fs";function D(s,e,t,o){return new Promise((r,n)=>{if(!("id"in e&&e.id!==null)){try{t.onmessage?.(e)}catch(l){n(l);return}r({jsonrpc:"2.0"});return}let a=`${s}:${e.id}`;o.set(a,{resolve:r,reject:n}),t.onmessage?t.onmessage(e):(o.delete(a),n(new Error(`No message handler registered for MCP server "${s}"`)))})}function x(s,e,t){if("id"in e&&e.id!==null){let o=`${s}:${e.id}`,r=t.get(o);if(r)return r.resolve(e),t.delete(o),!0}return!1}function K(s,e,t){let o=0,r=`${s}:`,n=Array.from(t.entries());for(let i of n){let[a,l]=i;a.startsWith(r)&&(l.reject(e),t.delete(a),o++)}return o}function A(){return Math.random().toString(36).substring(2,15)}function j(s,e){let t="type"in e&&!("subtype"in e)?{...e,subtype:e.type}:e;return{type:"control_request",request_id:s,request:t}}function O(s,e){return{type:"control_response",response:{subtype:"success",request_id:s,response:e}}}function N(s,e,t){return{type:"control_response",response:{subtype:"error",request_id:s,error:e,...t?{code:t}:{}}}}function U(s){return typeof s=="object"&&s!==null&&s.type==="control_response"}function z(s){return typeof s=="object"&&s!==null&&s.type==="control_request"}function J(s){return typeof s=="object"&&s!==null&&(s.type==="control_cancel_request"||s.type==="control_cancel")}function P(s){if(typeof s!="object"||s===null)return;let e=s,t=e.subtype;if(typeof t=="string")return t;let o=e.type;return typeof o=="string"?o:void 0}function H(s){if(typeof s!="object"||s===null)return!1;let e=s.type;return e==="keepalive"||e==="keep_alive"}function $(s){return typeof s=="object"&&s!==null&&s.type==="streamlined_text"}function Q(s){return typeof s=="object"&&s!==null&&s.type==="streamlined_tool_use_summary"}function L(s){return typeof s=="object"&&s!==null&&s.type==="post_turn_summary"}function F(s){return typeof s=="object"&&s!==null&&s.type==="result"}var I=class s{static INITIALIZE_TIMEOUT_MS=12e4;transport;inputStream;pendingRequests=new Map;pendingInboundRequests=new Map;hooks;hookCallbacks=new Map;nextHookCallbackId=0;sdkMcpServers;sdkMcpTransports;pendingMcpResponses;isSingleTurn;canUseTool;abortController;jsonSchema;initConfig;onElicitation;onAuthExpired;fetchJobToken;diagnostics;controlRequestTimeoutMs;resolveModel;resolveModelTimeoutMs;initResponse;initializationPromise;resultMessage;readLoopPromise;closed=!1;authExpiredFired=!1;protocolHandshakeValidated=!1;firstResultReceived=!1;firstResultReceivedResolve;constructor(e,t,o,r,n,i,a,l,c,p,d,f,m,u,y,g,b){if(this.transport=e,this.isSingleTurn=t,this.canUseTool=o,this.hooks=r??{},this.abortController=n,this.sdkMcpServers=i??new Map,this.sdkMcpTransports=m??new Map,this.pendingMcpResponses=u??new Map,this.jsonSchema=a,this.initConfig=l??{},this.onElicitation=c,this.onAuthExpired=d,this.fetchJobToken=y,this.diagnostics=p,this.controlRequestTimeoutMs=f??6e4,this.resolveModel=g,this.resolveModelTimeoutMs=b??500,this.inputStream=new v(()=>{this.close().catch(()=>{})}),this.readLoopPromise=this.readMessages().catch(S=>{this.inputStream.error(S)}),this.initializationPromise=this.performInitialize(),this.initializationPromise.catch(()=>{}),this.abortController){let S=this.abortController.signal;S.aborted?this.close().catch(()=>{}):S.addEventListener("abort",()=>{this.close().catch(()=>{})},{once:!0})}}[Symbol.asyncIterator](){return this}async next(){return this.inputStream.next()}async return(){return await this.close(),{done:!0,value:void 0}}async throw(e){return await this.inputStream.throw(e),{done:!0,value:void 0}}async readMessages(){let e;try{for await(let t of this.transport.readMessages()){if(this.closed)break;if(U(t)){this.handleControlResponse(t);continue}if(z(t)){this.handleControlRequest(t).catch(r=>{this.diagnostics?.record("[QueryRunner] Error handling control request:",r)});continue}if(J(t)){this.handleControlCancelRequest(t);continue}if(H(t)||$(t)||Q(t)||L(t))continue;if(F(t)){let r=t;this.resultMessage=r,this.firstResultReceived=!0,this.firstResultReceivedResolve?.(),this.firstResultReceivedResolve=void 0,this.inputStream.enqueue(r),this.isSingleTurn&&this.transport.endInput();continue}let o=t;if(o.type==="system"&&o.subtype==="init")try{this.validateProtocolHandshake(o)}catch(r){throw this.inputStream.error(r),r}if(this.onAuthExpired&&!this.authExpiredFired){let r=!1;(o.type==="auth_status"&&o.error||o.type==="assistant"&&o.error==="authentication_failed")&&(r=!0),r&&(this.authExpiredFired=!0,Promise.resolve(this.onAuthExpired()).catch(i=>{this.diagnostics?.record("[QueryRunner] onAuthExpired callback threw:",i)}))}this.inputStream.enqueue(o)}}catch(t){e=t}finally{let t=e instanceof Error?e:new Error("Transport closed");this.firstResultReceivedResolve?.(),this.firstResultReceivedResolve=void 0;for(let[,o]of this.pendingRequests)o.reject(t);this.pendingRequests.clear(),e!==void 0?this.inputStream.error(e):this.inputStream.done()}}async request(e,t){let o=A(),r=j(o,e),n=t?.timeoutMs??this.controlRequestTimeoutMs;return new Promise((i,a)=>{let l=null,c=()=>{l&&(clearTimeout(l),l=null)};this.pendingRequests.set(o,{resolve:p=>{c(),i(p)},reject:p=>{c(),a(p)}}),n>0&&Number.isFinite(n)&&(l=setTimeout(()=>{if(this.pendingRequests.has(o)){this.pendingRequests.delete(o);try{this.transport.write(JSON.stringify({type:"control_cancel_request",request_id:o})+`
5
5
  `)}catch(p){this.diagnostics?.record("[QueryRunner] Failed to send control_cancel_request on timeout:",p)}a(new Error(`Control request "${P(r.request)??"unknown"}" timed out after ${n}ms`))}},n));try{this.transport.write(JSON.stringify(r)+`
6
6
  `)}catch(p){c(),this.pendingRequests.delete(o),a(p)}})}handleControlResponse(e){let t=e.response,o=t.request_id,r=this.pendingRequests.get(o);if(r)if(this.pendingRequests.delete(o),t.subtype==="success")r.resolve(t.response);else{let n=new Error(t.error);t.code&&(n.code=t.code),r.reject(n),this.processPendingPermissionRequests(t.pending_permission_requests)}}processPendingPermissionRequests(e){if(e)for(let t of e)P(t.request)==="can_use_tool"&&this.handleControlRequest(t).catch(o=>{this.diagnostics?.record("[QueryRunner] Error handling pending permission request:",o)})}async handleControlRequest(e){let t=e.request_id,o=new AbortController;this.pendingInboundRequests.set(t,{abortController:o});try{let r=await this.awaitAbortable(this.processControlRequest(e,o.signal),o.signal);if(!o.signal.aborted){let n=O(t,r);this.transport.write(JSON.stringify(n)+`
7
7
  `)}}catch(r){if(!o.signal.aborted){let{error:n,code:i}=oe(r),a=N(t,n,i);this.transport.write(JSON.stringify(a)+`
8
8
  `)}}finally{this.pendingInboundRequests.delete(t)}}handleControlCancelRequest(e){let t=this.pendingInboundRequests.get(e.request_id);t&&(t.abortController.abort(),this.pendingInboundRequests.delete(e.request_id))}throwIfAborted(e){if(e.aborted)throw new k}validateProtocolHandshake(e){if(this.protocolHandshakeValidated)return;this.protocolHandshakeValidated=!0;let t=e.protocol_version,o=E;if(!t){this.diagnostics?.record(`[QueryRunner] CLI did not announce protocol_version. This SDK was built for ${o}. Consider upgrading qodercli for the version handshake.`);return}let r=W(t),n=W(o);if(!r||!n){this.diagnostics?.record(`[QueryRunner] Could not parse protocol_version "${t}" or built-in "${o}"; skipping handshake.`);return}if(r.major!==n.major)throw new w(t,o);r.minor<n.minor&&this.diagnostics?.record(`[QueryRunner] CLI protocol_version ${t} is older than this SDK's ${o}. New optional fields may be absent.`)}async awaitAbortable(e,t){if(t.aborted)throw new k;return new Promise((o,r)=>{let n=()=>{r(new k)};t.addEventListener("abort",n,{once:!0}),e.then(i=>{t.removeEventListener("abort",n),o(i)},i=>{t.removeEventListener("abort",n),r(i)})})}async processControlRequest(e,t){this.throwIfAborted(t);let o=e.request,r=P(o),n=o;switch(r){case"fetch_job_token":{if(!this.fetchJobToken)throw new Error("job_token_unavailable: No fetchJobToken callback configured");let i=n.reason??"initial",a=n.session_id,l=e.request_id,c=await this.awaitAbortable(this.fetchJobToken({requestId:l,reason:i,sessionId:a},{signal:t}),t);if(!c?.token)throw new Error("job_token_unavailable: Host did not provide a Job Token");return this.diagnostics?.record(`[QueryRunner] fetch_job_token fulfilled: reason=${i}`),{token:c.token}}case"can_use_tool":case"permission_response":{let i=n.tool_name,a=n.input??n.tool_input??{};if(!this.canUseTool)throw new Error("canUseTool callback is not provided.");let l=n.tool_use_id,c=n.permission_suggestions??n.suggestions,p=n.blocked_path,d=n.decision_reason,f=n.decision_reason_type,m=n.classifier_approvable,u=n.title,y=n.display_name,g=n.description,b=n.agent_id,S=ne(i,n.details,n.plan_path,n.plan_content),R=await this.awaitAbortable(this.canUseTool(i,a,{signal:t,suggestions:c,blockedPath:p,decisionReason:d,decisionReasonType:f,classifierApprovable:m,title:u,displayName:y,description:g,toolUseID:l,agentID:b,exitPlanMode:S}),t);if(R.behavior==="deny"&&!R.message)throw new Error("Permission deny result must include a message.");return R.behavior==="allow"?{...R,updatedInput:R.updatedInput??a,toolUseID:l}:{...R,toolUseID:l}}case"hook_callback":{let i=n.callback_id;if(!i)throw new Error("Hook callback missing callback_id");return this.invokeRegisteredHookCallback(i,n.input,n.tool_use_id,t)}case"mcp_message":{let i=n.server_name,a=n.message,l=this.sdkMcpTransports.get(i);if(!l)throw new Error(`Unknown in-process MCP server: ${i}`);return{mcp_response:await this.awaitAbortable(D(i,a,l,this.pendingMcpResponses),t)}}case"elicitation":case"elicitation_response":return this.onElicitation?await this.awaitAbortable(this.onElicitation({serverName:n.mcp_server_name??"",message:n.message??n.prompt??"",mode:n.mode,url:n.url,elicitationId:n.elicitation_id,requestedSchema:n.requested_schema,title:n.title,displayName:n.display_name,description:n.description},{signal:t}),t):{action:"cancel"};case"get_model_policy":{if(!this.resolveModel)return{type:"get_model_policy"};let i={purpose:n.purpose,sessionId:n.sessionId,turnIndex:n.turnIndex,availableModels:n.models??[]},a=this.resolveModelTimeoutMs,l=Promise.resolve(this.resolveModel(i)),c,p=new Promise((m,u)=>{c=setTimeout(()=>{u(new C(a))},a)}),d;try{d=await this.awaitAbortable(Promise.race([l,p]),t)}finally{clearTimeout(c)}let f={type:"get_model_policy",model:typeof d.model=="string"?d.model:d.model.model,parameters:d.parameters};if(typeof d.model!="string"){let{model:m,...u}=d.model;f.custom_model={...u,style:u.style??"openai"}}return f}default:throw new Error(`Unhandled control request subtype: ${r??"unknown"}`)}}async initialize(){return this.initializationPromise||(this.initializationPromise=this.performInitialize()),this.initializationPromise}async performInitialize(){let e={type:"initialize",modelPolicyProvider:this.resolveModel!==void 0,supportsCatalogReadyInitialize:!0,initializeTimeoutMs:s.INITIALIZE_TIMEOUT_MS},t={};for(let[r,n]of Object.entries(this.hooks)){if(!n||n.length===0)continue;let i=[];for(let a of n){let l=a.hooks.map(c=>{let p=`hook_${this.nextHookCallbackId++}`;return this.hookCallbacks.set(p,c),p});l.length!==0&&i.push({matcher:a.matcher,hookCallbackIds:l,timeout:a.timeout})}i.length>0&&(t[r]=i)}Object.keys(t).length>0&&(e.hooks=t),this.initConfig.systemPrompt!==void 0&&(e.systemPrompt=this.initConfig.systemPrompt),this.initConfig.appendSystemPrompt!==void 0&&(e.appendSystemPrompt=this.initConfig.appendSystemPrompt),this.initConfig.planModeInstructions!==void 0&&(e.planModeInstructions=this.initConfig.planModeInstructions),this.initConfig.agents&&(e.agents=this.initConfig.agents),this.initConfig.promptSuggestions!==void 0&&(e.promptSuggestions=this.initConfig.promptSuggestions),this.initConfig.enableFileCheckpointing!==void 0&&(e.enableFileCheckpointing=this.initConfig.enableFileCheckpointing),this.jsonSchema&&(e.jsonSchema=this.jsonSchema),this.sdkMcpServers.size>0&&(e.sdkMcpServers=Array.from(this.sdkMcpServers.keys()));let o=await this.request(e,{timeoutMs:s.INITIALIZE_TIMEOUT_MS});if(o&&typeof o=="object"){let r=o;this.initResponse=r}if(!this.initResponse)throw new Error("Failed to receive initialization response");return this.initResponse}async invokeRegisteredHookCallback(e,t,o,r){let n=this.hookCallbacks.get(e);if(!n)throw new Error(`Unknown hook callback: ${e}`);return await this.awaitAbortable(n(t,o,{signal:r}),r)??{continue:!0}}async initializationResult(){return this.initialize()}async streamInput(e){(async()=>{try{await this.initialize();let t=0;for await(let o of e){if(this.closed)break;t+=1,this.transport.write(JSON.stringify(o)+`
9
- `)}t>0&&this.hasBidirectionalNeeds()&&await this.waitForFirstResult(),this.transport.endInput()}catch(t){this.diagnostics?.record("[QueryRunner] streamInput error:",t),this.inputStream.error(t instanceof Error?t:new Error(String(t))),this.transport.endInput()}})().catch(()=>{})}async interrupt(){await this.request({type:"interrupt"})}async setPermissionMode(e){await this.request({type:"set_permission_mode",mode:e==="yolo"?"bypassPermissions":e})}hasBidirectionalNeeds(){return this.sdkMcpTransports.size>0||Object.keys(this.hooks).length>0||this.canUseTool!==void 0||this.onElicitation!==void 0||this.fetchJobToken!==void 0||this.resolveModel!==void 0}waitForFirstResult(){return this.firstResultReceived||this.closed?Promise.resolve():new Promise(e=>{if(this.abortController?.signal.aborted){e();return}this.firstResultReceivedResolve=e,this.abortController?.signal.addEventListener("abort",()=>e(),{once:!0})})}async setModel(e){await this.request({type:"set_model",model:e??""})}async setProxy(e){await this.request({type:"set_proxy",proxy:e||null})}async generateSessionTitle(e,t){return(await this.request({type:"generate_session_title",description:e,...t?.persist!==void 0?{persist:t.persist}:{}}))?.title??null}async addDirectories(e){if(!Array.isArray(e))throw new Error("directories must be an array");return await this.request({type:"add_directories",directories:e})}async applyFlagSettings(e){await this.request({type:"apply_flag_settings",settings:e})}async supportedCommands(){return(await this.initializationResult()).commands??[]}async getAvailableModels(){let e={subtype:"get_models"};return(await this.request(e))?.models??[]}async listByokProviders(){try{return(await this.request({type:"get_byok_config"}))?.providers??null}catch{return null}}async validateByokModel(e){try{let t=await this.request({type:"validate_byok_model",provider:e.provider,model:e.model,api_key:e.api_key,...e.url!==void 0?{url:e.url}:{},...e.style!==void 0?{style:e.style}:{}});return typeof t?.success=="boolean"?t.success:null}catch{return null}}async supportedAgents(){return(await this.initializationResult()).agents??[]}async accountInfo(){try{let t=await this.request({type:"account_info"});if(t?.account)return t.account}catch{}return(await this.initializationResult()).account??{}}async mcpServerStatus(){return(await this.request({type:"mcp_status"}))?.servers??[]}async getContextUsage(){return await this.request({type:"get_context_usage"})}async getUsageInfo(){try{let e=await this.request({type:"get_usage_info"});return se(e?.usage)?e.usage:null}catch{return null}}async reloadPlugins(){return await this.request({type:"reload_plugins"})}async rewindFiles(e,t){let o={type:"rewind_files",user_message_id:e};t?.dryRun&&(o.dry_run=!0);let n=await this.request(o);if(!t?.dryRun&&n?.canRewind===!1)throw new Error(typeof n.error=="string"&&n.error.length>0?n.error:"Unable to rewind files.");return n}async seedReadState(e,t){await this.request({type:"seed_read_state",path:e,mtime:t})}async reconnectMcpServer(e){await this.request({type:"mcp_reconnect",serverName:e})}async toggleMcpServer(e,t){await this.request({type:"mcp_toggle",serverName:e,enabled:t})}async setMcpServers(e){return await this.request({type:"mcp_set_servers",servers:e})??{added:[],removed:[],errors:{}}}async injectMcpToken(e,t){await this.request({type:"mcp_inject_token",serverName:e,token:t})}async mcpAuthenticate(e,t){let o=await this.request({type:"mcp_authenticate",serverName:e,...t!==void 0?{redirectUri:t}:{}}),r=o?.requiresUserAction===!0,n=typeof o?.authUrl=="string"?o.authUrl:void 0;if(r&&n===void 0)throw new Error("mcp_authenticate response set requiresUserAction=true but did not include an authUrl");return r?{authUrl:n,requiresUserAction:!0}:{requiresUserAction:!1}}async mcpSubmitOAuthCallbackUrl(e,t){await this.request({type:"mcp_oauth_callback_url",serverName:e,callbackUrl:t})}async mcpClearAuth(e){await this.request({type:"mcp_clear_auth",serverName:e})}async close(){if(this.closed)return;this.closed=!0;for(let[,t]of this.pendingInboundRequests)t.abortController.abort();this.pendingInboundRequests.clear(),this.hookCallbacks.clear();let e=new Error("SDK closing");for(let[t,o]of this.sdkMcpTransports){try{await o.close()}catch(r){this.diagnostics?.record(`[QueryRunner] error closing SDK MCP transport "${t}":`,r)}K(t,e,this.pendingMcpResponses)}this.transport.close();try{await this.readLoopPromise}catch{}}async[Symbol.asyncDispose](){await this.close()}};function _(s){return typeof s=="object"&&s!==null}function h(s){return typeof s=="number"&&Number.isFinite(s)}function V(s){return _(s)?h(s.total)&&h(s.used)&&h(s.remaining)&&h(s.percentage)&&typeof s.unit=="string":!1}function te(s){return _(s)?h(s.used)&&h(s.cap)&&h(s.remaining)&&h(s.percentage)&&typeof s.available=="boolean"&&typeof s.unit=="string":!1}function se(s){return!_(s)||typeof s.userId!="string"||s.userId.length===0||typeof s.userType!="string"||s.userType.length===0||!h(s.totalUsagePercentage)||typeof s.isHighestTier!="boolean"||!h(s.expiresAt)||!V(s.userQuota)||!V(s.addOnQuota)||typeof s.isQuotaExceeded!="boolean"||typeof s.isPlanQuotaProrated!="boolean"||!te(s.orgResourcePackage)?!1:(s.upgradeUrl===void 0||typeof s.upgradeUrl=="string")&&(!_(s.addOnQuota)||s.addOnQuota.detailUrl===void 0||typeof s.addOnQuota.detailUrl=="string")}function oe(s){let e=s instanceof Error?s.message:String(s),t=typeof s=="object"&&s!==null?s.code:void 0,o=typeof t=="string"&&t.length>0?t:void 0,r=/^([a-z][a-z0-9_]*):\s*(.*)$/.exec(e);if(r){let n=o??r[1];return(!o||o===r[1])&&(e=r[2]||e),{error:e,code:n}}return o?{error:e,code:o}:{error:e}}function ne(s,e,t,o){if(s!==q)return;let r=e!==null&&typeof e=="object"?e:void 0,n=r?.type===q||r?.type==="ExitPlanMode",i=n&&typeof r?.planPath=="string"&&r.planPath.length>0?r.planPath:typeof t=="string"&&t.length>0?t:void 0,a=n&&typeof r?.planContent=="string"&&r.planContent.length>0?r.planContent:typeof o=="string"&&o.length>0?o:void 0;if(!a&&i&&(a=B.readFileSync(i,"utf8").trim()||void 0),!(!i&&!a))return{planPath:i,planContent:a}}function W(s){let e=/^(\d+)\.(\d+)(?:\.\d+)?(?:[-+].*)?$/.exec(s);return e?{major:Number(e[1]),minor:Number(e[2])}:null}var T=class{sendMcpMessage;isClosed=!1;onclose;onerror;onmessage;constructor(e){this.sendMcpMessage=e}async start(){}async send(e){if(this.isClosed)throw new Error("Transport is closed");this.sendMcpMessage(e)}async close(){this.isClosed||(this.isClosed=!0,this.onclose?.())}get closed(){return this.isClosed}};function re(s){let{prompt:e,websocket:t,abortController:o,canUseTool:r,hooks:n,mcpServers:i,jsonSchema:a}=s,l=new Map,c=new Map,p=new Map;if(i)for(let[m,u]of Object.entries(i))if(u.type==="sdk"&&"instance"in u){let y=u.instance;l.set(m,y);let g=new T(b=>{x(m,b,p)});c.set(m,g),y.connect(g).catch(()=>{})}else throw new Error(`Browser SDK only supports SDK MCP servers. Server "${m}" has type "${u.type}".`);let d=new M({url:t.url,headers:t.headers,authMessage:t.authMessage,abortController:o}),f=new I(d,!0,r,n,o,l,a,{},void 0,void 0,void 0,void 0,c,p);return f.streamInput(e),f}export{Z as createSdkMcpServer,re as query,X as tool};
9
+ `)}t>0&&this.hasBidirectionalNeeds()&&await this.waitForFirstResult(),this.transport.endInput()}catch(t){this.diagnostics?.record("[QueryRunner] streamInput error:",t),this.inputStream.error(t instanceof Error?t:new Error(String(t))),this.transport.endInput()}})().catch(()=>{})}async interrupt(){await this.request({type:"interrupt"})}async setPermissionMode(e){await this.request({type:"set_permission_mode",mode:e==="yolo"?"bypassPermissions":e})}hasBidirectionalNeeds(){return this.sdkMcpTransports.size>0||Object.keys(this.hooks).length>0||this.canUseTool!==void 0||this.onElicitation!==void 0||this.fetchJobToken!==void 0||this.resolveModel!==void 0}waitForFirstResult(){return this.firstResultReceived||this.closed?Promise.resolve():new Promise(e=>{if(this.abortController?.signal.aborted){e();return}this.firstResultReceivedResolve=e,this.abortController?.signal.addEventListener("abort",()=>e(),{once:!0})})}async setModel(e){await this.request({type:"set_model",model:e??""})}async setProxy(e){await this.request({type:"set_proxy",proxy:e||null})}async generateSessionTitle(e,t){return(await this.request({type:"generate_session_title",description:e,...t?.persist!==void 0?{persist:t.persist}:{}}))?.title??null}async addDirectories(e){if(!Array.isArray(e))throw new Error("directories must be an array");return await this.request({type:"add_directories",directories:e})}async applyFlagSettings(e){await this.request({type:"apply_flag_settings",settings:e})}async supportedCommands(){return(await this.initializationResult()).commands??[]}async getAvailableModels(){let e={subtype:"get_models"};return(await this.request(e))?.models??[]}async listByokProviders(){try{return(await this.request({type:"get_byok_config"}))?.providers??null}catch{return null}}async validateByokModel(e){try{let t=await this.request({type:"validate_byok_model",provider:e.provider,model:e.model,api_key:e.api_key,...e.url!==void 0?{url:e.url}:{},...e.style!==void 0?{style:e.style}:{}});return typeof t?.success=="boolean"?t.success:null}catch{return null}}async supportedAgents(){return(await this.initializationResult()).agents??[]}async accountInfo(){try{let t=await this.request({type:"account_info"});if(t?.account)return t.account}catch{}return(await this.initializationResult()).account??{}}async mcpServerStatus(){return(await this.request({type:"mcp_status"}))?.servers??[]}async getContextUsage(){return await this.request({type:"get_context_usage"})}async getUsageInfo(){try{let e=await this.request({type:"get_usage_info"});return se(e?.usage)?e.usage:null}catch{return null}}async reloadPlugins(){return await this.request({type:"reload_plugins"})}async listPlugins(){return(await this.request({type:"list_plugins"})).plugins}async rewindFiles(e,t){let o={type:"rewind_files",user_message_id:e};t?.dryRun&&(o.dry_run=!0);let n=await this.request(o);if(!t?.dryRun&&n?.canRewind===!1)throw new Error(typeof n.error=="string"&&n.error.length>0?n.error:"Unable to rewind files.");return n}async seedReadState(e,t){await this.request({type:"seed_read_state",path:e,mtime:t})}async reconnectMcpServer(e){await this.request({type:"mcp_reconnect",serverName:e})}async toggleMcpServer(e,t){await this.request({type:"mcp_toggle",serverName:e,enabled:t})}async setMcpServers(e){return await this.request({type:"mcp_set_servers",servers:e})??{added:[],removed:[],errors:{}}}async injectMcpToken(e,t){await this.request({type:"mcp_inject_token",serverName:e,token:t})}async mcpAuthenticate(e,t){let o=await this.request({type:"mcp_authenticate",serverName:e,...t!==void 0?{redirectUri:t}:{}}),r=o?.requiresUserAction===!0,n=typeof o?.authUrl=="string"?o.authUrl:void 0;if(r&&n===void 0)throw new Error("mcp_authenticate response set requiresUserAction=true but did not include an authUrl");return r?{authUrl:n,requiresUserAction:!0}:{requiresUserAction:!1}}async mcpSubmitOAuthCallbackUrl(e,t){await this.request({type:"mcp_oauth_callback_url",serverName:e,callbackUrl:t})}async mcpClearAuth(e){await this.request({type:"mcp_clear_auth",serverName:e})}async close(){if(this.closed)return;this.closed=!0;for(let[,t]of this.pendingInboundRequests)t.abortController.abort();this.pendingInboundRequests.clear(),this.hookCallbacks.clear();let e=new Error("SDK closing");for(let[t,o]of this.sdkMcpTransports){try{await o.close()}catch(r){this.diagnostics?.record(`[QueryRunner] error closing SDK MCP transport "${t}":`,r)}K(t,e,this.pendingMcpResponses)}this.transport.close();try{await this.readLoopPromise}catch{}}async[Symbol.asyncDispose](){await this.close()}};function _(s){return typeof s=="object"&&s!==null}function h(s){return typeof s=="number"&&Number.isFinite(s)}function V(s){return _(s)?h(s.total)&&h(s.used)&&h(s.remaining)&&h(s.percentage)&&typeof s.unit=="string":!1}function te(s){return _(s)?h(s.used)&&h(s.cap)&&h(s.remaining)&&h(s.percentage)&&typeof s.available=="boolean"&&typeof s.unit=="string":!1}function se(s){return!_(s)||typeof s.userId!="string"||s.userId.length===0||typeof s.userType!="string"||s.userType.length===0||!h(s.totalUsagePercentage)||typeof s.isHighestTier!="boolean"||!h(s.expiresAt)||!V(s.userQuota)||!V(s.addOnQuota)||typeof s.isQuotaExceeded!="boolean"||typeof s.isPlanQuotaProrated!="boolean"||!te(s.orgResourcePackage)?!1:(s.upgradeUrl===void 0||typeof s.upgradeUrl=="string")&&(!_(s.addOnQuota)||s.addOnQuota.detailUrl===void 0||typeof s.addOnQuota.detailUrl=="string")}function oe(s){let e=s instanceof Error?s.message:String(s),t=typeof s=="object"&&s!==null?s.code:void 0,o=typeof t=="string"&&t.length>0?t:void 0,r=/^([a-z][a-z0-9_]*):\s*(.*)$/.exec(e);if(r){let n=o??r[1];return(!o||o===r[1])&&(e=r[2]||e),{error:e,code:n}}return o?{error:e,code:o}:{error:e}}function ne(s,e,t,o){if(s!==q)return;let r=e!==null&&typeof e=="object"?e:void 0,n=r?.type===q||r?.type==="ExitPlanMode",i=n&&typeof r?.planPath=="string"&&r.planPath.length>0?r.planPath:typeof t=="string"&&t.length>0?t:void 0,a=n&&typeof r?.planContent=="string"&&r.planContent.length>0?r.planContent:typeof o=="string"&&o.length>0?o:void 0;if(!a&&i&&(a=B.readFileSync(i,"utf8").trim()||void 0),!(!i&&!a))return{planPath:i,planContent:a}}function W(s){let e=/^(\d+)\.(\d+)(?:\.\d+)?(?:[-+].*)?$/.exec(s);return e?{major:Number(e[1]),minor:Number(e[2])}:null}var T=class{sendMcpMessage;isClosed=!1;onclose;onerror;onmessage;constructor(e){this.sendMcpMessage=e}async start(){}async send(e){if(this.isClosed)throw new Error("Transport is closed");this.sendMcpMessage(e)}async close(){this.isClosed||(this.isClosed=!0,this.onclose?.())}get closed(){return this.isClosed}};function re(s){let{prompt:e,websocket:t,abortController:o,canUseTool:r,hooks:n,mcpServers:i,jsonSchema:a}=s,l=new Map,c=new Map,p=new Map;if(i)for(let[m,u]of Object.entries(i))if(u.type==="sdk"&&"instance"in u){let y=u.instance;l.set(m,y);let g=new T(b=>{x(m,b,p)});c.set(m,g),y.connect(g).catch(()=>{})}else throw new Error(`Browser SDK only supports SDK MCP servers. Server "${m}" has type "${u.type}".`);let d=new M({url:t.url,headers:t.headers,authMessage:t.authMessage,abortController:o}),f=new I(d,!0,r,n,o,l,a,{},void 0,void 0,void 0,void 0,c,p);return f.streamInput(e),f}export{Z as createSdkMcpServer,re as query,X as tool};
@@ -28,8 +28,10 @@ export declare class WebSocketTransport implements Transport {
28
28
  private messages;
29
29
  private keepAliveTimer?;
30
30
  private exitError?;
31
+ private initialized;
31
32
  constructor(options: WebSocketTransportOptions);
32
- private initialize;
33
+ initialize(): Promise<void>;
34
+ private open;
33
35
  write(data: string): Promise<void>;
34
36
  close(): void;
35
37
  isReady(): boolean;
@@ -0,0 +1,8 @@
1
+ export type DefaultRuntimeTransport = 'process' | 'worker';
2
+ /**
3
+ * The default transport baked into the packaged SDK bundle.
4
+ *
5
+ * Development / plain `tsc` builds default to `process`. Release bundles replace
6
+ * `__QODER_DEFAULT_RUNTIME_TRANSPORT__` through esbuild `define`.
7
+ */
8
+ export declare const DEFAULT_RUNTIME_TRANSPORT: DefaultRuntimeTransport;
@@ -9,7 +9,7 @@
9
9
  * 4. Writes to stdin as JSON + newline
10
10
  * 5. Handles graceful shutdown: close stdin → wait → SIGTERM → wait → SIGKILL
11
11
  */
12
- import type { Transport } from './transport.js';
12
+ import type { QueryTransportProvider, Transport } from './transport.js';
13
13
  import type { StdoutMessage } from '../types/control.js';
14
14
  import type { SdkPluginConfig, ToolConfig } from '../types/common.js';
15
15
  import type { PermissionMode } from '../types/permissions.js';
@@ -106,7 +106,8 @@ type ToolsOption = string[] | {
106
106
  type: 'preset';
107
107
  preset: 'qodercli';
108
108
  };
109
- export declare class ProcessTransport implements Transport {
109
+ export declare class ProcessTransport implements Transport, QueryTransportProvider<ProcessTransportOptions> {
110
+ static readonly default: ProcessTransport;
110
111
  private process;
111
112
  private customHandle;
112
113
  private options;
@@ -114,13 +115,13 @@ export declare class ProcessTransport implements Transport {
114
115
  private closed;
115
116
  private initializePromise;
116
117
  private authExpiredFired;
117
- private authPayloadPath;
118
118
  private pendingInput;
119
- private generatedSettingsDir;
120
119
  private diagnostics?;
121
120
  private processExitError;
122
121
  private stderrTail;
122
+ private launchOptionsBuilder;
123
123
  constructor(options?: ProcessTransportOptions);
124
+ create(options: ProcessTransportOptions): Transport;
124
125
  /**
125
126
  * Build CLI arguments, resolve the executable, spawn the process,
126
127
  * and mark the transport as ready.
@@ -179,33 +180,6 @@ export declare class ProcessTransport implements Transport {
179
180
  * and is used directly as the command.
180
181
  */
181
182
  private resolveExecutable;
182
- /**
183
- * Build the environment variables for the child process.
184
- */
185
- private buildEnv;
186
- /**
187
- * Build the complete CLI argument array from options.
188
- */
189
- private buildArgs;
190
- private buildSettingsArg;
191
- private applyFileCheckpointingSetting;
192
- private applySettingsCompatibility;
193
- private toQoderDefaultPermissionMode;
194
- private applyAdditionalDirectories;
195
- private buildCliMcpServers;
196
- private collectMcpPolicyPermissionRules;
197
- private hasMcpPolicyRules;
198
- private applyMcpPolicyRules;
199
- private readSettingsFile;
200
- private writeGeneratedSettingsFile;
201
- /**
202
- * Create a one-shot auth payload file with restrictive permissions.
203
- * The CLI reads and deletes this file; SDK cleans up as fallback.
204
- */
205
- private createAuthPayloadFile;
206
- /** Convert InternalAuthOptions to the wire SdkAuthPayload format. */
207
- private buildAuthPayload;
208
- private resolveAccessToken;
209
183
  /** Best-effort cleanup of the auth payload file and its parent directory. */
210
184
  private cleanupAuthPayload;
211
185
  /** Fire `onAuthExpired` at most once per session. */
@@ -0,0 +1,6 @@
1
+ import { type ProcessTransportOptions } from './process-transport.js';
2
+ import type { QueryTransportProvider, Transport } from './transport.js';
3
+ export type QueryTransportCreateOptions = ProcessTransportOptions;
4
+ export type QueryTransportProviderOption = QueryTransportProvider<QueryTransportCreateOptions>;
5
+ export declare function isQueryTransportProvider(value: unknown): value is QueryTransportProviderOption;
6
+ export declare function createQueryTransport(provider: QueryTransportProviderOption, options: QueryTransportCreateOptions): Transport;