clay-server 4.2.0 → 4.3.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/lib/driver-continuation-access.js +54 -0
  2. package/lib/driver-continuation-lease.js +52 -0
  3. package/lib/driver-continuation-pair-transfer.js +86 -0
  4. package/lib/driver-continuation-pair.js +86 -0
  5. package/lib/driver-continuation-record.js +40 -0
  6. package/lib/driver-continuation-startup.js +68 -0
  7. package/lib/driver-continuation-transaction.js +61 -0
  8. package/lib/driver-continuation-trigger.js +110 -0
  9. package/lib/multi-worker-feature.js +11 -0
  10. package/lib/project-connection.js +3 -1
  11. package/lib/project-driver-continuation.js +499 -0
  12. package/lib/project-message-delivery.js +20 -0
  13. package/lib/project-pair-autonomous-stop.js +14 -8
  14. package/lib/project-pair-close-transaction.js +59 -0
  15. package/lib/project-pair-global-stop.js +18 -0
  16. package/lib/project-pair-lifecycle-status.js +34 -0
  17. package/lib/project-pair-lifecycle.js +117 -135
  18. package/lib/project-pair-message.js +1 -1
  19. package/lib/project-pair-owned-stop.js +7 -4
  20. package/lib/project-pair-replacement-state.js +5 -1
  21. package/lib/project-pair-result-capture.js +116 -0
  22. package/lib/project-pair-result-delivery.js +140 -0
  23. package/lib/project-pair-result-outbox.js +400 -0
  24. package/lib/project-pair-result-pipeline.js +16 -0
  25. package/lib/project-pair-result-recovery.js +229 -0
  26. package/lib/project-pair-structural-close.js +20 -0
  27. package/lib/project-pair-task-control.js +45 -18
  28. package/lib/project-pair-worker-close.js +68 -0
  29. package/lib/project-session-handoff.js +48 -55
  30. package/lib/project-session-pair-prompt.js +26 -0
  31. package/lib/project-session-pair.js +87 -106
  32. package/lib/project-sessions.js +4 -0
  33. package/lib/project-user-message.js +21 -0
  34. package/lib/project-worker-creation-proposal.js +176 -0
  35. package/lib/project-worker-permission.js +7 -8
  36. package/lib/project-worker-proposal-runner.js +45 -0
  37. package/lib/project-worker-proposal.js +79 -115
  38. package/lib/project.js +87 -3
  39. package/lib/public/app.js +1 -0
  40. package/lib/public/css/driver-continuation.css +56 -0
  41. package/lib/public/css/messages.css +12 -0
  42. package/lib/public/css/mobile-nav.css +29 -14
  43. package/lib/public/css/overlays.css +54 -25
  44. package/lib/public/css/pane.css +66 -12
  45. package/lib/public/css/sidebar.css +62 -7
  46. package/lib/public/index.html +3 -3
  47. package/lib/public/modules/app-connection.js +165 -74
  48. package/lib/public/modules/app-messages.js +31 -3
  49. package/lib/public/modules/driver-continuation-state.js +76 -0
  50. package/lib/public/modules/driver-continuation.js +260 -0
  51. package/lib/public/modules/message-delivery-ui.js +63 -0
  52. package/lib/public/modules/message-delivery.js +163 -6
  53. package/lib/public/modules/pair-result-status.js +87 -0
  54. package/lib/public/modules/permission-control.js +10 -5
  55. package/lib/public/modules/project-activation.js +10 -7
  56. package/lib/public/modules/session-creation-cta.js +46 -0
  57. package/lib/public/modules/sidebar-mobile.js +42 -30
  58. package/lib/public/modules/sidebar-sessions.js +77 -52
  59. package/lib/public/modules/split-group-helpers.js +74 -2
  60. package/lib/public/modules/split-pair-ui.js +28 -6
  61. package/lib/public/modules/split-pane-reconciler.js +28 -0
  62. package/lib/public/modules/split-pane-renderer.js +107 -0
  63. package/lib/public/modules/split-view.js +58 -188
  64. package/lib/public/modules/websocket-lifecycle.js +178 -0
  65. package/lib/public/modules/websocket-watchdog.js +126 -0
  66. package/lib/public/modules/worker-pane-lock.js +13 -3
  67. package/lib/public/style.css +1 -0
  68. package/lib/sdk-bridge.js +77 -0
  69. package/lib/server.js +1 -0
  70. package/lib/session-handoff-discovery.js +443 -0
  71. package/lib/session-handoff-mcp-server.js +32 -4
  72. package/lib/session-pair-factory.js +66 -0
  73. package/lib/session-pair-mcp-server.js +10 -5
  74. package/lib/session-pair-prompts.js +46 -25
  75. package/lib/session-pair-target.js +42 -0
  76. package/lib/session-pair-turn-control.js +30 -9
  77. package/lib/session-split-group-anchors.js +126 -0
  78. package/lib/session-split-group-persistence.js +136 -0
  79. package/lib/session-split-group-roles.js +164 -0
  80. package/lib/session-split-group-v2-store.js +146 -0
  81. package/lib/session-split-groups.js +293 -133
  82. package/lib/sessions.js +89 -22
  83. package/lib/ws-schema.js +8 -0
  84. package/package.json +1 -1
@@ -0,0 +1,178 @@
1
+ // websocket-lifecycle.js - bounded connection attempt and retry policy
2
+
3
+ var DEFAULTS = {
4
+ handshakeTimeoutMs: 12000,
5
+ stableConnectionMs: 15000,
6
+ retryMinMs: 1000,
7
+ retryMaxMs: 15000,
8
+ jitterRatio: 0.2,
9
+ authTimeoutMs: 4000
10
+ };
11
+
12
+ function createWebSocketLifecycle(options) {
13
+ var config = Object.assign({}, DEFAULTS, options || {});
14
+ var epoch = 0;
15
+ var retryAttempt = 0;
16
+ var retryTimer = null;
17
+ var handshakeTimer = null;
18
+ var stableTimer = null;
19
+ var authTimer = null;
20
+ var authInFlight = false;
21
+ var authCancel = null;
22
+ var authGeneration = 0;
23
+ var stableEpoch = 0;
24
+ var cancelled = false;
25
+ var offline = false;
26
+
27
+ function clearTimer(timer) {
28
+ if (timer) clearTimeout(timer);
29
+ return null;
30
+ }
31
+
32
+ function clearTimers() {
33
+ retryTimer = clearTimer(retryTimer);
34
+ handshakeTimer = clearTimer(handshakeTimer);
35
+ stableTimer = clearTimer(stableTimer);
36
+ authTimer = clearTimer(authTimer);
37
+ stableEpoch = 0;
38
+ if (authCancel) authCancel();
39
+ authCancel = null;
40
+ authInFlight = false;
41
+ }
42
+
43
+ function current(value) {
44
+ return value === epoch && !cancelled;
45
+ }
46
+
47
+ function canProceed(value) {
48
+ return current(value) && !offline;
49
+ }
50
+
51
+ function beginAttempt() {
52
+ clearTimers();
53
+ cancelled = false;
54
+ epoch += 1;
55
+ var attemptEpoch = epoch;
56
+ handshakeTimer = setTimeout(function () {
57
+ handshakeTimer = null;
58
+ if (current(attemptEpoch) && config.onHandshakeTimeout) config.onHandshakeTimeout(attemptEpoch);
59
+ }, config.handshakeTimeoutMs);
60
+ return attemptEpoch;
61
+ }
62
+
63
+ function delayForAttempt() {
64
+ var base = Math.min(config.retryMaxMs, config.retryMinMs * Math.pow(1.5, retryAttempt));
65
+ retryAttempt += 1;
66
+ var jitter = base * config.jitterRatio;
67
+ var random = config.random || Math.random;
68
+ return Math.min(config.retryMaxMs, Math.max(0, Math.round(base - jitter + random() * jitter * 2)));
69
+ }
70
+
71
+ function schedule(reason, callback) {
72
+ if (cancelled || offline || retryTimer) return null;
73
+ var scheduledEpoch = epoch;
74
+ var delay = delayForAttempt();
75
+ retryTimer = setTimeout(function () {
76
+ retryTimer = null;
77
+ if (!canProceed(scheduledEpoch)) return;
78
+ callback(scheduledEpoch, reason, delay);
79
+ }, delay);
80
+ return { epoch: scheduledEpoch, delay: delay };
81
+ }
82
+
83
+ function clearRetry() {
84
+ retryTimer = clearTimer(retryTimer);
85
+ }
86
+
87
+ function beginAuth(authEpoch, onTimeout, onCancel) {
88
+ if (!canProceed(authEpoch) || authInFlight) return null;
89
+ authInFlight = true;
90
+ authGeneration += 1;
91
+ var authToken = { epoch: authEpoch, generation: authGeneration };
92
+ authCancel = onCancel || null;
93
+ authTimer = setTimeout(function () {
94
+ authTimer = null;
95
+ authInFlight = false;
96
+ authCancel = null;
97
+ if (canProceed(authEpoch) && onTimeout) onTimeout(authEpoch);
98
+ }, config.authTimeoutMs);
99
+ return authToken;
100
+ }
101
+
102
+ function finishAuth(authEpoch, authToken) {
103
+ if (!authInFlight || !current(authEpoch) || !authToken || authToken.epoch !== authEpoch || authToken.generation !== authGeneration) return false;
104
+ authInFlight = false;
105
+ authCancel = null;
106
+ authTimer = clearTimer(authTimer);
107
+ return true;
108
+ }
109
+
110
+ function markOpen(attemptEpoch) {
111
+ if (!current(attemptEpoch)) return false;
112
+ handshakeTimer = clearTimer(handshakeTimer);
113
+ return true;
114
+ }
115
+
116
+ function markLive(attemptEpoch) {
117
+ if (!current(attemptEpoch)) return false;
118
+ handshakeTimer = clearTimer(handshakeTimer);
119
+ if (stableEpoch === attemptEpoch) return true;
120
+ stableEpoch = attemptEpoch;
121
+ stableTimer = clearTimer(stableTimer);
122
+ stableTimer = setTimeout(function () {
123
+ stableTimer = null;
124
+ if (current(attemptEpoch)) retryAttempt = 0;
125
+ }, config.stableConnectionMs);
126
+ return true;
127
+ }
128
+
129
+ function invalidate(attemptEpoch) {
130
+ if (attemptEpoch !== epoch) return false;
131
+ epoch += 1;
132
+ clearTimers();
133
+ return true;
134
+ }
135
+
136
+ function cancel() {
137
+ cancelled = true;
138
+ epoch += 1;
139
+ clearTimers();
140
+ }
141
+
142
+ function setOffline(value) {
143
+ var nextOffline = value === true;
144
+ if (nextOffline === offline) return offline;
145
+ offline = nextOffline;
146
+ if (offline) {
147
+ epoch += 1;
148
+ clearTimers();
149
+ }
150
+ return offline;
151
+ }
152
+
153
+ function wake(callback) {
154
+ offline = false;
155
+ if (!cancelled && callback) callback();
156
+ }
157
+
158
+ return {
159
+ beginAttempt: beginAttempt,
160
+ beginAuth: beginAuth,
161
+ cancel: cancel,
162
+ canProceed: canProceed,
163
+ clearRetry: clearRetry,
164
+ current: current,
165
+ finishAuth: finishAuth,
166
+ invalidate: invalidate,
167
+ markOpen: markOpen,
168
+ markLive: markLive,
169
+ schedule: schedule,
170
+ setOffline: setOffline,
171
+ wake: wake,
172
+ getRetryAttempt: function () { return retryAttempt; },
173
+ getEpoch: function () { return epoch; },
174
+ isOffline: function () { return offline; }
175
+ };
176
+ }
177
+
178
+ export { createWebSocketLifecycle };
@@ -0,0 +1,126 @@
1
+ // websocket-watchdog.js - suspendable liveness timers for the browser socket
2
+
3
+ function createWebSocketWatchdog(options) {
4
+ var suspended = false;
5
+ var heartbeatTimer = null;
6
+ var heartbeatDeadlineTimer = null;
7
+ var heartbeatSocket = null;
8
+ var heartbeatEpoch = 0;
9
+ var heartbeatGeneration = 0;
10
+ var deadlineGeneration = 0;
11
+ var probeTimer = null;
12
+ var probeSocket = null;
13
+ var probeEpoch = 0;
14
+ var probeStartedAt = 0;
15
+ var probeGeneration = 0;
16
+
17
+ function clearHeartbeatDeadline() {
18
+ deadlineGeneration += 1;
19
+ if (heartbeatDeadlineTimer) clearTimeout(heartbeatDeadlineTimer);
20
+ heartbeatDeadlineTimer = null;
21
+ }
22
+
23
+ function stopHeartbeat() {
24
+ heartbeatGeneration += 1;
25
+ clearHeartbeatDeadline();
26
+ if (heartbeatTimer) clearInterval(heartbeatTimer);
27
+ heartbeatTimer = null;
28
+ heartbeatSocket = null;
29
+ heartbeatEpoch = 0;
30
+ }
31
+
32
+ function clearProbe() {
33
+ probeGeneration += 1;
34
+ if (probeTimer) clearTimeout(probeTimer);
35
+ probeTimer = null;
36
+ probeSocket = null;
37
+ probeEpoch = 0;
38
+ probeStartedAt = 0;
39
+ }
40
+
41
+ function suspend() {
42
+ suspended = true;
43
+ stopHeartbeat();
44
+ clearProbe();
45
+ }
46
+
47
+ function resume() {
48
+ var changed = suspended;
49
+ suspended = false;
50
+ return changed;
51
+ }
52
+
53
+ function startHeartbeat(socket, epoch) {
54
+ stopHeartbeat();
55
+ if (suspended || !socket) return false;
56
+ heartbeatSocket = socket;
57
+ heartbeatEpoch = epoch;
58
+ var generation = heartbeatGeneration;
59
+ heartbeatTimer = setInterval(function () {
60
+ if (suspended || generation !== heartbeatGeneration) return;
61
+ if (!options.isCurrent(socket, epoch)) {
62
+ stopHeartbeat();
63
+ return;
64
+ }
65
+ clearHeartbeatDeadline();
66
+ var currentDeadlineGeneration = deadlineGeneration;
67
+ heartbeatDeadlineTimer = setTimeout(function () {
68
+ if (suspended || currentDeadlineGeneration !== deadlineGeneration) return;
69
+ heartbeatDeadlineTimer = null;
70
+ if (heartbeatSocket === socket && heartbeatEpoch === epoch && options.isCurrent(socket, epoch)) {
71
+ options.onFailure("heartbeat_timeout", epoch, null);
72
+ }
73
+ }, options.heartbeatDeadlineMs);
74
+ try {
75
+ options.sendPing(socket);
76
+ } catch (e) {
77
+ options.onFailure("heartbeat_error", epoch, null);
78
+ }
79
+ }, options.heartbeatIntervalMs);
80
+ return true;
81
+ }
82
+
83
+ function probe(socket, epoch) {
84
+ if (suspended) return "suspended";
85
+ if (probeTimer) return "pending";
86
+ probeSocket = socket;
87
+ probeEpoch = epoch;
88
+ probeStartedAt = options.now();
89
+ probeGeneration += 1;
90
+ var generation = probeGeneration;
91
+ probeTimer = setTimeout(function () {
92
+ if (suspended || generation !== probeGeneration) return;
93
+ probeTimer = null;
94
+ if (probeSocket === socket && probeEpoch === epoch && options.isCurrent(socket, epoch)) {
95
+ options.onFailure("probe_timeout", epoch, options.now() - probeStartedAt);
96
+ }
97
+ }, options.probeTimeoutMs);
98
+ try {
99
+ options.sendPing(socket);
100
+ } catch (e) {
101
+ if (generation !== probeGeneration) return "cleared";
102
+ var latency = options.now() - probeStartedAt;
103
+ clearProbe();
104
+ options.onFailure("probe_error", epoch, latency);
105
+ return "failed";
106
+ }
107
+ return "started";
108
+ }
109
+
110
+ function acceptPong(socket, epoch) {
111
+ if (heartbeatSocket === socket && heartbeatEpoch === epoch) clearHeartbeatDeadline();
112
+ if (probeSocket === socket && probeEpoch === epoch) clearProbe();
113
+ }
114
+
115
+ return {
116
+ acceptPong: acceptPong,
117
+ clearProbe: clearProbe,
118
+ probe: probe,
119
+ resume: resume,
120
+ startHeartbeat: startHeartbeat,
121
+ stopHeartbeat: stopHeartbeat,
122
+ suspend: suspend
123
+ };
124
+ }
125
+
126
+ export { createWebSocketWatchdog };
@@ -27,6 +27,18 @@ import { store } from './store.js';
27
27
  var STATUS_ID = "worker-pane-status";
28
28
  var LOCK_CLASS = "worker-pane-locked";
29
29
 
30
+ function configuredWorkerIds(group) {
31
+ if (!group || !group.pair || !Array.isArray(group.members)) return [];
32
+ var pair = group.pair;
33
+ var ids = Array.isArray(pair.workerIds) ? pair.workerIds :
34
+ (pair.workerId !== undefined ? [pair.workerId] : []);
35
+ if (pair.driverId === undefined || ids.length < 1 || ids.length > 2 || group.members.indexOf(pair.driverId) === -1) return [];
36
+ for (var i = 0; i < ids.length; i++) {
37
+ if (ids[i] === pair.driverId || group.members.indexOf(ids[i]) === -1) return [];
38
+ }
39
+ return ids;
40
+ }
41
+
30
42
  // Every interactive composer affordance. Queried lazily: a pane iframe and the
31
43
  // main window share this markup, and some ids are mobile-only.
32
44
  var LOCKED_CONTROL_IDS = [
@@ -64,9 +76,7 @@ export function isDriverOperatedView(state) {
64
76
  if (!sessionId) return false;
65
77
  var groups = snapshot.splitGroups || [];
66
78
  for (var i = 0; i < groups.length; i++) {
67
- var pair = groups[i] && groups[i].pair;
68
- if (!pair) continue;
69
- if (pair.workerId === sessionId) return true;
79
+ if (configuredWorkerIds(groups[i]).indexOf(sessionId) !== -1) return true;
70
80
  }
71
81
  return false;
72
82
  }
@@ -26,6 +26,7 @@
26
26
  @import url("css/loop.css");
27
27
  @import url("css/scheduler.css");
28
28
  @import url("css/project-logs.css");
29
+ @import url("css/driver-continuation.css");
29
30
  @import url("css/scheduled-tasks.css");
30
31
  @import url("css/scheduler-modal.css");
31
32
  @import url("css/home-hub.css");
package/lib/sdk-bridge.js CHANGED
@@ -603,6 +603,10 @@ function createSDKBridge(opts) {
603
603
  return { behavior: "allow", updatedInput: input };
604
604
  }
605
605
 
606
+ if (toolName === "propose_driver_continuation" || toolName === "mcp__clay-continuation__propose_driver_continuation") {
607
+ return { behavior: "allow", updatedInput: input };
608
+ }
609
+
606
610
  var safeCapsuleTools = {
607
611
  clay_tool_list: true,
608
612
  clay_tool_snapshot: true,
@@ -1004,6 +1008,26 @@ function createSDKBridge(opts) {
1004
1008
  mode: session.permissionMode || sm.currentPermissionMode || "default", effectivePermissionMode: message.permissionMode,
1005
1009
  permissionCapabilities: session.permissionCapabilities || { auto: false, mcpOverride: false },
1006
1010
  mcpPermissionModeOverrides: session.mcpPermissionModeOverrides || {} });
1011
+ if (typeof sm.broadcastSessionList === "function") sm.broadcastSessionList();
1012
+ return true;
1013
+ }
1014
+
1015
+ function settleContinuationStartup(session, queryInstance, queryGeneration, accepted, reason) {
1016
+ var probe = session._continuationStartupProbe;
1017
+ if (!probe || probe.queryInstance !== queryInstance || probe.queryGeneration !== queryGeneration) return false;
1018
+ if (!ownsQueryRuntime(session, queryInstance, queryGeneration)) return false;
1019
+ delete session._continuationStartupProbe;
1020
+ clearTimeout(probe.timer);
1021
+ if (probe.timedOut) {
1022
+ if (typeof probe.onLateStartup === "function") probe.onLateStartup({
1023
+ accepted: accepted === true,
1024
+ queryAlive: session.queryInstance === queryInstance,
1025
+ queryGeneration: queryGeneration,
1026
+ reason: reason || null,
1027
+ });
1028
+ return true;
1029
+ }
1030
+ probe.resolve({ accepted: accepted === true, reason: reason || null });
1007
1031
  return true;
1008
1032
  }
1009
1033
 
@@ -1054,7 +1078,16 @@ function createSDKBridge(opts) {
1054
1078
  }
1055
1079
  continue;
1056
1080
  }
1081
+ var continuationIdentity = msg && (msg.yokeType === "init" || msg.yokeType === "session_started");
1082
+ if (continuationIdentity && !ownsQueryRuntime(session, myQueryInstance, myQueryGeneration)) {
1083
+ continue;
1084
+ }
1057
1085
  processSDKMessage(session, msg);
1086
+ if (continuationIdentity) {
1087
+ settleContinuationStartup(session, myQueryInstance, myQueryGeneration, true, null);
1088
+ } else if (msg && msg.yokeType === "error") {
1089
+ settleContinuationStartup(session, myQueryInstance, myQueryGeneration, false, "The successor reported an error before initialization.");
1090
+ }
1058
1091
  // SDK init/status events are the only authority for runtime-effective
1059
1092
  // permission state. Setter acknowledgement deliberately does not
1060
1093
  // change this field.
@@ -1075,6 +1108,7 @@ function createSDKBridge(opts) {
1075
1108
  // so the session is still marked as processing. Send interrupted feedback.
1076
1109
  console.log("[sdk-bridge] processQueryStream ended: isProcessing=" + session.isProcessing + " taskStopRequested=" + session.taskStopRequested);
1077
1110
  var stillOwnsRuntime = session.queryInstance === myQueryInstance;
1111
+ settleContinuationStartup(session, myQueryInstance, myQueryGeneration, false, "The successor query ended before initialization.");
1078
1112
  if (session.isProcessing && session.taskStopRequested && stillOwnsRuntime) {
1079
1113
  session._lastTurnInterrupted = true;
1080
1114
  session.isProcessing = false;
@@ -1108,6 +1142,7 @@ function createSDKBridge(opts) {
1108
1142
  sm.broadcastSessionList();
1109
1143
  }
1110
1144
  } catch (err) {
1145
+ settleContinuationStartup(session, myQueryInstance, myQueryGeneration, false, err.message || "The successor query failed before initialization.");
1111
1146
  if (session.isProcessing && session.queryInstance === myQueryInstance) {
1112
1147
  session.isProcessing = false;
1113
1148
  session._awaitingTurnResult = false;
@@ -1202,6 +1237,7 @@ function createSDKBridge(opts) {
1202
1237
  sm.broadcastSessionList();
1203
1238
  }
1204
1239
  } finally {
1240
+ settleContinuationStartup(session, myQueryInstance, myQueryGeneration, false, "The successor query closed before initialization.");
1205
1241
  // Close the SDK query to terminate the underlying claude child process.
1206
1242
  // Without this, the process stays alive indefinitely (single-user mode).
1207
1243
  // Only clean up if the session still references OUR resources.
@@ -1398,6 +1434,46 @@ function createSDKBridge(opts) {
1398
1434
  }
1399
1435
  }
1400
1436
 
1437
+ // Continuation startup needs stronger evidence than a resolved startQuery
1438
+ // promise: createQuery and initial delivery failures are intentionally
1439
+ // contained inside startQuery. Return success only when the initial message
1440
+ // was accepted and that exact query emitted its provider initialization event.
1441
+ async function startQueryWithAcceptance(session, text, images, linuxUser, beforePush, onLateStartup) {
1442
+ var acceptedHandle = null;
1443
+ var acceptedGeneration = null;
1444
+ var resolveStartup;
1445
+ var startup = new Promise(function (resolve) { resolveStartup = resolve; });
1446
+ var result = await startQuery(session, text, images, linuxUser, beforePush, function () {
1447
+ acceptedHandle = session.queryInstance || null;
1448
+ acceptedGeneration = Number(session._sdkQueryGeneration || 0);
1449
+ session._continuationStartupProbe = {
1450
+ queryInstance: acceptedHandle,
1451
+ queryGeneration: acceptedGeneration,
1452
+ resolve: resolveStartup,
1453
+ onLateStartup: onLateStartup,
1454
+ timedOut: false,
1455
+ };
1456
+ session._continuationStartupProbe.timer = setTimeout(function () {
1457
+ var probe = session._continuationStartupProbe;
1458
+ if (!probe || probe.queryInstance !== acceptedHandle || probe.queryGeneration !== acceptedGeneration) return;
1459
+ probe.timedOut = true;
1460
+ probe.resolve({ accepted: false, timedOut: true, reason: "The successor did not initialize in time." });
1461
+ }, Number(opts.continuationStartupWaitMs || 15000));
1462
+ });
1463
+ var initialAccepted = result === true && !!acceptedHandle;
1464
+ if (!initialAccepted) resolveStartup({ accepted: false, reason: "The successor did not accept its initial query." });
1465
+ var startupResult = await startup;
1466
+ var accepted = initialAccepted && startupResult.accepted === true;
1467
+ return {
1468
+ accepted: accepted,
1469
+ initialAccepted: initialAccepted,
1470
+ queryAlive: session.queryInstance === acceptedHandle,
1471
+ queryGeneration: acceptedGeneration,
1472
+ timedOut: startupResult.timedOut === true,
1473
+ reason: accepted ? null : startupResult.reason || "The successor did not initialize its accepted query.",
1474
+ };
1475
+ }
1476
+
1401
1477
  async function startQueryInner(session, text, images, linuxUser, beforePush, onAccepted) {
1402
1478
  var sessionRuntimeEnv = getRuntimeEnv(session);
1403
1479
  var resumedAtQueryStart = !!session.cliSessionId;
@@ -2647,6 +2723,7 @@ function createSDKBridge(opts) {
2647
2723
  rollbackConversation: rollbackConversation,
2648
2724
  forkSession: forkSessionUnified,
2649
2725
  startQuery: startQuery,
2726
+ startQueryWithAcceptance: startQueryWithAcceptance,
2650
2727
  pushMessage: pushMessage,
2651
2728
  refreshSessionRuntime: refreshSessionRuntime,
2652
2729
  refreshEnvironmentRuntime: refreshEnvironmentRuntime,
package/lib/server.js CHANGED
@@ -1336,6 +1336,7 @@ function createServer(opts) {
1336
1336
  worktreeMeta: worktreeMeta || null,
1337
1337
  mcpBridgeToken: extra.mcpBridgeToken || null,
1338
1338
  isMate: extra.isMate || false,
1339
+ multiWorkerRuntimeEnabled: !extra.isMate,
1339
1340
  mateId: extra.mateId || (extra.isMate ? path.basename(cwd) : null),
1340
1341
  mateDisplayName: extra.mateDisplayName || "",
1341
1342
  isHostAgent: !!extra.isHostAgent,