clay-server 4.0.0-beta.2 → 4.0.0-beta.21

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 (177) hide show
  1. package/lib/background-task-timing.js +105 -0
  2. package/lib/capsule-display-floor.js +51 -0
  3. package/lib/capsule-frame-server.js +255 -0
  4. package/lib/capsule-mate-turn.js +105 -0
  5. package/lib/capsule-pig-logic.js +300 -0
  6. package/lib/capsule-server-runtimes.js +39 -0
  7. package/lib/capsules/pig/display.js +198 -0
  8. package/lib/capsules/pig/manifest.json +9 -0
  9. package/lib/capsules/pig/ui.json +84 -0
  10. package/lib/config.js +25 -1
  11. package/lib/daemon-projects.js +13 -8
  12. package/lib/daemon.js +127 -14
  13. package/lib/git-cli.js +95 -1
  14. package/lib/knowledge-import.js +436 -0
  15. package/lib/knowledge-record-store.js +188 -0
  16. package/lib/knowledge-search.js +240 -0
  17. package/lib/mate-knowledge-mcp-server.js +151 -0
  18. package/lib/mate-knowledge-migration.js +283 -0
  19. package/lib/mate-knowledge-service.js +488 -0
  20. package/lib/mate-knowledge-sync.js +482 -0
  21. package/lib/migrate-single-user.js +2 -0
  22. package/lib/notes-lifecycle.js +149 -0
  23. package/lib/notes.js +60 -3
  24. package/lib/os-users.js +3 -1
  25. package/lib/project-capsule-catalog.js +9 -1
  26. package/lib/project-capsule-turn.js +96 -0
  27. package/lib/project-connection.js +14 -1
  28. package/lib/project-http.js +15 -1
  29. package/lib/project-knowledge.js +22 -0
  30. package/lib/project-log-context.js +172 -0
  31. package/lib/project-log-feedback-delivery.js +118 -0
  32. package/lib/project-logs-comments.js +137 -0
  33. package/lib/project-logs-context-state.js +42 -0
  34. package/lib/project-logs-mcp-server.js +328 -0
  35. package/lib/project-logs-query.js +185 -0
  36. package/lib/project-logs-root.js +75 -0
  37. package/lib/project-logs-schema.js +259 -0
  38. package/lib/project-logs-service.js +463 -0
  39. package/lib/project-logs-snapshot.js +205 -0
  40. package/lib/project-logs-store.js +495 -0
  41. package/lib/project-logs-versioning.js +132 -0
  42. package/lib/project-logs.js +400 -0
  43. package/lib/project-mate-interaction.js +14 -0
  44. package/lib/project-mate-knowledge.js +110 -0
  45. package/lib/project-memory.js +22 -0
  46. package/lib/project-message-delivery.js +70 -0
  47. package/lib/project-pair-lifecycle.js +460 -0
  48. package/lib/project-session-handoff.js +1 -1
  49. package/lib/project-session-notes.js +64 -13
  50. package/lib/project-session-pair.js +159 -146
  51. package/lib/project-session-spawn.js +1 -1
  52. package/lib/project-sessions.js +58 -13
  53. package/lib/project-user-message.js +53 -4
  54. package/lib/project-vendor-login.js +20 -3
  55. package/lib/project-worker-permission.js +430 -0
  56. package/lib/project-worker-proposal.js +208 -62
  57. package/lib/project.js +178 -6
  58. package/lib/public/app.js +58 -35
  59. package/lib/public/css/admin.css +2 -2
  60. package/lib/public/css/capsule-ui.css +38 -0
  61. package/lib/public/css/command-palette.css +19 -9
  62. package/lib/public/css/git-placard.css +154 -0
  63. package/lib/public/css/home-hub.css +4 -0
  64. package/lib/public/css/home-session-actions.css +66 -0
  65. package/lib/public/css/home-sidebar.css +66 -0
  66. package/lib/public/css/input.css +163 -28
  67. package/lib/public/css/mobile-nav.css +80 -0
  68. package/lib/public/css/notifications-center.css +67 -0
  69. package/lib/public/css/pane.css +52 -0
  70. package/lib/public/css/project-logs.css +198 -0
  71. package/lib/public/css/scheduler.css +1 -1
  72. package/lib/public/css/session-actions.css +16 -101
  73. package/lib/public/css/sidebar.css +103 -0
  74. package/lib/public/css/sticky-notes.css +237 -229
  75. package/lib/public/css/worker-proposal.css +34 -1
  76. package/lib/public/index.html +45 -11
  77. package/lib/public/modules/admin.js +8 -8
  78. package/lib/public/modules/app-connection.js +109 -4
  79. package/lib/public/modules/app-home-hub.js +19 -7
  80. package/lib/public/modules/app-message-cards.js +2 -1
  81. package/lib/public/modules/app-messages.js +84 -7
  82. package/lib/public/modules/app-misc.js +2 -14
  83. package/lib/public/modules/app-notifications.js +11 -7
  84. package/lib/public/modules/app-panels.js +46 -4
  85. package/lib/public/modules/app-projects.js +13 -8
  86. package/lib/public/modules/app-rendering.js +1 -0
  87. package/lib/public/modules/background-tasks-ui.js +139 -16
  88. package/lib/public/modules/capsule-preference.js +44 -0
  89. package/lib/public/modules/chat-bubble-renderer.js +1 -1
  90. package/lib/public/modules/clay-log-links.js +70 -0
  91. package/lib/public/modules/command-palette.js +52 -15
  92. package/lib/public/modules/context-sources.js +0 -3
  93. package/lib/public/modules/git-agent-sessions.js +85 -0
  94. package/lib/public/modules/git-panel.js +111 -84
  95. package/lib/public/modules/git-placard.js +161 -0
  96. package/lib/public/modules/home-chat-empty-state.js +39 -0
  97. package/lib/public/modules/home-chat-identity.js +9 -0
  98. package/lib/public/modules/home-conversations-sheet.js +102 -48
  99. package/lib/public/modules/home-mate-chat.js +15 -35
  100. package/lib/public/modules/home-session-actions.js +6 -0
  101. package/lib/public/modules/home-sidebar-chat-list.js +101 -41
  102. package/lib/public/modules/home-sidebar.js +7 -0
  103. package/lib/public/modules/home-tool-frame.js +182 -0
  104. package/lib/public/modules/home-tools.js +138 -1
  105. package/lib/public/modules/input.js +38 -7
  106. package/lib/public/modules/markdown.js +2 -0
  107. package/lib/public/modules/mate-sidebar.js +0 -8
  108. package/lib/public/modules/message-delivery.js +97 -0
  109. package/lib/public/modules/paste-modal.js +84 -0
  110. package/lib/public/modules/project-logs-render.js +405 -0
  111. package/lib/public/modules/project-logs.js +461 -0
  112. package/lib/public/modules/project-removal-target.js +26 -0
  113. package/lib/public/modules/scheduler.js +17 -3
  114. package/lib/public/modules/session-actions.js +29 -105
  115. package/lib/public/modules/session-hierarchy.js +54 -0
  116. package/lib/public/modules/sidebar-mobile.js +40 -15
  117. package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
  118. package/lib/public/modules/sidebar-sessions.js +77 -11
  119. package/lib/public/modules/sidebar.js +17 -5
  120. package/lib/public/modules/split-group-helpers.js +8 -0
  121. package/lib/public/modules/split-view.js +5 -2
  122. package/lib/public/modules/sticky-note-markdown.js +5 -0
  123. package/lib/public/modules/sticky-notes-browser.js +326 -0
  124. package/lib/public/modules/sticky-notes-card.js +360 -0
  125. package/lib/public/modules/sticky-notes-editor.js +291 -0
  126. package/lib/public/modules/sticky-notes-shared.js +90 -0
  127. package/lib/public/modules/sticky-notes.js +170 -946
  128. package/lib/public/modules/tool-palette-order.js +143 -0
  129. package/lib/public/modules/tool-palette-overlays.js +159 -0
  130. package/lib/public/modules/tool-palette.js +21 -188
  131. package/lib/public/modules/tools.js +21 -1
  132. package/lib/public/modules/update-snooze.js +169 -0
  133. package/lib/public/modules/user-settings.js +4 -0
  134. package/lib/public/modules/worker-pane-lock.js +176 -0
  135. package/lib/public/modules/worker-proposal-state.js +16 -0
  136. package/lib/public/modules/worker-proposal.js +49 -12
  137. package/lib/public/style.css +3 -1
  138. package/lib/sdk-bridge.js +132 -46
  139. package/lib/sdk-message-processor.js +60 -14
  140. package/lib/server-experimental-settings.js +49 -0
  141. package/lib/server-global-ws.js +11 -0
  142. package/lib/server-home-chat-events.js +31 -1
  143. package/lib/server-home-chat.js +27 -4
  144. package/lib/server-home-clay-entry.js +1 -1
  145. package/lib/server-home-clay-session-links.js +34 -5
  146. package/lib/server-settings.js +5 -0
  147. package/lib/server-tools.js +127 -9
  148. package/lib/server.js +124 -18
  149. package/lib/session-driver-eligibility.js +38 -0
  150. package/lib/session-driver-orchestration.js +31 -0
  151. package/lib/session-hygiene.js +3 -0
  152. package/lib/session-notes-mcp-server.js +25 -5
  153. package/lib/session-pair-factory.js +247 -0
  154. package/lib/session-pair-mcp-server.js +46 -8
  155. package/lib/session-pair-prompts.js +79 -0
  156. package/lib/session-pair-turn-control.js +153 -0
  157. package/lib/session-provenance.js +119 -0
  158. package/lib/session-spawn-mcp-server.js +1 -1
  159. package/lib/session-split-groups.js +4 -1
  160. package/lib/session-title-policy.js +60 -0
  161. package/lib/session-visibility.js +39 -0
  162. package/lib/sessions.js +61 -11
  163. package/lib/tools-registry.js +89 -10
  164. package/lib/update-snooze.js +437 -0
  165. package/lib/users-experimental-preferences.js +30 -0
  166. package/lib/users-permissions.js +2 -2
  167. package/lib/users.js +22 -16
  168. package/lib/workspace-query-access.js +102 -0
  169. package/lib/workspace-query-service.js +24 -17
  170. package/lib/worktree.js +25 -38
  171. package/lib/ws-schema.js +38 -7
  172. package/lib/yoke/adapters/claude-worker.js +16 -6
  173. package/lib/yoke/adapters/claude.js +81 -4
  174. package/lib/yoke/adapters/codex.js +63 -15
  175. package/lib/yoke/codex-background-tasks.js +8 -2
  176. package/lib/yoke/vendor-registry.js +1 -1
  177. package/package.json +3 -3
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");
@@ -42,6 +43,7 @@ var { attachEmail: attachEmailModule } = require("./project-email");
42
43
  var { attachSessionSpawn } = require("./project-session-spawn");
43
44
  var { attachDelegatedSession } = require("./project-delegated-session");
44
45
  var { attachDelegatedFollowUp } = require("./project-delegated-follow-up");
46
+ var { attachCapsuleTurn } = require("./project-capsule-turn");
45
47
  var workspaceSessionRef = require("./workspace-query-service").sessionRef;
46
48
  var { attachSessionPair } = require("./project-session-pair");
47
49
  var { attachSessionHandoff } = require("./project-session-handoff");
@@ -49,8 +51,12 @@ var { attachSessionNotes, composeSystemPrompts } = require("./project-session-no
49
51
  var { attachSessionDocument } = require("./project-session-document");
50
52
  var { attachCapsuleCatalog } = require("./project-capsule-catalog");
51
53
  var { attachProjectWorkspaceQuery } = require("./project-workspace-query");
54
+ var { attachProjectLogs } = require("./project-logs");
55
+ var { attachProjectLogFeedbackDelivery } = require("./project-log-feedback-delivery");
56
+ var { attachProjectMateKnowledge } = require("./project-mate-knowledge");
52
57
  var { attachSplitGroups } = require("./session-split-groups");
53
58
  var toolControlMcp = require("./tool-control-mcp-server");
59
+ var capsuleFloor = require("./capsule-display-floor");
54
60
  var toolLlm = require("./tool-llm");
55
61
  // project-notifications is attached globally in server.js, passed via opts.notificationsModule
56
62
 
@@ -61,6 +67,10 @@ function createMateToolControlMcp(adapter, config) {
61
67
  var manifests = config.list(config.userId) || [];
62
68
  var tools = [];
63
69
  for (var i = 0; i < manifests.length; i++) {
70
+ // Skills go dark when the declarative Display floor does, so a Capsule
71
+ // the human cannot operate is never listed to a Mate either. The guard
72
+ // validates the Capsule's own Display tree, not a claim about it.
73
+ if (!capsuleFloor.hasUsableFloor(manifests[i])) continue;
64
74
  tools.push({
65
75
  id: manifests[i].id,
66
76
  name: manifests[i].name,
@@ -205,6 +215,7 @@ function createProjectContext(opts) {
205
215
  var updateChannel = opts.updateChannel || "stable";
206
216
  var osUsers = opts.osUsers || false;
207
217
  var projectOwnerId = opts.projectOwnerId || null;
218
+ var projectKnowledgeId = opts.projectKnowledgeId || null;
208
219
  var worktreeMeta = opts.worktreeMeta || null; // { parentSlug, branch, external }
209
220
  var isMate = opts.isMate || false;
210
221
  var mateId = opts.mateId || (isMate ? path.basename(cwd) : null);
@@ -395,6 +406,49 @@ function createProjectContext(opts) {
395
406
  }
396
407
  }
397
408
 
409
+ // Update version metadata goes only to admin-grade connections, and only to
410
+ // those not currently snoozing this exact version. Both decisions come from
411
+ // update-snooze.js; this loop owns nothing but the client set.
412
+ function broadcastUpdateAvailable(version) {
413
+ if (!version) return;
414
+ var now = Date.now();
415
+ var payload = JSON.stringify({ type: "update_available", version: version });
416
+ for (var ws of clients) {
417
+ if (ws.readyState !== 1) continue;
418
+ if (!updateSnooze.isUpdateAdmin(ws, usersModule)) continue;
419
+ var key = updateSnooze.userKeyFor(ws, usersModule);
420
+ if (updateSnooze.isSnoozed(key, version, now)) continue;
421
+ ws.send(payload);
422
+ }
423
+ }
424
+
425
+ // The install lifecycle frame. Every client needs it, because the daemon is
426
+ // about to restart and the UI blocks the screen — but only admin-grade
427
+ // connections get the version with it. Non-admins get the same frame minus
428
+ // the metadata, so behaviour is unchanged for them and nothing leaks.
429
+ function broadcastUpdateStarted(version) {
430
+ var withVersion = JSON.stringify({ type: "update_started", version: version || "" });
431
+ var withoutVersion = JSON.stringify({ type: "update_started" });
432
+ for (var ws of clients) {
433
+ if (ws.readyState !== 1) continue;
434
+ ws.send(updateSnooze.isUpdateAdmin(ws, usersModule) ? withVersion : withoutVersion);
435
+ }
436
+ }
437
+
438
+ // Tell every live connection of one user that a snooze took effect, so the
439
+ // banner clears on their other devices too rather than only where it was
440
+ // dismissed. Scoped by the same server-derived key the snooze was stored
441
+ // under, never by anything in a payload.
442
+ function sendToUpdateUser(userKey, obj) {
443
+ if (!userKey) return;
444
+ var data = JSON.stringify(obj);
445
+ for (var ws of clients) {
446
+ if (ws.readyState !== 1) continue;
447
+ if (updateSnooze.userKeyFor(ws, usersModule) !== userKey) continue;
448
+ ws.send(data);
449
+ }
450
+ }
451
+
398
452
  function broadcastClientCount() {
399
453
  var msg = { type: "client_count", count: clients.size };
400
454
  if (usersModule.isMultiUser()) {
@@ -624,6 +678,31 @@ function createProjectContext(opts) {
624
678
  isMate: isMate,
625
679
  mateId: mateId,
626
680
  });
681
+ var _logFeedbackDelivery = attachProjectLogFeedbackDelivery({
682
+ sm: sm,
683
+ getSdk: function () { return sdk; },
684
+ onProcessingChanged: onProcessingChanged,
685
+ getLinuxUserForSession: getLinuxUserForSession,
686
+ });
687
+ var _projectLogs = attachProjectLogs({
688
+ service: opts.projectLogsService || null,
689
+ sm: sm,
690
+ projectSlug: slug,
691
+ getProjectOwnerId: function () { return projectOwnerId; },
692
+ isMate: isMate,
693
+ mateId: mateId,
694
+ sendTo: sendTo,
695
+ getClients: function () { return clients; },
696
+ onFeedback: _logFeedbackDelivery.deliver,
697
+ });
698
+ var _mateKnowledge = attachProjectMateKnowledge({
699
+ service: opts.mateKnowledgeService || null,
700
+ sm: sm,
701
+ projectSlug: slug,
702
+ getProjectOwnerId: function () { return projectOwnerId; },
703
+ isMate: isMate,
704
+ mateId: mateId,
705
+ });
627
706
 
628
707
  // The SDK bridge is created after local MCP servers. Session spawning uses
629
708
  // a getter so tool handlers see the initialized bridge when they run.
@@ -739,6 +818,27 @@ function createProjectContext(opts) {
739
818
  }
740
819
  }
741
820
 
821
+ // Project Logs. Project sessions get the project-scoped set; Mate projects
822
+ // get the read-only cross-project set only when the Mate registry confirms
823
+ // authoritative builtin Clay.
824
+ try {
825
+ var projectLogsMcpConfig = _projectLogs.createMcpServer(adapter, null);
826
+ if (projectLogsMcpConfig) servers[projectLogsMcpConfig.name || "clay-logs"] = projectLogsMcpConfig;
827
+ } catch (e) {
828
+ console.error("[project] Failed to create clay-logs MCP server:", e.message);
829
+ }
830
+
831
+ // Mate Knowledge. Mate projects only; the registry decides whether this is
832
+ // one Mate's own scope or authoritative Clay's cross-Mate read view.
833
+ if (isMate) {
834
+ try {
835
+ var mateKnowledgeMcpConfig = _mateKnowledge.createMcpServer(adapter, null);
836
+ if (mateKnowledgeMcpConfig) servers[mateKnowledgeMcpConfig.name || "clay-knowledge"] = mateKnowledgeMcpConfig;
837
+ } catch (e) {
838
+ console.error("[project] Failed to create clay-knowledge MCP server:", e.message);
839
+ }
840
+ }
841
+
742
842
  // Session-bound access to the source of a handoff (main projects only).
743
843
  if (!isMate) {
744
844
  try {
@@ -903,6 +1003,24 @@ function createProjectContext(opts) {
903
1003
  }
904
1004
  continue;
905
1005
  }
1006
+ if (name === "clay-logs" && forSession) {
1007
+ try {
1008
+ var boundLogs = _projectLogs.createMcpServer(adapter, forSession);
1009
+ if (boundLogs) { filtered[name] = boundLogs; hasAny = true; }
1010
+ } catch (e) {
1011
+ console.error("[project] Failed to bind clay-logs MCP server:", e.message);
1012
+ }
1013
+ continue;
1014
+ }
1015
+ if (name === "clay-knowledge" && forSession) {
1016
+ try {
1017
+ var boundKnowledge = _mateKnowledge.createMcpServer(adapter, forSession);
1018
+ if (boundKnowledge) { filtered[name] = boundKnowledge; hasAny = true; }
1019
+ } catch (e) {
1020
+ console.error("[project] Failed to bind clay-knowledge MCP server:", e.message);
1021
+ }
1022
+ continue;
1023
+ }
906
1024
  if (name === "clay-tools" && forSession) {
907
1025
  try {
908
1026
  var boundToolControl = createToolControlMcpServer();
@@ -992,6 +1110,9 @@ function createProjectContext(opts) {
992
1110
  clayPort: serverPort,
993
1111
  clayTls: serverTls,
994
1112
  clayAuthToken: serverAuthToken,
1113
+ getWorkerPermissionRouter: function () {
1114
+ return isMate ? null : _sessionPair.workerPermission;
1115
+ },
995
1116
  onProcessingChanged: onProcessingChanged,
996
1117
  onTurnDone: function (session, preview) {
997
1118
  if (isMate) digestDmTurn(session, preview);
@@ -1021,6 +1142,8 @@ function createProjectContext(opts) {
1021
1142
  _sessionHandoff.getSystemPrompt(session),
1022
1143
  _sessionDocument.getSystemPrompt(session),
1023
1144
  _capsuleCatalog.getSystemPrompt(session),
1145
+ _projectLogs.getSystemPrompt(session),
1146
+ _mateKnowledge.getSystemPrompt(session),
1024
1147
  ]);
1025
1148
  },
1026
1149
  getRuntimeEnv: getRuntimeEnvForSession,
@@ -1035,7 +1158,9 @@ function createProjectContext(opts) {
1035
1158
  .concat(_debateProposal.getToolDefs(session))
1036
1159
  .concat(_mateCreationProposal.getToolDefs(session))
1037
1160
  .concat(_workspaceQuery.getDynamicToolDefs(session))
1038
- .concat(_workspaceQuery.getHistoryDynamicToolDefs(session));
1161
+ .concat(_workspaceQuery.getHistoryDynamicToolDefs(session))
1162
+ .concat(_projectLogs.getDynamicToolDefs(session))
1163
+ .concat(_mateKnowledge.getDynamicToolDefs(session));
1039
1164
  },
1040
1165
  });
1041
1166
 
@@ -1081,7 +1206,7 @@ function createProjectContext(opts) {
1081
1206
  fetchVersion(updateChannel).then(function (v) {
1082
1207
  if (v && isNewer(v, currentVersion)) {
1083
1208
  latestVersion = v;
1084
- if (broadcast) sendToAdmins({ type: "update_available", version: v });
1209
+ if (broadcast) broadcastUpdateAvailable(v);
1085
1210
  }
1086
1211
  }).catch(function (e) {
1087
1212
  console.error("[project] Background version check failed:", e.message || e);
@@ -1169,6 +1294,12 @@ function createProjectContext(opts) {
1169
1294
  }
1170
1295
 
1171
1296
  function handleMessage(ws, msg) {
1297
+ // --- Keep-alive (delegated to project-connection.js) ---
1298
+ // Answered before any routing so a ping can never be forwarded elsewhere.
1299
+ // _connection is assigned later in this factory than the other modules, so
1300
+ // the reference is guarded rather than assumed.
1301
+ if (_connection && _connection.handleKeepaliveMessage(ws, msg)) return;
1302
+
1172
1303
  if (ws._clayHomeDebateSlug && ws._clayHomeDebateSlug !== slug && /^debate_(hand_raise|comment|stop|conclude_response|user_floor_response)$/.test(msg.type || "") && opts.getProject) {
1173
1304
  var homeDebateCtx = opts.getProject(ws._clayHomeDebateSlug);
1174
1305
  if (homeDebateCtx) homeDebateCtx.handleMessage(ws, msg);
@@ -1188,11 +1319,11 @@ function createProjectContext(opts) {
1188
1319
  if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg);
1189
1320
  return;
1190
1321
  }
1191
- if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve") {
1322
+ if (msg.type === "home_clay_ask" || msg.type === "home_clay_session_resolve" || msg.type === "home_clay_log_resolve") {
1192
1323
  if (typeof opts.onDmMessage === "function") opts.onDmMessage(ws, msg, slug);
1193
1324
  return;
1194
1325
  }
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") {
1326
+ 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
1327
  if (typeof opts.onDmMessage === "function") {
1197
1328
  opts.onDmMessage(ws, msg, slug);
1198
1329
  }
@@ -1266,6 +1397,9 @@ function createProjectContext(opts) {
1266
1397
  // --- Knowledge file management (delegated to project-knowledge.js) ---
1267
1398
  if (_knowledge.handleKnowledgeMessage(ws, msg)) return;
1268
1399
 
1400
+ // --- Project Logs (delegated to project-logs.js) ---
1401
+ if (_projectLogs.handleLogsMessage(ws, msg)) return;
1402
+
1269
1403
  // --- Notifications (delegated to project-notifications.js) ---
1270
1404
  if (_notifications.handleNotificationMessage(ws, msg)) return;
1271
1405
 
@@ -1468,6 +1602,9 @@ function createProjectContext(opts) {
1468
1602
  send: send,
1469
1603
  sendTo: sendTo,
1470
1604
  sendToAdmins: sendToAdmins,
1605
+ broadcastUpdateAvailable: broadcastUpdateAvailable,
1606
+ broadcastUpdateStarted: broadcastUpdateStarted,
1607
+ sendToUpdateUser: sendToUpdateUser,
1471
1608
  sendToSession: sendToSession,
1472
1609
  sendToSessionOthers: sendToSessionOthers,
1473
1610
  opts: opts,
@@ -1477,6 +1614,7 @@ function createProjectContext(opts) {
1477
1614
  matesModule: matesModule,
1478
1615
  pushModule: pushModule,
1479
1616
  getSessionForWs: getSessionForWs,
1617
+ onHumanPairStop: function (session) { return _sessionPair.handleHumanStop(session); },
1480
1618
  getLinuxUserForSession: getLinuxUserForSession,
1481
1619
  ensureProjectAccessForSession: ensureProjectAccessForSession,
1482
1620
  getOsUserInfoForWs: getOsUserInfoForWs,
@@ -1530,6 +1668,16 @@ function createProjectContext(opts) {
1530
1668
  return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1531
1669
  },
1532
1670
  });
1671
+ var _capsuleTurn = attachCapsuleTurn({
1672
+ sm: sm,
1673
+ getSdk: function () { return sdk; },
1674
+ getLinuxUserForSession: getLinuxUserForSession,
1675
+ isMultiUser: function () { return usersModule.isMultiUser(); },
1676
+ resolveModel: function (principal) {
1677
+ var user = principal && principal.userId ? usersModule.findUserById(principal.userId) : null;
1678
+ return _models.resolveConfiguredModel({ _clayUser: user || null }, "standard");
1679
+ },
1680
+ });
1533
1681
  var _delegatedFollowUp = attachDelegatedFollowUp({
1534
1682
  sm: sm,
1535
1683
  getSdk: function () { return sdk; },
@@ -1546,6 +1694,13 @@ function createProjectContext(opts) {
1546
1694
 
1547
1695
  // --- User message handler (delegated to project-user-message.js) ---
1548
1696
  var _userMessage = attachUserMessage({
1697
+ // Exact live pair state decides whether a session is Driver-operated; the
1698
+ // handler never infers the role from the message.
1699
+ isDriverOperatedSession: function (session) {
1700
+ if (isMate || !_sessionPair.workerPermission) return false;
1701
+ return _sessionPair.workerPermission.isDriverOperated(session);
1702
+ },
1703
+ beginHumanPairTurn: function (session) { return _sessionPair.beginHumanTurn(session); },
1549
1704
  cwd: cwd,
1550
1705
  slug: slug,
1551
1706
  isMate: isMate,
@@ -1610,6 +1765,7 @@ function createProjectContext(opts) {
1610
1765
  getOsUserInfoForWs: getOsUserInfoForWs,
1611
1766
  getOsUserInfoForLinuxUser: getOsUserInfoForLinuxUser,
1612
1767
  getLinuxUserForSession: getLinuxUserForSession,
1768
+ refreshVendorAuthEverywhere: opts.refreshVendorAuthEverywhere,
1613
1769
  });
1614
1770
 
1615
1771
  // --- Filesystem handler (delegated to project-filesystem.js) ---
@@ -1733,6 +1889,10 @@ function createProjectContext(opts) {
1733
1889
  for (var wqti = 0; wqti < workspaceTools.length; wqti++) tools.push(workspaceTools[wqti]);
1734
1890
  var historyTools = _workspaceQuery.getHistoryBridgeTools(boundSession, normalizeToolSchema);
1735
1891
  for (var cht = 0; cht < historyTools.length; cht++) tools.push(historyTools[cht]);
1892
+ var logsTools = _projectLogs.getBridgeTools(boundSession, normalizeToolSchema);
1893
+ for (var plti = 0; plti < logsTools.length; plti++) tools.push(logsTools[plti]);
1894
+ var knowledgeTools = _mateKnowledge.getBridgeTools(boundSession, normalizeToolSchema);
1895
+ for (var mkti = 0; mkti < knowledgeTools.length; mkti++) tools.push(knowledgeTools[mkti]);
1736
1896
  }
1737
1897
 
1738
1898
  if (sessionOnly) return Promise.resolve(tools);
@@ -1748,7 +1908,7 @@ function createProjectContext(opts) {
1748
1908
  // Debate tools were added above only when this request had an
1749
1909
  // exact session. Never duplicate them or advertise the static,
1750
1910
  // intentionally unbound proposal server.
1751
- if (inAppNames[i] === "clay-debate" || inAppNames[i] === "clay-mate-creation" || inAppNames[i] === "clay-workspace" || inAppNames[i] === "clay-history") continue;
1911
+ 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;
1752
1912
  extractServerTools(inAppNames[i], localMcp[inAppNames[i]]);
1753
1913
  }
1754
1914
  }
@@ -1811,7 +1971,13 @@ function createProjectContext(opts) {
1811
1971
  if (boundSession && serverName === "clay-history") {
1812
1972
  return _workspaceQuery.callHistoryBridgeTool(boundSession, toolName, args);
1813
1973
  }
1814
- 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") {
1974
+ if (boundSession && serverName === "clay-logs") {
1975
+ return _projectLogs.callBridgeTool(boundSession, toolName, args);
1976
+ }
1977
+ if (boundSession && serverName === "clay-knowledge") {
1978
+ return _mateKnowledge.callBridgeTool(boundSession, toolName, args);
1979
+ }
1980
+ 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") {
1815
1981
  return Promise.reject(new Error("Session-bound tool requires a valid Clay session: " + serverName + "/" + toolName));
1816
1982
  }
1817
1983
  if (sessionOnly) return Promise.reject(new Error("Session tool not found: " + serverName + "/" + toolName));
@@ -2023,6 +2189,7 @@ function createProjectContext(opts) {
2023
2189
  isProcessing: hasProcessing,
2024
2190
  pendingPermissions: pendingPermCount,
2025
2191
  projectOwnerId: projectOwnerId,
2192
+ projectKnowledgeId: projectKnowledgeId,
2026
2193
  };
2027
2194
  if (isMate) {
2028
2195
  status.isMate = true;
@@ -2032,6 +2199,9 @@ function createProjectContext(opts) {
2032
2199
  status.isWorktree = true;
2033
2200
  status.parentSlug = worktreeMeta.parentSlug;
2034
2201
  status.branch = worktreeMeta.branch;
2202
+ status.changeSetId = worktreeMeta.changeSetId || null;
2203
+ status.baseCommit = worktreeMeta.baseCommit || null;
2204
+ status.headCommit = worktreeMeta.headCommit || null;
2035
2205
  status.worktreeExternal = worktreeMeta.external === true;
2036
2206
  }
2037
2207
  if (usersModule.isMultiUser()) {
@@ -2130,6 +2300,7 @@ function createProjectContext(opts) {
2130
2300
  createDelegatedSession: _delegatedSession.createDelegatedSession,
2131
2301
  inspectDelegatedFollowUp: _delegatedFollowUp.inspectDelegatedFollowUp,
2132
2302
  dispatchDelegatedFollowUp: _delegatedFollowUp.dispatchDelegatedFollowUp,
2303
+ deliverCapsuleTurn: _capsuleTurn.deliverCapsuleTurn,
2133
2304
  unregisterHomeDebateClient: function (ws) { homeDebateClients.delete(ws); },
2134
2305
  handleHomeDebateProposalResponse: function (ws, msg, session) { return _debateProposal.handleHomeMessage(ws, msg, session); },
2135
2306
  handleHomeMateCreationProposalResponse: function (ws, msg, session) { return _mateCreationProposal.handleHomeMessage(ws, msg, session); },
@@ -2141,6 +2312,7 @@ function createProjectContext(opts) {
2141
2312
  listKnowledgeFiles: _knowledge.listKnowledgeFiles,
2142
2313
  refreshCapsuleCatalog: _capsuleCatalog.refreshSessions,
2143
2314
  getNotificationsModule: function () { return _notifications; },
2315
+ refreshVendorAuth: _vendorLogin.refreshVendorAuth,
2144
2316
  getSchedules: _loop.getSchedules,
2145
2317
  importSchedule: _loop.importSchedule,
2146
2318
  removeSchedule: _loop.removeSchedule,
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
 
@@ -297,6 +289,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
297
289
  isHeadlessMode: false,
298
290
  savedMainSlug: null,
299
291
  connected: false,
292
+ pendingOutboundMessages: [],
300
293
  homeChatMateId: null,
301
294
  homeChatSessionId: null,
302
295
  homeChatSessionModel: null,
@@ -327,7 +320,27 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
327
320
  dockWidth: null,
328
321
  dockHasActivity: false,
329
322
  dockActivityToolId: null,
323
+ projectLogsOpen: false,
324
+ projectLogsWide: false,
325
+ projectLogsFullscreen: false,
326
+ projectLogsEntries: [],
327
+ projectLogsSelectedRef: null,
328
+ projectLogsView: 'list',
329
+ projectLogsCategory: '',
330
+ projectLogsContextMode: '',
331
+ projectLogsIsWorktree: false,
332
+ projectLogsListScroll: 0,
333
+ projectLogsListRequestId: null,
334
+ projectLogsReadRequestId: null,
335
+ projectLogsCommentRequestId: null,
336
+ projectLogsCommentStatusEl: null,
337
+ projectLogsDeleteRequestId: null,
338
+ projectLogsCanDelete: false,
339
+ projectLogsUnread: 0,
340
+ projectLogsSeenRevisions: {},
330
341
  installedTools: [],
342
+ capsulesEnabled: false,
343
+ capsulesPreferenceLoaded: false,
331
344
  homeToolRegistryLoaded: false,
332
345
  toolScanErrors: [],
333
346
 
@@ -480,6 +493,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
480
493
  // buttons exist in the DOM when sidebar.js (and later terminal.js /
481
494
  // mcp-ui.js / etc.) attach click handlers by ID.
482
495
  initToolPalettes();
496
+ initProjectLogs();
483
497
  initSidebar(sidebarCtx);
484
498
  var wsGetter = function () { return _getWsRef(); };
485
499
  initMateSidebar(wsGetter);
@@ -772,7 +786,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
772
786
  if (isHomeHubVisible()) hideHomeHub();
773
787
  if (newSlug && newSlug !== store.get('currentSlug')) {
774
788
  resetFileBrowser();
775
- closeArchive();
789
+ closeNotesBrowser();
776
790
  if (isSchedulerOpen()) closeScheduler();
777
791
  resetScheduler(newSlug);
778
792
  store.set({ currentSlug: newSlug });
@@ -944,8 +958,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
944
958
  if (!_perms.fileBrowser) {
945
959
  var fbBtn = document.getElementById("file-browser-btn");
946
960
  if (fbBtn) fbBtn.style.display = "none";
947
- var gitBtn = document.getElementById("git-sidebar-btn");
948
- if (gitBtn) gitBtn.style.display = "none";
961
+ var gitPlacardEl = document.getElementById("git-placard");
962
+ if (gitPlacardEl) gitPlacardEl.style.display = "none";
949
963
  }
950
964
  if (!_perms.skills) {
951
965
  var sBtn = document.getElementById("skills-btn");
@@ -954,10 +968,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
954
968
  if (msBtn) msBtn.style.display = "none";
955
969
  }
956
970
  if (!_perms.scheduledTasks) {
957
- var schBtn = document.getElementById("scheduler-btn");
971
+ var schBtn = document.getElementById("home-scheduler-btn");
958
972
  if (schBtn) schBtn.style.display = "none";
959
- var mateSchBtn = document.getElementById("mate-scheduler-btn");
960
- if (mateSchBtn) mateSchBtn.style.display = "none";
973
+ var schToolBtn = document.getElementById("scheduler-btn");
974
+ if (schToolBtn) schToolBtn.style.display = "none";
961
975
  }
962
976
  if (!_perms.createProject) {
963
977
  var addProjBtn = document.getElementById("icon-strip-add");
@@ -1036,6 +1050,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1036
1050
  fileViewerEl: $("file-viewer"),
1037
1051
  });
1038
1052
  initGitPanel();
1053
+ initWorkerPaneLock();
1039
1054
 
1040
1055
  // --- Terminal ---
1041
1056
  initTerminal({
@@ -1088,17 +1103,24 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1088
1103
  }
1089
1104
 
1090
1105
  // --- Sticky Notes ---
1091
- initStickyNotes({
1092
- get ws() { return _getWsRef(); },
1093
- get connected() { return store.get('connected'); },
1094
- });
1106
+ // The canvas reads the socket from ws-ref and the connection flag from the
1107
+ // store directly, so it needs no injected context.
1108
+ initStickyNotes();
1109
+ initNotesBrowser();
1110
+ // The browser refreshes from note messages without the canvas module having
1111
+ // to import it, which would be a cycle.
1112
+ setBrowserRefresh(function () { if (isNotesBrowserOpen()) renderNotesBrowser(); });
1113
+ // Opening the browser claims the single right workbench slot. Registered here
1114
+ // so the browser module never imports the other tools.
1115
+ registerExclusiveClosers([closeProjectLogs, closeScheduler, closeFileViewer, closeTerminal]);
1095
1116
 
1096
1117
  // --- Sticky Notes sidebar button (create new note) ---
1097
1118
  var stickyNotesSidebarBtn = $("sticky-notes-sidebar-btn");
1098
1119
  if (stickyNotesSidebarBtn) {
1099
1120
  stickyNotesSidebarBtn.addEventListener("click", function () {
1121
+ closeProjectLogs();
1100
1122
  if (isSchedulerOpen()) closeScheduler();
1101
- if (isArchiveOpen()) closeArchive();
1123
+ if (isNotesBrowserOpen()) closeNotesBrowser();
1102
1124
  showNotes();
1103
1125
  createNote();
1104
1126
  });
@@ -1109,22 +1131,23 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
1109
1131
  if (stickyNotesBadge) {
1110
1132
  stickyNotesBadge.addEventListener("click", function (e) {
1111
1133
  e.stopPropagation();
1134
+ closeProjectLogs();
1112
1135
  if (isSchedulerOpen()) closeScheduler();
1113
- if (isArchiveOpen()) {
1114
- closeArchive();
1136
+ if (isNotesBrowserOpen()) {
1137
+ closeNotesBrowser();
1115
1138
  } else {
1116
- openArchive();
1139
+ openNotesBrowser();
1117
1140
  }
1118
1141
  });
1119
1142
  }
1120
1143
 
1121
- // Close archive / scheduler panel when switching to other sidebar panels
1144
+ // Close the notes browser / scheduler panel when switching to other sidebar panels
1122
1145
  var fileBrowserBtn = $("file-browser-btn");
1123
- var gitSidebarBtn = $("git-sidebar-btn");
1146
+ var gitPlacardMoreBtn = $("git-placard-more");
1124
1147
  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(); });
1148
+ if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1149
+ if (gitPlacardMoreBtn) gitPlacardMoreBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1150
+ if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { closeProjectLogs(); if (isNotesBrowserOpen()) closeNotesBrowser(); if (isSchedulerOpen()) closeScheduler(); });
1128
1151
 
1129
1152
  // --- Ralph Loop UI (delegated to app-loop-ui.js + app-loop-wizard.js) ---
1130
1153
  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
  }