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
package/lib/sessions.js CHANGED
@@ -24,6 +24,7 @@ function createSessionManager(opts) {
24
24
  var sessionViewedListeners = [];
25
25
  var onSessionRenamed = opts.onSessionRenamed || function () {};
26
26
  var onSessionIdentityAssigned = opts.onSessionIdentityAssigned || function () {};
27
+ var sessionIdentityAssignedListeners = [];
27
28
  var onSessionHydrate = opts.onSessionHydrate || null;
28
29
 
29
30
  // --- Multi-session state ---
@@ -143,17 +144,32 @@ function createSessionManager(opts) {
143
144
  }
144
145
  }
145
146
 
146
- function sessionFilePath(cliSessionId) {
147
- return path.join(sessionsDir, cliSessionId + ".jsonl");
147
+ function sessionFilePath(recordId) {
148
+ return path.join(sessionsDir, recordId + ".jsonl");
149
+ }
150
+
151
+ // A Clay record must exist before a provider assigns its resumable id.
152
+ // Existing records keep their filename; fresh provider-less sessions use
153
+ // the already durable origin id and later store cliSessionId as metadata.
154
+ function sessionRecordId(session) {
155
+ if (!session) return null;
156
+ return session._sessionRecordId || session.cliSessionId || session.sessionOriginId || null;
157
+ }
158
+
159
+ function existingSessionRecordId(session) {
160
+ if (!session) return null;
161
+ return session._sessionRecordId || session.cliSessionId || null;
148
162
  }
149
163
 
150
164
  function saveSessionFile(session) {
151
- if (!session.cliSessionId) return;
152
165
  try {
166
+ var provenanceMeta = sessionProvenance.metadata(session);
167
+ var recordId = sessionRecordId(session);
168
+ if (!recordId) return false;
153
169
  var metaObj = {
154
170
  type: "meta",
155
171
  localId: session.localId,
156
- cliSessionId: session.cliSessionId,
172
+ cliSessionId: session.cliSessionId || null,
157
173
  title: session.title,
158
174
  titleProvisional: session.titleProvisional === true,
159
175
  titleAutoGenerated: session.titleAutoGenerated === true,
@@ -194,6 +210,8 @@ function createSessionManager(opts) {
194
210
  if (session.spawn) metaObj.spawn = session.spawn;
195
211
  if (session.assignment) metaObj.assignment = session.assignment;
196
212
  if (session.handoff) metaObj.handoff = session.handoff;
213
+ if (session.driverContinuation) metaObj.driverContinuation = session.driverContinuation;
214
+ if (session.driverContinuationDecline) metaObj.driverContinuationDecline = session.driverContinuationDecline;
197
215
  if (session.debateState) metaObj.debateState = session.debateState;
198
216
  if (session.debateSetupMode) metaObj.debateSetupMode = true;
199
217
  if (session.homeDebatePlanning) metaObj.homeDebatePlanning = true;
@@ -201,7 +219,6 @@ function createSessionManager(opts) {
201
219
  if (session.homeDebateInitialTopic) metaObj.homeDebateInitialTopic = session.homeDebateInitialTopic;
202
220
  if (session.homeClayEntryRequestId) metaObj.homeClayEntryRequestId = session.homeClayEntryRequestId;
203
221
  if (session.homeClayEntryMode) metaObj.homeClayEntryMode = session.homeClayEntryMode;
204
- var provenanceMeta = sessionProvenance.metadata(session);
205
222
  metaObj.sessionOriginId = provenanceMeta.sessionOriginId;
206
223
  if (provenanceMeta.sessionProvenance) metaObj.sessionProvenance = provenanceMeta.sessionProvenance;
207
224
  if (Array.isArray(session._workerGenerations)) metaObj.workerGenerations = session._workerGenerations;
@@ -210,7 +227,7 @@ function createSessionManager(opts) {
210
227
  for (var i = 0; i < session.history.length; i++) {
211
228
  lines.push(JSON.stringify(session.history[i]));
212
229
  }
213
- var sfPath = sessionFilePath(session.cliSessionId);
230
+ var sfPath = sessionFilePath(recordId);
214
231
  // Atomic write: write to temp file then rename, so a crash mid-write
215
232
  // cannot leave a truncated/corrupted session file.
216
233
  var tmpPath = sfPath + ".tmp." + process.pid;
@@ -219,22 +236,28 @@ function createSessionManager(opts) {
219
236
  try { fs.chmodSync(tmpPath, 0o600); } catch (chmodErr) {}
220
237
  }
221
238
  fs.renameSync(tmpPath, sfPath);
239
+ session._sessionRecordId = recordId;
240
+ return true;
222
241
  } catch(e) {
223
242
  console.error("[session] Failed to save session file:", e.message);
243
+ return false;
224
244
  }
225
245
  }
226
246
 
227
247
  function appendToSessionFile(session, obj) {
228
- if (!session.cliSessionId) return;
248
+ var recordId = existingSessionRecordId(session);
249
+ if (!recordId) return true;
229
250
  session.lastActivity = Date.now();
230
251
  try {
231
- var afPath = sessionFilePath(session.cliSessionId);
252
+ var afPath = sessionFilePath(recordId);
232
253
  fs.appendFileSync(afPath, JSON.stringify(obj) + "\n");
233
254
  if (process.platform !== "win32") {
234
255
  try { fs.chmodSync(afPath, 0o600); } catch (chmodErr) {}
235
256
  }
257
+ return true;
236
258
  } catch(e) {
237
259
  console.error("[session] Failed to append to session file:", e.message);
260
+ return false;
238
261
  }
239
262
  }
240
263
 
@@ -269,7 +292,8 @@ function createSessionManager(opts) {
269
292
 
270
293
  var meta;
271
294
  try { meta = JSON.parse(lines[0]); } catch { continue; }
272
- if (meta.type !== "meta" || !meta.cliSessionId) continue;
295
+ var pendingOrigin = typeof meta.sessionOriginId === "string" && meta.sessionOriginId.trim() && meta.sessionOriginId.length <= 128;
296
+ if (meta.type !== "meta" || (!meta.cliSessionId && !pendingOrigin)) continue;
273
297
 
274
298
  var history = [];
275
299
  for (var j = 1; j < lines.length; j++) {
@@ -278,7 +302,7 @@ function createSessionManager(opts) {
278
302
 
279
303
  var fileMtime = 0;
280
304
  try { fileMtime = fs.statSync(path.join(sessionsDir, files[i])).mtimeMs; } catch {}
281
- loaded.push({ meta: meta, history: history, mtime: fileMtime });
305
+ loaded.push({ meta: meta, history: history, mtime: fileMtime, recordId: files[i].slice(0, -".jsonl".length) });
282
306
  }
283
307
 
284
308
  loaded.sort(function(a, b) { return a.meta.createdAt - b.meta.createdAt; });
@@ -303,6 +327,7 @@ function createSessionManager(opts) {
303
327
  queryInstance: null,
304
328
  messageQueue: null,
305
329
  cliSessionId: m.cliSessionId,
330
+ _sessionRecordId: loaded[i].recordId,
306
331
  blocks: {},
307
332
  sentToolResults: {},
308
333
  pendingPermissions: {},
@@ -327,6 +352,8 @@ function createSessionManager(opts) {
327
352
  if (m.spawn) session.spawn = m.spawn;
328
353
  if (m.assignment) session.assignment = m.assignment;
329
354
  if (m.handoff) session.handoff = m.handoff;
355
+ if (m.driverContinuation) session.driverContinuation = m.driverContinuation;
356
+ if (m.driverContinuationDecline) session.driverContinuationDecline = m.driverContinuationDecline;
330
357
  if (m.debateState) session.debateState = m.debateState;
331
358
  if (m.debateSetupMode) session.debateSetupMode = true;
332
359
  if (m.homeDebatePlanning) session.homeDebatePlanning = true;
@@ -379,7 +406,7 @@ function createSessionManager(opts) {
379
406
  saveSessionFile(session);
380
407
  try {
381
408
  var preservedTime = new Date(activityTime);
382
- fs.utimesSync(sessionFilePath(session.cliSessionId), preservedTime, preservedTime);
409
+ fs.utimesSync(sessionFilePath(sessionRecordId(session)), preservedTime, preservedTime);
383
410
  } catch (e) {}
384
411
  delete session._provenanceMigrationNeeded;
385
412
  });
@@ -839,7 +866,7 @@ function createSessionManager(opts) {
839
866
  var _sessionVendor = session.vendor || defaultVendor || "claude";
840
867
  var _vendorCaps = _capsByVendor[_sessionVendor] || {};
841
868
  var _permissionState = require("./session-permission-mode").clientState(session, "default", defaultVendor);
842
- _send({ type: "session_switched", id: localId, cliSessionId: session.cliSessionId || null, loop: session.loop || null, vendor: session.vendor || null, model: session.model || null, effort: session.effort || null, hasHistory: (session.history && session.history.length > 0), capabilities: _vendorCaps, isProcessing: !!session.isProcessing, mode: session.mode || "gui", terminalId: typeof session.terminalId === "number" ? session.terminalId : null, runtimeMode: session.runtimeMode || null, runtimeTerminalId: typeof session.runtimeTerminalId === "number" ? session.runtimeTerminalId : null, tuiSuspended: !!session.tuiSuspended, dangerouslySkipPermissions: !!session.dangerouslySkipPermissions, permissionMode: _permissionState.requestedPermissionMode, effectivePermissionMode: _permissionState.effectivePermissionMode, permissionCapabilities: _permissionState.permissionCapabilities, mcpPermissionModeOverrides: _permissionState.mcpPermissionModeOverrides, autonomousRun: projectAutonomousRun(session.autonomousRun), loopInterviewBrief: session.loopInterviewBrief || null, loopInterviewHandoff: session.loopInterviewHandoff || null, scheduledTaskDraft: session.scheduledTaskDraft || null });
869
+ _send({ type: "session_switched", id: localId, sessionOriginId: session.sessionOriginId || null, cliSessionId: session.cliSessionId || null, loop: session.loop || null, vendor: session.vendor || null, model: session.model || null, effort: session.effort || null, hasHistory: (session.history && session.history.length > 0), capabilities: _vendorCaps, isProcessing: !!session.isProcessing, mode: session.mode || "gui", terminalId: typeof session.terminalId === "number" ? session.terminalId : null, runtimeMode: session.runtimeMode || null, runtimeTerminalId: typeof session.runtimeTerminalId === "number" ? session.runtimeTerminalId : null, tuiSuspended: !!session.tuiSuspended, dangerouslySkipPermissions: !!session.dangerouslySkipPermissions, permissionMode: _permissionState.requestedPermissionMode, effectivePermissionMode: _permissionState.effectivePermissionMode, permissionCapabilities: _permissionState.permissionCapabilities, mcpPermissionModeOverrides: _permissionState.mcpPermissionModeOverrides, autonomousRun: projectAutonomousRun(session.autonomousRun), loopInterviewBrief: session.loopInterviewBrief || null, loopInterviewHandoff: session.loopInterviewHandoff || null, scheduledTaskDraft: session.scheduledTaskDraft || null });
843
870
  // Send vendor-specific slash commands
844
871
  var _vendorCmds = (session.slashCommandsByVendor && session.slashCommandsByVendor[_sessionVendor])
845
872
  || session.slashCommands
@@ -908,10 +935,9 @@ function createSessionManager(opts) {
908
935
  session.worker = null;
909
936
  }
910
937
 
911
- if (session.cliSessionId) {
912
- rememberDeletedCliSession(session.cliSessionId);
913
- try { fs.unlinkSync(sessionFilePath(session.cliSessionId)); } catch(e) {}
914
- }
938
+ if (session.cliSessionId) rememberDeletedCliSession(session.cliSessionId);
939
+ var recordId = existingSessionRecordId(session);
940
+ if (recordId) try { fs.unlinkSync(sessionFilePath(recordId)); } catch(e) {}
915
941
 
916
942
  sessions.delete(localId);
917
943
  try { onSessionDeleted(localId, session); } catch (e) {
@@ -955,10 +981,9 @@ function createSessionManager(opts) {
955
981
  try { session.worker.kill(); } catch(e) {}
956
982
  session.worker = null;
957
983
  }
958
- if (session.cliSessionId) {
959
- rememberDeletedCliSession(session.cliSessionId);
960
- try { fs.unlinkSync(sessionFilePath(session.cliSessionId)); } catch(e) {}
961
- }
984
+ if (session.cliSessionId) rememberDeletedCliSession(session.cliSessionId);
985
+ var recordId = existingSessionRecordId(session);
986
+ if (recordId) try { fs.unlinkSync(sessionFilePath(recordId)); } catch(e) {}
962
987
  sessions.delete(localId);
963
988
  try { onSessionDeleted(localId, session); } catch (e) {
964
989
  console.error("[session] Session deletion hook failed:", e.message || e);
@@ -1024,7 +1049,7 @@ function createSessionManager(opts) {
1024
1049
  var outgoingObj = clientObj || obj;
1025
1050
  if (!outgoingObj._ts) outgoingObj._ts = obj._ts;
1026
1051
  session.history.push(obj);
1027
- appendToSessionFile(session, obj);
1052
+ if (appendToSessionFile(session, obj) === false) return false;
1028
1053
  // Per-session out-of-band subscribers mirror mate session events into
1029
1054
  // a parallel UI without joining the project's
1030
1055
  // ws clients set). Subscribers receive the same obj that goes to ws
@@ -1080,6 +1105,35 @@ function createSessionManager(opts) {
1080
1105
  }
1081
1106
  // Notify server for cross-project unread tracking
1082
1107
  if (obj.type === "done") onSessionDone(session);
1108
+ return true;
1109
+ }
1110
+
1111
+ function sendAndRecordDurably(session, obj, clientObj) {
1112
+ var recordId = existingSessionRecordId(session);
1113
+ if (!recordId || !fs.existsSync(sessionFilePath(recordId))) return false;
1114
+ var saved;
1115
+ try { saved = doSendAndRecord(session, obj, clientObj); }
1116
+ catch (error) {
1117
+ var exact = JSON.stringify(obj);
1118
+ if (hasDurableSessionRecord(session, function (record) { return JSON.stringify(record) === exact; })) return true;
1119
+ if (session.history[session.history.length - 1] === obj) session.history.pop();
1120
+ throw error;
1121
+ }
1122
+ if (saved === false && session.history[session.history.length - 1] === obj) session.history.pop();
1123
+ return saved === true;
1124
+ }
1125
+
1126
+ function hasDurableSessionRecord(session, predicate) {
1127
+ var recordId = existingSessionRecordId(session);
1128
+ if (!recordId || typeof predicate !== "function") return false;
1129
+ try {
1130
+ var lines = fs.readFileSync(sessionFilePath(recordId), "utf8").split("\n");
1131
+ for (var i = lines.length - 1; i >= 0; i--) {
1132
+ if (!lines[i]) continue;
1133
+ try { if (predicate(JSON.parse(lines[i]))) return true; } catch (error) {}
1134
+ }
1135
+ } catch (error) {}
1136
+ return false;
1083
1137
  }
1084
1138
 
1085
1139
  function resumeSession(cliSessionId, opts, targetWs) {
@@ -1340,8 +1394,19 @@ function createSessionManager(opts) {
1340
1394
  addOnSessionViewed: function (fn) { if (typeof fn === "function") sessionViewedListeners.push(fn); },
1341
1395
  setOnSessionRenamed: function (fn) { onSessionRenamed = fn || function () {}; },
1342
1396
  setOnSessionIdentityAssigned: function (fn) { onSessionIdentityAssigned = fn || function () {}; },
1397
+ addOnSessionIdentityAssigned: function (fn) {
1398
+ if (typeof fn !== "function") return function () {};
1399
+ sessionIdentityAssignedListeners.push(fn);
1400
+ return function () {
1401
+ sessionIdentityAssignedListeners = sessionIdentityAssignedListeners.filter(function (listener) { return listener !== fn; });
1402
+ };
1403
+ },
1343
1404
  notifySessionRenamed: function (localId) { onSessionRenamed(localId); },
1344
- notifySessionIdentityAssigned: function (localId) { onSessionIdentityAssigned(localId); },
1405
+ notifySessionIdentityAssigned: function (localId) {
1406
+ onSessionIdentityAssigned(localId);
1407
+ var listeners = sessionIdentityAssignedListeners.slice();
1408
+ for (var i = 0; i < listeners.length; i++) listeners[i](localId);
1409
+ },
1345
1410
  HISTORY_PAGE_SIZE: HISTORY_PAGE_SIZE,
1346
1411
  getActiveSession: getActiveSession,
1347
1412
  createSession: createSession,
@@ -1366,6 +1431,8 @@ function createSessionManager(opts) {
1366
1431
  saveSessionFile: saveSessionFile,
1367
1432
  appendToSessionFile: appendToSessionFile,
1368
1433
  sendAndRecord: doSendAndRecord,
1434
+ sendAndRecordDurably: sendAndRecordDurably,
1435
+ hasDurableSessionRecord: hasDurableSessionRecord,
1369
1436
  subscribeSession: function (localId, cb) {
1370
1437
  var session = sessions.get(localId);
1371
1438
  if (!session) return null;
package/lib/ws-schema.js CHANGED
@@ -41,9 +41,13 @@ var schema = {
41
41
  "split_group_rename": { direction: "c2s", handler: "lib/session-split-groups.js", description: "Rename a split group" },
42
42
  "split_group_dissolve": { direction: "c2s", handler: "lib/session-split-groups.js", description: "Separate a split group without deleting its sessions" },
43
43
  "split_group_set_pair": { direction: "c2s", handler: "lib/session-split-groups.js", description: "Assign Driver/Worker roles on a split group (driverId null clears them)" },
44
+ "split_worker_close": { direction: "c2s", handler: "lib/project-pair-worker-close.js", description: "Close one exact authenticated Worker generation while preserving its peer and session history" },
45
+ "split_worker_close_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Correlated result of an exact targeted Worker close" },
44
46
  "pair_session_options": { direction: "c2s", handler: "lib/project-session-pair.js", description: "Request vendors/models for the pair-session dialog (response reuses the same type)" },
45
47
  "pair_session_create": { direction: "c2s", handler: "lib/project-session-pair.js", description: "Create a Driver/Split Worker session pair as a split group" },
46
48
  "worker_proposal_response": { direction: "c2s", handler: "lib/project-worker-proposal.js", description: "Accept or decline an exact Driver Split Worker configuration with the selected runtime" },
49
+ "driver_continuation_response": { direction: "c2s", handler: "lib/project-driver-continuation.js", description: "Accept or decline an exact source-bound Driver continuation proposal" },
50
+ "driver_continuation_open_source": { direction: "c2s", handler: "lib/project-driver-continuation.js", description: "Resolve a successor's stable origin link to its authorized original Driver" },
47
51
  "project_assignment_response": { direction: "c2s", handler: "lib/workspace-assignment-service.js", description: "Approve or cancel an exact-session cross-project assignment proposal" },
48
52
  "home_clay_session_resolve": { direction: "c2s", handler: "lib/server-home-chat.js", description: "Resolve an opaque Mate session reference through the exact bound source session" },
49
53
  "home_clay_session_target": { direction: "s2c", handler: "lib/public/modules/command-palette.js", description: "Return an owner-validated navigation target for a rendered Mate session reference" },
@@ -101,6 +105,10 @@ var schema = {
101
105
  "pair_session_created": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Result of pair_session_create; carries the new group" },
102
106
  "worker_proposal": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Recorded Split Worker creation/replacement runtime card with Driver rationale" },
103
107
  "worker_proposal_update": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Worker card lifecycle and manual/auto decision audit update" },
108
+ "driver_continuation_proposal": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Recorded review card for a compact Driver continuation" },
109
+ "driver_continuation_update": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Durable exact-proposal continuation lifecycle update" },
110
+ "driver_continuation_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Correlated response to a continuation decision" },
111
+ "driver_continuation_context": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Compact inherited context and original-session link in a successor" },
104
112
  "project_assignment_proposal": { direction: "s2c", handler: "lib/public/modules/app-message-router.js", description: "Approval card for a new owner-bound project assignment" },
105
113
  "project_assignment_status": { direction: "s2c", handler: "lib/public/modules/app-message-router.js", description: "Durable project assignment lifecycle update" },
106
114
  "project_assignment_error": { direction: "s2c", handler: "lib/public/modules/app-message-router.js", description: "Rejected or stale project assignment response" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "4.2.0",
3
+ "version": "4.3.0-beta.10",
4
4
  "description": "Self-hosted team workspace for Claude Code and Codex. Multi-user, browser-based, with persistent AI mates.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js"