clay-server 3.8.1 → 4.0.0-beta.2

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 (189) hide show
  1. package/lib/ask-user-mcp-server.js +5 -119
  2. package/lib/builtin-mates.js +6 -6
  3. package/lib/claude-hook-installer.js +15 -0
  4. package/lib/clay-history-mcp-server.js +62 -297
  5. package/lib/daemon.js +1 -1
  6. package/lib/debate-model-selection.js +119 -0
  7. package/lib/home-debate-tool-policy.js +164 -0
  8. package/lib/home-response-notifications.js +26 -0
  9. package/lib/mate-creation-mcp-server.js +55 -0
  10. package/lib/mate-ready-creation.js +95 -0
  11. package/lib/mates.js +2 -0
  12. package/lib/notes.js +2 -1
  13. package/lib/project-ask-user.js +64 -0
  14. package/lib/project-capsule-catalog.js +101 -0
  15. package/lib/project-connection.js +4 -0
  16. package/lib/project-debate-proposal.js +133 -17
  17. package/lib/project-debate.js +214 -110
  18. package/lib/project-delegated-follow-up.js +84 -0
  19. package/lib/project-delegated-session.js +53 -0
  20. package/lib/project-filesystem.js +7 -9
  21. package/lib/project-knowledge.js +1 -0
  22. package/lib/project-mate-creation-proposal.js +120 -0
  23. package/lib/project-memory.js +14 -7
  24. package/lib/project-models.js +157 -32
  25. package/lib/project-session-notes.js +2 -2
  26. package/lib/project-session-pair.js +8 -8
  27. package/lib/project-sessions.js +66 -51
  28. package/lib/project-vendor-login.js +397 -0
  29. package/lib/project-worker-proposal.js +25 -25
  30. package/lib/project-workspace-query.js +144 -0
  31. package/lib/project.js +349 -102
  32. package/lib/public/app.js +85 -42
  33. package/lib/public/css/avatar-imprints.css +0 -1
  34. package/lib/public/css/base.css +4 -0
  35. package/lib/public/css/capsule-ui.css +389 -0
  36. package/lib/public/css/command-palette.css +306 -6
  37. package/lib/public/css/home-capsule-library.css +243 -0
  38. package/lib/public/css/home-capsule-source.css +192 -0
  39. package/lib/public/css/home-debate-live.css +146 -0
  40. package/lib/public/css/home-debate-planning.css +125 -0
  41. package/lib/public/css/home-debates-archive.css +281 -0
  42. package/lib/public/css/home-hub.css +896 -405
  43. package/lib/public/css/home-mate-creation.css +34 -0
  44. package/lib/public/css/home-mate-model-picker.css +131 -0
  45. package/lib/public/css/home-mate-settings.css +344 -0
  46. package/lib/public/css/home-session-actions.css +265 -0
  47. package/lib/public/css/home-sidebar.css +667 -0
  48. package/lib/public/css/icon-strip.css +1 -2
  49. package/lib/public/css/mates.css +7 -34
  50. package/lib/public/css/pane.css +1 -1
  51. package/lib/public/css/playbook.css +0 -80
  52. package/lib/public/css/sticky-notes.css +53 -117
  53. package/lib/public/css/tui-attention.css +0 -44
  54. package/lib/public/css/workspace-assignment.css +45 -0
  55. package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
  56. package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
  57. package/lib/public/index.html +93 -74
  58. package/lib/public/modules/app-connection.js +10 -1
  59. package/lib/public/modules/app-dm.js +43 -160
  60. package/lib/public/modules/app-home-hub.js +328 -585
  61. package/lib/public/modules/app-message-cards.js +242 -0
  62. package/lib/public/modules/app-message-router.js +84 -0
  63. package/lib/public/modules/app-messages.js +102 -37
  64. package/lib/public/modules/app-notifications.js +8 -119
  65. package/lib/public/modules/app-projects.js +9 -1
  66. package/lib/public/modules/app-rendering.js +21 -602
  67. package/lib/public/modules/avatar-imprint.js +11 -8
  68. package/lib/public/modules/chat-bubble-renderer.js +152 -0
  69. package/lib/public/modules/chat-render-runtime.js +198 -0
  70. package/lib/public/modules/command-palette.js +225 -436
  71. package/lib/public/modules/dm-render.js +82 -0
  72. package/lib/public/modules/home-capsule-creation-intent.js +31 -0
  73. package/lib/public/modules/home-capsule-library.js +146 -0
  74. package/lib/public/modules/home-capsule-source.js +383 -0
  75. package/lib/public/modules/home-chat-identity.js +35 -0
  76. package/lib/public/modules/home-chat-scroll.js +77 -0
  77. package/lib/public/modules/home-chat-stream-state.js +34 -0
  78. package/lib/public/modules/home-composer-focus.js +25 -0
  79. package/lib/public/modules/home-conversations-sheet.js +179 -0
  80. package/lib/public/modules/home-debate-activity.js +48 -0
  81. package/lib/public/modules/home-debate-controls.js +295 -0
  82. package/lib/public/modules/home-debate-launch.js +41 -0
  83. package/lib/public/modules/home-debate-live.js +284 -0
  84. package/lib/public/modules/home-debate-models.js +73 -0
  85. package/lib/public/modules/home-debate-planning.js +335 -0
  86. package/lib/public/modules/home-debates-archive.js +279 -0
  87. package/lib/public/modules/home-dock-resize.js +74 -0
  88. package/lib/public/modules/home-dock.js +446 -0
  89. package/lib/public/modules/home-mate-chat.js +496 -0
  90. package/lib/public/modules/home-mate-creation.js +109 -0
  91. package/lib/public/modules/home-mate-model-picker.js +281 -0
  92. package/lib/public/modules/home-mate-selection.js +38 -0
  93. package/lib/public/modules/home-mate-settings-menu.js +131 -0
  94. package/lib/public/modules/home-mate-settings.js +383 -0
  95. package/lib/public/modules/home-session-actions.js +373 -0
  96. package/lib/public/modules/home-session-model-confirmation.js +13 -0
  97. package/lib/public/modules/home-shell.js +9 -0
  98. package/lib/public/modules/home-sidebar-chat-list.js +63 -0
  99. package/lib/public/modules/home-sidebar.js +158 -0
  100. package/lib/public/modules/home-sub-surface.js +19 -0
  101. package/lib/public/modules/home-surface-boot.js +68 -0
  102. package/lib/public/modules/home-surface.js +141 -0
  103. package/lib/public/modules/home-tools.js +271 -0
  104. package/lib/public/modules/markdown.js +50 -2
  105. package/lib/public/modules/mate-management.js +86 -0
  106. package/lib/public/modules/mate-wizard.js +0 -7
  107. package/lib/public/modules/mention.js +17 -19
  108. package/lib/public/modules/pane-bridge.js +9 -0
  109. package/lib/public/modules/profile.js +4 -5
  110. package/lib/public/modules/project-settings.js +34 -28
  111. package/lib/public/modules/project-switcher.js +11 -5
  112. package/lib/public/modules/project-workspace-assignment.js +23 -0
  113. package/lib/public/modules/search-clay-chat.js +402 -0
  114. package/lib/public/modules/server-settings.js +14 -12
  115. package/lib/public/modules/session-actions.js +1 -1
  116. package/lib/public/modules/sidebar-mates.js +56 -552
  117. package/lib/public/modules/sidebar-mobile.js +7 -64
  118. package/lib/public/modules/sidebar-presence.js +37 -0
  119. package/lib/public/modules/split-pair-ui.js +13 -13
  120. package/lib/public/modules/split-view.js +7 -0
  121. package/lib/public/modules/sticky-notes.js +7 -6
  122. package/lib/public/modules/tool-input-composition.js +48 -0
  123. package/lib/public/modules/tool-llm-status.js +167 -0
  124. package/lib/public/modules/tool-renderer-advanced.js +285 -0
  125. package/lib/public/modules/tool-renderer-chart.js +158 -0
  126. package/lib/public/modules/tool-renderer-semantics.js +35 -0
  127. package/lib/public/modules/tool-renderer.js +464 -0
  128. package/lib/public/modules/tool-runtime.js +309 -0
  129. package/lib/public/modules/tool-ui-evaluator.js +97 -0
  130. package/lib/public/modules/tool-ui-tree.js +21 -0
  131. package/lib/public/modules/tui-attention.js +10 -0
  132. package/lib/public/modules/user-settings.js +16 -23
  133. package/lib/public/modules/vendor-login.js +287 -0
  134. package/lib/public/modules/worker-proposal.js +2 -2
  135. package/lib/public/modules/workspace-assignment-card.js +149 -0
  136. package/lib/public/modules/workspace-assignment-routing.js +4 -0
  137. package/lib/public/style.css +13 -2
  138. package/lib/runtime-env.js +65 -0
  139. package/lib/sdk-bridge.js +120 -32
  140. package/lib/sdk-message-processor.js +10 -6
  141. package/lib/server-home-capsule-creation.js +36 -0
  142. package/lib/server-home-chat-events.js +287 -0
  143. package/lib/server-home-chat.js +518 -0
  144. package/lib/server-home-clay-entry.js +65 -0
  145. package/lib/server-home-clay-session-links.js +26 -0
  146. package/lib/server-home-debate-planning.js +214 -0
  147. package/lib/server-home-debates.js +137 -0
  148. package/lib/server-home-mate-creation.js +261 -0
  149. package/lib/server-home-models.js +241 -0
  150. package/lib/server-home-preferences.js +61 -0
  151. package/lib/server-mates.js +37 -0
  152. package/lib/server-tools.js +377 -0
  153. package/lib/server.js +111 -59
  154. package/lib/session-pair-mcp-server.js +6 -6
  155. package/lib/sessions.js +18 -3
  156. package/lib/tool-capsule-source.js +142 -0
  157. package/lib/tool-control-mcp-server.js +126 -0
  158. package/lib/tool-llm.js +48 -0
  159. package/lib/tool-storage.js +77 -0
  160. package/lib/tool-ui-spec-advanced.js +82 -0
  161. package/lib/tool-ui-spec.js +261 -0
  162. package/lib/tools-registry.js +286 -0
  163. package/lib/users-home-dock-preferences.js +77 -0
  164. package/lib/users-home-surface-preferences.js +99 -0
  165. package/lib/users-preferences.js +4 -7
  166. package/lib/users.js +12 -0
  167. package/lib/whats-new-content.js +3 -3
  168. package/lib/workspace-assignment-service.js +420 -0
  169. package/lib/workspace-query-mcp-server.js +154 -0
  170. package/lib/workspace-query-service.js +492 -0
  171. package/lib/ws-schema.js +93 -12
  172. package/lib/yoke/adapters/acp.js +2 -1
  173. package/lib/yoke/adapters/antigravity.js +2 -1
  174. package/lib/yoke/adapters/claude-worker.js +11 -4
  175. package/lib/yoke/adapters/claude.js +73 -43
  176. package/lib/yoke/adapters/codex.js +40 -10
  177. package/lib/yoke/adapters/kiro.js +2 -1
  178. package/lib/yoke/claude-user-input.js +38 -0
  179. package/lib/yoke/codex-app-server.js +20 -2
  180. package/lib/yoke/codex-user-input.js +64 -0
  181. package/lib/yoke/complete-once.js +164 -0
  182. package/lib/yoke/index.js +5 -1
  183. package/lib/yoke/interface.js +19 -0
  184. package/lib/yoke/mcp-bridge-server.js +2 -6
  185. package/lib/yoke/user-input.js +254 -0
  186. package/package.json +3 -2
  187. package/lib/public/css/home-chat.css +0 -380
  188. package/lib/public/modules/home-chat.js +0 -438
  189. package/lib/server-clay-home.js +0 -245
@@ -7,7 +7,6 @@ import { iconHtml, refreshIcons } from './icons.js';
7
7
  import { parseEmojis } from './markdown.js';
8
8
  import { getCurrentTheme, getChatLayout, setChatLayout } from './theme.js';
9
9
  import { openCommandPalette } from './command-palette.js';
10
- import { getMateSessions } from './mate-sidebar.js';
11
10
  import { openProjectSettings } from './project-settings.js';
12
11
  import {
13
12
  getCachedSessions,
@@ -33,8 +32,8 @@ import { store } from './store.js';
33
32
  import { getWs } from './ws-ref.js';
34
33
  import { dismissOverlayPanels, closeSidebar } from './sidebar.js';
35
34
  import { switchProject, getCachedProjects } from './app-projects.js';
36
- import { openDm } from './app-dm.js';
37
35
  import { showHomeHub } from './app-home-hub.js';
36
+ import { openHomeChat } from './home-mate-chat.js';
38
37
  import { openTerminal } from './terminal.js';
39
38
  import { requestKnowledgeList } from './mate-knowledge.js';
40
39
  import { loadRootDirectory } from './filebrowser.js';
@@ -319,9 +318,9 @@ function renderSheetSessions(listEl) {
319
318
  if (type === "project") {
320
319
  renderMobileSessionsInto(sessionListEl);
321
320
  } else if (type === "mate") {
322
- // Mate DM: open the DM and show mate actions
323
- openDm(mateId);
324
- renderMateMobileActions(sessionListEl);
321
+ closeMobileSheet();
322
+ showHomeHub();
323
+ openHomeChat(mateId);
325
324
  }
326
325
 
327
326
  refreshIcons();
@@ -370,12 +369,8 @@ function renderSheetSessions(listEl) {
370
369
  // Track that chat sheet is open
371
370
  mobileChatSheetOpen = true;
372
371
 
373
- // --- Initial render: show mate actions if DM active, otherwise project sessions ---
374
- if (getCurrentDmUserId()) {
375
- renderSessionsForContext("mate", null, getCurrentDmUserId());
376
- } else {
377
- renderSessionsForContext("project", getCachedCurrentSlug(), null);
378
- }
372
+ // Mate chips navigate away immediately, so the sheet always renders project sessions.
373
+ renderSessionsForContext("project", getCachedCurrentSlug(), null);
379
374
  }
380
375
 
381
376
  // Helper: create a mobile session item element
@@ -659,54 +654,6 @@ function createMobileLoopGroup(loopId, children, groupKey) {
659
654
  return wrapper;
660
655
  }
661
656
 
662
- function renderMateMobileActions(container) {
663
- var newSessionBtn = document.createElement("button");
664
- newSessionBtn.className = "mobile-session-new";
665
- newSessionBtn.innerHTML = '<i data-lucide="plus" style="width:16px;height:16px"></i> New session';
666
- newSessionBtn.addEventListener("click", function () {
667
- if (getWs() && store.get('connected')) {
668
- getWs().send(JSON.stringify({ type: "new_session" }));
669
- }
670
- closeMobileSheet();
671
- });
672
- container.appendChild(newSessionBtn);
673
-
674
- var debateBtn = document.createElement("button");
675
- debateBtn.className = "mobile-session-new";
676
- debateBtn.innerHTML = '<i data-lucide="mic" style="width:16px;height:16px"></i> New debate';
677
- debateBtn.addEventListener("click", function () {
678
- closeMobileSheet();
679
- var targetBtn = document.getElementById("mate-debate-btn");
680
- if (targetBtn) setTimeout(function () { targetBtn.click(); }, 250);
681
- });
682
- container.appendChild(debateBtn);
683
-
684
- // Render mate session list
685
- var mateSessions = getMateSessions();
686
- if (mateSessions.length > 0) {
687
- var sorted = mateSessions.slice().sort(function (a, b) {
688
- return (b.lastActivity || 0) - (a.lastActivity || 0);
689
- });
690
-
691
- var currentGroup = "";
692
- for (var i = 0; i < sorted.length; i++) {
693
- var s = sorted[i];
694
- var group = getDateGroup(s.lastActivity || 0);
695
- if (group !== currentGroup) {
696
- currentGroup = group;
697
- var header = document.createElement("div");
698
- header.className = "mobile-sheet-group";
699
- header.textContent = group;
700
- container.appendChild(header);
701
- }
702
- var mateItem = createMobileSessionItem(s);
703
- container.appendChild(mateItem);
704
- }
705
- }
706
-
707
- refreshIcons();
708
- }
709
-
710
657
  // Helper: render sorted sessions into a container with date groups (with loop session grouping)
711
658
  function renderMobileSessionsInto(container) {
712
659
  // Mirrors the desktop sidebar's split button: one "New session" action on
@@ -902,11 +849,7 @@ export function refreshMobileChatSheet() {
902
849
 
903
850
  // Re-render sessions for current context
904
851
  sessionListEl.innerHTML = "";
905
- if (getCurrentDmUserId()) {
906
- renderMateMobileActions(sessionListEl);
907
- } else {
908
- renderMobileSessionsInto(sessionListEl);
909
- }
852
+ renderMobileSessionsInto(sessionListEl);
910
853
 
911
854
  refreshIcons();
912
855
  }
@@ -0,0 +1,37 @@
1
+ // Compact online-user presence renderer for the project sidebar.
2
+
3
+ import { userAvatarUrl } from './avatar.js';
4
+
5
+ var lastSidebarPresenceIds = [];
6
+
7
+ export function renderSidebarPresence(onlineUsers) {
8
+ var container = document.getElementById("sidebar-presence");
9
+ if (!container) return;
10
+ if (!onlineUsers || onlineUsers.length < 2) {
11
+ if (lastSidebarPresenceIds.length > 0) {
12
+ lastSidebarPresenceIds = [];
13
+ container.innerHTML = "";
14
+ }
15
+ return;
16
+ }
17
+ var newIds = onlineUsers.map(function (user) { return user.id; }).sort();
18
+ if (newIds.length === lastSidebarPresenceIds.length && newIds.every(function (id, index) { return id === lastSidebarPresenceIds[index]; })) return;
19
+ lastSidebarPresenceIds = newIds;
20
+ container.innerHTML = "";
21
+ var maxShow = 4;
22
+ for (var i = 0; i < Math.min(onlineUsers.length, maxShow); i++) {
23
+ var user = onlineUsers[i];
24
+ var image = document.createElement("img");
25
+ image.className = "sidebar-presence-avatar";
26
+ image.src = userAvatarUrl(user, 24);
27
+ image.alt = user.displayName;
28
+ image.dataset.tip = user.displayName + " (@" + user.username + ")";
29
+ container.appendChild(image);
30
+ }
31
+ if (onlineUsers.length > maxShow) {
32
+ var more = document.createElement("span");
33
+ more.className = "sidebar-presence-more";
34
+ more.textContent = "+" + (onlineUsers.length - maxShow);
35
+ container.appendChild(more);
36
+ }
37
+ }
@@ -5,8 +5,8 @@ import { buildAgentVendorSelect, fillAgentModels, buildAgentEffortSelect, fillAg
5
5
  import { showToast } from './utils.js';
6
6
 
7
7
  var pairDialog = null;
8
- // Set when the dialog was opened via "Add Worker" on an existing session:
9
- // that session becomes the Driver and the dialog only configures the Worker.
8
+ // Set when the dialog was opened via "Add Split Worker" on an existing session:
9
+ // that session becomes the Driver and the dialog only configures the Split Worker.
10
10
  var pendingDriver = null;
11
11
 
12
12
  function closePairDialog() {
@@ -35,7 +35,7 @@ function roleColumn(role, description, vendorSelect, modelSelect, effortSelect,
35
35
  col.className = "pair-modal-role";
36
36
  var heading = document.createElement("div");
37
37
  heading.className = "pair-modal-role-heading";
38
- heading.innerHTML = '<span class="pair-role-dot pair-role-' + role.toLowerCase() + '"></span><div><strong>' + role + '</strong><span>' + description + '</span></div>';
38
+ heading.innerHTML = '<span class="pair-role-dot pair-role-' + role.toLowerCase().replace(/ /g, "-") + '"></span><div><strong>' + role + '</strong><span>' + description + '</span></div>';
39
39
  col.appendChild(heading);
40
40
  var vendorField = fieldLabel("Vendor", vendorSelect);
41
41
  col.appendChild(vendorField.fragment);
@@ -82,13 +82,13 @@ export function showPairDialog(options) {
82
82
 
83
83
  var title = document.createElement("div");
84
84
  title.className = "wt-modal-title";
85
- title.textContent = driverInfo ? "Add Worker" : "Pair session";
85
+ title.textContent = driverInfo ? "Add Split Worker" : "Pair session";
86
86
  modal.appendChild(title);
87
87
  var desc = document.createElement("div");
88
88
  desc.className = "pair-modal-desc";
89
89
  desc.textContent = driverInfo
90
- ? "This session becomes the Driver; a new Worker opens beside it."
91
- : "One Driver plans and directs a visible Worker session.";
90
+ ? "This session becomes the Driver; a new Split Worker opens beside it."
91
+ : "One Driver plans and directs a visible Split Worker session.";
92
92
  modal.appendChild(desc);
93
93
 
94
94
  var driverVendor = buildAgentVendorSelect(installed, installed.indexOf("claude") !== -1 ? "claude" : installed[0]);
@@ -137,7 +137,7 @@ export function showPairDialog(options) {
137
137
  } else {
138
138
  roles.appendChild(roleColumn("Driver", "Plans, delegates, and integrates", driverVendor, driverModel, driverEffort, options));
139
139
  }
140
- roles.appendChild(roleColumn("Worker", "Executes delegated tasks", workerVendor, workerModel, workerEffort, options));
140
+ roles.appendChild(roleColumn("Split Worker", "Executes delegated tasks", workerVendor, workerModel, workerEffort, options));
141
141
  modal.appendChild(roles);
142
142
 
143
143
  var actions = document.createElement("div");
@@ -149,7 +149,7 @@ export function showPairDialog(options) {
149
149
  var createBtn = document.createElement("button");
150
150
  createBtn.type = "button";
151
151
  createBtn.className = "wt-modal-btn primary";
152
- createBtn.textContent = driverInfo ? "Add Worker" : "Create pair";
152
+ createBtn.textContent = driverInfo ? "Add Split Worker" : "Create pair";
153
153
  actions.appendChild(cancelBtn);
154
154
  actions.appendChild(createBtn);
155
155
  modal.appendChild(actions);
@@ -218,7 +218,7 @@ export function handleSplitDelegation(msg) {
218
218
  if (msg.active) states[msg.groupId] = msg;
219
219
  else delete states[msg.groupId];
220
220
  store.set({ splitDelegations: states });
221
- // Inside the worker's own pane, mirror the delegation into the composer
221
+ // Inside the Split Worker's own pane, mirror the delegation into the composer
222
222
  // notice (the delegated user_message shows it too; this covers the end).
223
223
  if (store.get('paneMode') && msg.to === store.get('activeSessionId')) {
224
224
  if (msg.active) showWorkerDelegationNotice(null);
@@ -252,7 +252,7 @@ export function syncPairChrome(host, split) {
252
252
  setBtn.type = "button";
253
253
  setBtn.className = "split-pair-set-driver";
254
254
  setBtn.textContent = "Set Driver";
255
- setBtn.title = "Make this session the Driver; the other pane becomes its Worker";
255
+ setBtn.title = "Make this session the Driver; the other pane becomes its Split Worker";
256
256
  setBtn.addEventListener("click", function () { sendSetPair(group.id, paneSessionId); });
257
257
  var titleEl = header.querySelector(".split-pane-title");
258
258
  var accessEl = header.querySelector(".split-pane-full-access");
@@ -264,11 +264,11 @@ export function syncPairChrome(host, split) {
264
264
  for (var pi = 0; pi < split.panes.length && pi < headers.length; pi++) {
265
265
  (function (sessionId, header) {
266
266
  var isDriver = sessionId === group.pair.driverId;
267
- var role = isDriver ? "Driver" : "Worker";
267
+ var role = isDriver ? "Driver" : "Split Worker";
268
268
  var badge = document.createElement("span");
269
- badge.className = "split-pair-role split-pair-role-" + role.toLowerCase();
269
+ badge.className = "split-pair-role split-pair-role-" + role.toLowerCase().replace(/ /g, "-");
270
270
  badge.textContent = role;
271
- badge.title = isDriver ? "Driver controls this Worker" : "Worker controlled by the Driver";
271
+ badge.title = isDriver ? "Driver controls this Split Worker" : "Split Worker controlled by the Driver";
272
272
  var title = header.querySelector(".split-pane-title");
273
273
  var access = header.querySelector(".split-pane-full-access");
274
274
  header.insertBefore(badge, access ? access.nextSibling : (title ? title.nextSibling : null));
@@ -11,6 +11,7 @@ import { groupedSessionIds, findSplitGroup } from './split-group-helpers.js';
11
11
  import { showConfirm } from './app-misc.js';
12
12
  import { syncPairChrome } from './split-pair-ui.js';
13
13
  import { presentMarkdownEdit } from './filebrowser.js';
14
+ import { autoStartLoginIfNeeded } from './vendor-login.js';
14
15
 
15
16
  var host = null;
16
17
  var nativeApp = null;
@@ -276,6 +277,12 @@ function handlePaneMessage(event) {
276
277
  if (present) presentMarkdownEdit(present);
277
278
  return;
278
279
  }
280
+ // Both panes can report auth_required for their own sessions. The shell runs
281
+ // one login flow for the project; repeat events are no-ops there.
282
+ if (msg.type === "clay-pane-auth-required") {
283
+ if (msg.message) autoStartLoginIfNeeded(msg.message);
284
+ return;
285
+ }
279
286
  if (msg.type !== "clay-pane-context") return;
280
287
  var frames = host.querySelectorAll(".split-pane-frame");
281
288
  for (var i = 0; i < frames.length; i++) {
@@ -11,7 +11,7 @@ var textTimers = {};
11
11
  var colorPickerEl = null;
12
12
  var formatToolbarEl = null;
13
13
 
14
- var NOTE_COLORS = ["yellow", "blue", "green", "pink", "orange", "purple"];
14
+ var NOTE_COLORS = ["purple", "green", "yellow", "blue", "pink", "orange"];
15
15
 
16
16
 
17
17
  function getContainerBounds() {
@@ -98,7 +98,8 @@ export function createNote() {
98
98
  type: "note_create",
99
99
  x: 60 + offset,
100
100
  y: 60 + offset,
101
- color: "yellow",
101
+ color: "purple",
102
+ opacity: 0.64,
102
103
  });
103
104
  }
104
105
 
@@ -154,7 +155,7 @@ function renderNote(data) {
154
155
  el.style.width = data.w + "px";
155
156
  el.style.height = data.h + "px";
156
157
  el.style.zIndex = 100 + (data.zIndex || 0);
157
- el.dataset.color = data.color || "yellow";
158
+ el.dataset.color = data.color || "purple";
158
159
 
159
160
  if (data.minimized) el.classList.add("minimized");
160
161
  if (data.hidden) el.classList.add("hidden");
@@ -217,7 +218,7 @@ function renderNote(data) {
217
218
  opacitySlider.type = "range";
218
219
  opacitySlider.min = "20";
219
220
  opacitySlider.max = "100";
220
- opacitySlider.value = String(Math.round((data.opacity || 1) * 100));
221
+ opacitySlider.value = String(Math.round((typeof data.opacity === "number" ? data.opacity : 0.64) * 100));
221
222
  opacitySlider.className = "sticky-note-opacity-slider";
222
223
  opacitySlider.title = "Opacity";
223
224
  opacityWrap.appendChild(opacitySlider);
@@ -813,7 +814,7 @@ export function handleNoteUpdated(msg) {
813
814
  entry.el.style.width = msg.note.w + "px";
814
815
  entry.el.style.height = msg.note.h + "px";
815
816
  entry.el.style.zIndex = 100 + (msg.note.zIndex || 0);
816
- entry.el.dataset.color = msg.note.color || "yellow";
817
+ entry.el.dataset.color = msg.note.color || "purple";
817
818
 
818
819
  // Update text only if not actively editing (check rendered or textarea focus)
819
820
  var textarea = entry.el.querySelector(".sticky-note-text");
@@ -926,7 +927,7 @@ function renderArchiveCards() {
926
927
  (function (noteData) {
927
928
  var card = document.createElement("div");
928
929
  card.className = "notes-archive-card" + (noteData.data.hidden ? " archived" : "");
929
- card.dataset.color = noteData.data.color || "yellow";
930
+ card.dataset.color = noteData.data.color || "purple";
930
931
 
931
932
  // Header with title + delete
932
933
  var header = document.createElement("div");
@@ -0,0 +1,48 @@
1
+ // Composition-safe action binding for declarative Capsule text controls.
2
+
3
+ var inputStates = new WeakMap();
4
+
5
+ export function isToolTextInputComposing(input) {
6
+ var state = inputStates.get(input);
7
+ return !!state && state.composing;
8
+ }
9
+
10
+ export function bindToolTextInput(input, commit, options) {
11
+ options = options || {};
12
+ var state = { composing: false, trailingValue: null };
13
+ inputStates.set(input, state);
14
+
15
+ function isAlive() {
16
+ return typeof options.isAlive !== "function" || options.isAlive(input);
17
+ }
18
+
19
+ input.addEventListener("compositionstart", function () {
20
+ state.composing = true;
21
+ state.trailingValue = null;
22
+ });
23
+
24
+ input.addEventListener("beforeinput", function (event) {
25
+ if (state.trailingValue === null && event && (event.isComposing || event.inputType === "insertCompositionText")) {
26
+ state.composing = true;
27
+ }
28
+ });
29
+
30
+ input.addEventListener("compositionend", function () {
31
+ state.composing = false;
32
+ state.trailingValue = input.value;
33
+ if (!isAlive()) return;
34
+ commit(input.value);
35
+ if (typeof options.onCompositionEnd === "function") options.onCompositionEnd(input);
36
+ });
37
+
38
+ input.addEventListener("input", function (event) {
39
+ if (state.composing || (event && event.isComposing)) return;
40
+ if (state.trailingValue !== null && input.value === state.trailingValue) {
41
+ state.trailingValue = null;
42
+ return;
43
+ }
44
+ state.trailingValue = null;
45
+ if (!isAlive()) return;
46
+ commit(input.value);
47
+ });
48
+ }
@@ -0,0 +1,167 @@
1
+ // Compact provider/model status for LLM-enabled Capsule surfaces.
2
+
3
+ import { getWs } from './ws-ref.js';
4
+
5
+ var surfaces = [];
6
+ var requestCounter = 0;
7
+ var activeRequests = Object.create(null);
8
+ var states = Object.create(null);
9
+ var subscribers = [];
10
+
11
+ export var TOOL_LLM_ALIASES = Object.freeze(["fast", "standard", "deep"]);
12
+
13
+ function safeAlias(alias) {
14
+ return alias === "fast" || alias === "deep" ? alias : "standard";
15
+ }
16
+
17
+ function isAlias(alias) {
18
+ return alias === "fast" || alias === "standard" || alias === "deep";
19
+ }
20
+
21
+ export function initialToolLlmAlias(manifest) {
22
+ return manifest && isAlias(manifest.modelAlias) ? manifest.modelAlias : null;
23
+ }
24
+
25
+ export function toolLlmDisplayValue(modelState) {
26
+ var ready = modelState && modelState.status === "ready" && modelState.vendorName && modelState.modelName;
27
+ return ready ? modelState.vendorName + " · " + modelState.modelName : "No model configured";
28
+ }
29
+
30
+ export function toolLlmShouldRetry(modelState) {
31
+ return !!modelState && modelState.status === "error";
32
+ }
33
+
34
+ function currentSurfaces() {
35
+ surfaces = surfaces.filter(function (surface) { return !!surface.root; });
36
+ return surfaces;
37
+ }
38
+
39
+ function notifyAlias(alias) {
40
+ var current = subscribers.slice();
41
+ for (var i = 0; i < current.length; i++) current[i](alias, getToolLlmConfiguration(alias));
42
+ }
43
+
44
+ export function getToolLlmConfiguration(alias) {
45
+ alias = safeAlias(alias);
46
+ return Object.assign({ status: "loading", vendorName: "", modelName: "", error: "" }, states[alias] || {});
47
+ }
48
+
49
+ export function subscribeToolLlmConfigurations(listener) {
50
+ subscribers.push(listener);
51
+ return function () {
52
+ var index = subscribers.indexOf(listener);
53
+ if (index !== -1) subscribers.splice(index, 1);
54
+ };
55
+ }
56
+
57
+ function renderSurface(surface) {
58
+ if (!surface.alias) {
59
+ surface.value.textContent = "Selected when Capsule runs";
60
+ surface.value.title = "The concrete model is selected when this Capsule requests an LLM capability.";
61
+ surface.error.classList.add("hidden");
62
+ surface.retry.classList.add("hidden");
63
+ return;
64
+ }
65
+ var state = states[surface.alias] || { status: "loading", vendorName: "", modelName: "", error: "" };
66
+ var ready = state.status === "ready" && state.vendorName && state.modelName;
67
+ surface.value.textContent = toolLlmDisplayValue(state);
68
+ surface.value.title = ready ? "Capsule " + surface.alias + " model: " + state.vendorName + " · " + state.modelName : "No configured Capsule model";
69
+ surface.error.textContent = state.error || "";
70
+ surface.error.classList.toggle("hidden", !state.error);
71
+ surface.retry.classList.toggle("hidden", !toolLlmShouldRetry(state));
72
+ surface.retry.disabled = false;
73
+ surface.retry.textContent = "Retry";
74
+ }
75
+
76
+ function renderAlias(alias) {
77
+ var current = currentSurfaces();
78
+ for (var i = 0; i < current.length; i++) {
79
+ if (current[i].alias === alias) renderSurface(current[i]);
80
+ }
81
+ }
82
+
83
+ export function requestToolLlmConfiguration(alias) {
84
+ alias = safeAlias(alias);
85
+ var ws = getWs();
86
+ if (!ws || ws.readyState !== 1) {
87
+ activeRequests[alias] = null;
88
+ states[alias] = { status: "error", vendorName: "", modelName: "", error: "Connect to Clay to check the Capsule model." };
89
+ renderAlias(alias);
90
+ notifyAlias(alias);
91
+ return;
92
+ }
93
+ requestCounter++;
94
+ activeRequests[alias] = "tool-llm-config-" + requestCounter;
95
+ states[alias] = { status: "loading", vendorName: "", modelName: "", error: "" };
96
+ renderAlias(alias);
97
+ notifyAlias(alias);
98
+ ws.send(JSON.stringify({ type: "tool_llm_config_get", requestId: activeRequests[alias], alias: alias }));
99
+ }
100
+
101
+ export function requestAllToolLlmConfigurations() {
102
+ for (var i = 0; i < TOOL_LLM_ALIASES.length; i++) requestToolLlmConfiguration(TOOL_LLM_ALIASES[i]);
103
+ }
104
+
105
+ export function handleToolLlmConfigState(msg) {
106
+ if (!isAlias(msg.alias)) return;
107
+ var alias = msg.alias;
108
+ if (msg.requestId && msg.requestId !== activeRequests[alias]) return;
109
+ activeRequests[alias] = null;
110
+ states[alias] = {
111
+ status: msg.status === "ready" ? "ready" : "error",
112
+ vendorName: msg.vendorName || msg.vendor || "",
113
+ modelName: msg.modelName || msg.model || "",
114
+ error: msg.error || "",
115
+ };
116
+ renderAlias(alias);
117
+ notifyAlias(alias);
118
+ }
119
+
120
+ export function createToolLlmStatus(alias) {
121
+ alias = isAlias(alias) ? alias : null;
122
+ var root = document.createElement("section");
123
+ root.className = "tool-llm-status";
124
+ root.setAttribute("aria-label", "Capsule model status");
125
+ var identity = document.createElement("div");
126
+ identity.className = "tool-llm-identity";
127
+ var label = document.createElement("span");
128
+ label.className = "tool-llm-label";
129
+ label.textContent = "Model";
130
+ var value = document.createElement("span");
131
+ value.className = "tool-llm-value";
132
+ value.setAttribute("aria-live", "polite");
133
+ identity.appendChild(label);
134
+ identity.appendChild(value);
135
+ var actions = document.createElement("div");
136
+ actions.className = "tool-llm-actions";
137
+ var retry = document.createElement("button");
138
+ retry.type = "button";
139
+ retry.className = "tool-llm-action hidden";
140
+ retry.addEventListener("click", function () {
141
+ if (surface.alias) requestToolLlmConfiguration(surface.alias);
142
+ });
143
+ var error = document.createElement("p");
144
+ error.className = "tool-llm-error hidden";
145
+ actions.appendChild(retry);
146
+ root.appendChild(identity);
147
+ root.appendChild(actions);
148
+ root.appendChild(error);
149
+ var surface = { root: root, alias: alias, value: value, retry: retry, error: error };
150
+ surfaces.push(surface);
151
+ renderSurface(surface);
152
+ if (alias) requestToolLlmConfiguration(alias);
153
+ return {
154
+ element: root,
155
+ setAlias: function (nextAlias) {
156
+ if (!isAlias(nextAlias)) return;
157
+ surface.alias = nextAlias;
158
+ renderSurface(surface);
159
+ requestToolLlmConfiguration(nextAlias);
160
+ },
161
+ dispose: function () {
162
+ surface.root = null;
163
+ var index = surfaces.indexOf(surface);
164
+ if (index !== -1) surfaces.splice(index, 1);
165
+ },
166
+ };
167
+ }