@camerontaylor/paseo-client 0.12.0-beta.1.fork.1 → 0.13.0-fork.1
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/connection/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/daemon-client-relay-e2ee-transport.d.ts +24 -4
- package/dist/daemon-client-relay-e2ee-transport.js +94 -14
- package/dist/daemon-client-transport.d.ts +1 -1
- package/dist/daemon-client-transport.js +1 -1
- package/dist/daemon-client.d.ts +103 -9
- package/dist/daemon-client.js +333 -56
- package/dist/hosts/index.d.ts +22 -0
- package/dist/hosts/index.js +188 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +37 -6
- package/dist/node/buffering.d.ts +10 -0
- package/dist/node/buffering.js +28 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.js +188 -0
- package/dist/node/ssh-tunnel.d.ts +9 -0
- package/dist/node/ssh-tunnel.js +79 -0
- package/package.json +12 -3
|
@@ -39,6 +39,7 @@ export declare const DEFAULT_CLIENT_CAPABILITIES: {
|
|
|
39
39
|
timeline_notifications: true;
|
|
40
40
|
plugin_timeline_items: true;
|
|
41
41
|
workspace_setup_blocked: true;
|
|
42
|
+
workspace_setup_observation: true;
|
|
42
43
|
durable_agent_queue: true;
|
|
43
44
|
durable_voice_input_v1: true;
|
|
44
45
|
explicit_event_subscriptions: true;
|
package/dist/connection/index.js
CHANGED
|
@@ -112,6 +112,7 @@ export const DEFAULT_CLIENT_CAPABILITIES = {
|
|
|
112
112
|
[CLIENT_CAPS.timelineNotifications]: true,
|
|
113
113
|
[CLIENT_CAPS.pluginTimelineItems]: true,
|
|
114
114
|
[CLIENT_CAPS.workspaceSetupBlocked]: true,
|
|
115
|
+
[CLIENT_CAPS.workspaceSetupObservation]: true,
|
|
115
116
|
[CLIENT_CAPS.durableAgentQueue]: true,
|
|
116
117
|
[CLIENT_CAPS.durableVoiceInputV1]: true,
|
|
117
118
|
[CLIENT_CAPS.explicitEventSubscriptions]: true,
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
+
import { type SecurityMode } from "@camerontaylor/paseo-relay/e2ee";
|
|
1
2
|
import type { DaemonTransport, DaemonTransportFactory, TransportLogger } from "./daemon-client-transport-types.js";
|
|
2
|
-
export
|
|
3
|
-
baseFactory: DaemonTransportFactory;
|
|
3
|
+
export interface RelayE2eeTransportOptions {
|
|
4
4
|
daemonPublicKeyB64: string;
|
|
5
5
|
logger: TransportLogger;
|
|
6
|
+
assertOutboundCapacity?: (wireBytes: number) => void;
|
|
7
|
+
/** Refuse to open unless the daemon negotiates at least this endpoint security mode. */
|
|
8
|
+
minimumMode?: SecurityMode;
|
|
9
|
+
/** Reports the negotiated mode once the daemon has authenticated the handshake. */
|
|
10
|
+
onSecurityMode?: (mode: SecurityMode) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createRelayE2eeTransportFactory(args: RelayE2eeTransportOptions & {
|
|
13
|
+
baseFactory: DaemonTransportFactory;
|
|
6
14
|
}): DaemonTransportFactory;
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Returns a user-facing message when this client closed the session itself
|
|
17
|
+
* because endpoint security could not be established, so reconnecting cannot help.
|
|
18
|
+
*
|
|
19
|
+
* The daemon's own policy close never reaches the client: both relays replace a
|
|
20
|
+
* daemon-side close with their own code (1012 on the wrangler relay).
|
|
21
|
+
*/
|
|
22
|
+
export declare function describeEndpointSecurityClose(event: unknown): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Relay upgrades carry routing only. Daemon credentials and subprotocols must
|
|
25
|
+
* never reach the relay; they travel inside the encrypted hello.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createRelayUpgradeTransportFactory(baseFactory: DaemonTransportFactory): DaemonTransportFactory;
|
|
28
|
+
export declare function createEncryptedTransport(base: DaemonTransport, options: RelayE2eeTransportOptions): DaemonTransport;
|
|
9
29
|
//# sourceMappingURL=daemon-client-relay-e2ee-transport.d.ts.map
|
|
@@ -1,20 +1,68 @@
|
|
|
1
1
|
import { MAX_RELAY_WEBSOCKET_MESSAGE_BYTES } from "@camerontaylor/paseo-protocol/websocket-message-limit";
|
|
2
|
-
import {
|
|
2
|
+
import { openClientSecureChannel, PROTECTED_HANDSHAKE_FAILED_CLOSE_CODE, } from "@camerontaylor/paseo-relay/e2ee";
|
|
3
3
|
import { extractRelayMessage, normalizeTransportPayload, messageTooLargeError, } from "./daemon-client-transport-utils.js";
|
|
4
4
|
export function createRelayE2eeTransportFactory(args) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const { baseFactory, ...options } = args;
|
|
6
|
+
return ({ url }) => createEncryptedTransport(baseFactory({ url }), options);
|
|
7
|
+
}
|
|
8
|
+
const DAEMON_REQUIRES_PROTECTED_REASON = "daemon requires protected endpoint security";
|
|
9
|
+
/**
|
|
10
|
+
* Returns a user-facing message when this client closed the session itself
|
|
11
|
+
* because endpoint security could not be established, so reconnecting cannot help.
|
|
12
|
+
*
|
|
13
|
+
* The daemon's own policy close never reaches the client: both relays replace a
|
|
14
|
+
* daemon-side close with their own code (1012 on the wrangler relay).
|
|
15
|
+
*/
|
|
16
|
+
export function describeEndpointSecurityClose(event) {
|
|
17
|
+
if (!event || typeof event !== "object")
|
|
18
|
+
return null;
|
|
19
|
+
const code = "code" in event ? event.code : undefined;
|
|
20
|
+
const reason = "reason" in event && typeof event.reason === "string" ? event.reason : "";
|
|
21
|
+
if (code === PROTECTED_HANDSHAKE_FAILED_CLOSE_CODE) {
|
|
22
|
+
return `Endpoint security handshake failed: ${reason || "protected mode unavailable"}`;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The first session message from the daemon is `server_info`. A daemon that can
|
|
28
|
+
* negotiate protected security advertises it there, so a legacy session with such
|
|
29
|
+
* a daemon was downgraded in transit and must not proceed to admission.
|
|
30
|
+
*/
|
|
31
|
+
function readServerInfoProtectedSupport(text) {
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = JSON.parse(text);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
if (!isRecord(parsed) || parsed.type !== "session" || !isRecord(parsed.message))
|
|
40
|
+
return null;
|
|
41
|
+
const message = parsed.message;
|
|
42
|
+
if (message.type !== "status" || !isRecord(message.payload))
|
|
43
|
+
return null;
|
|
44
|
+
if (message.payload.status !== "server_info")
|
|
45
|
+
return null;
|
|
46
|
+
const features = message.payload.features;
|
|
47
|
+
return isRecord(features) && features.relayProtectedSecurity === true;
|
|
48
|
+
}
|
|
49
|
+
function isRecord(value) {
|
|
50
|
+
return typeof value === "object" && value !== null;
|
|
9
51
|
}
|
|
10
|
-
|
|
11
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Relay upgrades carry routing only. Daemon credentials and subprotocols must
|
|
54
|
+
* never reach the relay; they travel inside the encrypted hello.
|
|
55
|
+
*/
|
|
56
|
+
export function createRelayUpgradeTransportFactory(baseFactory) {
|
|
12
57
|
return ({ url }) => baseFactory({ url });
|
|
13
58
|
}
|
|
14
|
-
export function createEncryptedTransport(base,
|
|
59
|
+
export function createEncryptedTransport(base, options) {
|
|
60
|
+
const { daemonPublicKeyB64, logger, minimumMode, onSecurityMode } = options;
|
|
61
|
+
const assertOutboundCapacity = options.assertOutboundCapacity ?? (() => { });
|
|
15
62
|
let channel = null;
|
|
16
63
|
let opened = false;
|
|
17
64
|
let closed = false;
|
|
65
|
+
let awaitingServerInfo = true;
|
|
18
66
|
const openHandlers = new Set();
|
|
19
67
|
const closeHandlers = new Set();
|
|
20
68
|
const errorHandlers = new Set();
|
|
@@ -43,6 +91,17 @@ export function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
|
43
91
|
if (closed) {
|
|
44
92
|
return;
|
|
45
93
|
}
|
|
94
|
+
if (awaitingServerInfo && typeof data === "string") {
|
|
95
|
+
const daemonSupportsProtected = readServerInfoProtectedSupport(data);
|
|
96
|
+
if (daemonSupportsProtected !== null) {
|
|
97
|
+
awaitingServerInfo = false;
|
|
98
|
+
if (daemonSupportsProtected && channel?.securityMode() === "legacy") {
|
|
99
|
+
logger.warn({ reason: DAEMON_REQUIRES_PROTECTED_REASON }, "relay_e2ee_downgrade_rejected");
|
|
100
|
+
channel.close(PROTECTED_HANDSHAKE_FAILED_CLOSE_CODE, DAEMON_REQUIRES_PROTECTED_REASON);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
46
105
|
emitHandlers(messageHandlers, data, data instanceof ArrayBuffer);
|
|
47
106
|
};
|
|
48
107
|
const relayTransport = {
|
|
@@ -61,18 +120,36 @@ export function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
|
61
120
|
}
|
|
62
121
|
base.send(String(data));
|
|
63
122
|
},
|
|
64
|
-
close
|
|
123
|
+
// The channel decides the close code. Report it now: a socket close event
|
|
124
|
+
// arrives asynchronously, and the consumer must not act on an earlier
|
|
125
|
+
// error before it has seen the code.
|
|
126
|
+
close: (code, reason) => {
|
|
127
|
+
base.close(code, reason);
|
|
128
|
+
emitClose({ code, reason });
|
|
129
|
+
},
|
|
65
130
|
onmessage: null,
|
|
66
131
|
onclose: null,
|
|
67
132
|
onerror: null,
|
|
68
133
|
};
|
|
69
134
|
const startHandshake = async () => {
|
|
70
135
|
try {
|
|
71
|
-
channel = await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
136
|
+
channel = await openClientSecureChannel(relayTransport, {
|
|
137
|
+
daemonPublicKeyB64,
|
|
138
|
+
...(minimumMode ? { minimumMode } : {}),
|
|
139
|
+
events: {
|
|
140
|
+
onopen: () => {
|
|
141
|
+
onSecurityMode?.(channel?.securityMode() ?? "legacy");
|
|
142
|
+
emitOpen();
|
|
143
|
+
},
|
|
144
|
+
onmessage: (data) => emitMessage(data),
|
|
145
|
+
onclose: (code, reason) => emitClose({ code, reason }),
|
|
146
|
+
// Every fatal channel error is followed by a close that carries the
|
|
147
|
+
// code and reason; forwarding the error first would make the consumer
|
|
148
|
+
// reconnect before it sees them.
|
|
149
|
+
onerror: (error) => {
|
|
150
|
+
logger.warn({ err: normalizeTransportError(error) }, "relay_e2ee_channel_error");
|
|
151
|
+
},
|
|
152
|
+
},
|
|
76
153
|
});
|
|
77
154
|
}
|
|
78
155
|
catch (error) {
|
|
@@ -109,6 +186,9 @@ export function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
|
109
186
|
if (wireBytes > MAX_RELAY_WEBSOCKET_MESSAGE_BYTES) {
|
|
110
187
|
throw messageTooLargeError(wireBytes, MAX_RELAY_WEBSOCKET_MESSAGE_BYTES);
|
|
111
188
|
}
|
|
189
|
+
// Encryption and its transport handoff are synchronous up to send's first await.
|
|
190
|
+
// Reject capacity failures here so a routed sender loses only its own channel.
|
|
191
|
+
assertOutboundCapacity(wireBytes);
|
|
112
192
|
void channel.send(payload).catch((error) => {
|
|
113
193
|
emitError(error);
|
|
114
194
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { DaemonTransport, DaemonTransportFactory, TransportLogger, WebSocketFactory, WebSocketLike, } from "./daemon-client-transport-types.js";
|
|
2
2
|
export { decodeMessageData, describeTransportClose, describeTransportError, encodeUtf8String, extractRelayMessage, normalizeTransportPayload, safeRandomId, } from "./daemon-client-transport-utils.js";
|
|
3
|
-
export { createEncryptedTransport, createRelayE2eeTransportFactory,
|
|
3
|
+
export { createEncryptedTransport, createRelayE2eeTransportFactory, createRelayUpgradeTransportFactory, describeEndpointSecurityClose, } from "./daemon-client-relay-e2ee-transport.js";
|
|
4
4
|
export { bindWsHandler, createWebSocketTransportFactory, defaultWebSocketFactory, } from "./daemon-client-websocket-transport.js";
|
|
5
5
|
//# sourceMappingURL=daemon-client-transport.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { decodeMessageData, describeTransportClose, describeTransportError, encodeUtf8String, extractRelayMessage, normalizeTransportPayload, safeRandomId, } from "./daemon-client-transport-utils.js";
|
|
2
|
-
export { createEncryptedTransport, createRelayE2eeTransportFactory,
|
|
2
|
+
export { createEncryptedTransport, createRelayE2eeTransportFactory, createRelayUpgradeTransportFactory, describeEndpointSecurityClose, } from "./daemon-client-relay-e2ee-transport.js";
|
|
3
3
|
export { bindWsHandler, createWebSocketTransportFactory, defaultWebSocketFactory, } from "./daemon-client-websocket-transport.js";
|
|
4
4
|
//# sourceMappingURL=daemon-client-transport.js.map
|
package/dist/daemon-client.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type HostRouteFrame } from "@camerontaylor/paseo-protocol/binary-frames/index";
|
|
2
|
+
import type { HostAdd, HostUpdate, HostDirectory } from "@camerontaylor/paseo-protocol/hosts";
|
|
1
3
|
import { type TimelineMessage } from "./timeline-subscription/index.js";
|
|
2
4
|
import { type OwnedSubscription, type TimelineSubscription } from "./connection/index.js";
|
|
3
5
|
import type { AgentQueueSnapshot, CreationSnapshot } from "@camerontaylor/paseo-protocol/messages";
|
|
@@ -48,6 +50,8 @@ export type ConnectionState = {
|
|
|
48
50
|
} | {
|
|
49
51
|
status: "disconnected";
|
|
50
52
|
reason?: string;
|
|
53
|
+
nextRetryAt?: string;
|
|
54
|
+
failureCode?: string;
|
|
51
55
|
} | {
|
|
52
56
|
status: "disposed";
|
|
53
57
|
};
|
|
@@ -110,10 +114,13 @@ export type DaemonEvent = {
|
|
|
110
114
|
export type DaemonEventHandler = (event: DaemonEvent) => void;
|
|
111
115
|
export type BrowserAutomationExecuteRequestMessage = BrowserAutomationExecuteRequest;
|
|
112
116
|
export type BrowserAutomationExecuteResponseMessage = BrowserAutomationExecuteResponse;
|
|
117
|
+
/** Endpoint security negotiated on a relay connection. See docs/relay-endpoint-security.md. */
|
|
118
|
+
export type RelaySecurityMode = "legacy" | "protected";
|
|
113
119
|
export interface DaemonClientConfig {
|
|
114
120
|
/** Deliver compact bodies/hash references to a caller-owned snapshot cache.
|
|
115
121
|
* The default keeps public SDK snapshot entries expanded. */
|
|
116
122
|
providerSnapshots?: "wire";
|
|
123
|
+
sessionPermissions?: import("@camerontaylor/paseo-protocol/messages").DaemonPermission[];
|
|
117
124
|
url: string;
|
|
118
125
|
clientId: string;
|
|
119
126
|
clientType?: "mobile" | "browser" | "cli" | "mcp" | "hub";
|
|
@@ -130,6 +137,10 @@ export interface DaemonClientConfig {
|
|
|
130
137
|
e2ee?: {
|
|
131
138
|
enabled?: boolean;
|
|
132
139
|
daemonPublicKeyB64?: string;
|
|
140
|
+
/** Refuse connections whose negotiated endpoint security is below this mode. */
|
|
141
|
+
minimumMode?: RelaySecurityMode;
|
|
142
|
+
/** Called with the negotiated mode after each authenticated relay handshake. */
|
|
143
|
+
onSecurityMode?: (mode: RelaySecurityMode) => void;
|
|
133
144
|
};
|
|
134
145
|
reconnect?: {
|
|
135
146
|
enabled?: boolean;
|
|
@@ -148,6 +159,8 @@ export interface DaemonClientTrace {
|
|
|
148
159
|
}
|
|
149
160
|
export interface SendMessageOptions {
|
|
150
161
|
sourceAgentId?: string;
|
|
162
|
+
sourceAgentServerId?: string;
|
|
163
|
+
sessionMode?: string;
|
|
151
164
|
messageId?: string;
|
|
152
165
|
/** What happens when the agent is mid-turn. The daemon interrupts the turn when omitted. */
|
|
153
166
|
activeTurnBehavior?: ActiveTurnBehavior;
|
|
@@ -180,10 +193,12 @@ export interface CreateAgentRequestOptions extends AgentConfigOverrides {
|
|
|
180
193
|
outputSchema?: Record<string, unknown>;
|
|
181
194
|
images?: CreateAgentRequestMessage["images"];
|
|
182
195
|
attachments?: CreateAgentRequestMessage["attachments"];
|
|
196
|
+
/** @deprecated Use createWorkspace({ source, agent, idempotencyKey }); rejected by createAgent. */
|
|
183
197
|
git?: GitSetupOptions;
|
|
184
198
|
worktree?: CreateAgentRequestMessage["worktree"];
|
|
185
199
|
autoArchive?: CreateAgentRequestMessage["autoArchive"];
|
|
186
200
|
background?: CreateAgentRequestMessage["background"];
|
|
201
|
+
/** @deprecated Use createWorkspace({ source, agent, idempotencyKey }); rejected by createAgent. */
|
|
187
202
|
worktreeName?: string;
|
|
188
203
|
requestId?: string;
|
|
189
204
|
labels?: Record<string, string>;
|
|
@@ -594,7 +609,13 @@ type CorrelatedResponsePayloads = {
|
|
|
594
609
|
type CorrelatedResponsePayload<TType extends CorrelatedResponseType> = CorrelatedResponsePayloads[TType];
|
|
595
610
|
export declare class DaemonConnectionError extends Error {
|
|
596
611
|
readonly code: "DAEMON_CONNECTION_LOST" | "DAEMON_REQUEST_TIMEOUT";
|
|
597
|
-
|
|
612
|
+
readonly serverId?: string;
|
|
613
|
+
readonly outcome?: "unknown";
|
|
614
|
+
constructor(message: string, code?: "DAEMON_CONNECTION_LOST" | "DAEMON_REQUEST_TIMEOUT", context?: {
|
|
615
|
+
serverId?: string;
|
|
616
|
+
outcome?: "unknown";
|
|
617
|
+
cause?: Error;
|
|
618
|
+
});
|
|
598
619
|
}
|
|
599
620
|
export declare function supportsUsageReports(features: ServerInfoStatusPayload["features"]): boolean;
|
|
600
621
|
/** Identifies the voice attachment a voice message belongs to. */
|
|
@@ -619,11 +640,14 @@ export declare class DaemonClient {
|
|
|
619
640
|
private connectTimeout;
|
|
620
641
|
private pendingGenericTransportErrorTimeout;
|
|
621
642
|
private reconnectAttempt;
|
|
643
|
+
private traceConnectionAttempt;
|
|
622
644
|
private shouldReconnect;
|
|
623
645
|
private connectPromise;
|
|
624
646
|
private connectResolve;
|
|
625
647
|
private connectReject;
|
|
626
648
|
private lastErrorValue;
|
|
649
|
+
private destinationServerId;
|
|
650
|
+
private connectionFailure;
|
|
627
651
|
private authFailureReasonValue;
|
|
628
652
|
private connectionState;
|
|
629
653
|
private readonly terminalStreams;
|
|
@@ -632,6 +656,12 @@ export declare class DaemonClient {
|
|
|
632
656
|
private completedBinaryFileReads;
|
|
633
657
|
private logger;
|
|
634
658
|
private pendingSendQueue;
|
|
659
|
+
/**
|
|
660
|
+
* Lowest relay endpoint security this client accepts on its next attempt.
|
|
661
|
+
* Starts at the configured minimum and rises to "protected" once a daemon
|
|
662
|
+
* negotiates it, so a later reconnect cannot be downgraded to legacy.
|
|
663
|
+
*/
|
|
664
|
+
private relaySecurityFloorValue;
|
|
635
665
|
private readonly logConnectionPath;
|
|
636
666
|
private readonly logServerId;
|
|
637
667
|
private readonly logClientIdHash;
|
|
@@ -655,10 +685,61 @@ export declare class DaemonClient {
|
|
|
655
685
|
verify?: boolean;
|
|
656
686
|
}): void;
|
|
657
687
|
private verifyConnection;
|
|
688
|
+
requireConnectedHosts(): void;
|
|
689
|
+
listHosts(): Promise<HostDirectory>;
|
|
690
|
+
observeHosts(): OwnedSubscription<HostDirectory>;
|
|
691
|
+
addHost(input: HostAdd): Promise<{
|
|
692
|
+
registrationId: string;
|
|
693
|
+
serverId: string | null;
|
|
694
|
+
label: string | null;
|
|
695
|
+
source: {
|
|
696
|
+
id: string;
|
|
697
|
+
key: string;
|
|
698
|
+
};
|
|
699
|
+
metadata: Record<string, string>;
|
|
700
|
+
enabled: boolean;
|
|
701
|
+
status: "error" | "connecting" | "disabled" | "online" | "offline";
|
|
702
|
+
targetDescription: string;
|
|
703
|
+
lastOnlineAt: string | null;
|
|
704
|
+
nextRetryAt: string | null;
|
|
705
|
+
error: {
|
|
706
|
+
code: string;
|
|
707
|
+
message: string;
|
|
708
|
+
} | null;
|
|
709
|
+
}>;
|
|
710
|
+
updateHost(registrationId: string, patch: HostUpdate): Promise<{
|
|
711
|
+
registrationId: string;
|
|
712
|
+
serverId: string | null;
|
|
713
|
+
label: string | null;
|
|
714
|
+
source: {
|
|
715
|
+
id: string;
|
|
716
|
+
key: string;
|
|
717
|
+
};
|
|
718
|
+
metadata: Record<string, string>;
|
|
719
|
+
enabled: boolean;
|
|
720
|
+
status: "error" | "connecting" | "disabled" | "online" | "offline";
|
|
721
|
+
targetDescription: string;
|
|
722
|
+
lastOnlineAt: string | null;
|
|
723
|
+
nextRetryAt: string | null;
|
|
724
|
+
error: {
|
|
725
|
+
code: string;
|
|
726
|
+
message: string;
|
|
727
|
+
} | null;
|
|
728
|
+
}>;
|
|
729
|
+
removeHost(registrationId: string): Promise<void>;
|
|
730
|
+
openHostRoute(serverId: string, scopeId: string): Promise<string>;
|
|
731
|
+
openHostLink(channelId: string): Promise<string>;
|
|
732
|
+
sendHostFrame(routeId: string, data: string | Uint8Array): void;
|
|
733
|
+
private readonly hostFrameListeners;
|
|
734
|
+
subscribeHostFrames(handler: (frame: HostRouteFrame) => void): () => void;
|
|
735
|
+
cancelHostRoute(scopeId: string): void;
|
|
736
|
+
closeHostRoute(routeId: string): void;
|
|
658
737
|
getConnectionState(): ConnectionState;
|
|
659
738
|
subscribeConnectionStatus(listener: (status: ConnectionState) => void): () => void;
|
|
660
739
|
get isConnected(): boolean;
|
|
661
740
|
get isConnecting(): boolean;
|
|
741
|
+
/** The relay endpoint security this client requires on its next attempt. */
|
|
742
|
+
get relaySecurityFloor(): RelaySecurityMode | undefined;
|
|
662
743
|
get lastError(): string | null;
|
|
663
744
|
get authFailureReason(): DaemonAuthFailureReason | null;
|
|
664
745
|
getLastLivenessRttMs(): number | null;
|
|
@@ -672,7 +753,9 @@ export declare class DaemonClient {
|
|
|
672
753
|
private beginTraceSection;
|
|
673
754
|
private endTraceSection;
|
|
674
755
|
private traceInstant;
|
|
756
|
+
private beginSessionDispatchTrace;
|
|
675
757
|
private sendJsonMessage;
|
|
758
|
+
private sendSessionPayload;
|
|
676
759
|
private sendTransportFrame;
|
|
677
760
|
/**
|
|
678
761
|
* Send a session message. For fire-and-forget messages (heartbeats, etc.),
|
|
@@ -703,6 +786,7 @@ export declare class DaemonClient {
|
|
|
703
786
|
private sendCorrelatedRequest;
|
|
704
787
|
private sendCorrelatedSessionRequest;
|
|
705
788
|
private sendNamespacedCorrelatedSessionRequest;
|
|
789
|
+
private unavailableError;
|
|
706
790
|
private sendSessionMessageStrict;
|
|
707
791
|
clearAgentAttention(agentId: string | string[]): Promise<void>;
|
|
708
792
|
clearWorkspaceAttention(workspaceId: string | string[]): Promise<void>;
|
|
@@ -825,6 +909,10 @@ export declare class DaemonClient {
|
|
|
825
909
|
type: "workspace.script.stop.response";
|
|
826
910
|
}>["payload"]>;
|
|
827
911
|
archiveWorkspace(workspaceId: string, requestId?: string): Promise<ArchiveWorkspacePayload>;
|
|
912
|
+
observeWorkspaceSetup(workspaceId: string, options?: {
|
|
913
|
+
signal?: AbortSignal;
|
|
914
|
+
}): OwnedSubscription<CorrelatedResponsePayload<"workspace.setup.subscribe.response">>;
|
|
915
|
+
private requireWorkspaceSetupObservation;
|
|
828
916
|
fetchWorkspaceSetupStatus(workspaceId: string, requestId?: string): Promise<WorkspaceSetupStatusPayload>;
|
|
829
917
|
runWorkspaceSetup(workspaceId: string, requestId?: string): Promise<Extract<SessionOutboundMessage, {
|
|
830
918
|
type: "workspace.setup.run.response";
|
|
@@ -916,8 +1004,12 @@ export declare class DaemonClient {
|
|
|
916
1004
|
}): Promise<SideConversationListPayload>;
|
|
917
1005
|
subscribeAgentTimeline(agentId: string, handler: (message: TimelineMessage) => void): TimelineSubscription;
|
|
918
1006
|
buildAgentForkContext(agentId: string, options?: AgentForkContextOptions): Promise<AgentForkContextPayload>;
|
|
919
|
-
sendAgentMessage(agentId: string, text: string, options?: SendMessageOptions): Promise<
|
|
920
|
-
|
|
1007
|
+
sendAgentMessage(agentId: string, text: string, options?: SendMessageOptions): Promise<{
|
|
1008
|
+
deliveryStatus?: "queued";
|
|
1009
|
+
}>;
|
|
1010
|
+
sendMessage(agentId: string, text: string, options?: SendMessageOptions): Promise<{
|
|
1011
|
+
deliveryStatus?: "queued";
|
|
1012
|
+
}>;
|
|
921
1013
|
/**
|
|
922
1014
|
* Admits a prompt into the durable queue with an explicit delivery intent.
|
|
923
1015
|
* `itemId` comes from the caller so an optimistic local row and the stored
|
|
@@ -1015,12 +1107,12 @@ export declare class DaemonClient {
|
|
|
1015
1107
|
}): Promise<CheckoutStatusPayload>;
|
|
1016
1108
|
private normalizeCheckoutDiffCompare;
|
|
1017
1109
|
getCheckoutDiff(cwd: string, compare: {
|
|
1018
|
-
mode: "uncommitted" | "base";
|
|
1110
|
+
mode: "uncommitted" | "base" | "all";
|
|
1019
1111
|
baseRef?: string;
|
|
1020
1112
|
ignoreWhitespace?: boolean;
|
|
1021
1113
|
}, requestId?: string): Promise<CheckoutDiffPayload>;
|
|
1022
1114
|
observeCheckoutDiff(cwd: string, compare: {
|
|
1023
|
-
mode: "uncommitted" | "base";
|
|
1115
|
+
mode: "uncommitted" | "base" | "all";
|
|
1024
1116
|
baseRef?: string;
|
|
1025
1117
|
ignoreWhitespace?: boolean;
|
|
1026
1118
|
}, options?: {
|
|
@@ -1171,6 +1263,8 @@ export declare class DaemonClient {
|
|
|
1171
1263
|
cwd: string;
|
|
1172
1264
|
path: string;
|
|
1173
1265
|
content: string;
|
|
1266
|
+
/** `base64` requires `server_info.features.fileByteWrites`. */
|
|
1267
|
+
contentEncoding?: "utf-8" | "base64";
|
|
1174
1268
|
expectedModifiedAt: string;
|
|
1175
1269
|
expectedRevision?: string;
|
|
1176
1270
|
}): Promise<FileWriteResult>;
|
|
@@ -1229,7 +1323,7 @@ export declare class DaemonClient {
|
|
|
1229
1323
|
connectHub(hubUrl: string, token: string, permissions?: readonly string[], requestId?: string): Promise<{
|
|
1230
1324
|
requestId: string;
|
|
1231
1325
|
status: {
|
|
1232
|
-
state: "
|
|
1326
|
+
state: "connecting" | "not_connected" | "connected" | "reconnecting" | "disconnecting" | "revoked";
|
|
1233
1327
|
daemonId: string | null;
|
|
1234
1328
|
hubOrigin: string | null;
|
|
1235
1329
|
permissions: ("daemon.read" | "daemon.manage" | "tunnel.manage" | "access.manage" | "workspace.read" | "workspace.write" | "workspace.manage" | "automation.manage" | "hub.execute")[];
|
|
@@ -1243,7 +1337,7 @@ export declare class DaemonClient {
|
|
|
1243
1337
|
}, requestId?: string): Promise<{
|
|
1244
1338
|
requestId: string;
|
|
1245
1339
|
status: {
|
|
1246
|
-
state: "
|
|
1340
|
+
state: "connecting" | "not_connected" | "connected" | "reconnecting" | "disconnecting" | "revoked";
|
|
1247
1341
|
daemonId: string | null;
|
|
1248
1342
|
hubOrigin: string | null;
|
|
1249
1343
|
permissions: ("daemon.read" | "daemon.manage" | "tunnel.manage" | "access.manage" | "workspace.read" | "workspace.write" | "workspace.manage" | "automation.manage" | "hub.execute")[];
|
|
@@ -1254,7 +1348,7 @@ export declare class DaemonClient {
|
|
|
1254
1348
|
getHubStatus(requestId?: string): Promise<{
|
|
1255
1349
|
requestId: string;
|
|
1256
1350
|
status: {
|
|
1257
|
-
state: "
|
|
1351
|
+
state: "connecting" | "not_connected" | "connected" | "reconnecting" | "disconnecting" | "revoked";
|
|
1258
1352
|
daemonId: string | null;
|
|
1259
1353
|
hubOrigin: string | null;
|
|
1260
1354
|
permissions: ("daemon.read" | "daemon.manage" | "tunnel.manage" | "access.manage" | "workspace.read" | "workspace.write" | "workspace.manage" | "automation.manage" | "hub.execute")[];
|
|
@@ -1265,7 +1359,7 @@ export declare class DaemonClient {
|
|
|
1265
1359
|
disconnectHub(force?: boolean, requestId?: string): Promise<{
|
|
1266
1360
|
requestId: string;
|
|
1267
1361
|
status: {
|
|
1268
|
-
state: "
|
|
1362
|
+
state: "connecting" | "not_connected" | "connected" | "reconnecting" | "disconnecting" | "revoked";
|
|
1269
1363
|
daemonId: string | null;
|
|
1270
1364
|
hubOrigin: string | null;
|
|
1271
1365
|
permissions: ("daemon.read" | "daemon.manage" | "tunnel.manage" | "access.manage" | "workspace.read" | "workspace.write" | "workspace.manage" | "automation.manage" | "hub.execute")[];
|