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