@getpaseo/server 0.1.12 → 0.1.14

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 (65) hide show
  1. package/dist/server/client/daemon-client.d.ts +84 -87
  2. package/dist/server/client/daemon-client.d.ts.map +1 -1
  3. package/dist/server/client/daemon-client.js +253 -299
  4. package/dist/server/client/daemon-client.js.map +1 -1
  5. package/dist/server/server/agent/agent-manager.d.ts +2 -1
  6. package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
  7. package/dist/server/server/agent/agent-manager.js +23 -0
  8. package/dist/server/server/agent/agent-manager.js.map +1 -1
  9. package/dist/server/server/agent/agent-sdk-types.d.ts +0 -15
  10. package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
  11. package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
  12. package/dist/server/server/agent/providers/claude-agent.js +268 -35
  13. package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
  14. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
  15. package/dist/server/server/agent/providers/codex-app-server-agent.js +85 -36
  16. package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
  17. package/dist/server/server/bootstrap.d.ts.map +1 -1
  18. package/dist/server/server/bootstrap.js +3 -1
  19. package/dist/server/server/bootstrap.js.map +1 -1
  20. package/dist/server/server/daemon-version.d.ts +5 -0
  21. package/dist/server/server/daemon-version.d.ts.map +1 -0
  22. package/dist/server/server/daemon-version.js +22 -0
  23. package/dist/server/server/daemon-version.js.map +1 -0
  24. package/dist/server/server/dictation/dictation-stream-manager.d.ts +1 -0
  25. package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -1
  26. package/dist/server/server/dictation/dictation-stream-manager.js +32 -1
  27. package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -1
  28. package/dist/server/server/package-version.d.ts +13 -0
  29. package/dist/server/server/package-version.d.ts.map +1 -0
  30. package/dist/server/server/package-version.js +47 -0
  31. package/dist/server/server/package-version.js.map +1 -0
  32. package/dist/server/server/persisted-config.d.ts +2 -2
  33. package/dist/server/server/pid-lock.d.ts.map +1 -1
  34. package/dist/server/server/pid-lock.js +16 -2
  35. package/dist/server/server/pid-lock.js.map +1 -1
  36. package/dist/server/server/session.d.ts +23 -21
  37. package/dist/server/server/session.d.ts.map +1 -1
  38. package/dist/server/server/session.js +975 -850
  39. package/dist/server/server/session.js.map +1 -1
  40. package/dist/server/server/websocket-server.d.ts +5 -1
  41. package/dist/server/server/websocket-server.d.ts.map +1 -1
  42. package/dist/server/server/websocket-server.js +27 -16
  43. package/dist/server/server/websocket-server.js.map +1 -1
  44. package/dist/server/shared/agent-attention-notification.d.ts +40 -0
  45. package/dist/server/shared/agent-attention-notification.d.ts.map +1 -0
  46. package/dist/server/shared/agent-attention-notification.js +130 -0
  47. package/dist/server/shared/agent-attention-notification.js.map +1 -0
  48. package/dist/server/shared/messages.d.ts +974 -619
  49. package/dist/server/shared/messages.d.ts.map +1 -1
  50. package/dist/server/shared/messages.js +285 -296
  51. package/dist/server/shared/messages.js.map +1 -1
  52. package/dist/server/utils/checkout-git.d.ts +3 -0
  53. package/dist/server/utils/checkout-git.d.ts.map +1 -1
  54. package/dist/server/utils/checkout-git.js +102 -23
  55. package/dist/server/utils/checkout-git.js.map +1 -1
  56. package/dist/server/utils/directory-suggestions.d.ts +15 -0
  57. package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
  58. package/dist/server/utils/directory-suggestions.js +348 -21
  59. package/dist/server/utils/directory-suggestions.js.map +1 -1
  60. package/dist/server/utils/worktree-metadata.d.ts +4 -4
  61. package/dist/server/utils/worktree.d.ts +1 -0
  62. package/dist/server/utils/worktree.d.ts.map +1 -1
  63. package/dist/server/utils/worktree.js +41 -77
  64. package/dist/server/utils/worktree.js.map +1 -1
  65. package/package.json +5 -5
@@ -1,10 +1,10 @@
1
- import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from "../shared/messages.js";
2
- import { getAgentProviderDefinition } from "../server/agent/provider-manifest.js";
3
- import { isRelayClientWebSocketUrl } from "../shared/daemon-endpoints.js";
4
- import { asUint8Array, decodeBinaryMuxFrame, encodeBinaryMuxFrame, BinaryMuxChannel, TerminalBinaryFlags, TerminalBinaryMessageType, } from "../shared/binary-mux.js";
5
- import { encodeTerminalKeyInput, } from "../shared/terminal-key-input.js";
6
- import { TerminalStreamManager, } from "./daemon-client-terminal-stream-manager.js";
7
- import { createRelayE2eeTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, encodeUtf8String, safeRandomId, } from "./daemon-client-transport.js";
1
+ import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from '../shared/messages.js';
2
+ import { getAgentProviderDefinition } from '../server/agent/provider-manifest.js';
3
+ import { isRelayClientWebSocketUrl } from '../shared/daemon-endpoints.js';
4
+ import { asUint8Array, decodeBinaryMuxFrame, encodeBinaryMuxFrame, BinaryMuxChannel, TerminalBinaryFlags, TerminalBinaryMessageType, } from '../shared/binary-mux.js';
5
+ import { encodeTerminalKeyInput } from '../shared/terminal-key-input.js';
6
+ import { TerminalStreamManager, } from './daemon-client-terminal-stream-manager.js';
7
+ import { createRelayE2eeTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, encodeUtf8String, safeRandomId, } from './daemon-client-transport.js';
8
8
  const consoleLogger = {
9
9
  debug: (obj, msg) => console.debug(msg, obj),
10
10
  info: (obj, msg) => console.info(msg, obj),
@@ -14,7 +14,7 @@ const consoleLogger = {
14
14
  class DaemonRpcError extends Error {
15
15
  constructor(params) {
16
16
  super(params.error);
17
- this.name = "DaemonRpcError";
17
+ this.name = 'DaemonRpcError';
18
18
  this.requestId = params.requestId;
19
19
  this.requestType = params.requestType;
20
20
  this.code = params.code;
@@ -28,7 +28,7 @@ const DEFAULT_DICTATION_FINISH_ACCEPT_TIMEOUT_MS = 15000;
28
28
  const DEFAULT_DICTATION_FINISH_FALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
29
29
  const DEFAULT_DICTATION_FINISH_TIMEOUT_GRACE_MS = 5000;
30
30
  function isWaiterTimeoutError(error) {
31
- return (error instanceof Error && error.message.startsWith("Timeout waiting for message"));
31
+ return error instanceof Error && error.message.startsWith('Timeout waiting for message');
32
32
  }
33
33
  export class DaemonClient {
34
34
  constructor(config) {
@@ -49,8 +49,7 @@ export class DaemonClient {
49
49
  this.connectResolve = null;
50
50
  this.connectReject = null;
51
51
  this.lastErrorValue = null;
52
- this.connectionState = { status: "idle" };
53
- this.agentUpdateSubscriptions = new Map();
52
+ this.connectionState = { status: 'idle' };
54
53
  this.checkoutDiffSubscriptions = new Map();
55
54
  this.terminalDirectorySubscriptions = new Set();
56
55
  this.pendingSendQueue = [];
@@ -73,9 +72,9 @@ export class DaemonClient {
73
72
  if (isRelayClientWebSocketUrl(this.config.url)) {
74
73
  try {
75
74
  const parsed = new URL(this.config.url);
76
- if (!parsed.searchParams.get("clientId")) {
75
+ if (!parsed.searchParams.get('clientId')) {
77
76
  this.relayClientId = `clt_${safeRandomId()}`;
78
- parsed.searchParams.set("clientId", this.relayClientId);
77
+ parsed.searchParams.set('clientId', this.relayClientId);
79
78
  this.config.url = parsed.toString();
80
79
  }
81
80
  }
@@ -88,7 +87,7 @@ export class DaemonClient {
88
87
  // Connection
89
88
  // ============================================================================
90
89
  async connect() {
91
- if (this.connectionState.status === "connected") {
90
+ if (this.connectionState.status === 'connected') {
92
91
  return;
93
92
  }
94
93
  if (this.connectPromise) {
@@ -104,15 +103,15 @@ export class DaemonClient {
104
103
  }
105
104
  attemptConnect() {
106
105
  if (!this.shouldReconnect) {
107
- this.rejectConnect(new Error("Daemon client is closed"));
106
+ this.rejectConnect(new Error('Daemon client is closed'));
108
107
  return;
109
108
  }
110
- if (this.connectionState.status === "connecting") {
109
+ if (this.connectionState.status === 'connecting') {
111
110
  return;
112
111
  }
113
112
  const headers = {};
114
113
  if (this.config.authHeader) {
115
- headers["Authorization"] = this.config.authHeader;
114
+ headers['Authorization'] = this.config.authHeader;
116
115
  }
117
116
  try {
118
117
  // If we reconnect while the previous socket is still open (common in browsers
@@ -122,13 +121,12 @@ export class DaemonClient {
122
121
  this.disposeTransport();
123
122
  const baseTransportFactory = this.config.transportFactory ??
124
123
  createWebSocketTransportFactory(this.config.webSocketFactory ?? defaultWebSocketFactory);
125
- const shouldUseRelayE2ee = this.config.e2ee?.enabled === true &&
126
- isRelayClientWebSocketUrl(this.config.url);
124
+ const shouldUseRelayE2ee = this.config.e2ee?.enabled === true && isRelayClientWebSocketUrl(this.config.url);
127
125
  let transportFactory = baseTransportFactory;
128
126
  if (shouldUseRelayE2ee) {
129
127
  const daemonPublicKeyB64 = this.config.e2ee?.daemonPublicKeyB64;
130
128
  if (!daemonPublicKeyB64) {
131
- throw new Error("daemonPublicKeyB64 is required for relay E2EE");
129
+ throw new Error('daemonPublicKeyB64 is required for relay E2EE');
132
130
  }
133
131
  transportFactory = createRelayE2eeTransportFactory({
134
132
  baseFactory: baseTransportFactory,
@@ -139,7 +137,7 @@ export class DaemonClient {
139
137
  const transport = transportFactory({ url: this.config.url, headers });
140
138
  this.transport = transport;
141
139
  this.updateConnectionState({
142
- status: "connecting",
140
+ status: 'connecting',
143
141
  attempt: this.reconnectAttempt,
144
142
  });
145
143
  this.transportCleanup = [
@@ -150,8 +148,7 @@ export class DaemonClient {
150
148
  }
151
149
  this.lastErrorValue = null;
152
150
  this.reconnectAttempt = 0;
153
- this.updateConnectionState({ status: "connected" });
154
- this.resubscribeAgentUpdates();
151
+ this.updateConnectionState({ status: 'connected' });
155
152
  this.resubscribeCheckoutDiffSubscriptions();
156
153
  this.resubscribeTerminalDirectorySubscriptions();
157
154
  this.flushPendingSendQueue();
@@ -163,10 +160,10 @@ export class DaemonClient {
163
160
  this.pendingGenericTransportErrorTimeout = null;
164
161
  }
165
162
  const closeRecord = event;
166
- const closeCode = closeRecord && typeof closeRecord === "object" && typeof closeRecord.code === "number"
163
+ const closeCode = closeRecord && typeof closeRecord === 'object' && typeof closeRecord.code === 'number'
167
164
  ? closeRecord.code
168
165
  : null;
169
- const closeReason = closeRecord && typeof closeRecord === "object" && typeof closeRecord.reason === "string"
166
+ const closeReason = closeRecord && typeof closeRecord === 'object' && typeof closeRecord.reason === 'string'
170
167
  ? closeRecord.reason
171
168
  : null;
172
169
  const reason = describeTransportClose(event);
@@ -174,7 +171,7 @@ export class DaemonClient {
174
171
  this.lastErrorValue = reason;
175
172
  }
176
173
  this.updateConnectionState({
177
- status: "disconnected",
174
+ status: 'disconnected',
178
175
  ...(reason ? { reason } : {}),
179
176
  });
180
177
  // When connecting over the relay, only one client connection is allowed at a time.
@@ -182,18 +179,18 @@ export class DaemonClient {
182
179
  // connection (which causes flapping where both sides repeatedly replace each other).
183
180
  if (isRelayClientWebSocketUrl(this.config.url) &&
184
181
  closeCode === 1008 &&
185
- (closeReason ?? reason) === "Replaced by new connection") {
182
+ (closeReason ?? reason) === 'Replaced by new connection') {
186
183
  this.shouldReconnect = false;
187
- this.clearWaiters(new Error(reason ?? "Replaced by new connection"));
188
- this.rejectPendingSendQueue(new Error(reason ?? "Replaced by new connection"));
189
- this.rejectConnect(new Error(reason ?? "Replaced by new connection"));
184
+ this.clearWaiters(new Error(reason ?? 'Replaced by new connection'));
185
+ this.rejectPendingSendQueue(new Error(reason ?? 'Replaced by new connection'));
186
+ this.rejectConnect(new Error(reason ?? 'Replaced by new connection'));
190
187
  return;
191
188
  }
192
189
  this.scheduleReconnect(reason);
193
190
  }),
194
191
  transport.onError((event) => {
195
192
  const reason = describeTransportError(event);
196
- const isGeneric = reason === "Transport error";
193
+ const isGeneric = reason === 'Transport error';
197
194
  // Browser WebSocket.onerror often provides no useful details and is followed
198
195
  // by a close event (often with code 1006). Prefer surfacing the close details
199
196
  // instead of immediately disconnecting with a generic "Transport error".
@@ -202,10 +199,10 @@ export class DaemonClient {
202
199
  if (!this.pendingGenericTransportErrorTimeout) {
203
200
  this.pendingGenericTransportErrorTimeout = setTimeout(() => {
204
201
  this.pendingGenericTransportErrorTimeout = null;
205
- if (this.connectionState.status === "connected" ||
206
- this.connectionState.status === "connecting") {
202
+ if (this.connectionState.status === 'connected' ||
203
+ this.connectionState.status === 'connecting') {
207
204
  this.lastErrorValue = reason;
208
- this.updateConnectionState({ status: "disconnected", reason });
205
+ this.updateConnectionState({ status: 'disconnected', reason });
209
206
  this.scheduleReconnect(reason);
210
207
  }
211
208
  }, 250);
@@ -217,14 +214,14 @@ export class DaemonClient {
217
214
  this.pendingGenericTransportErrorTimeout = null;
218
215
  }
219
216
  this.lastErrorValue = reason;
220
- this.updateConnectionState({ status: "disconnected", reason });
217
+ this.updateConnectionState({ status: 'disconnected', reason });
221
218
  this.scheduleReconnect(reason);
222
219
  }),
223
220
  transport.onMessage((data) => this.handleTransportMessage(data)),
224
221
  ];
225
222
  }
226
223
  catch (error) {
227
- const message = error instanceof Error ? error.message : "Failed to connect";
224
+ const message = error instanceof Error ? error.message : 'Failed to connect';
228
225
  this.lastErrorValue = message;
229
226
  this.scheduleReconnect(message);
230
227
  this.rejectConnect(error instanceof Error ? error : new Error(message));
@@ -255,20 +252,20 @@ export class DaemonClient {
255
252
  clearTimeout(this.reconnectTimeout);
256
253
  this.reconnectTimeout = null;
257
254
  }
258
- this.disposeTransport(1000, "Client closed");
259
- this.clearWaiters(new Error("Daemon client closed"));
255
+ this.disposeTransport(1000, 'Client closed');
256
+ this.clearWaiters(new Error('Daemon client closed'));
260
257
  this.terminalStreams.clearAll();
261
258
  this.updateConnectionState({
262
- status: "disconnected",
263
- reason: "client_closed",
259
+ status: 'disconnected',
260
+ reason: 'client_closed',
264
261
  });
265
262
  }
266
263
  ensureConnected() {
267
264
  if (!this.shouldReconnect) {
268
265
  this.shouldReconnect = true;
269
266
  }
270
- if (this.connectionState.status === "connected" ||
271
- this.connectionState.status === "connecting") {
267
+ if (this.connectionState.status === 'connected' ||
268
+ this.connectionState.status === 'connecting') {
272
269
  return;
273
270
  }
274
271
  void this.connect();
@@ -284,10 +281,10 @@ export class DaemonClient {
284
281
  };
285
282
  }
286
283
  get isConnected() {
287
- return this.connectionState.status === "connected";
284
+ return this.connectionState.status === 'connected';
288
285
  }
289
286
  get isConnecting() {
290
- return this.connectionState.status === "connecting";
287
+ return this.connectionState.status === 'connecting';
291
288
  }
292
289
  get lastError() {
293
290
  return this.lastErrorValue;
@@ -306,7 +303,7 @@ export class DaemonClient {
306
303
  };
307
304
  }
308
305
  on(arg1, arg2) {
309
- if (typeof arg1 === "function") {
306
+ if (typeof arg1 === 'function') {
310
307
  return this.subscribe(arg1);
311
308
  }
312
309
  const type = arg1;
@@ -335,7 +332,7 @@ export class DaemonClient {
335
332
  * For RPC methods that wait for responses, use `sendSessionMessageOrThrow` instead.
336
333
  */
337
334
  sendSessionMessage(message) {
338
- if (!this.transport || this.connectionState.status !== "connected") {
335
+ if (!this.transport || this.connectionState.status !== 'connected') {
339
336
  if (this.config.suppressSendErrors) {
340
337
  return;
341
338
  }
@@ -343,7 +340,7 @@ export class DaemonClient {
343
340
  }
344
341
  const payload = SessionInboundMessageSchema.parse(message);
345
342
  try {
346
- this.transport.send(JSON.stringify({ type: "session", message: payload }));
343
+ this.transport.send(JSON.stringify({ type: 'session', message: payload }));
347
344
  }
348
345
  catch (error) {
349
346
  if (this.config.suppressSendErrors) {
@@ -353,7 +350,7 @@ export class DaemonClient {
353
350
  }
354
351
  }
355
352
  sendBinaryFrame(frame) {
356
- if (!this.transport || this.connectionState.status !== "connected") {
353
+ if (!this.transport || this.connectionState.status !== 'connected') {
357
354
  if (this.config.suppressSendErrors) {
358
355
  return;
359
356
  }
@@ -378,13 +375,13 @@ export class DaemonClient {
378
375
  sendSessionMessageOrThrow(message) {
379
376
  const status = this.connectionState.status;
380
377
  // If connected, send immediately
381
- if (this.transport && status === "connected") {
378
+ if (this.transport && status === 'connected') {
382
379
  const payload = SessionInboundMessageSchema.parse(message);
383
- this.transport.send(JSON.stringify({ type: "session", message: payload }));
380
+ this.transport.send(JSON.stringify({ type: 'session', message: payload }));
384
381
  return Promise.resolve();
385
382
  }
386
383
  // If connecting, queue the message to be sent once connected
387
- if (status === "connecting") {
384
+ if (status === 'connecting') {
388
385
  return new Promise((resolve, reject) => {
389
386
  const timeoutHandle = setTimeout(() => {
390
387
  // Remove from queue
@@ -409,13 +406,13 @@ export class DaemonClient {
409
406
  for (const pending of queue) {
410
407
  clearTimeout(pending.timeoutHandle);
411
408
  try {
412
- if (this.transport && this.connectionState.status === "connected") {
409
+ if (this.transport && this.connectionState.status === 'connected') {
413
410
  const payload = SessionInboundMessageSchema.parse(pending.message);
414
- this.transport.send(JSON.stringify({ type: "session", message: payload }));
411
+ this.transport.send(JSON.stringify({ type: 'session', message: payload }));
415
412
  pending.resolve();
416
413
  }
417
414
  else {
418
- pending.reject(new Error("Connection lost before message could be sent"));
415
+ pending.reject(new Error('Connection lost before message could be sent'));
419
416
  }
420
417
  }
421
418
  catch (error) {
@@ -436,9 +433,9 @@ export class DaemonClient {
436
433
  }
437
434
  async sendRequest(params) {
438
435
  const { promise, cancel } = this.waitForWithCancel((msg) => {
439
- if (msg.type === "rpc_error" && msg.payload.requestId === params.requestId) {
436
+ if (msg.type === 'rpc_error' && msg.payload.requestId === params.requestId) {
440
437
  return {
441
- kind: "error",
438
+ kind: 'error',
442
439
  error: new DaemonRpcError({
443
440
  requestId: msg.payload.requestId,
444
441
  error: msg.payload.error,
@@ -451,7 +448,7 @@ export class DaemonClient {
451
448
  if (value === null) {
452
449
  return null;
453
450
  }
454
- return { kind: "ok", value };
451
+ return { kind: 'ok', value };
455
452
  }, params.timeout, params.options);
456
453
  try {
457
454
  await this.sendSessionMessageOrThrow(params.message);
@@ -463,7 +460,7 @@ export class DaemonClient {
463
460
  throw err;
464
461
  }
465
462
  const result = await promise;
466
- if (result.kind === "error") {
463
+ if (result.kind === 'error') {
467
464
  throw result.error;
468
465
  }
469
466
  return result.value;
@@ -506,23 +503,23 @@ export class DaemonClient {
506
503
  });
507
504
  }
508
505
  sendSessionMessageStrict(message) {
509
- if (!this.transport || this.connectionState.status !== "connected") {
510
- throw new Error("Transport not connected");
506
+ if (!this.transport || this.connectionState.status !== 'connected') {
507
+ throw new Error('Transport not connected');
511
508
  }
512
509
  const payload = SessionInboundMessageSchema.parse(message);
513
510
  try {
514
- this.transport.send(JSON.stringify({ type: "session", message: payload }));
511
+ this.transport.send(JSON.stringify({ type: 'session', message: payload }));
515
512
  }
516
513
  catch (error) {
517
514
  throw error instanceof Error ? error : new Error(String(error));
518
515
  }
519
516
  }
520
517
  clearAgentAttention(agentId) {
521
- this.sendSessionMessage({ type: "clear_agent_attention", agentId });
518
+ this.sendSessionMessage({ type: 'clear_agent_attention', agentId });
522
519
  }
523
520
  sendHeartbeat(params) {
524
521
  this.sendSessionMessage({
525
- type: "client_heartbeat",
522
+ type: 'client_heartbeat',
526
523
  deviceType: params.deviceType,
527
524
  focusedAgentId: params.focusedAgentId,
528
525
  lastActivityAt: params.lastActivityAt,
@@ -532,26 +529,25 @@ export class DaemonClient {
532
529
  }
533
530
  registerPushToken(token) {
534
531
  this.sendSessionMessage({
535
- type: "register_push_token",
532
+ type: 'register_push_token',
536
533
  token,
537
534
  });
538
535
  }
539
536
  async ping(params) {
540
- const requestId = params?.requestId ??
541
- `ping-${Date.now()}-${Math.random().toString(36).slice(2)}`;
537
+ const requestId = params?.requestId ?? `ping-${Date.now()}-${Math.random().toString(36).slice(2)}`;
542
538
  const clientSentAt = Date.now();
543
539
  const payload = await this.sendRequest({
544
540
  requestId,
545
- message: { type: "ping", requestId, clientSentAt },
541
+ message: { type: 'ping', requestId, clientSentAt },
546
542
  timeout: params?.timeoutMs ?? 5000,
547
543
  select: (msg) => {
548
- if (msg.type !== "pong")
544
+ if (msg.type !== 'pong')
549
545
  return null;
550
546
  if (msg.payload.requestId !== requestId)
551
547
  return null;
552
- if (typeof msg.payload.serverReceivedAt !== "number")
548
+ if (typeof msg.payload.serverReceivedAt !== 'number')
553
549
  return null;
554
- if (typeof msg.payload.serverSentAt !== "number")
550
+ if (typeof msg.payload.serverSentAt !== 'number')
555
551
  return null;
556
552
  return msg.payload;
557
553
  },
@@ -570,11 +566,12 @@ export class DaemonClient {
570
566
  async fetchAgents(options) {
571
567
  const resolvedRequestId = this.createRequestId(options?.requestId);
572
568
  const message = SessionInboundMessageSchema.parse({
573
- type: "fetch_agents_request",
569
+ type: 'fetch_agents_request',
574
570
  requestId: resolvedRequestId,
575
571
  ...(options?.filter ? { filter: options.filter } : {}),
576
572
  ...(options?.sort ? { sort: options.sort } : {}),
577
573
  ...(options?.page ? { page: options.page } : {}),
574
+ ...(options?.subscribe ? { subscribe: options.subscribe } : {}),
578
575
  });
579
576
  return this.sendRequest({
580
577
  requestId: resolvedRequestId,
@@ -582,7 +579,7 @@ export class DaemonClient {
582
579
  timeout: 10000,
583
580
  options: { skipQueue: true },
584
581
  select: (msg) => {
585
- if (msg.type !== "fetch_agents_response") {
582
+ if (msg.type !== 'fetch_agents_response') {
586
583
  return null;
587
584
  }
588
585
  if (msg.payload.requestId !== resolvedRequestId) {
@@ -595,7 +592,7 @@ export class DaemonClient {
595
592
  async fetchAgent(agentId, requestId) {
596
593
  const resolvedRequestId = this.createRequestId(requestId);
597
594
  const message = SessionInboundMessageSchema.parse({
598
- type: "fetch_agent_request",
595
+ type: 'fetch_agent_request',
599
596
  requestId: resolvedRequestId,
600
597
  agentId,
601
598
  });
@@ -605,7 +602,7 @@ export class DaemonClient {
605
602
  timeout: 10000,
606
603
  options: { skipQueue: true },
607
604
  select: (msg) => {
608
- if (msg.type !== "fetch_agent_response") {
605
+ if (msg.type !== 'fetch_agent_response') {
609
606
  return null;
610
607
  }
611
608
  if (msg.payload.requestId !== resolvedRequestId) {
@@ -619,45 +616,13 @@ export class DaemonClient {
619
616
  }
620
617
  return payload.agent;
621
618
  }
622
- subscribeAgentUpdates(options) {
623
- const subscriptionId = options?.subscriptionId ?? crypto.randomUUID();
624
- this.agentUpdateSubscriptions.set(subscriptionId, options?.filter);
625
- const message = SessionInboundMessageSchema.parse({
626
- type: "subscribe_agent_updates",
627
- subscriptionId,
628
- ...(options?.filter ? { filter: options.filter } : {}),
629
- });
630
- this.sendSessionMessage(message);
631
- return subscriptionId;
632
- }
633
- unsubscribeAgentUpdates(subscriptionId) {
634
- this.agentUpdateSubscriptions.delete(subscriptionId);
635
- const message = SessionInboundMessageSchema.parse({
636
- type: "unsubscribe_agent_updates",
637
- subscriptionId,
638
- });
639
- this.sendSessionMessage(message);
640
- }
641
- resubscribeAgentUpdates() {
642
- if (this.agentUpdateSubscriptions.size === 0) {
643
- return;
644
- }
645
- for (const [subscriptionId, filter] of this.agentUpdateSubscriptions) {
646
- const message = SessionInboundMessageSchema.parse({
647
- type: "subscribe_agent_updates",
648
- subscriptionId,
649
- ...(filter ? { filter } : {}),
650
- });
651
- this.sendSessionMessage(message);
652
- }
653
- }
654
619
  resubscribeCheckoutDiffSubscriptions() {
655
620
  if (this.checkoutDiffSubscriptions.size === 0) {
656
621
  return;
657
622
  }
658
623
  for (const [subscriptionId, subscription] of this.checkoutDiffSubscriptions) {
659
624
  const message = SessionInboundMessageSchema.parse({
660
- type: "subscribe_checkout_diff_request",
625
+ type: 'subscribe_checkout_diff_request',
661
626
  subscriptionId,
662
627
  cwd: subscription.cwd,
663
628
  compare: subscription.compare,
@@ -672,7 +637,7 @@ export class DaemonClient {
672
637
  }
673
638
  for (const cwd of this.terminalDirectorySubscriptions) {
674
639
  this.sendSessionMessage({
675
- type: "subscribe_terminals_request",
640
+ type: 'subscribe_terminals_request',
676
641
  cwd,
677
642
  });
678
643
  }
@@ -684,14 +649,12 @@ export class DaemonClient {
684
649
  const requestId = this.createRequestId(options.requestId);
685
650
  const config = resolveAgentConfig(options);
686
651
  const message = SessionInboundMessageSchema.parse({
687
- type: "create_agent_request",
652
+ type: 'create_agent_request',
688
653
  requestId,
689
654
  config,
690
655
  ...(options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}),
691
656
  ...(options.outputSchema ? { outputSchema: options.outputSchema } : {}),
692
- ...(options.images && options.images.length > 0
693
- ? { images: options.images }
694
- : {}),
657
+ ...(options.images && options.images.length > 0 ? { images: options.images } : {}),
695
658
  ...(options.git ? { git: options.git } : {}),
696
659
  ...(options.worktreeName ? { worktreeName: options.worktreeName } : {}),
697
660
  ...(options.labels && Object.keys(options.labels).length > 0
@@ -704,7 +667,7 @@ export class DaemonClient {
704
667
  timeout: 15000,
705
668
  options: { skipQueue: true },
706
669
  select: (msg) => {
707
- if (msg.type !== "status") {
670
+ if (msg.type !== 'status') {
708
671
  return null;
709
672
  }
710
673
  const created = AgentCreatedStatusPayloadSchema.safeParse(msg.payload);
@@ -718,7 +681,7 @@ export class DaemonClient {
718
681
  return null;
719
682
  },
720
683
  });
721
- if (status.status === "agent_create_failed") {
684
+ if (status.status === 'agent_create_failed') {
722
685
  throw new Error(status.error);
723
686
  }
724
687
  return status.agent;
@@ -726,7 +689,7 @@ export class DaemonClient {
726
689
  async deleteAgent(agentId) {
727
690
  const requestId = this.createRequestId();
728
691
  const message = SessionInboundMessageSchema.parse({
729
- type: "delete_agent_request",
692
+ type: 'delete_agent_request',
730
693
  agentId,
731
694
  requestId,
732
695
  });
@@ -736,7 +699,7 @@ export class DaemonClient {
736
699
  timeout: 10000,
737
700
  options: { skipQueue: true },
738
701
  select: (msg) => {
739
- if (msg.type !== "agent_deleted") {
702
+ if (msg.type !== 'agent_deleted') {
740
703
  return null;
741
704
  }
742
705
  if (msg.payload.requestId !== requestId) {
@@ -749,7 +712,7 @@ export class DaemonClient {
749
712
  async archiveAgent(agentId) {
750
713
  const requestId = this.createRequestId();
751
714
  const message = SessionInboundMessageSchema.parse({
752
- type: "archive_agent_request",
715
+ type: 'archive_agent_request',
753
716
  agentId,
754
717
  requestId,
755
718
  });
@@ -759,7 +722,7 @@ export class DaemonClient {
759
722
  timeout: 10000,
760
723
  options: { skipQueue: true },
761
724
  select: (msg) => {
762
- if (msg.type !== "agent_archived") {
725
+ if (msg.type !== 'agent_archived') {
763
726
  return null;
764
727
  }
765
728
  if (msg.payload.requestId !== requestId) {
@@ -773,7 +736,7 @@ export class DaemonClient {
773
736
  async updateAgent(agentId, updates) {
774
737
  const requestId = this.createRequestId();
775
738
  const message = SessionInboundMessageSchema.parse({
776
- type: "update_agent_request",
739
+ type: 'update_agent_request',
777
740
  agentId,
778
741
  ...(updates.name !== undefined ? { name: updates.name } : {}),
779
742
  ...(updates.labels && Object.keys(updates.labels).length > 0
@@ -787,7 +750,7 @@ export class DaemonClient {
787
750
  timeout: 10000,
788
751
  options: { skipQueue: true },
789
752
  select: (msg) => {
790
- if (msg.type !== "update_agent_response") {
753
+ if (msg.type !== 'update_agent_response') {
791
754
  return null;
792
755
  }
793
756
  if (msg.payload.requestId !== requestId) {
@@ -797,13 +760,13 @@ export class DaemonClient {
797
760
  },
798
761
  });
799
762
  if (!payload.accepted) {
800
- throw new Error(payload.error ?? "updateAgent rejected");
763
+ throw new Error(payload.error ?? 'updateAgent rejected');
801
764
  }
802
765
  }
803
766
  async resumeAgent(handle, overrides) {
804
767
  const requestId = this.createRequestId();
805
768
  const message = SessionInboundMessageSchema.parse({
806
- type: "resume_agent_request",
769
+ type: 'resume_agent_request',
807
770
  requestId,
808
771
  handle,
809
772
  ...(overrides ? { overrides } : {}),
@@ -814,7 +777,7 @@ export class DaemonClient {
814
777
  timeout: 15000,
815
778
  options: { skipQueue: true },
816
779
  select: (msg) => {
817
- if (msg.type !== "status") {
780
+ if (msg.type !== 'status') {
818
781
  return null;
819
782
  }
820
783
  const resumed = AgentResumedStatusPayloadSchema.safeParse(msg.payload);
@@ -829,7 +792,7 @@ export class DaemonClient {
829
792
  async refreshAgent(agentId, requestId) {
830
793
  const resolvedRequestId = this.createRequestId(requestId);
831
794
  const message = SessionInboundMessageSchema.parse({
832
- type: "refresh_agent_request",
795
+ type: 'refresh_agent_request',
833
796
  agentId,
834
797
  requestId: resolvedRequestId,
835
798
  });
@@ -839,7 +802,7 @@ export class DaemonClient {
839
802
  timeout: 15000,
840
803
  options: { skipQueue: true },
841
804
  select: (msg) => {
842
- if (msg.type !== "status") {
805
+ if (msg.type !== 'status') {
843
806
  return null;
844
807
  }
845
808
  const refreshed = AgentRefreshedStatusPayloadSchema.safeParse(msg.payload);
@@ -853,12 +816,12 @@ export class DaemonClient {
853
816
  async fetchAgentTimeline(agentId, options = {}) {
854
817
  const resolvedRequestId = this.createRequestId(options.requestId);
855
818
  const message = SessionInboundMessageSchema.parse({
856
- type: "fetch_agent_timeline_request",
819
+ type: 'fetch_agent_timeline_request',
857
820
  agentId,
858
821
  requestId: resolvedRequestId,
859
822
  ...(options.direction ? { direction: options.direction } : {}),
860
823
  ...(options.cursor ? { cursor: options.cursor } : {}),
861
- ...(typeof options.limit === "number" ? { limit: options.limit } : {}),
824
+ ...(typeof options.limit === 'number' ? { limit: options.limit } : {}),
862
825
  ...(options.projection ? { projection: options.projection } : {}),
863
826
  });
864
827
  const payload = await this.sendRequest({
@@ -867,7 +830,7 @@ export class DaemonClient {
867
830
  timeout: 15000,
868
831
  options: { skipQueue: true },
869
832
  select: (msg) => {
870
- if (msg.type !== "fetch_agent_timeline_response") {
833
+ if (msg.type !== 'fetch_agent_timeline_response') {
871
834
  return null;
872
835
  }
873
836
  if (msg.payload.requestId !== resolvedRequestId) {
@@ -888,7 +851,7 @@ export class DaemonClient {
888
851
  const requestId = this.createRequestId();
889
852
  const messageId = options?.messageId ?? crypto.randomUUID();
890
853
  const message = SessionInboundMessageSchema.parse({
891
- type: "send_agent_message_request",
854
+ type: 'send_agent_message_request',
892
855
  requestId,
893
856
  agentId,
894
857
  text,
@@ -901,7 +864,7 @@ export class DaemonClient {
901
864
  timeout: 15000,
902
865
  options: { skipQueue: true },
903
866
  select: (msg) => {
904
- if (msg.type !== "send_agent_message_response") {
867
+ if (msg.type !== 'send_agent_message_response') {
905
868
  return null;
906
869
  }
907
870
  if (msg.payload.requestId !== requestId) {
@@ -911,19 +874,19 @@ export class DaemonClient {
911
874
  },
912
875
  });
913
876
  if (!payload.accepted) {
914
- throw new Error(payload.error ?? "sendAgentMessage rejected");
877
+ throw new Error(payload.error ?? 'sendAgentMessage rejected');
915
878
  }
916
879
  }
917
880
  async sendMessage(agentId, text, options) {
918
881
  await this.sendAgentMessage(agentId, text, options);
919
882
  }
920
883
  async cancelAgent(agentId) {
921
- this.sendSessionMessage({ type: "cancel_agent_request", agentId });
884
+ this.sendSessionMessage({ type: 'cancel_agent_request', agentId });
922
885
  }
923
886
  async setAgentMode(agentId, modeId) {
924
887
  const requestId = this.createRequestId();
925
888
  const message = SessionInboundMessageSchema.parse({
926
- type: "set_agent_mode_request",
889
+ type: 'set_agent_mode_request',
927
890
  agentId,
928
891
  modeId,
929
892
  requestId,
@@ -934,7 +897,7 @@ export class DaemonClient {
934
897
  timeout: 15000,
935
898
  options: { skipQueue: true },
936
899
  select: (msg) => {
937
- if (msg.type !== "set_agent_mode_response") {
900
+ if (msg.type !== 'set_agent_mode_response') {
938
901
  return null;
939
902
  }
940
903
  if (msg.payload.requestId !== requestId) {
@@ -944,13 +907,13 @@ export class DaemonClient {
944
907
  },
945
908
  });
946
909
  if (!payload.accepted) {
947
- throw new Error(payload.error ?? "setAgentMode rejected");
910
+ throw new Error(payload.error ?? 'setAgentMode rejected');
948
911
  }
949
912
  }
950
913
  async setAgentModel(agentId, modelId) {
951
914
  const requestId = this.createRequestId();
952
915
  const message = SessionInboundMessageSchema.parse({
953
- type: "set_agent_model_request",
916
+ type: 'set_agent_model_request',
954
917
  agentId,
955
918
  modelId,
956
919
  requestId,
@@ -961,7 +924,7 @@ export class DaemonClient {
961
924
  timeout: 15000,
962
925
  options: { skipQueue: true },
963
926
  select: (msg) => {
964
- if (msg.type !== "set_agent_model_response") {
927
+ if (msg.type !== 'set_agent_model_response') {
965
928
  return null;
966
929
  }
967
930
  if (msg.payload.requestId !== requestId) {
@@ -971,13 +934,13 @@ export class DaemonClient {
971
934
  },
972
935
  });
973
936
  if (!payload.accepted) {
974
- throw new Error(payload.error ?? "setAgentModel rejected");
937
+ throw new Error(payload.error ?? 'setAgentModel rejected');
975
938
  }
976
939
  }
977
940
  async setAgentThinkingOption(agentId, thinkingOptionId) {
978
941
  const requestId = this.createRequestId();
979
942
  const message = SessionInboundMessageSchema.parse({
980
- type: "set_agent_thinking_request",
943
+ type: 'set_agent_thinking_request',
981
944
  agentId,
982
945
  thinkingOptionId,
983
946
  requestId,
@@ -988,7 +951,7 @@ export class DaemonClient {
988
951
  timeout: 15000,
989
952
  options: { skipQueue: true },
990
953
  select: (msg) => {
991
- if (msg.type !== "set_agent_thinking_response") {
954
+ if (msg.type !== 'set_agent_thinking_response') {
992
955
  return null;
993
956
  }
994
957
  if (msg.payload.requestId !== requestId) {
@@ -998,13 +961,13 @@ export class DaemonClient {
998
961
  },
999
962
  });
1000
963
  if (!payload.accepted) {
1001
- throw new Error(payload.error ?? "setAgentThinkingOption rejected");
964
+ throw new Error(payload.error ?? 'setAgentThinkingOption rejected');
1002
965
  }
1003
966
  }
1004
967
  async restartServer(reason, requestId) {
1005
968
  const resolvedRequestId = this.createRequestId(requestId);
1006
969
  const message = SessionInboundMessageSchema.parse({
1007
- type: "restart_server_request",
970
+ type: 'restart_server_request',
1008
971
  ...(reason && reason.trim().length > 0 ? { reason } : {}),
1009
972
  requestId: resolvedRequestId,
1010
973
  });
@@ -1014,7 +977,7 @@ export class DaemonClient {
1014
977
  timeout: 10000,
1015
978
  options: { skipQueue: true },
1016
979
  select: (msg) => {
1017
- if (msg.type !== "status") {
980
+ if (msg.type !== 'status') {
1018
981
  return null;
1019
982
  }
1020
983
  const restarted = RestartRequestedStatusPayloadSchema.safeParse(msg.payload);
@@ -1034,7 +997,7 @@ export class DaemonClient {
1034
997
  async setVoiceMode(enabled, agentId) {
1035
998
  const requestId = this.createRequestId();
1036
999
  const message = SessionInboundMessageSchema.parse({
1037
- type: "set_voice_mode",
1000
+ type: 'set_voice_mode',
1038
1001
  enabled,
1039
1002
  ...(agentId ? { agentId } : {}),
1040
1003
  requestId,
@@ -1044,7 +1007,7 @@ export class DaemonClient {
1044
1007
  message,
1045
1008
  timeout: 10000,
1046
1009
  select: (msg) => {
1047
- if (msg.type !== "set_voice_mode_response") {
1010
+ if (msg.type !== 'set_voice_mode_response') {
1048
1011
  return null;
1049
1012
  }
1050
1013
  if (msg.payload.requestId !== requestId) {
@@ -1054,19 +1017,19 @@ export class DaemonClient {
1054
1017
  },
1055
1018
  });
1056
1019
  if (!response.accepted) {
1057
- const codeSuffix = typeof response.reasonCode === "string" && response.reasonCode.trim().length > 0
1020
+ const codeSuffix = typeof response.reasonCode === 'string' && response.reasonCode.trim().length > 0
1058
1021
  ? ` (${response.reasonCode})`
1059
- : "";
1060
- throw new Error((response.error ?? "Failed to set voice mode") + codeSuffix);
1022
+ : '';
1023
+ throw new Error((response.error ?? 'Failed to set voice mode') + codeSuffix);
1061
1024
  }
1062
1025
  return response;
1063
1026
  }
1064
1027
  async sendVoiceAudioChunk(audio, format, isLast) {
1065
- this.sendSessionMessage({ type: "voice_audio_chunk", audio, format, isLast });
1028
+ this.sendSessionMessage({ type: 'voice_audio_chunk', audio, format, isLast });
1066
1029
  }
1067
1030
  async startDictationStream(dictationId, format) {
1068
1031
  const ack = this.waitForWithCancel((msg) => {
1069
- if (msg.type !== "dictation_stream_ack") {
1032
+ if (msg.type !== 'dictation_stream_ack') {
1070
1033
  return null;
1071
1034
  }
1072
1035
  if (msg.payload.dictationId !== dictationId) {
@@ -1079,7 +1042,7 @@ export class DaemonClient {
1079
1042
  }, 30000, { skipQueue: true });
1080
1043
  const ackPromise = ack.promise.then(() => undefined);
1081
1044
  const streamError = this.waitForWithCancel((msg) => {
1082
- if (msg.type !== "dictation_stream_error") {
1045
+ if (msg.type !== 'dictation_stream_error') {
1083
1046
  return null;
1084
1047
  }
1085
1048
  if (msg.payload.dictationId !== dictationId) {
@@ -1090,9 +1053,9 @@ export class DaemonClient {
1090
1053
  const errorPromise = streamError.promise.then((payload) => {
1091
1054
  throw new Error(payload.error);
1092
1055
  });
1093
- const cleanupError = new Error("Cancelled dictation start waiter");
1056
+ const cleanupError = new Error('Cancelled dictation start waiter');
1094
1057
  try {
1095
- this.sendSessionMessageStrict({ type: "dictation_stream_start", dictationId, format });
1058
+ this.sendSessionMessageStrict({ type: 'dictation_stream_start', dictationId, format });
1096
1059
  await Promise.race([ackPromise, errorPromise]);
1097
1060
  }
1098
1061
  finally {
@@ -1103,11 +1066,17 @@ export class DaemonClient {
1103
1066
  }
1104
1067
  }
1105
1068
  sendDictationStreamChunk(dictationId, seq, audio, format) {
1106
- this.sendSessionMessageStrict({ type: "dictation_stream_chunk", dictationId, seq, audio, format });
1069
+ this.sendSessionMessageStrict({
1070
+ type: 'dictation_stream_chunk',
1071
+ dictationId,
1072
+ seq,
1073
+ audio,
1074
+ format,
1075
+ });
1107
1076
  }
1108
1077
  async finishDictationStream(dictationId, finalSeq) {
1109
1078
  const final = this.waitForWithCancel((msg) => {
1110
- if (msg.type !== "dictation_stream_final") {
1079
+ if (msg.type !== 'dictation_stream_final') {
1111
1080
  return null;
1112
1081
  }
1113
1082
  if (msg.payload.dictationId !== dictationId) {
@@ -1116,7 +1085,7 @@ export class DaemonClient {
1116
1085
  return msg.payload;
1117
1086
  }, 0, { skipQueue: true });
1118
1087
  const streamError = this.waitForWithCancel((msg) => {
1119
- if (msg.type !== "dictation_stream_error") {
1088
+ if (msg.type !== 'dictation_stream_error') {
1120
1089
  return null;
1121
1090
  }
1122
1091
  if (msg.payload.dictationId !== dictationId) {
@@ -1125,7 +1094,7 @@ export class DaemonClient {
1125
1094
  return msg.payload;
1126
1095
  }, 0, { skipQueue: true });
1127
1096
  const finishAccepted = this.waitForWithCancel((msg) => {
1128
- if (msg.type !== "dictation_stream_finish_accepted") {
1097
+ if (msg.type !== 'dictation_stream_finish_accepted') {
1129
1098
  return null;
1130
1099
  }
1131
1100
  if (msg.payload.dictationId !== dictationId) {
@@ -1139,68 +1108,64 @@ export class DaemonClient {
1139
1108
  });
1140
1109
  const finishAcceptedPromise = finishAccepted.promise;
1141
1110
  const finalOutcomePromise = finalPromise.then((payload) => ({
1142
- kind: "final",
1111
+ kind: 'final',
1143
1112
  payload,
1144
1113
  }));
1145
1114
  const errorOutcomePromise = errorPromise.then(() => ({
1146
- kind: "error",
1147
- error: new Error("Unexpected dictation stream error state"),
1115
+ kind: 'error',
1116
+ error: new Error('Unexpected dictation stream error state'),
1148
1117
  }), (error) => ({
1149
- kind: "error",
1118
+ kind: 'error',
1150
1119
  error: error instanceof Error ? error : new Error(String(error)),
1151
1120
  }));
1152
- const finishAcceptedOutcomePromise = finishAcceptedPromise.then((payload) => ({ kind: "accepted", payload }), (error) => {
1121
+ const finishAcceptedOutcomePromise = finishAcceptedPromise.then((payload) => ({ kind: 'accepted', payload }), (error) => {
1153
1122
  if (isWaiterTimeoutError(error)) {
1154
- return { kind: "accepted_timeout" };
1123
+ return { kind: 'accepted_timeout' };
1155
1124
  }
1156
1125
  return {
1157
- kind: "accepted_error",
1126
+ kind: 'accepted_error',
1158
1127
  error: error instanceof Error ? error : new Error(String(error)),
1159
1128
  };
1160
1129
  });
1161
1130
  const waitForFinalResult = async (timeoutMs) => {
1162
1131
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
1163
1132
  const outcome = await Promise.race([finalOutcomePromise, errorOutcomePromise]);
1164
- if (outcome.kind === "error") {
1133
+ if (outcome.kind === 'error') {
1165
1134
  throw outcome.error;
1166
1135
  }
1167
1136
  return outcome.payload;
1168
1137
  }
1169
1138
  let timeoutHandle = null;
1170
1139
  const timeoutPromise = new Promise((resolve) => {
1171
- timeoutHandle = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs);
1140
+ timeoutHandle = setTimeout(() => resolve({ kind: 'timeout' }), timeoutMs);
1172
1141
  });
1173
- const outcome = await Promise.race([
1174
- finalOutcomePromise,
1175
- errorOutcomePromise,
1176
- timeoutPromise,
1177
- ]);
1142
+ const outcome = await Promise.race([finalOutcomePromise, errorOutcomePromise, timeoutPromise]);
1178
1143
  if (timeoutHandle) {
1179
1144
  clearTimeout(timeoutHandle);
1180
1145
  }
1181
- if (outcome.kind === "timeout") {
1146
+ if (outcome.kind === 'timeout') {
1182
1147
  throw new Error(`Timeout waiting for dictation finalization (${timeoutMs}ms)`);
1183
1148
  }
1184
- if (outcome.kind === "error") {
1149
+ if (outcome.kind === 'error') {
1185
1150
  throw outcome.error;
1186
1151
  }
1187
1152
  return outcome.payload;
1188
1153
  };
1189
- const cleanupError = new Error("Cancelled dictation finish waiter");
1154
+ const cleanupError = new Error('Cancelled dictation finish waiter');
1190
1155
  try {
1191
- this.sendSessionMessageStrict({ type: "dictation_stream_finish", dictationId, finalSeq });
1156
+ this.sendSessionMessageStrict({ type: 'dictation_stream_finish', dictationId, finalSeq });
1192
1157
  const firstOutcome = await Promise.race([
1193
1158
  finalOutcomePromise,
1194
1159
  errorOutcomePromise,
1195
1160
  finishAcceptedOutcomePromise,
1196
1161
  ]);
1197
- if (firstOutcome.kind === "final") {
1162
+ if (firstOutcome.kind === 'final') {
1198
1163
  return firstOutcome.payload;
1199
1164
  }
1200
- if (firstOutcome.kind === "error") {
1165
+ if (firstOutcome.kind === 'error') {
1201
1166
  throw firstOutcome.error;
1202
1167
  }
1203
- if (firstOutcome.kind === "accepted") {
1168
+ if (firstOutcome.kind === 'accepted') {
1204
1169
  return await waitForFinalResult(firstOutcome.payload.timeoutMs + DEFAULT_DICTATION_FINISH_TIMEOUT_GRACE_MS);
1205
1170
  }
1206
1171
  return await waitForFinalResult(DEFAULT_DICTATION_FINISH_FALLBACK_TIMEOUT_MS);
@@ -1215,13 +1180,13 @@ export class DaemonClient {
1215
1180
  }
1216
1181
  }
1217
1182
  cancelDictationStream(dictationId) {
1218
- this.sendSessionMessageStrict({ type: "dictation_stream_cancel", dictationId });
1183
+ this.sendSessionMessageStrict({ type: 'dictation_stream_cancel', dictationId });
1219
1184
  }
1220
1185
  async abortRequest() {
1221
- this.sendSessionMessage({ type: "abort_request" });
1186
+ this.sendSessionMessage({ type: 'abort_request' });
1222
1187
  }
1223
1188
  async audioPlayed(id) {
1224
- this.sendSessionMessage({ type: "audio_played", id });
1189
+ this.sendSessionMessage({ type: 'audio_played', id });
1225
1190
  }
1226
1191
  // ============================================================================
1227
1192
  // Git Operations
@@ -1236,7 +1201,7 @@ export class DaemonClient {
1236
1201
  }
1237
1202
  const resolvedRequestId = this.createRequestId(requestId);
1238
1203
  const message = SessionInboundMessageSchema.parse({
1239
- type: "checkout_status_request",
1204
+ type: 'checkout_status_request',
1240
1205
  cwd,
1241
1206
  requestId: resolvedRequestId,
1242
1207
  });
@@ -1246,7 +1211,7 @@ export class DaemonClient {
1246
1211
  timeout: 60000,
1247
1212
  options: { skipQueue: true },
1248
1213
  select: (msg) => {
1249
- if (msg.type !== "checkout_status_response") {
1214
+ if (msg.type !== 'checkout_status_response') {
1250
1215
  return null;
1251
1216
  }
1252
1217
  if (msg.payload.requestId !== resolvedRequestId) {
@@ -1268,14 +1233,14 @@ export class DaemonClient {
1268
1233
  return responsePromise;
1269
1234
  }
1270
1235
  normalizeCheckoutDiffCompare(compare) {
1271
- if (compare.mode === "uncommitted") {
1272
- return { mode: "uncommitted" };
1236
+ if (compare.mode === 'uncommitted') {
1237
+ return { mode: 'uncommitted' };
1273
1238
  }
1274
1239
  const trimmedBaseRef = compare.baseRef?.trim();
1275
1240
  if (!trimmedBaseRef) {
1276
- return { mode: "base" };
1241
+ return { mode: 'base' };
1277
1242
  }
1278
- return { mode: "base", baseRef: trimmedBaseRef };
1243
+ return { mode: 'base', baseRef: trimmedBaseRef };
1279
1244
  }
1280
1245
  async getCheckoutDiff(cwd, compare, requestId) {
1281
1246
  const oneShotSubscriptionId = `oneshot-checkout-diff:${crypto.randomUUID()}`;
@@ -1310,7 +1275,7 @@ export class DaemonClient {
1310
1275
  });
1311
1276
  const resolvedRequestId = this.createRequestId(options?.requestId);
1312
1277
  const message = SessionInboundMessageSchema.parse({
1313
- type: "subscribe_checkout_diff_request",
1278
+ type: 'subscribe_checkout_diff_request',
1314
1279
  subscriptionId,
1315
1280
  cwd,
1316
1281
  compare: normalizedCompare,
@@ -1320,7 +1285,7 @@ export class DaemonClient {
1320
1285
  return await this.sendCorrelatedRequest({
1321
1286
  requestId: resolvedRequestId,
1322
1287
  message,
1323
- responseType: "subscribe_checkout_diff_response",
1288
+ responseType: 'subscribe_checkout_diff_response',
1324
1289
  timeout: 60000,
1325
1290
  options: { skipQueue: true },
1326
1291
  selectPayload: (payload) => {
@@ -1344,7 +1309,7 @@ export class DaemonClient {
1344
1309
  unsubscribeCheckoutDiff(subscriptionId) {
1345
1310
  this.checkoutDiffSubscriptions.delete(subscriptionId);
1346
1311
  this.sendSessionMessage({
1347
- type: "unsubscribe_checkout_diff_request",
1312
+ type: 'unsubscribe_checkout_diff_request',
1348
1313
  subscriptionId,
1349
1314
  });
1350
1315
  }
@@ -1352,12 +1317,12 @@ export class DaemonClient {
1352
1317
  return this.sendCorrelatedSessionRequest({
1353
1318
  requestId,
1354
1319
  message: {
1355
- type: "checkout_commit_request",
1320
+ type: 'checkout_commit_request',
1356
1321
  cwd,
1357
1322
  message: input.message,
1358
1323
  addAll: input.addAll,
1359
1324
  },
1360
- responseType: "checkout_commit_response",
1325
+ responseType: 'checkout_commit_response',
1361
1326
  timeout: 60000,
1362
1327
  });
1363
1328
  }
@@ -1365,13 +1330,13 @@ export class DaemonClient {
1365
1330
  return this.sendCorrelatedSessionRequest({
1366
1331
  requestId,
1367
1332
  message: {
1368
- type: "checkout_merge_request",
1333
+ type: 'checkout_merge_request',
1369
1334
  cwd,
1370
1335
  baseRef: input.baseRef,
1371
1336
  strategy: input.strategy,
1372
1337
  requireCleanTarget: input.requireCleanTarget,
1373
1338
  },
1374
- responseType: "checkout_merge_response",
1339
+ responseType: 'checkout_merge_response',
1375
1340
  timeout: 60000,
1376
1341
  });
1377
1342
  }
@@ -1379,12 +1344,12 @@ export class DaemonClient {
1379
1344
  return this.sendCorrelatedSessionRequest({
1380
1345
  requestId,
1381
1346
  message: {
1382
- type: "checkout_merge_from_base_request",
1347
+ type: 'checkout_merge_from_base_request',
1383
1348
  cwd,
1384
1349
  baseRef: input.baseRef,
1385
1350
  requireCleanTarget: input.requireCleanTarget,
1386
1351
  },
1387
- responseType: "checkout_merge_from_base_response",
1352
+ responseType: 'checkout_merge_from_base_response',
1388
1353
  timeout: 60000,
1389
1354
  });
1390
1355
  }
@@ -1392,10 +1357,10 @@ export class DaemonClient {
1392
1357
  return this.sendCorrelatedSessionRequest({
1393
1358
  requestId,
1394
1359
  message: {
1395
- type: "checkout_push_request",
1360
+ type: 'checkout_push_request',
1396
1361
  cwd,
1397
1362
  },
1398
- responseType: "checkout_push_response",
1363
+ responseType: 'checkout_push_response',
1399
1364
  timeout: 60000,
1400
1365
  });
1401
1366
  }
@@ -1403,13 +1368,13 @@ export class DaemonClient {
1403
1368
  return this.sendCorrelatedSessionRequest({
1404
1369
  requestId,
1405
1370
  message: {
1406
- type: "checkout_pr_create_request",
1371
+ type: 'checkout_pr_create_request',
1407
1372
  cwd,
1408
1373
  title: input.title,
1409
1374
  body: input.body,
1410
1375
  baseRef: input.baseRef,
1411
1376
  },
1412
- responseType: "checkout_pr_create_response",
1377
+ responseType: 'checkout_pr_create_response',
1413
1378
  timeout: 60000,
1414
1379
  });
1415
1380
  }
@@ -1417,10 +1382,10 @@ export class DaemonClient {
1417
1382
  return this.sendCorrelatedSessionRequest({
1418
1383
  requestId,
1419
1384
  message: {
1420
- type: "checkout_pr_status_request",
1385
+ type: 'checkout_pr_status_request',
1421
1386
  cwd,
1422
1387
  },
1423
- responseType: "checkout_pr_status_response",
1388
+ responseType: 'checkout_pr_status_response',
1424
1389
  timeout: 60000,
1425
1390
  });
1426
1391
  }
@@ -1428,11 +1393,11 @@ export class DaemonClient {
1428
1393
  return this.sendCorrelatedSessionRequest({
1429
1394
  requestId,
1430
1395
  message: {
1431
- type: "paseo_worktree_list_request",
1396
+ type: 'paseo_worktree_list_request',
1432
1397
  cwd: input.cwd,
1433
1398
  repoRoot: input.repoRoot,
1434
1399
  },
1435
- responseType: "paseo_worktree_list_response",
1400
+ responseType: 'paseo_worktree_list_response',
1436
1401
  timeout: 60000,
1437
1402
  });
1438
1403
  }
@@ -1440,12 +1405,12 @@ export class DaemonClient {
1440
1405
  return this.sendCorrelatedSessionRequest({
1441
1406
  requestId,
1442
1407
  message: {
1443
- type: "paseo_worktree_archive_request",
1408
+ type: 'paseo_worktree_archive_request',
1444
1409
  worktreePath: input.worktreePath,
1445
1410
  repoRoot: input.repoRoot,
1446
1411
  branchName: input.branchName,
1447
1412
  },
1448
- responseType: "paseo_worktree_archive_response",
1413
+ responseType: 'paseo_worktree_archive_response',
1449
1414
  timeout: 20000,
1450
1415
  });
1451
1416
  }
@@ -1453,11 +1418,11 @@ export class DaemonClient {
1453
1418
  return this.sendCorrelatedSessionRequest({
1454
1419
  requestId,
1455
1420
  message: {
1456
- type: "validate_branch_request",
1421
+ type: 'validate_branch_request',
1457
1422
  cwd: options.cwd,
1458
1423
  branchName: options.branchName,
1459
1424
  },
1460
- responseType: "validate_branch_response",
1425
+ responseType: 'validate_branch_response',
1461
1426
  timeout: 10000,
1462
1427
  });
1463
1428
  }
@@ -1465,12 +1430,12 @@ export class DaemonClient {
1465
1430
  return this.sendCorrelatedSessionRequest({
1466
1431
  requestId,
1467
1432
  message: {
1468
- type: "branch_suggestions_request",
1433
+ type: 'branch_suggestions_request',
1469
1434
  cwd: options.cwd,
1470
1435
  query: options.query,
1471
1436
  limit: options.limit,
1472
1437
  },
1473
- responseType: "branch_suggestions_response",
1438
+ responseType: 'branch_suggestions_response',
1474
1439
  timeout: 10000,
1475
1440
  });
1476
1441
  }
@@ -1478,27 +1443,30 @@ export class DaemonClient {
1478
1443
  return this.sendCorrelatedSessionRequest({
1479
1444
  requestId,
1480
1445
  message: {
1481
- type: "directory_suggestions_request",
1446
+ type: 'directory_suggestions_request',
1482
1447
  query: options.query,
1448
+ cwd: options.cwd,
1449
+ includeFiles: options.includeFiles,
1450
+ includeDirectories: options.includeDirectories,
1483
1451
  limit: options.limit,
1484
1452
  },
1485
- responseType: "directory_suggestions_response",
1453
+ responseType: 'directory_suggestions_response',
1486
1454
  timeout: 10000,
1487
1455
  });
1488
1456
  }
1489
1457
  // ============================================================================
1490
1458
  // File Explorer
1491
1459
  // ============================================================================
1492
- async exploreFileSystem(agentId, path, mode = "list", requestId) {
1460
+ async exploreFileSystem(agentId, path, mode = 'list', requestId) {
1493
1461
  return this.sendCorrelatedSessionRequest({
1494
1462
  requestId,
1495
1463
  message: {
1496
- type: "file_explorer_request",
1464
+ type: 'file_explorer_request',
1497
1465
  agentId,
1498
1466
  path,
1499
1467
  mode,
1500
1468
  },
1501
- responseType: "file_explorer_response",
1469
+ responseType: 'file_explorer_response',
1502
1470
  timeout: 10000,
1503
1471
  });
1504
1472
  }
@@ -1506,11 +1474,11 @@ export class DaemonClient {
1506
1474
  return this.sendCorrelatedSessionRequest({
1507
1475
  requestId,
1508
1476
  message: {
1509
- type: "file_download_token_request",
1477
+ type: 'file_download_token_request',
1510
1478
  agentId,
1511
1479
  path,
1512
1480
  },
1513
- responseType: "file_download_token_response",
1481
+ responseType: 'file_download_token_response',
1514
1482
  timeout: 10000,
1515
1483
  });
1516
1484
  }
@@ -1518,10 +1486,10 @@ export class DaemonClient {
1518
1486
  return this.sendCorrelatedSessionRequest({
1519
1487
  requestId,
1520
1488
  message: {
1521
- type: "project_icon_request",
1489
+ type: 'project_icon_request',
1522
1490
  cwd,
1523
1491
  },
1524
- responseType: "project_icon_response",
1492
+ responseType: 'project_icon_response',
1525
1493
  timeout: 10000,
1526
1494
  });
1527
1495
  }
@@ -1532,11 +1500,11 @@ export class DaemonClient {
1532
1500
  return this.sendCorrelatedSessionRequest({
1533
1501
  requestId: options?.requestId,
1534
1502
  message: {
1535
- type: "list_provider_models_request",
1503
+ type: 'list_provider_models_request',
1536
1504
  provider,
1537
1505
  cwd: options?.cwd,
1538
1506
  },
1539
- responseType: "list_provider_models_response",
1507
+ responseType: 'list_provider_models_response',
1540
1508
  timeout: 30000,
1541
1509
  });
1542
1510
  }
@@ -1544,9 +1512,9 @@ export class DaemonClient {
1544
1512
  return this.sendCorrelatedSessionRequest({
1545
1513
  requestId: options?.requestId,
1546
1514
  message: {
1547
- type: "list_available_providers_request",
1515
+ type: 'list_available_providers_request',
1548
1516
  },
1549
- responseType: "list_available_providers_response",
1517
+ responseType: 'list_available_providers_response',
1550
1518
  timeout: 30000,
1551
1519
  });
1552
1520
  }
@@ -1554,9 +1522,9 @@ export class DaemonClient {
1554
1522
  return this.sendCorrelatedSessionRequest({
1555
1523
  requestId,
1556
1524
  message: {
1557
- type: "speech_models_list_request",
1525
+ type: 'speech_models_list_request',
1558
1526
  },
1559
- responseType: "speech_models_list_response",
1527
+ responseType: 'speech_models_list_response',
1560
1528
  timeout: 30000,
1561
1529
  });
1562
1530
  }
@@ -1564,34 +1532,24 @@ export class DaemonClient {
1564
1532
  return this.sendCorrelatedSessionRequest({
1565
1533
  requestId: options?.requestId,
1566
1534
  message: {
1567
- type: "speech_models_download_request",
1535
+ type: 'speech_models_download_request',
1568
1536
  modelIds: options?.modelIds,
1569
1537
  },
1570
- responseType: "speech_models_download_response",
1538
+ responseType: 'speech_models_download_response',
1571
1539
  timeout: 30 * 60 * 1000,
1572
1540
  });
1573
1541
  }
1574
- async listCommands(agentId, requestId) {
1575
- return this.sendCorrelatedSessionRequest({
1576
- requestId,
1577
- message: {
1578
- type: "list_commands_request",
1579
- agentId,
1580
- },
1581
- responseType: "list_commands_response",
1582
- timeout: 30000,
1583
- });
1584
- }
1585
- async executeCommand(agentId, commandName, args, requestId) {
1542
+ async listCommands(agentId, requestIdOrOptions) {
1543
+ const requestId = typeof requestIdOrOptions === 'string' ? requestIdOrOptions : requestIdOrOptions?.requestId;
1544
+ const draftConfig = typeof requestIdOrOptions === 'string' ? undefined : requestIdOrOptions?.draftConfig;
1586
1545
  return this.sendCorrelatedSessionRequest({
1587
1546
  requestId,
1588
1547
  message: {
1589
- type: "execute_command_request",
1548
+ type: 'list_commands_request',
1590
1549
  agentId,
1591
- commandName,
1592
- args,
1550
+ ...(draftConfig ? { draftConfig } : {}),
1593
1551
  },
1594
- responseType: "execute_command_response",
1552
+ responseType: 'list_commands_response',
1595
1553
  timeout: 30000,
1596
1554
  });
1597
1555
  }
@@ -1600,7 +1558,7 @@ export class DaemonClient {
1600
1558
  // ============================================================================
1601
1559
  async respondToPermission(agentId, requestId, response) {
1602
1560
  this.sendSessionMessage({
1603
- type: "agent_permission_response",
1561
+ type: 'agent_permission_response',
1604
1562
  agentId,
1605
1563
  requestId,
1606
1564
  response,
@@ -1608,7 +1566,7 @@ export class DaemonClient {
1608
1566
  }
1609
1567
  async respondToPermissionAndWait(agentId, requestId, response, timeout = 15000) {
1610
1568
  const message = SessionInboundMessageSchema.parse({
1611
- type: "agent_permission_response",
1569
+ type: 'agent_permission_response',
1612
1570
  agentId,
1613
1571
  requestId,
1614
1572
  response,
@@ -1619,7 +1577,7 @@ export class DaemonClient {
1619
1577
  timeout,
1620
1578
  options: { skipQueue: true },
1621
1579
  select: (msg) => {
1622
- if (msg.type !== "agent_permission_resolved") {
1580
+ if (msg.type !== 'agent_permission_resolved') {
1623
1581
  return null;
1624
1582
  }
1625
1583
  if (msg.payload.requestId !== requestId) {
@@ -1649,7 +1607,7 @@ export class DaemonClient {
1649
1607
  async waitForFinish(agentId, timeout = 60000) {
1650
1608
  const requestId = this.createRequestId();
1651
1609
  const message = SessionInboundMessageSchema.parse({
1652
- type: "wait_for_finish_request",
1610
+ type: 'wait_for_finish_request',
1653
1611
  requestId,
1654
1612
  agentId,
1655
1613
  timeoutMs: timeout,
@@ -1657,7 +1615,7 @@ export class DaemonClient {
1657
1615
  const payload = await this.sendCorrelatedRequest({
1658
1616
  requestId,
1659
1617
  message,
1660
- responseType: "wait_for_finish_response",
1618
+ responseType: 'wait_for_finish_response',
1661
1619
  timeout: timeout + 5000,
1662
1620
  options: { skipQueue: true },
1663
1621
  });
@@ -1673,35 +1631,35 @@ export class DaemonClient {
1673
1631
  // ============================================================================
1674
1632
  subscribeTerminals(input) {
1675
1633
  this.terminalDirectorySubscriptions.add(input.cwd);
1676
- if (!this.transport || this.connectionState.status !== "connected") {
1634
+ if (!this.transport || this.connectionState.status !== 'connected') {
1677
1635
  return;
1678
1636
  }
1679
1637
  this.sendSessionMessage({
1680
- type: "subscribe_terminals_request",
1638
+ type: 'subscribe_terminals_request',
1681
1639
  cwd: input.cwd,
1682
1640
  });
1683
1641
  }
1684
1642
  unsubscribeTerminals(input) {
1685
1643
  this.terminalDirectorySubscriptions.delete(input.cwd);
1686
- if (!this.transport || this.connectionState.status !== "connected") {
1644
+ if (!this.transport || this.connectionState.status !== 'connected') {
1687
1645
  return;
1688
1646
  }
1689
1647
  this.sendSessionMessage({
1690
- type: "unsubscribe_terminals_request",
1648
+ type: 'unsubscribe_terminals_request',
1691
1649
  cwd: input.cwd,
1692
1650
  });
1693
1651
  }
1694
1652
  async listTerminals(cwd, requestId) {
1695
1653
  const resolvedRequestId = this.createRequestId(requestId);
1696
1654
  const message = SessionInboundMessageSchema.parse({
1697
- type: "list_terminals_request",
1655
+ type: 'list_terminals_request',
1698
1656
  cwd,
1699
1657
  requestId: resolvedRequestId,
1700
1658
  });
1701
1659
  return this.sendCorrelatedRequest({
1702
1660
  requestId: resolvedRequestId,
1703
1661
  message,
1704
- responseType: "list_terminals_response",
1662
+ responseType: 'list_terminals_response',
1705
1663
  timeout: 10000,
1706
1664
  options: { skipQueue: true },
1707
1665
  });
@@ -1709,7 +1667,7 @@ export class DaemonClient {
1709
1667
  async createTerminal(cwd, name, requestId) {
1710
1668
  const resolvedRequestId = this.createRequestId(requestId);
1711
1669
  const message = SessionInboundMessageSchema.parse({
1712
- type: "create_terminal_request",
1670
+ type: 'create_terminal_request',
1713
1671
  cwd,
1714
1672
  name,
1715
1673
  requestId: resolvedRequestId,
@@ -1717,7 +1675,7 @@ export class DaemonClient {
1717
1675
  return this.sendCorrelatedRequest({
1718
1676
  requestId: resolvedRequestId,
1719
1677
  message,
1720
- responseType: "create_terminal_response",
1678
+ responseType: 'create_terminal_response',
1721
1679
  timeout: 10000,
1722
1680
  options: { skipQueue: true },
1723
1681
  });
@@ -1725,27 +1683,27 @@ export class DaemonClient {
1725
1683
  async subscribeTerminal(terminalId, requestId) {
1726
1684
  const resolvedRequestId = this.createRequestId(requestId);
1727
1685
  const message = SessionInboundMessageSchema.parse({
1728
- type: "subscribe_terminal_request",
1686
+ type: 'subscribe_terminal_request',
1729
1687
  terminalId,
1730
1688
  requestId: resolvedRequestId,
1731
1689
  });
1732
1690
  return this.sendCorrelatedRequest({
1733
1691
  requestId: resolvedRequestId,
1734
1692
  message,
1735
- responseType: "subscribe_terminal_response",
1693
+ responseType: 'subscribe_terminal_response',
1736
1694
  timeout: 10000,
1737
1695
  options: { skipQueue: true },
1738
1696
  });
1739
1697
  }
1740
1698
  unsubscribeTerminal(terminalId) {
1741
1699
  this.sendSessionMessage({
1742
- type: "unsubscribe_terminal_request",
1700
+ type: 'unsubscribe_terminal_request',
1743
1701
  terminalId,
1744
1702
  });
1745
1703
  }
1746
1704
  sendTerminalInput(terminalId, message) {
1747
1705
  this.sendSessionMessage({
1748
- type: "terminal_input",
1706
+ type: 'terminal_input',
1749
1707
  terminalId,
1750
1708
  message,
1751
1709
  });
@@ -1753,14 +1711,14 @@ export class DaemonClient {
1753
1711
  async killTerminal(terminalId, requestId) {
1754
1712
  const resolvedRequestId = this.createRequestId(requestId);
1755
1713
  const message = SessionInboundMessageSchema.parse({
1756
- type: "kill_terminal_request",
1714
+ type: 'kill_terminal_request',
1757
1715
  terminalId,
1758
1716
  requestId: resolvedRequestId,
1759
1717
  });
1760
1718
  return this.sendCorrelatedRequest({
1761
1719
  requestId: resolvedRequestId,
1762
1720
  message,
1763
- responseType: "kill_terminal_response",
1721
+ responseType: 'kill_terminal_response',
1764
1722
  timeout: 10000,
1765
1723
  options: { skipQueue: true },
1766
1724
  });
@@ -1768,7 +1726,7 @@ export class DaemonClient {
1768
1726
  async attachTerminalStream(terminalId, options, requestId) {
1769
1727
  const resolvedRequestId = this.createRequestId(requestId);
1770
1728
  const message = SessionInboundMessageSchema.parse({
1771
- type: "attach_terminal_stream_request",
1729
+ type: 'attach_terminal_stream_request',
1772
1730
  terminalId,
1773
1731
  requestId: resolvedRequestId,
1774
1732
  ...(options?.resumeOffset !== undefined ? { resumeOffset: options.resumeOffset } : {}),
@@ -1778,7 +1736,7 @@ export class DaemonClient {
1778
1736
  return this.sendCorrelatedRequest({
1779
1737
  requestId: resolvedRequestId,
1780
1738
  message,
1781
- responseType: "attach_terminal_stream_response",
1739
+ responseType: 'attach_terminal_stream_response',
1782
1740
  timeout: 10000,
1783
1741
  options: { skipQueue: true },
1784
1742
  });
@@ -1786,14 +1744,14 @@ export class DaemonClient {
1786
1744
  async detachTerminalStream(streamId, requestId) {
1787
1745
  const resolvedRequestId = this.createRequestId(requestId);
1788
1746
  const message = SessionInboundMessageSchema.parse({
1789
- type: "detach_terminal_stream_request",
1747
+ type: 'detach_terminal_stream_request',
1790
1748
  streamId,
1791
1749
  requestId: resolvedRequestId,
1792
1750
  });
1793
1751
  const payload = await this.sendCorrelatedRequest({
1794
1752
  requestId: resolvedRequestId,
1795
1753
  message,
1796
- responseType: "detach_terminal_stream_response",
1754
+ responseType: 'detach_terminal_stream_response',
1797
1755
  timeout: 10000,
1798
1756
  options: { skipQueue: true },
1799
1757
  });
@@ -1820,7 +1778,7 @@ export class DaemonClient {
1820
1778
  });
1821
1779
  }
1822
1780
  sendTerminalStreamInput(streamId, data) {
1823
- const payload = typeof data === "string" ? encodeUtf8String(data) : data;
1781
+ const payload = typeof data === 'string' ? encodeUtf8String(data) : data;
1824
1782
  this.sendBinaryFrame({
1825
1783
  channel: BinaryMuxChannel.Terminal,
1826
1784
  messageType: TerminalBinaryMessageType.InputUtf8,
@@ -1849,7 +1807,7 @@ export class DaemonClient {
1849
1807
  }
1850
1808
  async waitForTerminalOutput(terminalId, timeout = 5000) {
1851
1809
  return this.waitFor((msg) => {
1852
- if (msg.type !== "terminal_output") {
1810
+ if (msg.type !== 'terminal_output') {
1853
1811
  return null;
1854
1812
  }
1855
1813
  if (msg.payload.terminalId !== terminalId) {
@@ -1864,7 +1822,7 @@ export class DaemonClient {
1864
1822
  createRequestId(requestId) {
1865
1823
  return requestId ?? crypto.randomUUID();
1866
1824
  }
1867
- disposeTransport(code = 1001, reason = "Reconnecting") {
1825
+ disposeTransport(code = 1001, reason = 'Reconnecting') {
1868
1826
  this.cleanupTransport();
1869
1827
  if (this.transport) {
1870
1828
  try {
@@ -1892,9 +1850,7 @@ export class DaemonClient {
1892
1850
  this.transportCleanup = [];
1893
1851
  }
1894
1852
  handleTransportMessage(data) {
1895
- const rawData = data && typeof data === "object" && "data" in data
1896
- ? data.data
1897
- : data;
1853
+ const rawData = data && typeof data === 'object' && 'data' in data ? data.data : data;
1898
1854
  const rawBytes = asUint8Array(rawData);
1899
1855
  if (rawBytes) {
1900
1856
  const frame = decodeBinaryMuxFrame(rawBytes);
@@ -1916,11 +1872,11 @@ export class DaemonClient {
1916
1872
  }
1917
1873
  const parsed = WSOutboundMessageSchema.safeParse(parsedJson);
1918
1874
  if (!parsed.success) {
1919
- const msgType = parsedJson?.message?.type ?? "unknown";
1920
- this.logger.warn({ msgType, error: parsed.error.message }, "Message validation failed");
1875
+ const msgType = parsedJson?.message?.type ?? 'unknown';
1876
+ this.logger.warn({ msgType, error: parsed.error.message }, 'Message validation failed');
1921
1877
  return;
1922
1878
  }
1923
- if (parsed.data.type === "pong") {
1879
+ if (parsed.data.type === 'pong') {
1924
1880
  return;
1925
1881
  }
1926
1882
  this.handleSessionMessage(parsed.data.message);
@@ -1956,7 +1912,7 @@ export class DaemonClient {
1956
1912
  this.reconnectTimeout = null;
1957
1913
  }
1958
1914
  if (!this.shouldReconnect || this.config.reconnect?.enabled === false) {
1959
- this.rejectConnect(new Error(reason ?? "Transport disconnected before connect"));
1915
+ this.rejectConnect(new Error(reason ?? 'Transport disconnected before connect'));
1960
1916
  return;
1961
1917
  }
1962
1918
  const attempt = this.reconnectAttempt;
@@ -1964,16 +1920,16 @@ export class DaemonClient {
1964
1920
  const maxDelay = this.config.reconnect?.maxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS;
1965
1921
  const delay = Math.min(baseDelay * 2 ** attempt, maxDelay);
1966
1922
  this.reconnectAttempt = attempt + 1;
1967
- if (typeof reason === "string" && reason.trim().length > 0) {
1923
+ if (typeof reason === 'string' && reason.trim().length > 0) {
1968
1924
  this.lastErrorValue = reason.trim();
1969
1925
  }
1970
1926
  // Clear all pending waiters and queued sends since the connection was lost
1971
1927
  // and responses from the previous connection will never arrive.
1972
- this.clearWaiters(new Error(reason ?? "Connection lost"));
1973
- this.rejectPendingSendQueue(new Error(reason ?? "Connection lost"));
1928
+ this.clearWaiters(new Error(reason ?? 'Connection lost'));
1929
+ this.rejectPendingSendQueue(new Error(reason ?? 'Connection lost'));
1974
1930
  this.terminalStreams.clearAll();
1975
1931
  this.updateConnectionState({
1976
- status: "disconnected",
1932
+ status: 'disconnected',
1977
1933
  ...(reason ? { reason } : {}),
1978
1934
  });
1979
1935
  this.reconnectTimeout = setTimeout(() => {
@@ -1985,7 +1941,7 @@ export class DaemonClient {
1985
1941
  }, delay);
1986
1942
  }
1987
1943
  handleSessionMessage(msg) {
1988
- if (msg.type === "terminal_stream_exit") {
1944
+ if (msg.type === 'terminal_stream_exit') {
1989
1945
  this.terminalStreams.clearStream({ streamId: msg.payload.streamId });
1990
1946
  }
1991
1947
  if (this.rawMessageListeners.size > 0) {
@@ -2040,36 +1996,34 @@ export class DaemonClient {
2040
1996
  }
2041
1997
  toEvent(msg) {
2042
1998
  switch (msg.type) {
2043
- case "agent_update":
1999
+ case 'agent_update':
2044
2000
  return {
2045
- type: "agent_update",
2046
- agentId: msg.payload.kind === "upsert"
2047
- ? msg.payload.agent.id
2048
- : msg.payload.agentId,
2001
+ type: 'agent_update',
2002
+ agentId: msg.payload.kind === 'upsert' ? msg.payload.agent.id : msg.payload.agentId,
2049
2003
  payload: msg.payload,
2050
2004
  };
2051
- case "agent_stream":
2005
+ case 'agent_stream':
2052
2006
  return {
2053
- type: "agent_stream",
2007
+ type: 'agent_stream',
2054
2008
  agentId: msg.payload.agentId,
2055
2009
  event: msg.payload.event,
2056
2010
  timestamp: msg.payload.timestamp,
2057
- ...(typeof msg.payload.seq === "number" ? { seq: msg.payload.seq } : {}),
2058
- ...(typeof msg.payload.epoch === "string" ? { epoch: msg.payload.epoch } : {}),
2011
+ ...(typeof msg.payload.seq === 'number' ? { seq: msg.payload.seq } : {}),
2012
+ ...(typeof msg.payload.epoch === 'string' ? { epoch: msg.payload.epoch } : {}),
2059
2013
  };
2060
- case "status":
2061
- return { type: "status", payload: msg.payload };
2062
- case "agent_deleted":
2063
- return { type: "agent_deleted", agentId: msg.payload.agentId };
2064
- case "agent_permission_request":
2014
+ case 'status':
2015
+ return { type: 'status', payload: msg.payload };
2016
+ case 'agent_deleted':
2017
+ return { type: 'agent_deleted', agentId: msg.payload.agentId };
2018
+ case 'agent_permission_request':
2065
2019
  return {
2066
- type: "agent_permission_request",
2020
+ type: 'agent_permission_request',
2067
2021
  agentId: msg.payload.agentId,
2068
2022
  request: msg.payload.request,
2069
2023
  };
2070
- case "agent_permission_resolved":
2024
+ case 'agent_permission_resolved':
2071
2025
  return {
2072
- type: "agent_permission_resolved",
2026
+ type: 'agent_permission_resolved',
2073
2027
  agentId: msg.payload.agentId,
2074
2028
  requestId: msg.payload.requestId,
2075
2029
  resolution: msg.payload.resolution,
@@ -2150,7 +2104,7 @@ function resolveAgentConfig(options) {
2150
2104
  };
2151
2105
  const merged = config ? { ...baseConfig, ...config } : baseConfig;
2152
2106
  if (!merged.provider || !merged.cwd) {
2153
- throw new Error("createAgent requires provider and cwd");
2107
+ throw new Error('createAgent requires provider and cwd');
2154
2108
  }
2155
2109
  if (!merged.modeId) {
2156
2110
  merged.modeId = getAgentProviderDefinition(merged.provider).defaultModeId ?? undefined;