@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.
@@ -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;
@@ -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 declare function createRelayE2eeTransportFactory(args: {
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
- export declare function createRelayTransportFactory(baseFactory: DaemonTransportFactory): DaemonTransportFactory;
8
- export declare function createEncryptedTransport(base: DaemonTransport, daemonPublicKeyB64: string, logger: TransportLogger): DaemonTransport;
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 { createClientChannel, } from "@camerontaylor/paseo-relay/e2ee";
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
- return ({ url }) => {
6
- const base = args.baseFactory({ url });
7
- return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger);
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
- export function createRelayTransportFactory(baseFactory) {
11
- // The relay upgrade precedes E2EE. Only the encrypted hello may carry daemon credentials.
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, daemonPublicKeyB64, logger) {
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: (code, reason) => base.close(code, reason),
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 createClientChannel(relayTransport, daemonPublicKeyB64, {
72
- onopen: emitOpen,
73
- onmessage: (data) => emitMessage(data),
74
- onclose: (code, reason) => emitClose({ code, reason }),
75
- onerror: (error) => emitError(error),
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, createRelayTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
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, createRelayTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
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
@@ -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
- constructor(message: string, code?: "DAEMON_CONNECTION_LOST" | "DAEMON_REQUEST_TIMEOUT");
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<void>;
920
- sendMessage(agentId: string, text: string, options?: SendMessageOptions): Promise<void>;
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: "not_connected" | "connecting" | "connected" | "reconnecting" | "disconnecting" | "revoked";
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: "not_connected" | "connecting" | "connected" | "reconnecting" | "disconnecting" | "revoked";
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: "not_connected" | "connecting" | "connected" | "reconnecting" | "disconnecting" | "revoked";
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: "not_connected" | "connecting" | "connected" | "reconnecting" | "disconnecting" | "revoked";
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")[];