@getpaseo/server 0.1.2 → 0.1.4
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-relay-e2ee-transport.d.ts +8 -0
- package/dist/server/client/daemon-client-relay-e2ee-transport.d.ts.map +1 -0
- package/dist/server/client/daemon-client-relay-e2ee-transport.js +161 -0
- package/dist/server/client/daemon-client-relay-e2ee-transport.js.map +1 -0
- package/dist/server/client/daemon-client-terminal-stream-manager.d.ts +43 -0
- package/dist/server/client/daemon-client-terminal-stream-manager.d.ts.map +1 -0
- package/dist/server/client/daemon-client-terminal-stream-manager.js +130 -0
- package/dist/server/client/daemon-client-terminal-stream-manager.js.map +1 -0
- package/dist/server/client/daemon-client-transport-types.d.ts +34 -0
- package/dist/server/client/daemon-client-transport-types.d.ts.map +1 -0
- package/dist/server/client/daemon-client-transport-types.js +2 -0
- package/dist/server/client/daemon-client-transport-types.js.map +1 -0
- package/dist/server/client/daemon-client-transport-utils.d.ts +9 -0
- package/dist/server/client/daemon-client-transport-utils.d.ts.map +1 -0
- package/dist/server/client/daemon-client-transport-utils.js +121 -0
- package/dist/server/client/daemon-client-transport-utils.js.map +1 -0
- package/dist/server/client/daemon-client-transport.d.ts +5 -0
- package/dist/server/client/daemon-client-transport.d.ts.map +1 -0
- package/dist/server/client/daemon-client-transport.js +4 -0
- package/dist/server/client/daemon-client-transport.js.map +1 -0
- package/dist/server/client/daemon-client-websocket-transport.d.ts +7 -0
- package/dist/server/client/daemon-client-websocket-transport.d.ts.map +1 -0
- package/dist/server/client/daemon-client-websocket-transport.js +64 -0
- package/dist/server/client/daemon-client-websocket-transport.js.map +1 -0
- package/dist/server/client/daemon-client.d.ts +54 -36
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +497 -800
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +52 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +238 -10
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +4 -4
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +62 -12
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +4 -4
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +213 -50
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts +7 -0
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +100 -19
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +0 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +67 -30
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +293 -266
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +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 +49 -14
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +5 -4
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +8 -2
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +121 -45
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +87 -35
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +2 -2
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +23 -6
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +0 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +0 -10
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
- package/dist/server/server/agent/stt-manager.d.ts +3 -2
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -1
- package/dist/server/server/agent/stt-manager.js +5 -3
- package/dist/server/server/agent/stt-manager.js.map +1 -1
- package/dist/server/server/agent/timeline-projection.d.ts +19 -0
- package/dist/server/server/agent/timeline-projection.d.ts.map +1 -0
- package/dist/server/server/agent/timeline-projection.js +142 -0
- package/dist/server/server/agent/timeline-projection.js.map +1 -0
- package/dist/server/server/agent/tts-manager.d.ts +3 -2
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -1
- package/dist/server/server/agent/tts-manager.js +5 -17
- package/dist/server/server/agent/tts-manager.js.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts +20 -0
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -0
- package/dist/server/server/agent-attention-policy.js +40 -0
- package/dist/server/server/agent-attention-policy.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +13 -20
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.d.ts +10 -2
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.js +83 -27
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -1
- package/dist/server/server/exports.d.ts +2 -1
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +1 -0
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +36 -22
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +2 -0
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/relay-transport.d.ts +3 -2
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +99 -16
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/session.d.ts +34 -16
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +619 -328
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/provider-resolver.d.ts +3 -0
- package/dist/server/server/speech/provider-resolver.d.ts.map +1 -0
- package/dist/server/server/speech/provider-resolver.js +7 -0
- package/dist/server/server/speech/provider-resolver.js.map +1 -0
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/config.js +11 -8
- package/dist/server/server/speech/providers/local/config.js.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.d.ts +1 -0
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.js +13 -9
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +73 -54
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/config.js +10 -5
- package/dist/server/server/speech/providers/openai/config.js.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.js +17 -6
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.js +25 -4
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -1
- package/dist/server/server/speech/speech-runtime.d.ts +26 -3
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.js +468 -85
- package/dist/server/server/speech/speech-runtime.js.map +1 -1
- package/dist/server/server/speech/speech-types.d.ts +3 -0
- package/dist/server/server/speech/speech-types.d.ts.map +1 -1
- package/dist/server/server/speech/speech-types.js +1 -0
- package/dist/server/server/speech/speech-types.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +23 -7
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +288 -102
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/shared/binary-mux.d.ts +31 -0
- package/dist/server/shared/binary-mux.d.ts.map +1 -0
- package/dist/server/shared/binary-mux.js +101 -0
- package/dist/server/shared/binary-mux.js.map +1 -0
- package/dist/server/shared/messages.d.ts +5206 -4814
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +225 -58
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/terminal-key-input.d.ts +9 -0
- package/dist/server/shared/terminal-key-input.d.ts.map +1 -0
- package/dist/server/shared/terminal-key-input.js +132 -0
- package/dist/server/shared/terminal-key-input.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +17 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +89 -0
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +9 -1
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +314 -75
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/worktree.d.ts.map +1 -1
- package/dist/server/utils/worktree.js +33 -4
- package/dist/server/utils/worktree.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema, AgentRefreshedStatusPayloadSchema, AgentResumedStatusPayloadSchema, RestartRequestedStatusPayloadSchema, SessionInboundMessageSchema, WSOutboundMessageSchema, } from "../shared/messages.js";
|
|
2
2
|
import { getAgentProviderDefinition } from "../server/agent/provider-manifest.js";
|
|
3
|
-
import { createClientChannel, } from "@getpaseo/relay/e2ee";
|
|
4
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";
|
|
5
8
|
const consoleLogger = {
|
|
6
9
|
debug: (obj, msg) => console.debug(msg, obj),
|
|
7
10
|
info: (obj, msg) => console.info(msg, obj),
|
|
@@ -21,6 +24,12 @@ const DEFAULT_RECONNECT_BASE_DELAY_MS = 1500;
|
|
|
21
24
|
const DEFAULT_RECONNECT_MAX_DELAY_MS = 30000;
|
|
22
25
|
/** Default timeout for waiting for connection before sending queued messages */
|
|
23
26
|
const DEFAULT_SEND_QUEUE_TIMEOUT_MS = 10000;
|
|
27
|
+
const DEFAULT_DICTATION_FINISH_ACCEPT_TIMEOUT_MS = 15000;
|
|
28
|
+
const DEFAULT_DICTATION_FINISH_FALLBACK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
29
|
+
const DEFAULT_DICTATION_FINISH_TIMEOUT_GRACE_MS = 5000;
|
|
30
|
+
function isWaiterTimeoutError(error) {
|
|
31
|
+
return (error instanceof Error && error.message.startsWith("Timeout waiting for message"));
|
|
32
|
+
}
|
|
24
33
|
export class DaemonClient {
|
|
25
34
|
constructor(config) {
|
|
26
35
|
this.config = config;
|
|
@@ -46,6 +55,17 @@ export class DaemonClient {
|
|
|
46
55
|
this.pendingSendQueue = [];
|
|
47
56
|
this.relayClientId = null;
|
|
48
57
|
this.logger = config.logger ?? consoleLogger;
|
|
58
|
+
this.terminalStreams = new TerminalStreamManager({
|
|
59
|
+
sendAck: (ack) => {
|
|
60
|
+
this.sendBinaryFrame({
|
|
61
|
+
channel: BinaryMuxChannel.Terminal,
|
|
62
|
+
messageType: TerminalBinaryMessageType.Ack,
|
|
63
|
+
streamId: ack.streamId,
|
|
64
|
+
offset: ack.offset,
|
|
65
|
+
payload: new Uint8Array(0),
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
});
|
|
49
69
|
// Relay requires a clientId so the daemon can create an independent
|
|
50
70
|
// socket + E2EE channel per connected client. Generate one per DaemonClient
|
|
51
71
|
// instance (stable across reconnects in this tab/app session).
|
|
@@ -235,6 +255,7 @@ export class DaemonClient {
|
|
|
235
255
|
}
|
|
236
256
|
this.disposeTransport(1000, "Client closed");
|
|
237
257
|
this.clearWaiters(new Error("Daemon client closed"));
|
|
258
|
+
this.terminalStreams.clearAll();
|
|
238
259
|
this.updateConnectionState({
|
|
239
260
|
status: "disconnected",
|
|
240
261
|
reason: "client_closed",
|
|
@@ -329,6 +350,23 @@ export class DaemonClient {
|
|
|
329
350
|
throw error instanceof Error ? error : new Error(String(error));
|
|
330
351
|
}
|
|
331
352
|
}
|
|
353
|
+
sendBinaryFrame(frame) {
|
|
354
|
+
if (!this.transport || this.connectionState.status !== "connected") {
|
|
355
|
+
if (this.config.suppressSendErrors) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
throw new Error(`Transport not connected (status: ${this.connectionState.status})`);
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
this.transport.send(encodeBinaryMuxFrame(frame));
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
if (this.config.suppressSendErrors) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
332
370
|
/**
|
|
333
371
|
* Send a session message for RPC methods that create waiters.
|
|
334
372
|
* If the connection is still being established ("connecting"), the message
|
|
@@ -428,6 +466,43 @@ export class DaemonClient {
|
|
|
428
466
|
}
|
|
429
467
|
return result.value;
|
|
430
468
|
}
|
|
469
|
+
async sendCorrelatedRequest(params) {
|
|
470
|
+
return this.sendRequest({
|
|
471
|
+
requestId: params.requestId,
|
|
472
|
+
message: params.message,
|
|
473
|
+
timeout: params.timeout,
|
|
474
|
+
options: params.options,
|
|
475
|
+
select: (msg) => {
|
|
476
|
+
const correlated = msg;
|
|
477
|
+
if (correlated.type !== params.responseType) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
const payload = correlated.payload;
|
|
481
|
+
if (payload.requestId !== params.requestId) {
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
if (!params.selectPayload) {
|
|
485
|
+
return payload;
|
|
486
|
+
}
|
|
487
|
+
return params.selectPayload(payload);
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
sendCorrelatedSessionRequest(params) {
|
|
492
|
+
const resolvedRequestId = this.createRequestId(params.requestId);
|
|
493
|
+
const message = SessionInboundMessageSchema.parse({
|
|
494
|
+
...params.message,
|
|
495
|
+
requestId: resolvedRequestId,
|
|
496
|
+
});
|
|
497
|
+
return this.sendCorrelatedRequest({
|
|
498
|
+
requestId: resolvedRequestId,
|
|
499
|
+
message,
|
|
500
|
+
responseType: params.responseType,
|
|
501
|
+
timeout: params.timeout,
|
|
502
|
+
options: { skipQueue: true },
|
|
503
|
+
...(params.selectPayload ? { selectPayload: params.selectPayload } : {}),
|
|
504
|
+
});
|
|
505
|
+
}
|
|
431
506
|
sendSessionMessageStrict(message) {
|
|
432
507
|
if (!this.transport || this.connectionState.status !== "connected") {
|
|
433
508
|
throw new Error("Transport not connected");
|
|
@@ -621,6 +696,7 @@ export class DaemonClient {
|
|
|
621
696
|
requestId,
|
|
622
697
|
config,
|
|
623
698
|
...(options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}),
|
|
699
|
+
...(options.outputSchema ? { outputSchema: options.outputSchema } : {}),
|
|
624
700
|
...(options.images && options.images.length > 0
|
|
625
701
|
? { images: options.images }
|
|
626
702
|
: {}),
|
|
@@ -702,6 +778,36 @@ export class DaemonClient {
|
|
|
702
778
|
});
|
|
703
779
|
return { archivedAt: result.archivedAt };
|
|
704
780
|
}
|
|
781
|
+
async updateAgent(agentId, updates) {
|
|
782
|
+
const requestId = this.createRequestId();
|
|
783
|
+
const message = SessionInboundMessageSchema.parse({
|
|
784
|
+
type: "update_agent_request",
|
|
785
|
+
agentId,
|
|
786
|
+
...(updates.name !== undefined ? { name: updates.name } : {}),
|
|
787
|
+
...(updates.labels && Object.keys(updates.labels).length > 0
|
|
788
|
+
? { labels: updates.labels }
|
|
789
|
+
: {}),
|
|
790
|
+
requestId,
|
|
791
|
+
});
|
|
792
|
+
const payload = await this.sendRequest({
|
|
793
|
+
requestId,
|
|
794
|
+
message,
|
|
795
|
+
timeout: 10000,
|
|
796
|
+
options: { skipQueue: true },
|
|
797
|
+
select: (msg) => {
|
|
798
|
+
if (msg.type !== "update_agent_response") {
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
if (msg.payload.requestId !== requestId) {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
return msg.payload;
|
|
805
|
+
},
|
|
806
|
+
});
|
|
807
|
+
if (!payload.accepted) {
|
|
808
|
+
throw new Error(payload.error ?? "updateAgent rejected");
|
|
809
|
+
}
|
|
810
|
+
}
|
|
705
811
|
async resumeAgent(handle, overrides) {
|
|
706
812
|
const requestId = this.createRequestId();
|
|
707
813
|
const message = SessionInboundMessageSchema.parse({
|
|
@@ -752,20 +858,24 @@ export class DaemonClient {
|
|
|
752
858
|
},
|
|
753
859
|
});
|
|
754
860
|
}
|
|
755
|
-
async
|
|
756
|
-
const resolvedRequestId = this.createRequestId(requestId);
|
|
861
|
+
async fetchAgentTimeline(agentId, options = {}) {
|
|
862
|
+
const resolvedRequestId = this.createRequestId(options.requestId);
|
|
757
863
|
const message = SessionInboundMessageSchema.parse({
|
|
758
|
-
type: "
|
|
864
|
+
type: "fetch_agent_timeline_request",
|
|
759
865
|
agentId,
|
|
760
866
|
requestId: resolvedRequestId,
|
|
867
|
+
...(options.direction ? { direction: options.direction } : {}),
|
|
868
|
+
...(options.cursor ? { cursor: options.cursor } : {}),
|
|
869
|
+
...(typeof options.limit === "number" ? { limit: options.limit } : {}),
|
|
870
|
+
...(options.projection ? { projection: options.projection } : {}),
|
|
761
871
|
});
|
|
762
872
|
const payload = await this.sendRequest({
|
|
763
873
|
requestId: resolvedRequestId,
|
|
764
874
|
message,
|
|
765
|
-
timeout:
|
|
875
|
+
timeout: 15000,
|
|
766
876
|
options: { skipQueue: true },
|
|
767
877
|
select: (msg) => {
|
|
768
|
-
if (msg.type !== "
|
|
878
|
+
if (msg.type !== "fetch_agent_timeline_response") {
|
|
769
879
|
return null;
|
|
770
880
|
}
|
|
771
881
|
if (msg.payload.requestId !== resolvedRequestId) {
|
|
@@ -777,11 +887,7 @@ export class DaemonClient {
|
|
|
777
887
|
if (payload.error) {
|
|
778
888
|
throw new Error(payload.error);
|
|
779
889
|
}
|
|
780
|
-
|
|
781
|
-
if (!agent) {
|
|
782
|
-
throw new Error(`Agent not found after initialize: ${agentId}`);
|
|
783
|
-
}
|
|
784
|
-
return agent;
|
|
890
|
+
return payload;
|
|
785
891
|
}
|
|
786
892
|
// ============================================================================
|
|
787
893
|
// Agent Interaction
|
|
@@ -941,7 +1047,7 @@ export class DaemonClient {
|
|
|
941
1047
|
...(agentId ? { agentId } : {}),
|
|
942
1048
|
requestId,
|
|
943
1049
|
});
|
|
944
|
-
|
|
1050
|
+
const response = await this.sendRequest({
|
|
945
1051
|
requestId,
|
|
946
1052
|
message,
|
|
947
1053
|
timeout: 10000,
|
|
@@ -955,11 +1061,18 @@ export class DaemonClient {
|
|
|
955
1061
|
return msg.payload;
|
|
956
1062
|
},
|
|
957
1063
|
});
|
|
1064
|
+
if (!response.accepted) {
|
|
1065
|
+
const codeSuffix = typeof response.reasonCode === "string" && response.reasonCode.trim().length > 0
|
|
1066
|
+
? ` (${response.reasonCode})`
|
|
1067
|
+
: "";
|
|
1068
|
+
throw new Error((response.error ?? "Failed to set voice mode") + codeSuffix);
|
|
1069
|
+
}
|
|
1070
|
+
return response;
|
|
958
1071
|
}
|
|
959
1072
|
async sendVoiceAudioChunk(audio, format, isLast) {
|
|
960
1073
|
this.sendSessionMessage({ type: "voice_audio_chunk", audio, format, isLast });
|
|
961
1074
|
}
|
|
962
|
-
startDictationStream(dictationId, format) {
|
|
1075
|
+
async startDictationStream(dictationId, format) {
|
|
963
1076
|
const ack = this.waitForWithCancel((msg) => {
|
|
964
1077
|
if (msg.type !== "dictation_stream_ack") {
|
|
965
1078
|
return null;
|
|
@@ -985,23 +1098,22 @@ export class DaemonClient {
|
|
|
985
1098
|
const errorPromise = streamError.promise.then((payload) => {
|
|
986
1099
|
throw new Error(payload.error);
|
|
987
1100
|
});
|
|
1101
|
+
const cleanupError = new Error("Cancelled dictation start waiter");
|
|
988
1102
|
try {
|
|
989
1103
|
this.sendSessionMessageStrict({ type: "dictation_stream_start", dictationId, format });
|
|
1104
|
+
await Promise.race([ackPromise, errorPromise]);
|
|
990
1105
|
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
streamError.cancel(err);
|
|
1106
|
+
finally {
|
|
1107
|
+
ack.cancel(cleanupError);
|
|
1108
|
+
streamError.cancel(cleanupError);
|
|
995
1109
|
void ackPromise.catch(() => undefined);
|
|
996
1110
|
void errorPromise.catch(() => undefined);
|
|
997
|
-
throw err;
|
|
998
1111
|
}
|
|
999
|
-
return Promise.race([ackPromise, errorPromise]);
|
|
1000
1112
|
}
|
|
1001
1113
|
sendDictationStreamChunk(dictationId, seq, audio, format) {
|
|
1002
1114
|
this.sendSessionMessageStrict({ type: "dictation_stream_chunk", dictationId, seq, audio, format });
|
|
1003
1115
|
}
|
|
1004
|
-
finishDictationStream(dictationId, finalSeq) {
|
|
1116
|
+
async finishDictationStream(dictationId, finalSeq) {
|
|
1005
1117
|
const final = this.waitForWithCancel((msg) => {
|
|
1006
1118
|
if (msg.type !== "dictation_stream_final") {
|
|
1007
1119
|
return null;
|
|
@@ -1010,7 +1122,7 @@ export class DaemonClient {
|
|
|
1010
1122
|
return null;
|
|
1011
1123
|
}
|
|
1012
1124
|
return msg.payload;
|
|
1013
|
-
},
|
|
1125
|
+
}, 0, { skipQueue: true });
|
|
1014
1126
|
const streamError = this.waitForWithCancel((msg) => {
|
|
1015
1127
|
if (msg.type !== "dictation_stream_error") {
|
|
1016
1128
|
return null;
|
|
@@ -1019,23 +1131,96 @@ export class DaemonClient {
|
|
|
1019
1131
|
return null;
|
|
1020
1132
|
}
|
|
1021
1133
|
return msg.payload;
|
|
1022
|
-
},
|
|
1134
|
+
}, 0, { skipQueue: true });
|
|
1135
|
+
const finishAccepted = this.waitForWithCancel((msg) => {
|
|
1136
|
+
if (msg.type !== "dictation_stream_finish_accepted") {
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
if (msg.payload.dictationId !== dictationId) {
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
return msg.payload;
|
|
1143
|
+
}, DEFAULT_DICTATION_FINISH_ACCEPT_TIMEOUT_MS, { skipQueue: true });
|
|
1023
1144
|
const finalPromise = final.promise;
|
|
1024
1145
|
const errorPromise = streamError.promise.then((payload) => {
|
|
1025
1146
|
throw new Error(payload.error);
|
|
1026
1147
|
});
|
|
1148
|
+
const finishAcceptedPromise = finishAccepted.promise;
|
|
1149
|
+
const finalOutcomePromise = finalPromise.then((payload) => ({
|
|
1150
|
+
kind: "final",
|
|
1151
|
+
payload,
|
|
1152
|
+
}));
|
|
1153
|
+
const errorOutcomePromise = errorPromise.then(() => ({
|
|
1154
|
+
kind: "error",
|
|
1155
|
+
error: new Error("Unexpected dictation stream error state"),
|
|
1156
|
+
}), (error) => ({
|
|
1157
|
+
kind: "error",
|
|
1158
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1159
|
+
}));
|
|
1160
|
+
const finishAcceptedOutcomePromise = finishAcceptedPromise.then((payload) => ({ kind: "accepted", payload }), (error) => {
|
|
1161
|
+
if (isWaiterTimeoutError(error)) {
|
|
1162
|
+
return { kind: "accepted_timeout" };
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
kind: "accepted_error",
|
|
1166
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1167
|
+
};
|
|
1168
|
+
});
|
|
1169
|
+
const waitForFinalResult = async (timeoutMs) => {
|
|
1170
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1171
|
+
const outcome = await Promise.race([finalOutcomePromise, errorOutcomePromise]);
|
|
1172
|
+
if (outcome.kind === "error") {
|
|
1173
|
+
throw outcome.error;
|
|
1174
|
+
}
|
|
1175
|
+
return outcome.payload;
|
|
1176
|
+
}
|
|
1177
|
+
let timeoutHandle = null;
|
|
1178
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1179
|
+
timeoutHandle = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs);
|
|
1180
|
+
});
|
|
1181
|
+
const outcome = await Promise.race([
|
|
1182
|
+
finalOutcomePromise,
|
|
1183
|
+
errorOutcomePromise,
|
|
1184
|
+
timeoutPromise,
|
|
1185
|
+
]);
|
|
1186
|
+
if (timeoutHandle) {
|
|
1187
|
+
clearTimeout(timeoutHandle);
|
|
1188
|
+
}
|
|
1189
|
+
if (outcome.kind === "timeout") {
|
|
1190
|
+
throw new Error(`Timeout waiting for dictation finalization (${timeoutMs}ms)`);
|
|
1191
|
+
}
|
|
1192
|
+
if (outcome.kind === "error") {
|
|
1193
|
+
throw outcome.error;
|
|
1194
|
+
}
|
|
1195
|
+
return outcome.payload;
|
|
1196
|
+
};
|
|
1197
|
+
const cleanupError = new Error("Cancelled dictation finish waiter");
|
|
1027
1198
|
try {
|
|
1028
1199
|
this.sendSessionMessageStrict({ type: "dictation_stream_finish", dictationId, finalSeq });
|
|
1200
|
+
const firstOutcome = await Promise.race([
|
|
1201
|
+
finalOutcomePromise,
|
|
1202
|
+
errorOutcomePromise,
|
|
1203
|
+
finishAcceptedOutcomePromise,
|
|
1204
|
+
]);
|
|
1205
|
+
if (firstOutcome.kind === "final") {
|
|
1206
|
+
return firstOutcome.payload;
|
|
1207
|
+
}
|
|
1208
|
+
if (firstOutcome.kind === "error") {
|
|
1209
|
+
throw firstOutcome.error;
|
|
1210
|
+
}
|
|
1211
|
+
if (firstOutcome.kind === "accepted") {
|
|
1212
|
+
return await waitForFinalResult(firstOutcome.payload.timeoutMs + DEFAULT_DICTATION_FINISH_TIMEOUT_GRACE_MS);
|
|
1213
|
+
}
|
|
1214
|
+
return await waitForFinalResult(DEFAULT_DICTATION_FINISH_FALLBACK_TIMEOUT_MS);
|
|
1029
1215
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1216
|
+
finally {
|
|
1217
|
+
final.cancel(cleanupError);
|
|
1218
|
+
streamError.cancel(cleanupError);
|
|
1219
|
+
finishAccepted.cancel(cleanupError);
|
|
1034
1220
|
void finalPromise.catch(() => undefined);
|
|
1035
1221
|
void errorPromise.catch(() => undefined);
|
|
1036
|
-
|
|
1222
|
+
void finishAcceptedPromise.catch(() => undefined);
|
|
1037
1223
|
}
|
|
1038
|
-
return Promise.race([finalPromise, errorPromise]);
|
|
1039
1224
|
}
|
|
1040
1225
|
cancelDictationStream(dictationId) {
|
|
1041
1226
|
this.sendSessionMessageStrict({ type: "dictation_stream_cancel", dictationId });
|
|
@@ -1140,22 +1325,17 @@ export class DaemonClient {
|
|
|
1140
1325
|
requestId: resolvedRequestId,
|
|
1141
1326
|
});
|
|
1142
1327
|
try {
|
|
1143
|
-
return await this.
|
|
1328
|
+
return await this.sendCorrelatedRequest({
|
|
1144
1329
|
requestId: resolvedRequestId,
|
|
1145
1330
|
message,
|
|
1331
|
+
responseType: "subscribe_checkout_diff_response",
|
|
1146
1332
|
timeout: 60000,
|
|
1147
1333
|
options: { skipQueue: true },
|
|
1148
|
-
|
|
1149
|
-
if (
|
|
1334
|
+
selectPayload: (payload) => {
|
|
1335
|
+
if (payload.subscriptionId !== subscriptionId) {
|
|
1150
1336
|
return null;
|
|
1151
1337
|
}
|
|
1152
|
-
|
|
1153
|
-
return null;
|
|
1154
|
-
}
|
|
1155
|
-
if (msg.payload.subscriptionId !== subscriptionId) {
|
|
1156
|
-
return null;
|
|
1157
|
-
}
|
|
1158
|
-
return msg.payload;
|
|
1338
|
+
return payload;
|
|
1159
1339
|
},
|
|
1160
1340
|
});
|
|
1161
1341
|
}
|
|
@@ -1177,465 +1357,238 @@ export class DaemonClient {
|
|
|
1177
1357
|
});
|
|
1178
1358
|
}
|
|
1179
1359
|
async checkoutCommit(cwd, input, requestId) {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
});
|
|
1188
|
-
return this.sendRequest({
|
|
1189
|
-
requestId: resolvedRequestId,
|
|
1190
|
-
message,
|
|
1191
|
-
timeout: 60000,
|
|
1192
|
-
options: { skipQueue: true },
|
|
1193
|
-
select: (msg) => {
|
|
1194
|
-
if (msg.type !== "checkout_commit_response") {
|
|
1195
|
-
return null;
|
|
1196
|
-
}
|
|
1197
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1198
|
-
return null;
|
|
1199
|
-
}
|
|
1200
|
-
return msg.payload;
|
|
1360
|
+
return this.sendCorrelatedSessionRequest({
|
|
1361
|
+
requestId,
|
|
1362
|
+
message: {
|
|
1363
|
+
type: "checkout_commit_request",
|
|
1364
|
+
cwd,
|
|
1365
|
+
message: input.message,
|
|
1366
|
+
addAll: input.addAll,
|
|
1201
1367
|
},
|
|
1368
|
+
responseType: "checkout_commit_response",
|
|
1369
|
+
timeout: 60000,
|
|
1202
1370
|
});
|
|
1203
1371
|
}
|
|
1204
1372
|
async checkoutMerge(cwd, input, requestId) {
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
});
|
|
1214
|
-
return this.sendRequest({
|
|
1215
|
-
requestId: resolvedRequestId,
|
|
1216
|
-
message,
|
|
1217
|
-
timeout: 60000,
|
|
1218
|
-
options: { skipQueue: true },
|
|
1219
|
-
select: (msg) => {
|
|
1220
|
-
if (msg.type !== "checkout_merge_response") {
|
|
1221
|
-
return null;
|
|
1222
|
-
}
|
|
1223
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1224
|
-
return null;
|
|
1225
|
-
}
|
|
1226
|
-
return msg.payload;
|
|
1373
|
+
return this.sendCorrelatedSessionRequest({
|
|
1374
|
+
requestId,
|
|
1375
|
+
message: {
|
|
1376
|
+
type: "checkout_merge_request",
|
|
1377
|
+
cwd,
|
|
1378
|
+
baseRef: input.baseRef,
|
|
1379
|
+
strategy: input.strategy,
|
|
1380
|
+
requireCleanTarget: input.requireCleanTarget,
|
|
1227
1381
|
},
|
|
1382
|
+
responseType: "checkout_merge_response",
|
|
1383
|
+
timeout: 60000,
|
|
1228
1384
|
});
|
|
1229
1385
|
}
|
|
1230
1386
|
async checkoutMergeFromBase(cwd, input, requestId) {
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
});
|
|
1239
|
-
return this.sendRequest({
|
|
1240
|
-
requestId: resolvedRequestId,
|
|
1241
|
-
message,
|
|
1242
|
-
timeout: 60000,
|
|
1243
|
-
options: { skipQueue: true },
|
|
1244
|
-
select: (msg) => {
|
|
1245
|
-
if (msg.type !== "checkout_merge_from_base_response") {
|
|
1246
|
-
return null;
|
|
1247
|
-
}
|
|
1248
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1249
|
-
return null;
|
|
1250
|
-
}
|
|
1251
|
-
return msg.payload;
|
|
1387
|
+
return this.sendCorrelatedSessionRequest({
|
|
1388
|
+
requestId,
|
|
1389
|
+
message: {
|
|
1390
|
+
type: "checkout_merge_from_base_request",
|
|
1391
|
+
cwd,
|
|
1392
|
+
baseRef: input.baseRef,
|
|
1393
|
+
requireCleanTarget: input.requireCleanTarget,
|
|
1252
1394
|
},
|
|
1395
|
+
responseType: "checkout_merge_from_base_response",
|
|
1396
|
+
timeout: 60000,
|
|
1253
1397
|
});
|
|
1254
1398
|
}
|
|
1255
1399
|
async checkoutPush(cwd, requestId) {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
});
|
|
1262
|
-
return this.sendRequest({
|
|
1263
|
-
requestId: resolvedRequestId,
|
|
1264
|
-
message,
|
|
1265
|
-
timeout: 60000,
|
|
1266
|
-
options: { skipQueue: true },
|
|
1267
|
-
select: (msg) => {
|
|
1268
|
-
if (msg.type !== "checkout_push_response") {
|
|
1269
|
-
return null;
|
|
1270
|
-
}
|
|
1271
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1272
|
-
return null;
|
|
1273
|
-
}
|
|
1274
|
-
return msg.payload;
|
|
1400
|
+
return this.sendCorrelatedSessionRequest({
|
|
1401
|
+
requestId,
|
|
1402
|
+
message: {
|
|
1403
|
+
type: "checkout_push_request",
|
|
1404
|
+
cwd,
|
|
1275
1405
|
},
|
|
1406
|
+
responseType: "checkout_push_response",
|
|
1407
|
+
timeout: 60000,
|
|
1276
1408
|
});
|
|
1277
1409
|
}
|
|
1278
1410
|
async checkoutPrCreate(cwd, input, requestId) {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
});
|
|
1288
|
-
return this.sendRequest({
|
|
1289
|
-
requestId: resolvedRequestId,
|
|
1290
|
-
message,
|
|
1291
|
-
timeout: 60000,
|
|
1292
|
-
options: { skipQueue: true },
|
|
1293
|
-
select: (msg) => {
|
|
1294
|
-
if (msg.type !== "checkout_pr_create_response") {
|
|
1295
|
-
return null;
|
|
1296
|
-
}
|
|
1297
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1298
|
-
return null;
|
|
1299
|
-
}
|
|
1300
|
-
return msg.payload;
|
|
1411
|
+
return this.sendCorrelatedSessionRequest({
|
|
1412
|
+
requestId,
|
|
1413
|
+
message: {
|
|
1414
|
+
type: "checkout_pr_create_request",
|
|
1415
|
+
cwd,
|
|
1416
|
+
title: input.title,
|
|
1417
|
+
body: input.body,
|
|
1418
|
+
baseRef: input.baseRef,
|
|
1301
1419
|
},
|
|
1420
|
+
responseType: "checkout_pr_create_response",
|
|
1421
|
+
timeout: 60000,
|
|
1302
1422
|
});
|
|
1303
1423
|
}
|
|
1304
1424
|
async checkoutPrStatus(cwd, requestId) {
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
});
|
|
1311
|
-
return this.sendRequest({
|
|
1312
|
-
requestId: resolvedRequestId,
|
|
1313
|
-
message,
|
|
1314
|
-
timeout: 60000,
|
|
1315
|
-
options: { skipQueue: true },
|
|
1316
|
-
select: (msg) => {
|
|
1317
|
-
if (msg.type !== "checkout_pr_status_response") {
|
|
1318
|
-
return null;
|
|
1319
|
-
}
|
|
1320
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1321
|
-
return null;
|
|
1322
|
-
}
|
|
1323
|
-
return msg.payload;
|
|
1425
|
+
return this.sendCorrelatedSessionRequest({
|
|
1426
|
+
requestId,
|
|
1427
|
+
message: {
|
|
1428
|
+
type: "checkout_pr_status_request",
|
|
1429
|
+
cwd,
|
|
1324
1430
|
},
|
|
1431
|
+
responseType: "checkout_pr_status_response",
|
|
1432
|
+
timeout: 60000,
|
|
1325
1433
|
});
|
|
1326
1434
|
}
|
|
1327
1435
|
async getPaseoWorktreeList(input, requestId) {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
});
|
|
1335
|
-
return this.sendRequest({
|
|
1336
|
-
requestId: resolvedRequestId,
|
|
1337
|
-
message,
|
|
1338
|
-
timeout: 60000,
|
|
1339
|
-
options: { skipQueue: true },
|
|
1340
|
-
select: (msg) => {
|
|
1341
|
-
if (msg.type !== "paseo_worktree_list_response") {
|
|
1342
|
-
return null;
|
|
1343
|
-
}
|
|
1344
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1345
|
-
return null;
|
|
1346
|
-
}
|
|
1347
|
-
return msg.payload;
|
|
1436
|
+
return this.sendCorrelatedSessionRequest({
|
|
1437
|
+
requestId,
|
|
1438
|
+
message: {
|
|
1439
|
+
type: "paseo_worktree_list_request",
|
|
1440
|
+
cwd: input.cwd,
|
|
1441
|
+
repoRoot: input.repoRoot,
|
|
1348
1442
|
},
|
|
1443
|
+
responseType: "paseo_worktree_list_response",
|
|
1444
|
+
timeout: 60000,
|
|
1349
1445
|
});
|
|
1350
1446
|
}
|
|
1351
1447
|
async archivePaseoWorktree(input, requestId) {
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
requestId: resolvedRequestId,
|
|
1362
|
-
message,
|
|
1448
|
+
return this.sendCorrelatedSessionRequest({
|
|
1449
|
+
requestId,
|
|
1450
|
+
message: {
|
|
1451
|
+
type: "paseo_worktree_archive_request",
|
|
1452
|
+
worktreePath: input.worktreePath,
|
|
1453
|
+
repoRoot: input.repoRoot,
|
|
1454
|
+
branchName: input.branchName,
|
|
1455
|
+
},
|
|
1456
|
+
responseType: "paseo_worktree_archive_response",
|
|
1363
1457
|
timeout: 20000,
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
async validateBranch(options, requestId) {
|
|
1461
|
+
return this.sendCorrelatedSessionRequest({
|
|
1462
|
+
requestId,
|
|
1463
|
+
message: {
|
|
1464
|
+
type: "validate_branch_request",
|
|
1465
|
+
cwd: options.cwd,
|
|
1466
|
+
branchName: options.branchName,
|
|
1373
1467
|
},
|
|
1468
|
+
responseType: "validate_branch_response",
|
|
1469
|
+
timeout: 10000,
|
|
1374
1470
|
});
|
|
1375
1471
|
}
|
|
1376
|
-
async
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
requestId: resolvedRequestId,
|
|
1385
|
-
message,
|
|
1386
|
-
timeout: 10000,
|
|
1387
|
-
options: { skipQueue: true },
|
|
1388
|
-
select: (msg) => {
|
|
1389
|
-
if (msg.type !== "git_diff_response") {
|
|
1390
|
-
return null;
|
|
1391
|
-
}
|
|
1392
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1393
|
-
return null;
|
|
1394
|
-
}
|
|
1395
|
-
return msg.payload;
|
|
1472
|
+
async getBranchSuggestions(options, requestId) {
|
|
1473
|
+
return this.sendCorrelatedSessionRequest({
|
|
1474
|
+
requestId,
|
|
1475
|
+
message: {
|
|
1476
|
+
type: "branch_suggestions_request",
|
|
1477
|
+
cwd: options.cwd,
|
|
1478
|
+
query: options.query,
|
|
1479
|
+
limit: options.limit,
|
|
1396
1480
|
},
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1399
|
-
async getHighlightedDiff(agentId, requestId) {
|
|
1400
|
-
const resolvedRequestId = this.createRequestId(requestId);
|
|
1401
|
-
const message = SessionInboundMessageSchema.parse({
|
|
1402
|
-
type: "highlighted_diff_request",
|
|
1403
|
-
agentId,
|
|
1404
|
-
requestId: resolvedRequestId,
|
|
1405
|
-
});
|
|
1406
|
-
return this.sendRequest({
|
|
1407
|
-
requestId: resolvedRequestId,
|
|
1408
|
-
message,
|
|
1481
|
+
responseType: "branch_suggestions_response",
|
|
1409
1482
|
timeout: 10000,
|
|
1410
|
-
options: { skipQueue: true },
|
|
1411
|
-
select: (msg) => {
|
|
1412
|
-
if (msg.type !== "highlighted_diff_response") {
|
|
1413
|
-
return null;
|
|
1414
|
-
}
|
|
1415
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1416
|
-
return null;
|
|
1417
|
-
}
|
|
1418
|
-
return msg.payload;
|
|
1419
|
-
},
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
async validateBranch(options, requestId) {
|
|
1423
|
-
const resolvedRequestId = this.createRequestId(requestId);
|
|
1424
|
-
const message = SessionInboundMessageSchema.parse({
|
|
1425
|
-
type: "validate_branch_request",
|
|
1426
|
-
cwd: options.cwd,
|
|
1427
|
-
branchName: options.branchName,
|
|
1428
|
-
requestId: resolvedRequestId,
|
|
1429
|
-
});
|
|
1430
|
-
return this.sendRequest({
|
|
1431
|
-
requestId: resolvedRequestId,
|
|
1432
|
-
message,
|
|
1433
|
-
timeout: 10000,
|
|
1434
|
-
options: { skipQueue: true },
|
|
1435
|
-
select: (msg) => {
|
|
1436
|
-
if (msg.type !== "validate_branch_response") {
|
|
1437
|
-
return null;
|
|
1438
|
-
}
|
|
1439
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1440
|
-
return null;
|
|
1441
|
-
}
|
|
1442
|
-
return msg.payload;
|
|
1443
|
-
},
|
|
1444
1483
|
});
|
|
1445
1484
|
}
|
|
1446
1485
|
// ============================================================================
|
|
1447
1486
|
// File Explorer
|
|
1448
1487
|
// ============================================================================
|
|
1449
1488
|
async exploreFileSystem(agentId, path, mode = "list", requestId) {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
});
|
|
1458
|
-
return this.sendRequest({
|
|
1459
|
-
requestId: resolvedRequestId,
|
|
1460
|
-
message,
|
|
1461
|
-
timeout: 10000,
|
|
1462
|
-
options: { skipQueue: true },
|
|
1463
|
-
select: (msg) => {
|
|
1464
|
-
if (msg.type !== "file_explorer_response") {
|
|
1465
|
-
return null;
|
|
1466
|
-
}
|
|
1467
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1468
|
-
return null;
|
|
1469
|
-
}
|
|
1470
|
-
return msg.payload;
|
|
1489
|
+
return this.sendCorrelatedSessionRequest({
|
|
1490
|
+
requestId,
|
|
1491
|
+
message: {
|
|
1492
|
+
type: "file_explorer_request",
|
|
1493
|
+
agentId,
|
|
1494
|
+
path,
|
|
1495
|
+
mode,
|
|
1471
1496
|
},
|
|
1497
|
+
responseType: "file_explorer_response",
|
|
1498
|
+
timeout: 10000,
|
|
1472
1499
|
});
|
|
1473
1500
|
}
|
|
1474
1501
|
async requestDownloadToken(agentId, path, requestId) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
});
|
|
1482
|
-
return this.sendRequest({
|
|
1483
|
-
requestId: resolvedRequestId,
|
|
1484
|
-
message,
|
|
1485
|
-
timeout: 10000,
|
|
1486
|
-
options: { skipQueue: true },
|
|
1487
|
-
select: (msg) => {
|
|
1488
|
-
if (msg.type !== "file_download_token_response") {
|
|
1489
|
-
return null;
|
|
1490
|
-
}
|
|
1491
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1492
|
-
return null;
|
|
1493
|
-
}
|
|
1494
|
-
return msg.payload;
|
|
1502
|
+
return this.sendCorrelatedSessionRequest({
|
|
1503
|
+
requestId,
|
|
1504
|
+
message: {
|
|
1505
|
+
type: "file_download_token_request",
|
|
1506
|
+
agentId,
|
|
1507
|
+
path,
|
|
1495
1508
|
},
|
|
1509
|
+
responseType: "file_download_token_response",
|
|
1510
|
+
timeout: 10000,
|
|
1496
1511
|
});
|
|
1497
1512
|
}
|
|
1498
1513
|
async requestProjectIcon(cwd, requestId) {
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
});
|
|
1505
|
-
return this.sendRequest({
|
|
1506
|
-
requestId: resolvedRequestId,
|
|
1507
|
-
message,
|
|
1508
|
-
timeout: 10000,
|
|
1509
|
-
options: { skipQueue: true },
|
|
1510
|
-
select: (msg) => {
|
|
1511
|
-
if (msg.type !== "project_icon_response") {
|
|
1512
|
-
return null;
|
|
1513
|
-
}
|
|
1514
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1515
|
-
return null;
|
|
1516
|
-
}
|
|
1517
|
-
return msg.payload;
|
|
1514
|
+
return this.sendCorrelatedSessionRequest({
|
|
1515
|
+
requestId,
|
|
1516
|
+
message: {
|
|
1517
|
+
type: "project_icon_request",
|
|
1518
|
+
cwd,
|
|
1518
1519
|
},
|
|
1520
|
+
responseType: "project_icon_response",
|
|
1521
|
+
timeout: 10000,
|
|
1519
1522
|
});
|
|
1520
1523
|
}
|
|
1521
1524
|
// ============================================================================
|
|
1522
1525
|
// Provider Models / Commands
|
|
1523
1526
|
// ============================================================================
|
|
1524
1527
|
async listProviderModels(provider, options) {
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
requestId: resolvedRequestId,
|
|
1534
|
-
message,
|
|
1528
|
+
return this.sendCorrelatedSessionRequest({
|
|
1529
|
+
requestId: options?.requestId,
|
|
1530
|
+
message: {
|
|
1531
|
+
type: "list_provider_models_request",
|
|
1532
|
+
provider,
|
|
1533
|
+
cwd: options?.cwd,
|
|
1534
|
+
},
|
|
1535
|
+
responseType: "list_provider_models_response",
|
|
1535
1536
|
timeout: 30000,
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
}
|
|
1544
|
-
return msg.payload;
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
async listAvailableProviders(options) {
|
|
1540
|
+
return this.sendCorrelatedSessionRequest({
|
|
1541
|
+
requestId: options?.requestId,
|
|
1542
|
+
message: {
|
|
1543
|
+
type: "list_available_providers_request",
|
|
1545
1544
|
},
|
|
1545
|
+
responseType: "list_available_providers_response",
|
|
1546
|
+
timeout: 30000,
|
|
1546
1547
|
});
|
|
1547
1548
|
}
|
|
1548
1549
|
async listSpeechModels(requestId) {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
});
|
|
1554
|
-
return this.sendRequest({
|
|
1555
|
-
requestId: resolvedRequestId,
|
|
1556
|
-
message,
|
|
1557
|
-
timeout: 30000,
|
|
1558
|
-
options: { skipQueue: true },
|
|
1559
|
-
select: (msg) => {
|
|
1560
|
-
if (msg.type !== "speech_models_list_response") {
|
|
1561
|
-
return null;
|
|
1562
|
-
}
|
|
1563
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1564
|
-
return null;
|
|
1565
|
-
}
|
|
1566
|
-
return msg.payload;
|
|
1550
|
+
return this.sendCorrelatedSessionRequest({
|
|
1551
|
+
requestId,
|
|
1552
|
+
message: {
|
|
1553
|
+
type: "speech_models_list_request",
|
|
1567
1554
|
},
|
|
1555
|
+
responseType: "speech_models_list_response",
|
|
1556
|
+
timeout: 30000,
|
|
1568
1557
|
});
|
|
1569
1558
|
}
|
|
1570
1559
|
async downloadSpeechModels(options) {
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
});
|
|
1577
|
-
return this.sendRequest({
|
|
1578
|
-
requestId: resolvedRequestId,
|
|
1579
|
-
message,
|
|
1580
|
-
timeout: 30 * 60 * 1000,
|
|
1581
|
-
options: { skipQueue: true },
|
|
1582
|
-
select: (msg) => {
|
|
1583
|
-
if (msg.type !== "speech_models_download_response") {
|
|
1584
|
-
return null;
|
|
1585
|
-
}
|
|
1586
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1587
|
-
return null;
|
|
1588
|
-
}
|
|
1589
|
-
return msg.payload;
|
|
1560
|
+
return this.sendCorrelatedSessionRequest({
|
|
1561
|
+
requestId: options?.requestId,
|
|
1562
|
+
message: {
|
|
1563
|
+
type: "speech_models_download_request",
|
|
1564
|
+
modelIds: options?.modelIds,
|
|
1590
1565
|
},
|
|
1566
|
+
responseType: "speech_models_download_response",
|
|
1567
|
+
timeout: 30 * 60 * 1000,
|
|
1591
1568
|
});
|
|
1592
1569
|
}
|
|
1593
1570
|
async listCommands(agentId, requestId) {
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
});
|
|
1600
|
-
return this.sendRequest({
|
|
1601
|
-
requestId: resolvedRequestId,
|
|
1602
|
-
message,
|
|
1603
|
-
timeout: 30000,
|
|
1604
|
-
options: { skipQueue: true },
|
|
1605
|
-
select: (msg) => {
|
|
1606
|
-
if (msg.type !== "list_commands_response") {
|
|
1607
|
-
return null;
|
|
1608
|
-
}
|
|
1609
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1610
|
-
return null;
|
|
1611
|
-
}
|
|
1612
|
-
return msg.payload;
|
|
1571
|
+
return this.sendCorrelatedSessionRequest({
|
|
1572
|
+
requestId,
|
|
1573
|
+
message: {
|
|
1574
|
+
type: "list_commands_request",
|
|
1575
|
+
agentId,
|
|
1613
1576
|
},
|
|
1577
|
+
responseType: "list_commands_response",
|
|
1578
|
+
timeout: 30000,
|
|
1614
1579
|
});
|
|
1615
1580
|
}
|
|
1616
1581
|
async executeCommand(agentId, commandName, args, requestId) {
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
});
|
|
1625
|
-
return this.sendRequest({
|
|
1626
|
-
requestId: resolvedRequestId,
|
|
1627
|
-
message,
|
|
1628
|
-
timeout: 30000,
|
|
1629
|
-
options: { skipQueue: true },
|
|
1630
|
-
select: (msg) => {
|
|
1631
|
-
if (msg.type !== "execute_command_response") {
|
|
1632
|
-
return null;
|
|
1633
|
-
}
|
|
1634
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1635
|
-
return null;
|
|
1636
|
-
}
|
|
1637
|
-
return msg.payload;
|
|
1582
|
+
return this.sendCorrelatedSessionRequest({
|
|
1583
|
+
requestId,
|
|
1584
|
+
message: {
|
|
1585
|
+
type: "execute_command_request",
|
|
1586
|
+
agentId,
|
|
1587
|
+
commandName,
|
|
1588
|
+
args,
|
|
1638
1589
|
},
|
|
1590
|
+
responseType: "execute_command_response",
|
|
1591
|
+
timeout: 30000,
|
|
1639
1592
|
});
|
|
1640
1593
|
}
|
|
1641
1594
|
// ============================================================================
|
|
@@ -1697,25 +1650,18 @@ export class DaemonClient {
|
|
|
1697
1650
|
agentId,
|
|
1698
1651
|
timeoutMs: timeout,
|
|
1699
1652
|
});
|
|
1700
|
-
const payload = await this.
|
|
1653
|
+
const payload = await this.sendCorrelatedRequest({
|
|
1701
1654
|
requestId,
|
|
1702
1655
|
message,
|
|
1656
|
+
responseType: "wait_for_finish_response",
|
|
1703
1657
|
timeout: timeout + 5000,
|
|
1704
1658
|
options: { skipQueue: true },
|
|
1705
|
-
select: (msg) => {
|
|
1706
|
-
if (msg.type !== "wait_for_finish_response") {
|
|
1707
|
-
return null;
|
|
1708
|
-
}
|
|
1709
|
-
if (msg.payload.requestId !== requestId) {
|
|
1710
|
-
return null;
|
|
1711
|
-
}
|
|
1712
|
-
return msg.payload;
|
|
1713
|
-
},
|
|
1714
1659
|
});
|
|
1715
1660
|
return {
|
|
1716
1661
|
status: payload.status,
|
|
1717
1662
|
final: payload.final,
|
|
1718
1663
|
error: payload.error,
|
|
1664
|
+
lastMessage: payload.lastMessage,
|
|
1719
1665
|
};
|
|
1720
1666
|
}
|
|
1721
1667
|
// ============================================================================
|
|
@@ -1728,20 +1674,12 @@ export class DaemonClient {
|
|
|
1728
1674
|
cwd,
|
|
1729
1675
|
requestId: resolvedRequestId,
|
|
1730
1676
|
});
|
|
1731
|
-
return this.
|
|
1677
|
+
return this.sendCorrelatedRequest({
|
|
1732
1678
|
requestId: resolvedRequestId,
|
|
1733
1679
|
message,
|
|
1680
|
+
responseType: "list_terminals_response",
|
|
1734
1681
|
timeout: 10000,
|
|
1735
1682
|
options: { skipQueue: true },
|
|
1736
|
-
select: (msg) => {
|
|
1737
|
-
if (msg.type !== "list_terminals_response") {
|
|
1738
|
-
return null;
|
|
1739
|
-
}
|
|
1740
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1741
|
-
return null;
|
|
1742
|
-
}
|
|
1743
|
-
return msg.payload;
|
|
1744
|
-
},
|
|
1745
1683
|
});
|
|
1746
1684
|
}
|
|
1747
1685
|
async createTerminal(cwd, name, requestId) {
|
|
@@ -1752,20 +1690,12 @@ export class DaemonClient {
|
|
|
1752
1690
|
name,
|
|
1753
1691
|
requestId: resolvedRequestId,
|
|
1754
1692
|
});
|
|
1755
|
-
return this.
|
|
1693
|
+
return this.sendCorrelatedRequest({
|
|
1756
1694
|
requestId: resolvedRequestId,
|
|
1757
1695
|
message,
|
|
1696
|
+
responseType: "create_terminal_response",
|
|
1758
1697
|
timeout: 10000,
|
|
1759
1698
|
options: { skipQueue: true },
|
|
1760
|
-
select: (msg) => {
|
|
1761
|
-
if (msg.type !== "create_terminal_response") {
|
|
1762
|
-
return null;
|
|
1763
|
-
}
|
|
1764
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1765
|
-
return null;
|
|
1766
|
-
}
|
|
1767
|
-
return msg.payload;
|
|
1768
|
-
},
|
|
1769
1699
|
});
|
|
1770
1700
|
}
|
|
1771
1701
|
async subscribeTerminal(terminalId, requestId) {
|
|
@@ -1775,20 +1705,12 @@ export class DaemonClient {
|
|
|
1775
1705
|
terminalId,
|
|
1776
1706
|
requestId: resolvedRequestId,
|
|
1777
1707
|
});
|
|
1778
|
-
return this.
|
|
1708
|
+
return this.sendCorrelatedRequest({
|
|
1779
1709
|
requestId: resolvedRequestId,
|
|
1780
1710
|
message,
|
|
1711
|
+
responseType: "subscribe_terminal_response",
|
|
1781
1712
|
timeout: 10000,
|
|
1782
1713
|
options: { skipQueue: true },
|
|
1783
|
-
select: (msg) => {
|
|
1784
|
-
if (msg.type !== "subscribe_terminal_response") {
|
|
1785
|
-
return null;
|
|
1786
|
-
}
|
|
1787
|
-
if (msg.payload.requestId !== resolvedRequestId) {
|
|
1788
|
-
return null;
|
|
1789
|
-
}
|
|
1790
|
-
return msg.payload;
|
|
1791
|
-
},
|
|
1792
1714
|
});
|
|
1793
1715
|
}
|
|
1794
1716
|
unsubscribeTerminal(terminalId) {
|
|
@@ -1811,20 +1733,94 @@ export class DaemonClient {
|
|
|
1811
1733
|
terminalId,
|
|
1812
1734
|
requestId: resolvedRequestId,
|
|
1813
1735
|
});
|
|
1814
|
-
return this.
|
|
1736
|
+
return this.sendCorrelatedRequest({
|
|
1815
1737
|
requestId: resolvedRequestId,
|
|
1816
1738
|
message,
|
|
1739
|
+
responseType: "kill_terminal_response",
|
|
1817
1740
|
timeout: 10000,
|
|
1818
1741
|
options: { skipQueue: true },
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
async attachTerminalStream(terminalId, options, requestId) {
|
|
1745
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1746
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1747
|
+
type: "attach_terminal_stream_request",
|
|
1748
|
+
terminalId,
|
|
1749
|
+
requestId: resolvedRequestId,
|
|
1750
|
+
...(options?.resumeOffset !== undefined ? { resumeOffset: options.resumeOffset } : {}),
|
|
1751
|
+
...(options?.rows !== undefined ? { rows: options.rows } : {}),
|
|
1752
|
+
...(options?.cols !== undefined ? { cols: options.cols } : {}),
|
|
1753
|
+
});
|
|
1754
|
+
return this.sendCorrelatedRequest({
|
|
1755
|
+
requestId: resolvedRequestId,
|
|
1756
|
+
message,
|
|
1757
|
+
responseType: "attach_terminal_stream_response",
|
|
1758
|
+
timeout: 10000,
|
|
1759
|
+
options: { skipQueue: true },
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
async detachTerminalStream(streamId, requestId) {
|
|
1763
|
+
const resolvedRequestId = this.createRequestId(requestId);
|
|
1764
|
+
const message = SessionInboundMessageSchema.parse({
|
|
1765
|
+
type: "detach_terminal_stream_request",
|
|
1766
|
+
streamId,
|
|
1767
|
+
requestId: resolvedRequestId,
|
|
1768
|
+
});
|
|
1769
|
+
const payload = await this.sendCorrelatedRequest({
|
|
1770
|
+
requestId: resolvedRequestId,
|
|
1771
|
+
message,
|
|
1772
|
+
responseType: "detach_terminal_stream_response",
|
|
1773
|
+
timeout: 10000,
|
|
1774
|
+
options: { skipQueue: true },
|
|
1775
|
+
});
|
|
1776
|
+
this.terminalStreams.clearStream({ streamId });
|
|
1777
|
+
return payload;
|
|
1778
|
+
}
|
|
1779
|
+
onTerminalStreamData(streamId, handler) {
|
|
1780
|
+
return this.terminalStreams.subscribe({ streamId, handler });
|
|
1781
|
+
}
|
|
1782
|
+
async waitForTerminalStreamData(streamId, predicate, timeout = 5000) {
|
|
1783
|
+
return new Promise((resolve, reject) => {
|
|
1784
|
+
const timeoutHandle = setTimeout(() => {
|
|
1785
|
+
unsubscribe();
|
|
1786
|
+
reject(new Error(`Timeout waiting for terminal stream data (${timeout}ms)`));
|
|
1787
|
+
}, timeout);
|
|
1788
|
+
const unsubscribe = this.onTerminalStreamData(streamId, (chunk) => {
|
|
1789
|
+
if (!predicate(chunk)) {
|
|
1790
|
+
return;
|
|
1825
1791
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1792
|
+
clearTimeout(timeoutHandle);
|
|
1793
|
+
unsubscribe();
|
|
1794
|
+
resolve(chunk);
|
|
1795
|
+
});
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
sendTerminalStreamInput(streamId, data) {
|
|
1799
|
+
const payload = typeof data === "string" ? encodeUtf8String(data) : data;
|
|
1800
|
+
this.sendBinaryFrame({
|
|
1801
|
+
channel: BinaryMuxChannel.Terminal,
|
|
1802
|
+
messageType: TerminalBinaryMessageType.InputUtf8,
|
|
1803
|
+
streamId,
|
|
1804
|
+
offset: 0,
|
|
1805
|
+
payload,
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
sendTerminalStreamKey(streamId, input) {
|
|
1809
|
+
const encoded = encodeTerminalKeyInput(input);
|
|
1810
|
+
if (!encoded) {
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
this.sendTerminalStreamInput(streamId, encoded);
|
|
1814
|
+
}
|
|
1815
|
+
sendTerminalStreamAck(streamId, offset) {
|
|
1816
|
+
const normalizedOffset = Math.max(0, Math.floor(offset));
|
|
1817
|
+
this.terminalStreams.noteAck({ streamId, offset: normalizedOffset });
|
|
1818
|
+
this.sendBinaryFrame({
|
|
1819
|
+
channel: BinaryMuxChannel.Terminal,
|
|
1820
|
+
messageType: TerminalBinaryMessageType.Ack,
|
|
1821
|
+
streamId,
|
|
1822
|
+
offset: normalizedOffset,
|
|
1823
|
+
payload: new Uint8Array(0),
|
|
1828
1824
|
});
|
|
1829
1825
|
}
|
|
1830
1826
|
async waitForTerminalOutput(terminalId, timeout = 5000) {
|
|
@@ -1875,6 +1871,14 @@ export class DaemonClient {
|
|
|
1875
1871
|
const rawData = data && typeof data === "object" && "data" in data
|
|
1876
1872
|
? data.data
|
|
1877
1873
|
: data;
|
|
1874
|
+
const rawBytes = asUint8Array(rawData);
|
|
1875
|
+
if (rawBytes) {
|
|
1876
|
+
const frame = decodeBinaryMuxFrame(rawBytes);
|
|
1877
|
+
if (frame) {
|
|
1878
|
+
this.handleBinaryFrame(frame);
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1878
1882
|
const payload = decodeMessageData(rawData);
|
|
1879
1883
|
if (!payload) {
|
|
1880
1884
|
return;
|
|
@@ -1897,6 +1901,20 @@ export class DaemonClient {
|
|
|
1897
1901
|
}
|
|
1898
1902
|
this.handleSessionMessage(parsed.data.message);
|
|
1899
1903
|
}
|
|
1904
|
+
handleBinaryFrame(frame) {
|
|
1905
|
+
if (frame.channel === BinaryMuxChannel.Terminal &&
|
|
1906
|
+
frame.messageType === TerminalBinaryMessageType.OutputUtf8) {
|
|
1907
|
+
const chunk = {
|
|
1908
|
+
streamId: frame.streamId,
|
|
1909
|
+
offset: frame.offset,
|
|
1910
|
+
endOffset: frame.offset + (frame.payload?.byteLength ?? 0),
|
|
1911
|
+
replay: Boolean((frame.flags ?? 0) & TerminalBinaryFlags.Replay),
|
|
1912
|
+
data: frame.payload ?? new Uint8Array(0),
|
|
1913
|
+
};
|
|
1914
|
+
this.terminalStreams.receiveChunk({ chunk });
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1900
1918
|
updateConnectionState(next) {
|
|
1901
1919
|
this.connectionState = next;
|
|
1902
1920
|
for (const listener of this.connectionListeners) {
|
|
@@ -1929,6 +1947,7 @@ export class DaemonClient {
|
|
|
1929
1947
|
// and responses from the previous connection will never arrive.
|
|
1930
1948
|
this.clearWaiters(new Error(reason ?? "Connection lost"));
|
|
1931
1949
|
this.rejectPendingSendQueue(new Error(reason ?? "Connection lost"));
|
|
1950
|
+
this.terminalStreams.clearAll();
|
|
1932
1951
|
this.updateConnectionState({
|
|
1933
1952
|
status: "disconnected",
|
|
1934
1953
|
...(reason ? { reason } : {}),
|
|
@@ -1942,6 +1961,9 @@ export class DaemonClient {
|
|
|
1942
1961
|
}, delay);
|
|
1943
1962
|
}
|
|
1944
1963
|
handleSessionMessage(msg) {
|
|
1964
|
+
if (msg.type === "terminal_stream_exit") {
|
|
1965
|
+
this.terminalStreams.clearStream({ streamId: msg.payload.streamId });
|
|
1966
|
+
}
|
|
1945
1967
|
if (this.rawMessageListeners.size > 0) {
|
|
1946
1968
|
for (const handler of this.rawMessageListeners) {
|
|
1947
1969
|
try {
|
|
@@ -2008,6 +2030,8 @@ export class DaemonClient {
|
|
|
2008
2030
|
agentId: msg.payload.agentId,
|
|
2009
2031
|
event: msg.payload.event,
|
|
2010
2032
|
timestamp: msg.payload.timestamp,
|
|
2033
|
+
...(typeof msg.payload.seq === "number" ? { seq: msg.payload.seq } : {}),
|
|
2034
|
+
...(typeof msg.payload.epoch === "string" ? { epoch: msg.payload.epoch } : {}),
|
|
2011
2035
|
};
|
|
2012
2036
|
case "status":
|
|
2013
2037
|
return { type: "status", payload: msg.payload };
|
|
@@ -2093,333 +2117,6 @@ export class DaemonClient {
|
|
|
2093
2117
|
return { promise, cancel };
|
|
2094
2118
|
}
|
|
2095
2119
|
}
|
|
2096
|
-
// ============================================================================
|
|
2097
|
-
// Helpers
|
|
2098
|
-
// ============================================================================
|
|
2099
|
-
function defaultWebSocketFactory(url, _options) {
|
|
2100
|
-
const globalWs = globalThis.WebSocket;
|
|
2101
|
-
if (!globalWs) {
|
|
2102
|
-
throw new Error("WebSocket is not available in this runtime");
|
|
2103
|
-
}
|
|
2104
|
-
return new globalWs(url);
|
|
2105
|
-
}
|
|
2106
|
-
function createWebSocketTransportFactory(factory) {
|
|
2107
|
-
return ({ url, headers }) => {
|
|
2108
|
-
const ws = factory(url, { headers });
|
|
2109
|
-
return {
|
|
2110
|
-
send: (data) => {
|
|
2111
|
-
if (typeof ws.readyState === "number" && ws.readyState !== 1) {
|
|
2112
|
-
throw new Error(`WebSocket not open (readyState=${ws.readyState})`);
|
|
2113
|
-
}
|
|
2114
|
-
ws.send(data);
|
|
2115
|
-
},
|
|
2116
|
-
close: (code, reason) => ws.close(code, reason),
|
|
2117
|
-
onOpen: (handler) => bindWsHandler(ws, "open", handler),
|
|
2118
|
-
onClose: (handler) => bindWsHandler(ws, "close", handler),
|
|
2119
|
-
onError: (handler) => bindWsHandler(ws, "error", handler),
|
|
2120
|
-
onMessage: (handler) => bindWsHandler(ws, "message", handler),
|
|
2121
|
-
};
|
|
2122
|
-
};
|
|
2123
|
-
}
|
|
2124
|
-
function createRelayE2eeTransportFactory(args) {
|
|
2125
|
-
return ({ url, headers }) => {
|
|
2126
|
-
const base = args.baseFactory({ url, headers });
|
|
2127
|
-
return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger);
|
|
2128
|
-
};
|
|
2129
|
-
}
|
|
2130
|
-
function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
2131
|
-
let channel = null;
|
|
2132
|
-
let opened = false;
|
|
2133
|
-
let closed = false;
|
|
2134
|
-
const openHandlers = new Set();
|
|
2135
|
-
const closeHandlers = new Set();
|
|
2136
|
-
const errorHandlers = new Set();
|
|
2137
|
-
const messageHandlers = new Set();
|
|
2138
|
-
const emitOpen = () => {
|
|
2139
|
-
if (opened || closed)
|
|
2140
|
-
return;
|
|
2141
|
-
opened = true;
|
|
2142
|
-
for (const handler of openHandlers) {
|
|
2143
|
-
try {
|
|
2144
|
-
handler();
|
|
2145
|
-
}
|
|
2146
|
-
catch {
|
|
2147
|
-
// no-op
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
};
|
|
2151
|
-
const emitClose = (event) => {
|
|
2152
|
-
if (closed)
|
|
2153
|
-
return;
|
|
2154
|
-
closed = true;
|
|
2155
|
-
for (const handler of closeHandlers) {
|
|
2156
|
-
try {
|
|
2157
|
-
handler(event);
|
|
2158
|
-
}
|
|
2159
|
-
catch {
|
|
2160
|
-
// no-op
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
};
|
|
2164
|
-
const emitError = (event) => {
|
|
2165
|
-
if (closed)
|
|
2166
|
-
return;
|
|
2167
|
-
for (const handler of errorHandlers) {
|
|
2168
|
-
try {
|
|
2169
|
-
handler(event);
|
|
2170
|
-
}
|
|
2171
|
-
catch {
|
|
2172
|
-
// no-op
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
};
|
|
2176
|
-
const emitMessage = (data) => {
|
|
2177
|
-
if (closed)
|
|
2178
|
-
return;
|
|
2179
|
-
for (const handler of messageHandlers) {
|
|
2180
|
-
try {
|
|
2181
|
-
handler(data);
|
|
2182
|
-
}
|
|
2183
|
-
catch {
|
|
2184
|
-
// no-op
|
|
2185
|
-
}
|
|
2186
|
-
}
|
|
2187
|
-
};
|
|
2188
|
-
const relayTransport = {
|
|
2189
|
-
send: (data) => {
|
|
2190
|
-
if (typeof data === "string") {
|
|
2191
|
-
base.send(data);
|
|
2192
|
-
return;
|
|
2193
|
-
}
|
|
2194
|
-
if (data instanceof ArrayBuffer) {
|
|
2195
|
-
if (typeof TextDecoder !== "undefined") {
|
|
2196
|
-
base.send(new TextDecoder().decode(data));
|
|
2197
|
-
return;
|
|
2198
|
-
}
|
|
2199
|
-
if (typeof Buffer !== "undefined") {
|
|
2200
|
-
base.send(Buffer.from(data).toString("utf8"));
|
|
2201
|
-
return;
|
|
2202
|
-
}
|
|
2203
|
-
base.send(String(data));
|
|
2204
|
-
return;
|
|
2205
|
-
}
|
|
2206
|
-
base.send(String(data));
|
|
2207
|
-
},
|
|
2208
|
-
close: (code, reason) => base.close(code, reason),
|
|
2209
|
-
onmessage: null,
|
|
2210
|
-
onclose: null,
|
|
2211
|
-
onerror: null,
|
|
2212
|
-
};
|
|
2213
|
-
const startHandshake = async () => {
|
|
2214
|
-
try {
|
|
2215
|
-
channel = await createClientChannel(relayTransport, daemonPublicKeyB64, {
|
|
2216
|
-
onopen: emitOpen,
|
|
2217
|
-
onmessage: (data) => emitMessage(data),
|
|
2218
|
-
onclose: (code, reason) => emitClose({ code, reason }),
|
|
2219
|
-
onerror: (error) => emitError(error),
|
|
2220
|
-
});
|
|
2221
|
-
}
|
|
2222
|
-
catch (error) {
|
|
2223
|
-
logger.warn({ err: error }, "relay_e2ee_handshake_failed");
|
|
2224
|
-
emitError(error);
|
|
2225
|
-
base.close(1011, "E2EE handshake failed");
|
|
2226
|
-
}
|
|
2227
|
-
};
|
|
2228
|
-
base.onOpen(() => {
|
|
2229
|
-
void startHandshake();
|
|
2230
|
-
});
|
|
2231
|
-
base.onMessage((event) => {
|
|
2232
|
-
relayTransport.onmessage?.(extractRelayMessageData(event));
|
|
2233
|
-
});
|
|
2234
|
-
base.onClose((event) => {
|
|
2235
|
-
const record = event;
|
|
2236
|
-
relayTransport.onclose?.(record?.code ?? 0, record?.reason ?? "");
|
|
2237
|
-
emitClose(event);
|
|
2238
|
-
});
|
|
2239
|
-
base.onError((event) => {
|
|
2240
|
-
relayTransport.onerror?.(event instanceof Error ? event : new Error(String(event)));
|
|
2241
|
-
emitError(event);
|
|
2242
|
-
});
|
|
2243
|
-
return {
|
|
2244
|
-
send: (data) => {
|
|
2245
|
-
if (!channel) {
|
|
2246
|
-
throw new Error("Encrypted channel not ready");
|
|
2247
|
-
}
|
|
2248
|
-
void channel.send(data).catch((error) => {
|
|
2249
|
-
emitError(error);
|
|
2250
|
-
});
|
|
2251
|
-
},
|
|
2252
|
-
close: (code, reason) => {
|
|
2253
|
-
if (channel) {
|
|
2254
|
-
channel.close(code, reason);
|
|
2255
|
-
}
|
|
2256
|
-
else {
|
|
2257
|
-
base.close(code, reason);
|
|
2258
|
-
}
|
|
2259
|
-
emitClose({ code, reason });
|
|
2260
|
-
},
|
|
2261
|
-
onMessage: (handler) => {
|
|
2262
|
-
messageHandlers.add(handler);
|
|
2263
|
-
return () => messageHandlers.delete(handler);
|
|
2264
|
-
},
|
|
2265
|
-
onOpen: (handler) => {
|
|
2266
|
-
openHandlers.add(handler);
|
|
2267
|
-
if (opened) {
|
|
2268
|
-
try {
|
|
2269
|
-
handler();
|
|
2270
|
-
}
|
|
2271
|
-
catch {
|
|
2272
|
-
// no-op
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
return () => openHandlers.delete(handler);
|
|
2276
|
-
},
|
|
2277
|
-
onClose: (handler) => {
|
|
2278
|
-
closeHandlers.add(handler);
|
|
2279
|
-
if (closed) {
|
|
2280
|
-
try {
|
|
2281
|
-
handler();
|
|
2282
|
-
}
|
|
2283
|
-
catch {
|
|
2284
|
-
// no-op
|
|
2285
|
-
}
|
|
2286
|
-
}
|
|
2287
|
-
return () => closeHandlers.delete(handler);
|
|
2288
|
-
},
|
|
2289
|
-
onError: (handler) => {
|
|
2290
|
-
errorHandlers.add(handler);
|
|
2291
|
-
return () => errorHandlers.delete(handler);
|
|
2292
|
-
},
|
|
2293
|
-
};
|
|
2294
|
-
}
|
|
2295
|
-
function extractRelayMessageData(event) {
|
|
2296
|
-
const raw = event && typeof event === "object" && "data" in event
|
|
2297
|
-
? event.data
|
|
2298
|
-
: event;
|
|
2299
|
-
if (typeof raw === "string")
|
|
2300
|
-
return raw;
|
|
2301
|
-
if (raw instanceof ArrayBuffer)
|
|
2302
|
-
return raw;
|
|
2303
|
-
if (ArrayBuffer.isView(raw)) {
|
|
2304
|
-
const view = new Uint8Array(raw.buffer, raw.byteOffset, raw.byteLength);
|
|
2305
|
-
const out = new Uint8Array(view.byteLength);
|
|
2306
|
-
out.set(view);
|
|
2307
|
-
return out.buffer;
|
|
2308
|
-
}
|
|
2309
|
-
return String(raw ?? "");
|
|
2310
|
-
}
|
|
2311
|
-
function bindWsHandler(ws, event, handler) {
|
|
2312
|
-
if (typeof ws.addEventListener === "function") {
|
|
2313
|
-
ws.addEventListener(event, handler);
|
|
2314
|
-
return () => {
|
|
2315
|
-
if (typeof ws.removeEventListener === "function") {
|
|
2316
|
-
ws.removeEventListener(event, handler);
|
|
2317
|
-
}
|
|
2318
|
-
};
|
|
2319
|
-
}
|
|
2320
|
-
if (typeof ws.on === "function") {
|
|
2321
|
-
ws.on(event, handler);
|
|
2322
|
-
return () => {
|
|
2323
|
-
if (typeof ws.off === "function") {
|
|
2324
|
-
ws.off(event, handler);
|
|
2325
|
-
return;
|
|
2326
|
-
}
|
|
2327
|
-
if (typeof ws.removeListener === "function") {
|
|
2328
|
-
ws.removeListener(event, handler);
|
|
2329
|
-
}
|
|
2330
|
-
};
|
|
2331
|
-
}
|
|
2332
|
-
const prop = `on${event}`;
|
|
2333
|
-
const previous = ws[prop];
|
|
2334
|
-
ws[prop] = handler;
|
|
2335
|
-
return () => {
|
|
2336
|
-
if (ws[prop] === handler) {
|
|
2337
|
-
ws[prop] = previous ?? null;
|
|
2338
|
-
}
|
|
2339
|
-
};
|
|
2340
|
-
}
|
|
2341
|
-
function describeTransportClose(event) {
|
|
2342
|
-
if (!event) {
|
|
2343
|
-
return "Transport closed";
|
|
2344
|
-
}
|
|
2345
|
-
if (event instanceof Error) {
|
|
2346
|
-
return event.message;
|
|
2347
|
-
}
|
|
2348
|
-
if (typeof event === "string") {
|
|
2349
|
-
return event;
|
|
2350
|
-
}
|
|
2351
|
-
if (typeof event === "object") {
|
|
2352
|
-
const record = event;
|
|
2353
|
-
if (typeof record.reason === "string" && record.reason.trim().length > 0) {
|
|
2354
|
-
return record.reason.trim();
|
|
2355
|
-
}
|
|
2356
|
-
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
2357
|
-
return record.message.trim();
|
|
2358
|
-
}
|
|
2359
|
-
if (typeof record.code === "number") {
|
|
2360
|
-
return `Transport closed (code ${record.code})`;
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
|
-
return "Transport closed";
|
|
2364
|
-
}
|
|
2365
|
-
function describeTransportError(event) {
|
|
2366
|
-
if (!event) {
|
|
2367
|
-
return "Transport error";
|
|
2368
|
-
}
|
|
2369
|
-
if (event instanceof Error) {
|
|
2370
|
-
return event.message;
|
|
2371
|
-
}
|
|
2372
|
-
if (typeof event === "string") {
|
|
2373
|
-
return event;
|
|
2374
|
-
}
|
|
2375
|
-
if (typeof event === "object") {
|
|
2376
|
-
const record = event;
|
|
2377
|
-
if (typeof record.message === "string" && record.message.trim().length > 0) {
|
|
2378
|
-
return record.message.trim();
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
return "Transport error";
|
|
2382
|
-
}
|
|
2383
|
-
function safeRandomId() {
|
|
2384
|
-
try {
|
|
2385
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
2386
|
-
return crypto.randomUUID();
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2389
|
-
catch {
|
|
2390
|
-
// ignore
|
|
2391
|
-
}
|
|
2392
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
2393
|
-
}
|
|
2394
|
-
function decodeMessageData(data) {
|
|
2395
|
-
if (data === null || data === undefined) {
|
|
2396
|
-
return null;
|
|
2397
|
-
}
|
|
2398
|
-
if (typeof data === "string") {
|
|
2399
|
-
return data;
|
|
2400
|
-
}
|
|
2401
|
-
if (typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) {
|
|
2402
|
-
if (typeof Buffer !== "undefined") {
|
|
2403
|
-
return Buffer.from(data).toString("utf8");
|
|
2404
|
-
}
|
|
2405
|
-
if (typeof TextDecoder !== "undefined") {
|
|
2406
|
-
return new TextDecoder().decode(data);
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
if (ArrayBuffer.isView(data)) {
|
|
2410
|
-
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
2411
|
-
if (typeof Buffer !== "undefined") {
|
|
2412
|
-
return Buffer.from(view).toString("utf8");
|
|
2413
|
-
}
|
|
2414
|
-
if (typeof TextDecoder !== "undefined") {
|
|
2415
|
-
return new TextDecoder().decode(view);
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
if (typeof data.toString === "function") {
|
|
2419
|
-
return data.toString();
|
|
2420
|
-
}
|
|
2421
|
-
return null;
|
|
2422
|
-
}
|
|
2423
2120
|
function resolveAgentConfig(options) {
|
|
2424
2121
|
const { config, provider, cwd, initialPrompt: _initialPrompt, images: _images, git: _git, worktreeName: _worktreeName, requestId: _requestId, labels: _labels, ...overrides } = options;
|
|
2425
2122
|
const baseConfig = {
|