clay-server 4.0.0-beta.9 → 4.0.1-beta.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.
Files changed (188) hide show
  1. package/lib/capsule-display-floor.js +51 -0
  2. package/lib/capsule-frame-server.js +255 -0
  3. package/lib/capsule-mate-turn.js +105 -0
  4. package/lib/capsule-pig-logic.js +300 -0
  5. package/lib/capsule-server-runtimes.js +39 -0
  6. package/lib/capsules/pig/display.js +198 -0
  7. package/lib/capsules/pig/manifest.json +9 -0
  8. package/lib/capsules/pig/ui.json +84 -0
  9. package/lib/config.js +25 -1
  10. package/lib/daemon-projects.js +13 -8
  11. package/lib/daemon.js +127 -14
  12. package/lib/git-cli.js +95 -1
  13. package/lib/knowledge-import.js +436 -0
  14. package/lib/knowledge-record-store.js +188 -0
  15. package/lib/knowledge-search.js +240 -0
  16. package/lib/mate-knowledge-mcp-server.js +151 -0
  17. package/lib/mate-knowledge-migration.js +283 -0
  18. package/lib/mate-knowledge-service.js +488 -0
  19. package/lib/mate-knowledge-sync.js +482 -0
  20. package/lib/migrate-single-user.js +2 -0
  21. package/lib/notes-lifecycle.js +149 -0
  22. package/lib/notes.js +60 -3
  23. package/lib/os-users.js +3 -1
  24. package/lib/project-capsule-catalog.js +9 -1
  25. package/lib/project-capsule-turn.js +96 -0
  26. package/lib/project-connection.js +15 -1
  27. package/lib/project-file-history.js +223 -0
  28. package/lib/project-file-watch.js +77 -49
  29. package/lib/project-filesystem.js +31 -220
  30. package/lib/project-http.js +15 -1
  31. package/lib/project-knowledge.js +22 -0
  32. package/lib/project-log-context.js +172 -0
  33. package/lib/project-log-feedback-delivery.js +118 -0
  34. package/lib/project-logs-comments.js +137 -0
  35. package/lib/project-logs-context-state.js +42 -0
  36. package/lib/project-logs-mcp-server.js +328 -0
  37. package/lib/project-logs-query.js +185 -0
  38. package/lib/project-logs-root.js +75 -0
  39. package/lib/project-logs-schema.js +259 -0
  40. package/lib/project-logs-service.js +463 -0
  41. package/lib/project-logs-snapshot.js +205 -0
  42. package/lib/project-logs-store.js +495 -0
  43. package/lib/project-logs-versioning.js +132 -0
  44. package/lib/project-logs.js +400 -0
  45. package/lib/project-mate-interaction.js +14 -0
  46. package/lib/project-mate-knowledge.js +110 -0
  47. package/lib/project-memory.js +22 -0
  48. package/lib/project-message-delivery.js +70 -0
  49. package/lib/project-pair-lifecycle.js +460 -0
  50. package/lib/project-request-access.js +66 -0
  51. package/lib/project-session-handoff.js +1 -1
  52. package/lib/project-session-notes.js +64 -13
  53. package/lib/project-session-pair.js +159 -146
  54. package/lib/project-session-spawn.js +1 -1
  55. package/lib/project-sessions.js +71 -16
  56. package/lib/project-user-message.js +53 -4
  57. package/lib/project-worker-permission.js +430 -0
  58. package/lib/project-worker-proposal.js +208 -62
  59. package/lib/project.js +191 -6
  60. package/lib/public/app.js +64 -35
  61. package/lib/public/css/admin.css +2 -2
  62. package/lib/public/css/capsule-ui.css +38 -0
  63. package/lib/public/css/command-palette.css +45 -9
  64. package/lib/public/css/git-placard.css +154 -0
  65. package/lib/public/css/home-hub.css +4 -0
  66. package/lib/public/css/home-session-actions.css +66 -0
  67. package/lib/public/css/home-sidebar.css +66 -0
  68. package/lib/public/css/input.css +84 -3
  69. package/lib/public/css/messages.css +40 -1
  70. package/lib/public/css/mobile-nav.css +80 -0
  71. package/lib/public/css/notifications-center.css +67 -0
  72. package/lib/public/css/pane.css +97 -10
  73. package/lib/public/css/project-logs.css +198 -0
  74. package/lib/public/css/scheduler.css +1 -1
  75. package/lib/public/css/session-actions.css +16 -101
  76. package/lib/public/css/sidebar.css +103 -0
  77. package/lib/public/css/sticky-notes.css +237 -229
  78. package/lib/public/css/worker-proposal.css +36 -3
  79. package/lib/public/index.html +43 -11
  80. package/lib/public/modules/admin.js +8 -8
  81. package/lib/public/modules/app-connection.js +124 -6
  82. package/lib/public/modules/app-home-hub.js +12 -8
  83. package/lib/public/modules/app-message-cards.js +2 -1
  84. package/lib/public/modules/app-message-router.js +1 -1
  85. package/lib/public/modules/app-messages.js +92 -11
  86. package/lib/public/modules/app-misc.js +2 -14
  87. package/lib/public/modules/app-notifications.js +11 -7
  88. package/lib/public/modules/app-panels.js +3 -2
  89. package/lib/public/modules/app-projects.js +56 -18
  90. package/lib/public/modules/app-rendering.js +1 -0
  91. package/lib/public/modules/capsule-preference.js +44 -0
  92. package/lib/public/modules/chat-bubble-renderer.js +1 -1
  93. package/lib/public/modules/clay-log-links.js +70 -0
  94. package/lib/public/modules/command-palette.js +52 -15
  95. package/lib/public/modules/context-sources.js +0 -3
  96. package/lib/public/modules/git-agent-sessions.js +85 -0
  97. package/lib/public/modules/git-panel.js +111 -84
  98. package/lib/public/modules/git-placard.js +161 -0
  99. package/lib/public/modules/home-chat-empty-state.js +39 -0
  100. package/lib/public/modules/home-chat-identity.js +9 -0
  101. package/lib/public/modules/home-conversations-sheet.js +102 -48
  102. package/lib/public/modules/home-mate-chat.js +15 -35
  103. package/lib/public/modules/home-session-actions.js +6 -0
  104. package/lib/public/modules/home-sidebar-chat-list.js +101 -41
  105. package/lib/public/modules/home-sidebar.js +7 -0
  106. package/lib/public/modules/home-surface-boot.js +7 -3
  107. package/lib/public/modules/home-tool-frame.js +182 -0
  108. package/lib/public/modules/home-tools.js +138 -1
  109. package/lib/public/modules/input.js +38 -7
  110. package/lib/public/modules/markdown.js +2 -0
  111. package/lib/public/modules/mate-sidebar.js +0 -8
  112. package/lib/public/modules/message-delivery.js +97 -0
  113. package/lib/public/modules/paste-modal.js +84 -0
  114. package/lib/public/modules/project-activation.js +45 -0
  115. package/lib/public/modules/project-logs-render.js +405 -0
  116. package/lib/public/modules/project-logs.js +461 -0
  117. package/lib/public/modules/project-removal-target.js +26 -0
  118. package/lib/public/modules/scheduler.js +17 -3
  119. package/lib/public/modules/search-clay-chat.js +47 -6
  120. package/lib/public/modules/search-clay-controls.js +86 -0
  121. package/lib/public/modules/session-actions.js +29 -105
  122. package/lib/public/modules/session-hierarchy.js +54 -0
  123. package/lib/public/modules/sidebar-mobile.js +40 -15
  124. package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
  125. package/lib/public/modules/sidebar-sessions.js +77 -11
  126. package/lib/public/modules/sidebar.js +17 -5
  127. package/lib/public/modules/split-group-helpers.js +8 -0
  128. package/lib/public/modules/split-pair-ui.js +15 -4
  129. package/lib/public/modules/split-view.js +5 -2
  130. package/lib/public/modules/split-worker-runtime.js +24 -0
  131. package/lib/public/modules/sticky-note-markdown.js +5 -0
  132. package/lib/public/modules/sticky-notes-browser.js +326 -0
  133. package/lib/public/modules/sticky-notes-card.js +360 -0
  134. package/lib/public/modules/sticky-notes-editor.js +291 -0
  135. package/lib/public/modules/sticky-notes-shared.js +90 -0
  136. package/lib/public/modules/sticky-notes.js +170 -946
  137. package/lib/public/modules/thinking-lifecycle.js +175 -0
  138. package/lib/public/modules/thinking-summary.js +28 -0
  139. package/lib/public/modules/thinking-view.js +75 -0
  140. package/lib/public/modules/tool-palette-order.js +143 -0
  141. package/lib/public/modules/tool-palette-overlays.js +159 -0
  142. package/lib/public/modules/tool-palette.js +21 -188
  143. package/lib/public/modules/tools.js +31 -123
  144. package/lib/public/modules/update-snooze.js +169 -0
  145. package/lib/public/modules/user-settings.js +4 -0
  146. package/lib/public/modules/worker-pane-lock.js +176 -0
  147. package/lib/public/modules/worker-proposal-state.js +16 -0
  148. package/lib/public/modules/worker-proposal.js +49 -20
  149. package/lib/public/style.css +3 -1
  150. package/lib/sdk-bridge.js +136 -47
  151. package/lib/sdk-message-processor.js +36 -7
  152. package/lib/server-experimental-settings.js +49 -0
  153. package/lib/server-global-ws.js +11 -0
  154. package/lib/server-home-chat-events.js +34 -1
  155. package/lib/server-home-chat.js +62 -4
  156. package/lib/server-home-clay-entry.js +1 -1
  157. package/lib/server-home-clay-session-links.js +34 -5
  158. package/lib/server-settings.js +5 -0
  159. package/lib/server-tools.js +127 -9
  160. package/lib/server.js +137 -22
  161. package/lib/session-driver-eligibility.js +38 -0
  162. package/lib/session-driver-orchestration.js +31 -0
  163. package/lib/session-hygiene.js +3 -0
  164. package/lib/session-notes-mcp-server.js +25 -5
  165. package/lib/session-pair-factory.js +247 -0
  166. package/lib/session-pair-mcp-server.js +46 -8
  167. package/lib/session-pair-prompts.js +79 -0
  168. package/lib/session-pair-turn-control.js +153 -0
  169. package/lib/session-provenance.js +119 -0
  170. package/lib/session-spawn-mcp-server.js +1 -1
  171. package/lib/session-split-groups.js +4 -1
  172. package/lib/session-title-policy.js +60 -0
  173. package/lib/session-visibility.js +41 -0
  174. package/lib/sessions.js +57 -10
  175. package/lib/tools-registry.js +89 -10
  176. package/lib/update-snooze.js +437 -0
  177. package/lib/users-experimental-preferences.js +30 -0
  178. package/lib/users-permissions.js +6 -6
  179. package/lib/users.js +22 -16
  180. package/lib/workspace-query-access.js +102 -0
  181. package/lib/workspace-query-service.js +24 -17
  182. package/lib/worktree.js +25 -38
  183. package/lib/ws-schema.js +44 -7
  184. package/lib/yoke/adapters/claude-worker.js +16 -6
  185. package/lib/yoke/adapters/claude.js +12 -0
  186. package/lib/yoke/adapters/codex.js +24 -14
  187. package/lib/yoke/vendor-registry.js +1 -1
  188. package/package.json +2 -2
package/lib/project.js CHANGED
@@ -9,6 +9,7 @@ var runtimeEnv = require("./runtime-env");
9
9
  var { createTerminalManager } = require("./terminal-manager");
10
10
  var { createNotesManager } = require("./notes");
11
11
  var { fetchLatestVersion, fetchVersion, isNewer } = require("./updater");
12
+ var updateSnooze = require("./update-snooze");
12
13
  var { execFileSync, spawn } = require("child_process");
13
14
  var usersModule = require("./users");
14
15
  var { resolveOsUserInfo, fsAsUser, grantProjectAccess } = require("./os-users");
@@ -25,6 +26,7 @@ var { attachMemory } = require("./project-memory");
25
26
  var { attachMateInteraction } = require("./project-mate-interaction");
26
27
  var { attachUserMention } = require("./project-user-mention");
27
28
  var { attachLoop } = require("./project-loop");
29
+ var { attachRequestAccess } = require("./project-request-access");
28
30
  var { attachFileWatch } = require("./project-file-watch");
29
31
  var { attachHTTP } = require("./project-http");
30
32
  var { attachImage } = require("./project-image");
@@ -42,6 +44,7 @@ var { attachEmail: attachEmailModule } = require("./project-email");
42
44
  var { attachSessionSpawn } = require("./project-session-spawn");
43
45
  var { attachDelegatedSession } = require("./project-delegated-session");
44
46
  var { attachDelegatedFollowUp } = require("./project-delegated-follow-up");
47
+ var { attachCapsuleTurn } = require("./project-capsule-turn");
45
48
  var workspaceSessionRef = require("./workspace-query-service").sessionRef;
46
49
  var { attachSessionPair } = require("./project-session-pair");
47
50
  var { attachSessionHandoff } = require("./project-session-handoff");
@@ -49,8 +52,12 @@ var { attachSessionNotes, composeSystemPrompts } = require("./project-session-no
49
52
  var { attachSessionDocument } = require("./project-session-document");
50
53
  var { attachCapsuleCatalog } = require("./project-capsule-catalog");
51
54
  var { attachProjectWorkspaceQuery } = require("./project-workspace-query");
55
+ var { attachProjectLogs } = require("./project-logs");
56
+ var { attachProjectLogFeedbackDelivery } = require("./project-log-feedback-delivery");
57
+ var { attachProjectMateKnowledge } = require("./project-mate-knowledge");
52
58
  var { attachSplitGroups } = require("./session-split-groups");
53
59
  var toolControlMcp = require("./tool-control-mcp-server");
60
+ var capsuleFloor = require("./capsule-display-floor");
54
61
  var toolLlm = require("./tool-llm");
55
62
  // project-notifications is attached globally in server.js, passed via opts.notificationsModule
56
63
 
@@ -61,6 +68,10 @@ function createMateToolControlMcp(adapter, config) {
61
68
  var manifests = config.list(config.userId) || [];
62
69
  var tools = [];
63
70
  for (var i = 0; i < manifests.length; i++) {
71
+ // Skills go dark when the declarative Display floor does, so a Capsule
72
+ // the human cannot operate is never listed to a Mate either. The guard
73
+ // validates the Capsule's own Display tree, not a claim about it.
74
+ if (!capsuleFloor.hasUsableFloor(manifests[i])) continue;
64
75
  tools.push({
65
76
  id: manifests[i].id,
66
77
  name: manifests[i].name,
@@ -205,6 +216,7 @@ function createProjectContext(opts) {
205
216
  var updateChannel = opts.updateChannel || "stable";
206
217
  var osUsers = opts.osUsers || false;
207
218
  var projectOwnerId = opts.projectOwnerId || null;
219
+ var projectKnowledgeId = opts.projectKnowledgeId || null;
208
220
  var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch, external }
209
221
  var isMate = opts.isMate || false;
210
222
  var mateId = opts.mateId || (isMate ? path.basename(cwd) : null);
@@ -395,6 +407,49 @@ function createProjectContext(opts) {
395
407
  }
396
408
  }
397
409
 
410
+ // Update version metadata goes only to admin-grade connections, and only to
411
+ // those not currently snoozing this exact version. Both decisions come from
412
+ // update-snooze.js; this loop owns nothing but the client set.
413
+ function broadcastUpdateAvailable(version) {
414
+ if (!version) return;
415
+ var now = Date.now();
416
+ var payload = JSON.stringify({ type: "update_available", version: version });
417
+ for (var ws of clients) {
418
+ if (ws.readyState !== 1) continue;
419
+ if (!updateSnooze.isUpdateAdmin(ws, usersModule)) continue;
420
+ var key = updateSnooze.userKeyFor(ws, usersModule);
421
+ if (updateSnooze.isSnoozed(key, version, now)) continue;
422
+ ws.send(payload);
423
+ }
424
+ }
425
+
426
+ // The install lifecycle frame. Every client needs it, because the daemon is
427
+ // about to restart and the UI blocks the screen — but only admin-grade
428
+ // connections get the version with it. Non-admins get the same frame minus
429
+ // the metadata, so behaviour is unchanged for them and nothing leaks.
430
+ function broadcastUpdateStarted(version) {
431
+ var withVersion = JSON.stringify({ type: "update_started", version: version || "" });
432
+ var withoutVersion = JSON.stringify({ type: "update_started" });
433
+ for (var ws of clients) {
434
+ if (ws.readyState !== 1) continue;
435
+ ws.send(updateSnooze.isUpdateAdmin(ws, usersModule) ? withVersion : withoutVersion);
436
+ }
437
+ }
438
+
439
+ // Tell every live connection of one user that a snooze took effect, so the
440
+ // banner clears on their other devices too rather than only where it was
441
+ // dismissed. Scoped by the same server-derived key the snooze was stored
442
+ // under, never by anything in a payload.
443
+ function sendToUpdateUser(userKey, obj) {
444
+ if (!userKey) return;
445
+ var data = JSON.stringify(obj);
446
+ for (var ws of clients) {
447
+ if (ws.readyState !== 1) continue;
448
+ if (updateSnooze.userKeyFor(ws, usersModule) !== userKey) continue;
449
+ ws.send(data);
450
+ }
451
+ }
452
+
398
453
  function broadcastClientCount() {
399
454
  var msg = { type: "client_count", count: clients.size };
400
455
  if (usersModule.isMultiUser()) {
@@ -459,8 +514,14 @@ function createProjectContext(opts) {
459
514
  getProjectOwnerId: function () { return projectOwnerId; },
460
515
  });
461
516
 
517
+ var _requestAccess = attachRequestAccess({
518
+ slug: slug, opts: opts, usersModule: usersModule, osUsers: osUsers,
519
+ sendTo: sendTo, getOsUserInfoForWs: getOsUserInfoForWs,
520
+ });
521
+
462
522
  // --- File/directory watcher engine (delegated to project-file-watch.js) ---
463
523
  var _fileWatch = attachFileWatch({
524
+ requestAccess: _requestAccess, fsAsUser: fsAsUser,
464
525
  cwd: cwd,
465
526
  send: send,
466
527
  sendTo: sendTo,
@@ -624,6 +685,31 @@ function createProjectContext(opts) {
624
685
  isMate: isMate,
625
686
  mateId: mateId,
626
687
  });
688
+ var _logFeedbackDelivery = attachProjectLogFeedbackDelivery({
689
+ sm: sm,
690
+ getSdk: function () { return sdk; },
691
+ onProcessingChanged: onProcessingChanged,
692
+ getLinuxUserForSession: getLinuxUserForSession,
693
+ });
694
+ var _projectLogs = attachProjectLogs({
695
+ service: opts.projectLogsService || null,
696
+ sm: sm,
697
+ projectSlug: slug,
698
+ getProjectOwnerId: function () { return projectOwnerId; },
699
+ isMate: isMate,
700
+ mateId: mateId,
701
+ sendTo: sendTo,
702
+ getClients: function () { return clients; },
703
+ onFeedback: _logFeedbackDelivery.deliver,
704
+ });
705
+ var _mateKnowledge = attachProjectMateKnowledge({
706
+ service: opts.mateKnowledgeService || null,
707
+ sm: sm,
708
+ projectSlug: slug,
709
+ getProjectOwnerId: function () { return projectOwnerId; },
710
+ isMate: isMate,
711
+ mateId: mateId,
712
+ });
627
713
 
628
714
  // The SDK bridge is created after local MCP servers. Session spawning uses
629
715
  // a getter so tool handlers see the initialized bridge when they run.
@@ -739,6 +825,27 @@ function createProjectContext(opts) {
739
825
  }
740
826
  }
741
827
 
828
+ // Project Logs. Project sessions get the project-scoped set; Mate projects
829
+ // get the read-only cross-project set only when the Mate registry confirms
830
+ // authoritative builtin Clay.
831
+ try {
832
+ var projectLogsMcpConfig = _projectLogs.createMcpServer(adapter, null);
833
+ if (projectLogsMcpConfig) servers[projectLogsMcpConfig.name || "clay-logs"] = projectLogsMcpConfig;
834
+ } catch (e) {
835
+ console.error("[project] Failed to create clay-logs MCP server:", e.message);
836
+ }
837
+
838
+ // Mate Knowledge. Mate projects only; the registry decides whether this is
839
+ // one Mate's own scope or authoritative Clay's cross-Mate read view.
840
+ if (isMate) {
841
+ try {
842
+ var mateKnowledgeMcpConfig = _mateKnowledge.createMcpServer(adapter, null);
843
+ if (mateKnowledgeMcpConfig) servers[mateKnowledgeMcpConfig.name || "clay-knowledge"] = mateKnowledgeMcpConfig;
844
+ } catch (e) {
845
+ console.error("[project] Failed to create clay-knowledge MCP server:", e.message);
846
+ }
847
+ }
848
+
742
849
  // Session-bound access to the source of a handoff (main projects only).
743
850
  if (!isMate) {
744
851
  try {
@@ -903,6 +1010,24 @@ function createProjectContext(opts) {
903
1010
  }
904
1011
  continue;
905
1012
  }
1013
+ if (name === "clay-logs" && forSession) {
1014
+ try {
1015
+ var boundLogs = _projectLogs.createMcpServer(adapter, forSession);
1016
+ if (boundLogs) { filtered[name] = boundLogs; hasAny = true; }
1017
+ } catch (e) {
1018
+ console.error("[project] Failed to bind clay-logs MCP server:", e.message);
1019
+ }
1020
+ continue;
1021
+ }
1022
+ if (name === "clay-knowledge" && forSession) {
1023
+ try {
1024
+ var boundKnowledge = _mateKnowledge.createMcpServer(adapter, forSession);
1025
+ if (boundKnowledge) { filtered[name] = boundKnowledge; hasAny = true; }
1026
+ } catch (e) {
1027
+ console.error("[project] Failed to bind clay-knowledge MCP server:", e.message);
1028
+ }
1029
+ continue;
1030
+ }
906
1031
  if (name === "clay-tools" && forSession) {
907
1032
  try {
908
1033
  var boundToolControl = createToolControlMcpServer();
@@ -992,6 +1117,9 @@ function createProjectContext(opts) {
992
1117
  clayPort: serverPort,
993
1118
  clayTls: serverTls,
994
1119
  clayAuthToken: serverAuthToken,
1120
+ getWorkerPermissionRouter: function () {
1121
+ return isMate ? null : _sessionPair.workerPermission;
1122
+ },
995
1123
  onProcessingChanged: onProcessingChanged,
996
1124
  onTurnDone: function (session, preview) {
997
1125
  if (isMate) digestDmTurn(session, preview);
@@ -1021,6 +1149,8 @@ function createProjectContext(opts) {
1021
1149
  _sessionHandoff.getSystemPrompt(session),
1022
1150
  _sessionDocument.getSystemPrompt(session),
1023
1151
  _capsuleCatalog.getSystemPrompt(session),
1152
+ _projectLogs.getSystemPrompt(session),
1153
+ _mateKnowledge.getSystemPrompt(session),
1024
1154
  ]);
1025
1155
  },
1026
1156
  getRuntimeEnv: getRuntimeEnvForSession,
@@ -1035,7 +1165,9 @@ function createProjectContext(opts) {
1035
1165
  .concat(_debateProposal.getToolDefs(session))
1036
1166
  .concat(_mateCreationProposal.getToolDefs(session))
1037
1167
  .concat(_workspaceQuery.getDynamicToolDefs(session))
1038
- .concat(_workspaceQuery.getHistoryDynamicToolDefs(session));
1168
+ .concat(_workspaceQuery.getHistoryDynamicToolDefs(session))
1169
+ .concat(_projectLogs.getDynamicToolDefs(session))
1170
+ .concat(_mateKnowledge.getDynamicToolDefs(session));
1039
1171
  },
1040
1172
  });
1041
1173
 
@@ -1081,7 +1213,7 @@ function createProjectContext(opts) {
1081
1213
  fetchVersion(updateChannel).then(function (v) {
1082
1214
  if (v && isNewer(v, currentVersion)) {
1083
1215
  latestVersion = v;
1084
- if (broadcast) sendToAdmins({ type: "update_available", version: v });
1216
+ if (broadcast) broadcastUpdateAvailable(v);
1085
1217
  }
1086
1218
  }).catch(function (e) {
1087
1219
  console.error("[project] Background version check failed:", e.message || e);
@@ -1169,6 +1301,13 @@ function createProjectContext(opts) {
1169
1301
  }
1170
1302
 
1171
1303
  function handleMessage(ws, msg) {
1304
+ if (!_requestAccess.permitMessage(ws, msg)) return;
1305
+ // --- Keep-alive (delegated to project-connection.js) ---
1306
+ // Answered before any routing so a ping can never be forwarded elsewhere.
1307
+ // _connection is assigned later in this factory than the other modules, so
1308
+ // the reference is guarded rather than assumed.
1309
+ if (_connection && _connection.handleKeepaliveMessage(ws, msg)) return;
1310
+
1172
1311
  if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && /^debate_(hand_raise|comment|stop|conclude_response|user_floor_response)$/.test(msg.type || "") && opts.getProject) {
1173
1312
  var homeDebateCtx = opts.getProject(ws._clayHomeDebateSlug);
1174
1313
  if (homeDebateCtx) homeDebateCtx.handleMessage(ws, msg);
@@ -1188,11 +1327,15 @@ function createProjectContext(opts) {
1188
1327
  if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg);
1189
1328
  return;
1190
1329
  }
1191
- if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve") {
1330
+ if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve" || msg.type === "home_clay_log_resolve") {
1331
+ if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
1332
+ return;
1333
+ }
1334
+ if (msg.type === "home_mate_stop" || msg.type === "home_mate_permission_response") {
1192
1335
  if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
1193
1336
  return;
1194
1337
  }
1195
- if (msg.type === "project_assignment_response" || msg.type === "dm_open" || msg.type === "dm_send" || msg.type === "dm_list" || msg.type === "dm_typing" || msg.type === "dm_add_favorite" || msg.type === "dm_remove_favorite" || msg.type === "mate_create" || msg.type === "mate_list" || msg.type === "mate_delete" || msg.type === "mate_update" || msg.type === "mate_readd_builtin" || msg.type === "mate_list_available_builtins" || msg.type === "email_accounts_list" || msg.type === "email_account_add" || msg.type === "email_account_remove" || msg.type === "email_account_test" || msg.type === "home_debates_list" || msg.type === "home_mate_present" || msg.type === "home_mate_open" || msg.type === "home_mate_sessions_list" || msg.type === "home_mate_session_open" || msg.type === "home_mate_send" || msg.type === "home_mate_new_session" || msg.type === "home_mate_debate_plan" || msg.type === "home_debate_proposal_response" || msg.type === "home_mate_creation_plan" || msg.type === "home_mate_creation_proposal_response" || msg.type === "home_mate_close" || msg.type === "home_mate_memory_list" || msg.type === "home_mate_knowledge_list" || msg.type === "home_mate_models_get" || msg.type === "home_mate_model_set" || msg.type === "home_dock_get" || msg.type === "home_dock_set" || msg.type === "home_surface_get" || msg.type === "home_surface_set" || msg.type === "tools_list" || msg.type === "tool_get" || msg.type === "tool_install" || msg.type === "tool_remove" || msg.type === "tool_storage_op" || msg.type === "tool_llm_op" || msg.type === "tool_llm_config_get" || msg.type === "tool_control_response" || msg.type === "tool_source_get" || msg.type === "tool_mate_access_set") {
1338
+ if (msg.type === "project_assignment_response" || msg.type === "dm_open" || msg.type === "dm_send" || msg.type === "dm_list" || msg.type === "dm_typing" || msg.type === "dm_add_favorite" || msg.type === "dm_remove_favorite" || msg.type === "mate_create" || msg.type === "mate_list" || msg.type === "mate_delete" || msg.type === "mate_update" || msg.type === "mate_readd_builtin" || msg.type === "mate_list_available_builtins" || msg.type === "email_accounts_list" || msg.type === "email_account_add" || msg.type === "email_account_remove" || msg.type === "email_account_test" || msg.type === "home_debates_list" || msg.type === "home_mate_present" || msg.type === "home_mate_open" || msg.type === "home_mate_sessions_list" || msg.type === "home_mate_session_open" || msg.type === "home_mate_send" || msg.type === "home_mate_new_session" || msg.type === "home_mate_debate_plan" || msg.type === "home_debate_proposal_response" || msg.type === "home_mate_creation_plan" || msg.type === "home_mate_creation_proposal_response" || msg.type === "home_mate_close" || msg.type === "home_mate_memory_list" || msg.type === "home_mate_knowledge_list" || msg.type === "home_mate_models_get" || msg.type === "home_mate_model_set" || msg.type === "home_dock_get" || msg.type === "home_dock_set" || msg.type === "home_surface_get" || msg.type === "home_surface_set" || msg.type === "tools_list" || msg.type === "tool_get" || msg.type === "tool_install" || msg.type === "tool_remove" || msg.type === "tool_storage_op" || msg.type === "tool_llm_op" || msg.type === "tool_llm_config_get" || msg.type === "tool_control_response" || msg.type === "tool_source_get" || msg.type === "tool_mate_access_set" || msg.type === "tool_server_control" || msg.type === "tool_frame_url") {
1196
1339
  if (typeof opts.onDmMessage === "function") {
1197
1340
  opts.onDmMessage(ws, msg, slug);
1198
1341
  }
@@ -1266,6 +1409,9 @@ function createProjectContext(opts) {
1266
1409
  // --- Knowledge file management (delegated to project-knowledge.js) ---
1267
1410
  if (_knowledge.handleKnowledgeMessage(ws, msg)) return;
1268
1411
 
1412
+ // --- Project Logs (delegated to project-logs.js) ---
1413
+ if (_projectLogs.handleLogsMessage(ws, msg)) return;
1414
+
1269
1415
  // --- Notifications (delegated to project-notifications.js) ---
1270
1416
  if (_notifications.handleNotificationMessage(ws, msg)) return;
1271
1417
 
@@ -1468,6 +1614,9 @@ function createProjectContext(opts) {
1468
1614
  send: send,
1469
1615
  sendTo: sendTo,
1470
1616
  sendToAdmins: sendToAdmins,
1617
+ broadcastUpdateAvailable: broadcastUpdateAvailable,
1618
+ broadcastUpdateStarted: broadcastUpdateStarted,
1619
+ sendToUpdateUser: sendToUpdateUser,
1471
1620
  sendToSession: sendToSession,
1472
1621
  sendToSessionOthers: sendToSessionOthers,
1473
1622
  opts: opts,
@@ -1477,6 +1626,7 @@ function createProjectContext(opts) {
1477
1626
  matesModule: matesModule,
1478
1627
  pushModule: pushModule,
1479
1628
  getSessionForWs: getSessionForWs,
1629
+ onHumanPairStop: function (session) { return _sessionPair.handleHumanStop(session); },
1480
1630
  getLinuxUserForSession: getLinuxUserForSession,
1481
1631
  ensureProjectAccessForSession: ensureProjectAccessForSession,
1482
1632
  getOsUserInfoForWs: getOsUserInfoForWs,
@@ -1530,6 +1680,16 @@ function createProjectContext(opts) {
1530
1680
  return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1531
1681
  },
1532
1682
  });
1683
+ var _capsuleTurn = attachCapsuleTurn({
1684
+ sm: sm,
1685
+ getSdk: function () { return sdk; },
1686
+ getLinuxUserForSession: getLinuxUserForSession,
1687
+ isMultiUser: function () { return usersModule.isMultiUser(); },
1688
+ resolveModel: function (principal) {
1689
+ var user = principal && principal.userId ? usersModule.findUserById(principal.userId) : null;
1690
+ return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1691
+ },
1692
+ });
1533
1693
  var _delegatedFollowUp = attachDelegatedFollowUp({
1534
1694
  sm: sm,
1535
1695
  getSdk: function () { return sdk; },
@@ -1546,6 +1706,13 @@ function createProjectContext(opts) {
1546
1706
 
1547
1707
  // --- User message handler (delegated to project-user-message.js) ---
1548
1708
  var _userMessage = attachUserMessage({
1709
+ // Exact live pair state decides whether a session is Driver-operated; the
1710
+ // handler never infers the role from the message.
1711
+ isDriverOperatedSession: function (session) {
1712
+ if (isMate || !_sessionPair.workerPermission) return false;
1713
+ return _sessionPair.workerPermission.isDriverOperated(session);
1714
+ },
1715
+ beginHumanPairTurn: function (session) { return _sessionPair.beginHumanTurn(session); },
1549
1716
  cwd: cwd,
1550
1717
  slug: slug,
1551
1718
  isMate: isMate,
@@ -1615,6 +1782,7 @@ function createProjectContext(opts) {
1615
1782
 
1616
1783
  // --- Filesystem handler (delegated to project-filesystem.js) ---
1617
1784
  var _filesystem = attachFilesystem({
1785
+ requestAccess: _requestAccess,
1618
1786
  cwd: cwd,
1619
1787
  slug: slug,
1620
1788
  osUsers: osUsers,
@@ -1734,6 +1902,10 @@ function createProjectContext(opts) {
1734
1902
  for (var wqti = 0; wqti < workspaceTools.length; wqti++) tools.push(workspaceTools[wqti]);
1735
1903
  var historyTools = _workspaceQuery.getHistoryBridgeTools(boundSession, normalizeToolSchema);
1736
1904
  for (var cht = 0; cht < historyTools.length; cht++) tools.push(historyTools[cht]);
1905
+ var logsTools = _projectLogs.getBridgeTools(boundSession, normalizeToolSchema);
1906
+ for (var plti = 0; plti < logsTools.length; plti++) tools.push(logsTools[plti]);
1907
+ var knowledgeTools = _mateKnowledge.getBridgeTools(boundSession, normalizeToolSchema);
1908
+ for (var mkti = 0; mkti < knowledgeTools.length; mkti++) tools.push(knowledgeTools[mkti]);
1737
1909
  }
1738
1910
 
1739
1911
  if (sessionOnly) return Promise.resolve(tools);
@@ -1749,7 +1921,7 @@ function createProjectContext(opts) {
1749
1921
  // Debate tools were added above only when this request had an
1750
1922
  // exact session. Never duplicate them or advertise the static,
1751
1923
  // intentionally unbound proposal server.
1752
- if (inAppNames[i] === "clay-debate" || inAppNames[i] === "clay-mate-creation" || inAppNames[i] === "clay-workspace" || inAppNames[i] === "clay-history") continue;
1924
+ if (inAppNames[i] === "clay-debate" || inAppNames[i] === "clay-mate-creation" || inAppNames[i] === "clay-workspace" || inAppNames[i] === "clay-history" || inAppNames[i] === "clay-logs" || inAppNames[i] === "clay-knowledge") continue;
1753
1925
  extractServerTools(inAppNames[i], localMcp[inAppNames[i]]);
1754
1926
  }
1755
1927
  }
@@ -1812,7 +1984,13 @@ function createProjectContext(opts) {
1812
1984
  if (boundSession && serverName === "clay-history") {
1813
1985
  return _workspaceQuery.callHistoryBridgeTool(boundSession, toolName, args);
1814
1986
  }
1815
- if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents" || serverName === "clay-debate" || serverName === "clay-mate-creation" || serverName === "clay-workspace" || serverName === "clay-history") {
1987
+ if (boundSession && serverName === "clay-logs") {
1988
+ return _projectLogs.callBridgeTool(boundSession, toolName, args);
1989
+ }
1990
+ if (boundSession && serverName === "clay-knowledge") {
1991
+ return _mateKnowledge.callBridgeTool(boundSession, toolName, args);
1992
+ }
1993
+ if (serverName === "clay-sessions" || serverName === "clay-notes" || serverName === "clay-handoff" || serverName === "clay-documents" || serverName === "clay-debate" || serverName === "clay-mate-creation" || serverName === "clay-workspace" || serverName === "clay-history" || serverName === "clay-logs" || serverName === "clay-knowledge") {
1816
1994
  return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
1817
1995
  }
1818
1996
  if (sessionOnly) return Promise.reject(new Error("Session tool not found: " + serverName + "/" + toolName));
@@ -2024,6 +2202,7 @@ function createProjectContext(opts) {
2024
2202
  isProcessing: hasProcessing,
2025
2203
  pendingPermissions: pendingPermCount,
2026
2204
  projectOwnerId: projectOwnerId,
2205
+ projectKnowledgeId: projectKnowledgeId,
2027
2206
  };
2028
2207
  if (isMate) {
2029
2208
  status.isMate = true;
@@ -2033,6 +2212,9 @@ function createProjectContext(opts) {
2033
2212
  status.isWorktree = true;
2034
2213
  status.parentSlug = worktreeMeta.parentSlug;
2035
2214
  status.branch = worktreeMeta.branch;
2215
+ status.changeSetId = worktreeMeta.changeSetId || null;
2216
+ status.baseCommit = worktreeMeta.baseCommit || null;
2217
+ status.headCommit = worktreeMeta.headCommit || null;
2036
2218
  status.worktreeExternal = worktreeMeta.external === true;
2037
2219
  }
2038
2220
  if (usersModule.isMultiUser()) {
@@ -2131,10 +2313,13 @@ function createProjectContext(opts) {
2131
2313
  createDelegatedSession: _delegatedSession.createDelegatedSession,
2132
2314
  inspectDelegatedFollowUp: _delegatedFollowUp.inspectDelegatedFollowUp,
2133
2315
  dispatchDelegatedFollowUp: _delegatedFollowUp.dispatchDelegatedFollowUp,
2316
+ deliverCapsuleTurn: _capsuleTurn.deliverCapsuleTurn,
2134
2317
  unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
2135
2318
  handleHomeDebateProposalResponse: function (ws, msg, session) { return _debateProposal.handleHomeMessage(ws, msg, session); },
2136
2319
  handleHomeMateCreationProposalResponse: function (ws, msg, session) { return _mateCreationProposal.handleHomeMessage(ws, msg, session); },
2137
2320
  handleHomeAskUserResponse: function (msg, session) { return _sessions.respondToAskUser(session, msg); },
2321
+ handleHomePermissionResponse: function (ws, msg, session) { return _sessions.respondToHomePermission(ws, msg, session); },
2322
+ stopHomeSession: function (session) { return _sessions.stopHomeSession(session); },
2138
2323
  handleHomeDebateControl: function (ws, msg, session) { return _debate.handleHomeControl(ws, msg, session); },
2139
2324
  getVendorModelCatalog: _models.getVendorCatalog,
2140
2325
  getVendorModelAvailability: _models.getVendorAvailability,
package/lib/public/app.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { avatarUrl, userAvatarUrl, mateAvatarUrl } from './modules/avatar.js';
2
- import { showToast, copyToClipboard, escapeHtml } from './modules/utils.js';
2
+ import { showToast, escapeHtml } from './modules/utils.js';
3
3
  import { refreshIcons, iconHtml } from './modules/icons.js';
4
4
  import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, closeMermaidModal, parseEmojis } from './modules/markdown.js';
5
5
  import { initSidebar, updatePageTitle, spawnDustParticles } from './modules/sidebar.js';
@@ -27,9 +27,11 @@ import { initInput, clearPendingImages, handleInputSync, autoResize, builtinComm
27
27
  import { initQrCode, triggerShare } from './modules/qrcode.js';
28
28
  import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
29
29
  import { initGitPanel } from './modules/git-panel.js';
30
+ import { initWorkerPaneLock } from './modules/worker-pane-lock.js';
30
31
  import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
31
32
  import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
32
- import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen, hideNotes, showNotes, isNotesVisible, createNote } from './modules/sticky-notes.js';
33
+ import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, hideNotes, showNotes, isNotesVisible, createNote, setBrowserRefresh } from './modules/sticky-notes.js';
34
+ import { initNotesBrowser, openNotesBrowser, closeNotesBrowser, isNotesBrowserOpen, renderNotesBrowser, registerExclusiveClosers } from './modules/sticky-notes-browser.js';
33
35
  import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
34
36
  import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, resetTurnMetaCost, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
35
37
  import { initServerSettings, updateSettingsStats, updateDaemonConfig, handleSetPinResult, handleKeepAwakeChanged, handleAutoContinueChanged, handleRestartResult, handleShutdownResult, handleSharedEnv, handleSharedEnvSaved, handleGlobalClaudeMdRead, handleGlobalClaudeMdWrite } from './modules/server-settings.js';
@@ -42,6 +44,7 @@ import { initSTT } from './modules/stt.js';
42
44
  import { initProfile, getProfileLang } from './modules/profile.js';
43
45
  import { initUserSettings } from './modules/user-settings.js';
44
46
  import { initToolPalettes } from './modules/tool-palette.js';
47
+ import { initProjectLogs, closeProjectLogs } from './modules/project-logs.js';
45
48
  import { initProjectSwitcher } from './modules/project-switcher.js';
46
49
  import { initSplitView } from './modules/split-view.js';
47
50
  import { initPaneBridge } from './modules/pane-bridge.js';
@@ -64,7 +67,8 @@ import { initCursors, handleRemoteCursorMove as _curHandleRemoteCursorMove, hand
64
67
  import { initFavicon, updateFavicon as _favUpdateFavicon, setSendBtnMode as _favSetSendBtnMode, blinkIO as _favBlinkIO, blinkSessionDot as _favBlinkSessionDot, updateCrossProjectBlink as _favUpdateCrossProjectBlink, startUrgentBlink as _favStartUrgentBlink, stopUrgentBlink as _favStopUrgentBlink, setActivity as _favSetActivity } from './modules/app-favicon.js';
65
68
  import { initHeader, closeSessionInfoPopover as _hdrCloseSessionInfoPopover, updateHistorySentinel as _hdrUpdateHistorySentinel, requestMoreHistory as _hdrRequestMoreHistory, prependOlderHistory as _hdrPrependOlderHistory } from './modules/app-header.js';
66
69
  import { initSessionActions } from './modules/session-actions.js';
67
- import { initMisc, flushPendingExtMessages, showImageModal as _miscShowImageModal, closeImageModal as _miscCloseImageModal, showPasteModal as _miscShowPasteModal, closePasteModal as _miscClosePasteModal, showConfirm as _miscShowConfirm, hideConfirm as _miscHideConfirm, showForceChangePinOverlay as _miscShowForceChangePinOverlay, sendExtensionCommand as _miscSendExtensionCommand, handleExtensionResult as _miscHandleExtensionResult } from './modules/app-misc.js';
70
+ import { initMisc, flushPendingExtMessages, showImageModal as _miscShowImageModal, closeImageModal as _miscCloseImageModal, showConfirm as _miscShowConfirm, hideConfirm as _miscHideConfirm, showForceChangePinOverlay as _miscShowForceChangePinOverlay, sendExtensionCommand as _miscSendExtensionCommand, handleExtensionResult as _miscHandleExtensionResult } from './modules/app-misc.js';
71
+ import { showPasteModal } from './modules/paste-modal.js';
68
72
  import { initSkillInstall, requireSkills as _siRequireSkills, handleSkillInstallWs as _siHandleSkillInstallWs } from './modules/app-skills-install.js';
69
73
  import { initDebateUi, showDebateConcludeConfirm as _debShowDebateConcludeConfirm, exitDebateConcludeMode as _debExitDebateConcludeMode, handleDebateConcludeSend as _debHandleDebateConcludeSend, showDebateEndedMode as _debShowDebateEndedMode, exitDebateEndedMode as _debExitDebateEndedMode, showDebateUserFloor as _debShowDebateUserFloor, exitDebateFloorMode as _debExitDebateFloorMode, handleDebateFloorSend as _debHandleDebateFloorSend, renderDebateUserFloorDone as _debRenderDebateUserFloorDone, showDebateSticky as _debShowDebateSticky, showDebateBottomBar as _debShowDebateBottomBar, removeDebateBottomBar as _debRemoveDebateBottomBar, sendDebateStickyComment as _debSendDebateStickyComment, updateDebateRound as _debUpdateDebateRound } from './modules/app-debate-ui.js';
70
74
  import { initLoopUi, updateLoopInputVisibility as _loopUpdateLoopInputVisibility, updateLoopButton as _loopUpdateLoopButton, showLoopBanner as _loopShowLoopBanner, updateLoopBanner as _loopUpdateLoopBanner, updateRalphBars as _loopUpdateRalphBars, showRalphCraftingBar as _loopShowRalphCraftingBar, showRalphApprovalBar as _loopShowRalphApprovalBar, updateRalphApprovalStatus as _loopUpdateRalphApprovalStatus, openRalphPreviewModal as _loopOpenRalphPreviewModal, showExecModal as _loopShowExecModal, closeExecModal as _loopCloseExecModal, updateExecModalStatus as _loopUpdateExecModalStatus } from './modules/app-loop-ui.js';
@@ -203,16 +207,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
203
207
  }
204
208
 
205
209
  // Modal close handlers (replaces inline onclick)
206
- $("paste-modal").querySelector(".confirm-backdrop").addEventListener("click", function() {
207
- $("paste-modal").classList.add("hidden");
208
- });
209
- $("paste-modal").querySelector(".paste-modal-close").addEventListener("click", function() {
210
- $("paste-modal").classList.add("hidden");
211
- });
212
- $("paste-modal").querySelector(".paste-modal-copy").addEventListener("click", function() {
213
- var body = $("paste-modal-body");
214
- if (body) copyToClipboard(body.textContent, "Copied to clipboard");
215
- });
216
210
  $("mermaid-modal").querySelector(".confirm-backdrop").addEventListener("click", closeMermaidModal);
217
211
  $("mermaid-modal").querySelector(".mermaid-modal-btn[title='Close']").addEventListener("click", closeMermaidModal);
218
212
  $("image-modal").querySelector(".confirm-backdrop").addEventListener("click", closeImageModal);
@@ -260,9 +254,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
260
254
  // --- Header session rename, session info popover -> modules/app-header.js
261
255
  function closeSessionInfoPopover() { _hdrCloseSessionInfoPopover(); }
262
256
 
263
- // --- Modals (confirm, paste) -> modules/app-misc.js
264
- function showPasteModal(text) { _miscShowPasteModal(text); }
265
- function closePasteModal() { _miscClosePasteModal(); }
257
+ // --- Confirmation modal -> modules/app-misc.js
266
258
  function showConfirm(text, onConfirm, okLabel, destructive) { _miscShowConfirm(text, onConfirm, okLabel, destructive); }
267
259
  function hideConfirm() { _miscHideConfirm(); }
268
260
 
@@ -285,6 +277,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
285
277
  projectName: projectName,
286
278
  cwd: "",
287
279
  currentSlug: currentSlug,
280
+ activeProjectSlug: null,
281
+ sessionActivatedProjectSlug: null,
282
+ socketPath: null,
283
+ pendingHomeProjectSlug: null,
288
284
  currentProjectOwnerId: null,
289
285
  isOsUsers: false,
290
286
  skipPermsEnabled: false,
@@ -297,6 +293,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
297
293
  isHeadlessMode: false,
298
294
  savedMainSlug: null,
299
295
  connected: false,
296
+ pendingOutboundMessages: [],
297
+ searchClayChatState: null,
300
298
  homeChatMateId: null,
301
299
  homeChatSessionId: null,
302
300
  homeChatSessionModel: null,
@@ -327,7 +325,27 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
327
325
  dockWidth: null,
328
326
  dockHasActivity: false,
329
327
  dockActivityToolId: null,
328
+ projectLogsOpen: false,
329
+ projectLogsWide: false,
330
+ projectLogsFullscreen: false,
331
+ projectLogsEntries: [],
332
+ projectLogsSelectedRef: null,
333
+ projectLogsView: 'list',
334
+ projectLogsCategory: '',
335
+ projectLogsContextMode: '',
336
+ projectLogsIsWorktree: false,
337
+ projectLogsListScroll: 0,
338
+ projectLogsListRequestId: null,
339
+ projectLogsReadRequestId: null,
340
+ projectLogsCommentRequestId: null,
341
+ projectLogsCommentStatusEl: null,
342
+ projectLogsDeleteRequestId: null,
343
+ projectLogsCanDelete: false,
344
+ projectLogsUnread: 0,
345
+ projectLogsSeenRevisions: {},
330
346
  installedTools: [],
347
+ capsulesEnabled: false,
348
+ capsulesPreferenceLoaded: false,
331
349
  homeToolRegistryLoaded: false,
332
350
  toolScanErrors: [],
333
351
 
@@ -360,6 +378,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
360
378
  currentMsgEl: null,
361
379
  currentFullText: "",
362
380
  matePreThinkingEl: null,
381
+ thinkingState: null,
363
382
  // panels
364
383
  fileViewerFullscreen: false,
365
384
  markdownSlidesActive: false,
@@ -480,6 +499,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
480
499
  // buttons exist in the DOM when sidebar.js (and later terminal.js /
481
500
  // mcp-ui.js / etc.) attach click handlers by ID.
482
501
  initToolPalettes();
502
+ initProjectLogs();
483
503
  initSidebar(sidebarCtx);
484
504
  var wsGetter = function () { return _getWsRef(); };
485
505
  initMateSidebar(wsGetter);
@@ -772,7 +792,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
772
792
  if (isHomeHubVisible()) hideHomeHub();
773
793
  if (newSlug && newSlug !== store.get('currentSlug')) {
774
794
  resetFileBrowser();
775
- closeArchive();
795
+ closeNotesBrowser();
776
796
  if (isSchedulerOpen()) closeScheduler();
777
797
  resetScheduler(newSlug);
778
798
  store.set({ currentSlug: newSlug });
@@ -944,8 +964,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
944
964
  if (!_perms.fileBrowser) {
945
965
  var fbBtn = document.getElementById("file-browser-btn");
946
966
  if (fbBtn) fbBtn.style.display = "none";
947
- var gitBtn = document.getElementById("git-sidebar-btn");
948
- if (gitBtn) gitBtn.style.display = "none";
967
+ var gitPlacardEl = document.getElementById("git-placard");
968
+ if (gitPlacardEl) gitPlacardEl.style.display = "none";
949
969
  }
950
970
  if (!_perms.skills) {
951
971
  var sBtn = document.getElementById("skills-btn");
@@ -954,10 +974,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
954
974
  if (msBtn) msBtn.style.display = "none";
955
975
  }
956
976
  if (!_perms.scheduledTasks) {
957
- var schBtn = document.getElementById("scheduler-btn");
977
+ var schBtn = document.getElementById("home-scheduler-btn");
958
978
  if (schBtn) schBtn.style.display = "none";
959
- var mateSchBtn = document.getElementById("mate-scheduler-btn");
960
- if (mateSchBtn) mateSchBtn.style.display = "none";
979
+ var schToolBtn = document.getElementById("scheduler-btn");
980
+ if (schToolBtn) schToolBtn.style.display = "none";
961
981
  }
962
982
  if (!_perms.createProject) {
963
983
  var addProjBtn = document.getElementById("icon-strip-add");
@@ -1036,6 +1056,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1036
1056
  fileViewerEl: $("file-viewer"),
1037
1057
  });
1038
1058
  initGitPanel();
1059
+ initWorkerPaneLock();
1039
1060
 
1040
1061
  // --- Terminal ---
1041
1062
  initTerminal({
@@ -1088,17 +1109,24 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1088
1109
  }
1089
1110
 
1090
1111
  // --- Sticky Notes ---
1091
- initStickyNotes({
1092
- get ws() { return _getWsRef(); },
1093
- get connected() { return store.get('connected'); },
1094
- });
1112
+ // The canvas reads the socket from ws-ref and the connection flag from the
1113
+ // store directly, so it needs no injected context.
1114
+ initStickyNotes();
1115
+ initNotesBrowser();
1116
+ // The browser refreshes from note messages without the canvas module having
1117
+ // to import it, which would be a cycle.
1118
+ setBrowserRefresh(function () { if (isNotesBrowserOpen()) renderNotesBrowser(); });
1119
+ // Opening the browser claims the single right workbench slot. Registered here
1120
+ // so the browser module never imports the other tools.
1121
+ registerExclusiveClosers([closeProjectLogs, closeScheduler, closeFileViewer, closeTerminal]);
1095
1122
 
1096
1123
  // --- Sticky Notes sidebar button (create new note) ---
1097
1124
  var stickyNotesSidebarBtn = $("sticky-notes-sidebar-btn");
1098
1125
  if (stickyNotesSidebarBtn) {
1099
1126
  stickyNotesSidebarBtn.addEventListener("click", function () {
1127
+ closeProjectLogs();
1100
1128
  if (isSchedulerOpen()) closeScheduler();
1101
- if (isArchiveOpen()) closeArchive();
1129
+ if (isNotesBrowserOpen()) closeNotesBrowser();
1102
1130
  showNotes();
1103
1131
  createNote();
1104
1132
  });
@@ -1109,22 +1137,23 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1109
1137
  if (stickyNotesBadge) {
1110
1138
  stickyNotesBadge.addEventListener("click", function (e) {
1111
1139
  e.stopPropagation();
1140
+ closeProjectLogs();
1112
1141
  if (isSchedulerOpen()) closeScheduler();
1113
- if (isArchiveOpen()) {
1114
- closeArchive();
1142
+ if (isNotesBrowserOpen()) {
1143
+ closeNotesBrowser();
1115
1144
  } else {
1116
- openArchive();
1145
+ openNotesBrowser();
1117
1146
  }
1118
1147
  });
1119
1148
  }
1120
1149
 
1121
- // Close archive / scheduler panel when switching to other sidebar panels
1150
+ // Close the notes browser / scheduler panel when switching to other sidebar panels
1122
1151
  var fileBrowserBtn = $("file-browser-btn");
1123
- var gitSidebarBtn = $("git-sidebar-btn");
1152
+ var gitPlacardMoreBtn = $("git-placard-more");
1124
1153
  var terminalSidebarBtn = $("terminal-sidebar-btn");
1125
- if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
1126
- if (gitSidebarBtn) gitSidebarBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
1127
- if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
1154
+ if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1155
+ if (gitPlacardMoreBtn) gitPlacardMoreBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1156
+ if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1128
1157
 
1129
1158
  // --- Ralph Loop UI (delegated to app-loop-ui.js + app-loop-wizard.js) ---
1130
1159
  function updateLoopInputVisibility(loop) { _loopUpdateLoopInputVisibility(loop); }
@@ -651,7 +651,7 @@
651
651
  }
652
652
 
653
653
  /* --- Session visibility indicator --- */
654
- .session-private-icon {
654
+ .session-shared-icon {
655
655
  display: inline-flex;
656
656
  align-items: center;
657
657
  margin-right: 4px;
@@ -659,7 +659,7 @@
659
659
  vertical-align: middle;
660
660
  }
661
661
 
662
- .session-private-icon svg {
662
+ .session-shared-icon svg {
663
663
  width: 12px;
664
664
  height: 12px;
665
665
  }