clay-server 5.0.2-beta.1 → 5.1.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 (162) hide show
  1. package/LICENSES/README.md +4 -0
  2. package/LICENSES/dicebear-avatars.md +16 -0
  3. package/lib/daemon-project-access.js +7 -1
  4. package/lib/daemon.js +2 -0
  5. package/lib/dicebear-avatar.js +62 -0
  6. package/lib/knowledge-db-service.js +175 -0
  7. package/lib/knowledge-db-validation.js +0 -0
  8. package/lib/knowledge-document-index.js +49 -0
  9. package/lib/knowledge-draft-store.js +56 -0
  10. package/lib/knowledge-file-store.js +199 -0
  11. package/lib/knowledge-markdown.js +128 -0
  12. package/lib/mate-knowledge-mcp-server.js +29 -6
  13. package/lib/mate-knowledge-service.js +23 -2
  14. package/lib/mate-knowledge-sync.js +36 -21
  15. package/lib/mate-workspace-color.js +4 -0
  16. package/lib/mates.js +18 -0
  17. package/lib/project-connection.js +36 -2
  18. package/lib/project-debate-proposal.js +6 -0
  19. package/lib/project-debate-workspace.js +43 -0
  20. package/lib/project-debate.js +1 -0
  21. package/lib/project-file-path.js +2 -3
  22. package/lib/project-knowledge.js +315 -136
  23. package/lib/project-mate-creation-proposal.js +1 -0
  24. package/lib/project-request-access.js +13 -1
  25. package/lib/project-sessions.js +39 -2
  26. package/lib/project-user-knowledge.js +60 -0
  27. package/lib/project.js +59 -18
  28. package/lib/public/app.js +73 -34
  29. package/lib/public/clay-studio-wordmark-bold.svg +20 -0
  30. package/lib/public/css/clay-workspace.css +105 -0
  31. package/lib/public/css/debates-workbench.css +47 -0
  32. package/lib/public/css/filebrowser.css +10 -0
  33. package/lib/public/css/home-debate-live.css +26 -0
  34. package/lib/public/css/home-hub.css +3 -1
  35. package/lib/public/css/home-mate-model-picker.css +15 -131
  36. package/lib/public/css/home-mate-settings.css +168 -16
  37. package/lib/public/css/icon-strip.css +249 -32
  38. package/lib/public/css/mate-conversation.css +176 -0
  39. package/lib/public/css/mate-knowledge-workbench.css +118 -0
  40. package/lib/public/css/mate-workspace-color.css +16 -0
  41. package/lib/public/css/mates.css +28 -28
  42. package/lib/public/css/messages.css +1 -114
  43. package/lib/public/css/mobile-nav.css +16 -16
  44. package/lib/public/css/overlays.css +8 -0
  45. package/lib/public/css/project-logs.css +7 -0
  46. package/lib/public/css/project-mate-creation.css +105 -0
  47. package/lib/public/css/right-workbench.css +3 -3
  48. package/lib/public/css/session-folders.css +80 -21
  49. package/lib/public/css/sidebar.css +183 -107
  50. package/lib/public/css/title-bar.css +151 -0
  51. package/lib/public/css/worker-delegation.css +47 -0
  52. package/lib/public/css/worker-proposal.css +72 -150
  53. package/lib/public/css/you.css +74 -0
  54. package/lib/public/index.html +33 -101
  55. package/lib/public/modules/account-island.js +230 -0
  56. package/lib/public/modules/app-cursors.js +19 -43
  57. package/lib/public/modules/app-debate-ui.js +4 -3
  58. package/lib/public/modules/app-header.js +106 -0
  59. package/lib/public/modules/app-message-router.js +12 -3
  60. package/lib/public/modules/app-messages.js +34 -9
  61. package/lib/public/modules/app-notifications.js +4 -7
  62. package/lib/public/modules/app-projects.js +5 -38
  63. package/lib/public/modules/app-rendering.js +12 -13
  64. package/lib/public/modules/avatar.js +25 -9
  65. package/lib/public/modules/chat-render-runtime.js +16 -4
  66. package/lib/public/modules/command-palette.js +2 -15
  67. package/lib/public/modules/cursor-sharing-preference.js +3 -3
  68. package/lib/public/modules/debate-controls.js +299 -0
  69. package/lib/public/modules/debate.js +2 -0
  70. package/lib/public/modules/debates-workbench.js +339 -0
  71. package/lib/public/modules/default-ai.js +81 -65
  72. package/lib/public/modules/filebrowser.js +28 -8
  73. package/lib/public/modules/home-debate-controls.js +18 -289
  74. package/lib/public/modules/home-mate-avatar-editor.js +228 -0
  75. package/lib/public/modules/home-mate-color-picker.js +66 -0
  76. package/lib/public/modules/home-mate-creation.js +1 -1
  77. package/lib/public/modules/home-mate-instructions.js +90 -0
  78. package/lib/public/modules/home-mate-model-picker.js +80 -271
  79. package/lib/public/modules/home-mate-profile-editor.js +72 -0
  80. package/lib/public/modules/home-mate-settings.js +118 -125
  81. package/lib/public/modules/home-shell.js +3 -0
  82. package/lib/public/modules/home-surface-boot.js +1 -9
  83. package/lib/public/modules/html-preview.js +19 -0
  84. package/lib/public/modules/icon-strip-tooltip.js +95 -0
  85. package/lib/public/modules/knowledge-db-edit-state.js +35 -0
  86. package/lib/public/modules/knowledge-db-workbench.js +234 -0
  87. package/lib/public/modules/knowledge-history-state.js +55 -0
  88. package/lib/public/modules/knowledge-markdown-editor.js +57 -0
  89. package/lib/public/modules/knowledge-preview-links.js +70 -0
  90. package/lib/public/modules/knowledge-workbench-shell.js +21 -0
  91. package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
  92. package/lib/public/modules/mate-knowledge-workbench.js +500 -0
  93. package/lib/public/modules/mate-knowledge.js +11 -3
  94. package/lib/public/modules/mate-management.js +54 -10
  95. package/lib/public/modules/mate-sidebar.js +11 -1
  96. package/lib/public/modules/mate-workspace-color.js +33 -0
  97. package/lib/public/modules/mention.js +5 -13
  98. package/lib/public/modules/profile.js +51 -18
  99. package/lib/public/modules/project-chat-identity.js +79 -0
  100. package/lib/public/modules/project-debate-planning-workspace.js +250 -0
  101. package/lib/public/modules/project-debate-workspace.js +185 -0
  102. package/lib/public/modules/project-header-identity.js +127 -0
  103. package/lib/public/modules/project-logs-render.js +9 -4
  104. package/lib/public/modules/project-mate-creation-workspace.js +414 -0
  105. package/lib/public/modules/project-mate-navigation.js +238 -0
  106. package/lib/public/modules/project-session-navigation.js +29 -0
  107. package/lib/public/modules/project-switcher.js +6 -8
  108. package/lib/public/modules/projects-hub-view.js +5 -6
  109. package/lib/public/modules/projects-hub.js +2 -6
  110. package/lib/public/modules/qrcode.js +27 -8
  111. package/lib/public/modules/search-clay-chat.js +8 -11
  112. package/lib/public/modules/session-activity-tooltip.js +12 -0
  113. package/lib/public/modules/session-create-form.js +86 -14
  114. package/lib/public/modules/session-create.js +50 -7
  115. package/lib/public/modules/session-list-visibility.js +41 -0
  116. package/lib/public/modules/session-presence-ui.js +4 -1
  117. package/lib/public/modules/session-title-marquee.js +51 -0
  118. package/lib/public/modules/sidebar-mates.js +3 -50
  119. package/lib/public/modules/sidebar-mobile.js +63 -60
  120. package/lib/public/modules/sidebar-projects.js +84 -97
  121. package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
  122. package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
  123. package/lib/public/modules/sidebar-sessions.js +49 -50
  124. package/lib/public/modules/sidebar.js +11 -13
  125. package/lib/public/modules/thinking-lifecycle.js +7 -6
  126. package/lib/public/modules/tool-palette-order.js +4 -3
  127. package/lib/public/modules/tool-palette.js +13 -3
  128. package/lib/public/modules/tools.js +22 -22
  129. package/lib/public/modules/worker-proposal.js +42 -8
  130. package/lib/public/modules/worker-runtime-picker.js +115 -0
  131. package/lib/public/modules/you-activity.js +121 -0
  132. package/lib/public/modules/you.js +251 -0
  133. package/lib/public/style.css +16 -8
  134. package/lib/public/vendor/codemirror/LICENSE +21 -0
  135. package/lib/public/vendor/codemirror/codemirror.css +344 -0
  136. package/lib/public/vendor/codemirror/codemirror.js +9884 -0
  137. package/lib/public/vendor/codemirror/continuelist.js +101 -0
  138. package/lib/public/vendor/codemirror/markdown.js +886 -0
  139. package/lib/public/vendor/codemirror/show-hint.css +37 -0
  140. package/lib/public/vendor/codemirror/show-hint.js +523 -0
  141. package/lib/sdk-bridge.js +15 -3
  142. package/lib/server-admin.js +11 -0
  143. package/lib/server-home-chat-events.js +1 -1
  144. package/lib/server-home-chat.js +25 -3
  145. package/lib/server-home-debate-planning.js +4 -1
  146. package/lib/server-home-debates.js +2 -0
  147. package/lib/server-home-mate-creation.js +4 -1
  148. package/lib/server-mate-instructions.js +44 -0
  149. package/lib/server-mates.js +12 -3
  150. package/lib/server-palette.js +1 -1
  151. package/lib/server-settings.js +65 -1
  152. package/lib/server-user-knowledge.js +119 -0
  153. package/lib/server.js +21 -1
  154. package/lib/session-visibility.js +7 -2
  155. package/lib/sessions.js +32 -6
  156. package/lib/user-knowledge-service.js +167 -0
  157. package/lib/users-permissions.js +7 -0
  158. package/lib/users-project-mate-filter-preferences.js +39 -0
  159. package/lib/users.js +6 -0
  160. package/lib/workspace-query-access.js +4 -1
  161. package/lib/ws-schema.js +50 -0
  162. package/package.json +10 -1
@@ -1,3 +1,8 @@
1
+ import { handleYouMessage } from './you.js';
2
+ import { handleYouActivity } from './you-activity.js';
3
+ import { handleProjectDebateMessage } from './project-debate-workspace.js';
4
+ import { openMateWorkspace, renderProjectMates } from './project-mate-navigation.js';
5
+ import { refreshProjectAssistantIdentities } from './project-chat-identity.js';
1
6
  import { handleLinearResult } from './linear-panel.js';
2
7
  import { handleSharedBrowserMessage } from './shared-browser.js';
3
8
  import { openWireframe } from './wireframe-workbench.js';
@@ -25,12 +30,13 @@ import { updateDmBadge, setMentionActive, renderUserStrip } from './sidebar-mate
25
30
  import { renderSidebarPresence } from './sidebar-presence.js';
26
31
  import { refreshMobileChatSheet } from './sidebar-mobile.js';
27
32
  import { renderMateSessionList, handleMateSearchResults, updateMateSidebarProfile } from './mate-sidebar.js';
28
- import { openHomeChat, handleHomeMateHistory, handleHomeMateDelta, handleHomeMateSegment, handleHomeMateDone, handleHomeMateError, handleHomeMateSessionsState } from './home-mate-chat.js';
33
+ import { handleHomeMateHistory, handleHomeMateDelta, handleHomeMateSegment, handleHomeMateDone, handleHomeMateError, handleHomeMateSessionsState } from './home-mate-chat.js';
29
34
  import { handleHomeSurfaceState } from './home-surface.js';
30
35
  import { handleDefaultVendorMessage } from './default-vendor.js';
31
36
  import { handleContextViewMessage } from './context-view-preference.js';
32
- import { handleHomeMateMemoryState, handleHomeMateKnowledgeState } from './home-mate-settings.js';
33
- import { renderKnowledgeList, handleKnowledgeContent } from './mate-knowledge.js';
37
+ import { handleHomeMateMemoryState, handleHomeMateKnowledgeState, syncHomeMateSettingsTarget, handleHomeMateAvatarError } from './home-mate-settings.js';
38
+ import { renderKnowledgeList, handleKnowledgeContent, handleKnowledgeMutation } from './mate-knowledge.js';
39
+ import { handleKnowledgeWorkbenchMessage } from './mate-knowledge-workbench.js';
34
40
  import { renderMemoryList } from './mate-memory.js';
35
41
  import { handlePaletteSessionSwitch, setPaletteVersion } from './command-palette.js';
36
42
  import { handleFindInSessionResults } from './session-search.js';
@@ -83,7 +89,6 @@ import { getModelInfoUpdate, modelEntryValue, modelEntryMatches, handleModelSele
83
89
  import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel, markContextUnavailable } from './app-panels.js';
84
90
  import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress, finishProjectSessionActivation } from './app-projects.js';
85
91
  import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
86
- import { hideHomeHub, showHomeHub } from './app-home-hub.js';
87
92
  import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest, handleToolServerState, handleToolServerEvent, handleCapsuleGameSession } from './home-tools.js';
88
93
  import { handleHomeDockState } from './home-dock.js';
89
94
  import { handleToolFrameUrlState } from './home-tool-frame.js';
@@ -110,6 +115,7 @@ var connectOverlay = document.getElementById("connect-overlay");
110
115
  initMessageDeliveryUi();
111
116
 
112
117
  export function processMessage(msg) {
118
+ if (handleProjectDebateMessage(msg)) return;
113
119
  if (handleMcpConnectionMessage(msg)) return;
114
120
  if (handleSharedBrowserMessage(msg)) return;
115
121
  if (msg.type === "vendor_login_browser_frame" || msg.type === "vendor_login_browser_status") {
@@ -120,6 +126,7 @@ export function processMessage(msg) {
120
126
  if (handleAutonomousRunMessage(msg)) return;
121
127
  if (handleLoopInterviewMessage(msg)) return;
122
128
  if (handleScheduledTaskMessage(msg)) return;
129
+ if (handleKnowledgeWorkbenchMessage(msg)) return;
123
130
  if (handleSessionCreateMessage(msg)) return;
124
131
  if (msg && msg.type === "new_session_result" && handleNewSessionResult(msg)) return;
125
132
  if (handleDefaultVendorMessage(msg)) return;
@@ -172,6 +179,7 @@ export function processMessage(msg) {
172
179
  return;
173
180
  }
174
181
  if (msg.type === "knowledge_saved" || msg.type === "knowledge_deleted" || msg.type === "knowledge_promoted" || msg.type === "knowledge_depromoted") {
182
+ handleKnowledgeMutation(msg);
175
183
  return;
176
184
  }
177
185
  if (msg.type === "memory_list") {
@@ -338,8 +346,7 @@ export function processMessage(msg) {
338
346
  store.set({ dmMode: false });
339
347
  }
340
348
  messagesEl.innerHTML = "";
341
- showHomeHub();
342
- openHomeChat(msg.mateId);
349
+ openMateWorkspace(msg.mateId);
343
350
  }
344
351
  // Clear the flag and notify server that mate DM is closed
345
352
  if (store.get('returningFromMateDm')) {
@@ -363,7 +370,12 @@ export function processMessage(msg) {
363
370
  clearProjectSplitState();
364
371
  }
365
372
  detachTuiView();
366
- store.set({ projectName: msg.project || msg.cwd, vendorInfo: msg.vendors || {} });
373
+ store.set({
374
+ projectName: msg.project || msg.cwd,
375
+ vendorInfo: msg.vendors || {},
376
+ activeProjectMateId: msg.isMate && msg.mateId ? msg.mateId : null,
377
+ activeProjectMateName: msg.isMate ? (msg.mateDisplayName || msg.project || "Mate") : "",
378
+ });
367
379
  if (msg.cwd) store.set({ cwd: msg.cwd });
368
380
  if (msg.slug) store.set({ currentSlug: msg.slug, activeProjectSlug: msg.slug, sessionListProjectSlug: null, splitGroupsProjectSlug: null });
369
381
  try { var _is = store.snap(); localStorage.setItem("clay-project-name-" + (_is.currentSlug || "default"), _is.projectName); } catch (e) {}
@@ -397,6 +409,7 @@ export function processMessage(msg) {
397
409
  var spBanner = document.getElementById("skip-perms-pill");
398
410
  if (spBanner) spBanner.classList.toggle("hidden", msg.dangerouslySkipPermissions !== true);
399
411
  updateProjectList(msg);
412
+ renderProjectMates();
400
413
  refreshProjectSessionVisibilitySettings(msg.projects);
401
414
  break;
402
415
 
@@ -877,7 +890,8 @@ export function processMessage(msg) {
877
890
  var _effectiveTerminalId = (typeof msg.runtimeTerminalId === "number")
878
891
  ? msg.runtimeTerminalId
879
892
  : (typeof msg.terminalId === "number" ? msg.terminalId : null);
880
- store.set({ activeSessionId: msg.id, sessionOriginId: msg.sessionOriginId || null, cliSessionId: msg.cliSessionId || null, currentModel: msg.model || "", currentEffort: msg.effort || store.get('currentEffort'), vendorCapabilities: msg.capabilities || {}, sessionIsProcessing: !!msg.isProcessing, activeSessionMode: _effectiveMode, activeTerminalId: _effectiveTerminalId, sessionHasHistory: !!msg.hasHistory, sessionVendorBound: !!msg.vendor || !!msg.hasHistory, sessionFullAccess: msg.permissionMode === "bypassPermissions", currentMode: msg.permissionMode || store.get('currentMode'), effectivePermissionMode: msg.effectivePermissionMode || null, permissionCapabilities: msg.permissionCapabilities || { auto: false, mcpOverride: false }, mcpPermissionModeOverrides: msg.mcpPermissionModeOverrides || {} });
893
+ var _sessionRole = msg.sessionRole === "worker" ? "worker" : "driver";
894
+ store.set({ activeSessionId: msg.id, sessionOriginId: msg.sessionOriginId || null, cliSessionId: msg.cliSessionId || null, currentModel: msg.model || "", currentEffort: msg.effort || store.get('currentEffort'), vendorCapabilities: msg.capabilities || {}, sessionIsProcessing: !!msg.isProcessing, activeSessionMode: _effectiveMode, activeTerminalId: _effectiveTerminalId, sessionHasHistory: !!msg.hasHistory, sessionVendorBound: !!msg.vendor || !!msg.hasHistory, sessionFullAccess: msg.permissionMode === "bypassPermissions", currentMode: msg.permissionMode || store.get('currentMode'), effectivePermissionMode: msg.effectivePermissionMode || null, permissionCapabilities: msg.permissionCapabilities || { auto: false, mcpOverride: false }, mcpPermissionModeOverrides: msg.mcpPermissionModeOverrides || {}, activeSessionMateId: _sessionRole === "worker" ? null : (store.get('activeProjectMateId') || null), activeSessionMateName: _sessionRole === "worker" ? "" : (store.get('activeProjectMateName') || "") });
881
895
  handleScheduledTaskSessionSwitched(msg);
882
896
  requestLoopInterviewState();
883
897
  activateDeliverySession(msg.id, msg.cliSessionId || null, msg.sessionOriginId || null);
@@ -958,7 +972,7 @@ export function processMessage(msg) {
958
972
  }
959
973
  // Reload survival: a restored active session that is a split-group
960
974
  // member reopens its group (no-op when a split is already open).
961
- if (finishProjectSessionActivation()) hideHomeHub();
975
+ finishProjectSessionActivation();
962
976
  maybeRestoreSplitGroup();
963
977
  break;
964
978
 
@@ -1745,6 +1759,13 @@ export function processMessage(msg) {
1745
1759
  handleNoteDeleteResult(msg);
1746
1760
  break;
1747
1761
 
1762
+ case "you_result":
1763
+ case "you_changed":
1764
+ case "you_reviewed":
1765
+ handleYouMessage(msg);
1766
+ handleYouActivity(msg);
1767
+ break;
1768
+
1748
1769
  case "project_logs_state":
1749
1770
  handleProjectLogsState(msg);
1750
1771
  break;
@@ -1930,6 +1951,8 @@ export function processMessage(msg) {
1930
1951
  }
1931
1952
  }
1932
1953
  store.set({ cachedMatesList: _cml });
1954
+ refreshProjectAssistantIdentities(messagesEl);
1955
+ syncHomeMateSettingsTarget(msg);
1933
1956
  // renderUserStrip is handled by the store subscriber
1934
1957
  // Update mate sidebar if currently viewing this mate
1935
1958
  if (store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate && store.get('dmTargetUser').id === msg.mate.id) {
@@ -1966,6 +1989,7 @@ export function processMessage(msg) {
1966
1989
 
1967
1990
  case "mate_list":
1968
1991
  store.set({ cachedMatesList: msg.mates || [], cachedAvailableBuiltins: msg.availableBuiltins || [] });
1992
+ refreshProjectAssistantIdentities(messagesEl);
1969
1993
  // renderUserStrip is handled by the store subscriber
1970
1994
  break;
1971
1995
 
@@ -1974,6 +1998,7 @@ export function processMessage(msg) {
1974
1998
  break;
1975
1999
 
1976
2000
  case "mate_error":
2001
+ handleHomeMateAvatarError(msg);
1977
2002
  showToast(msg.error || "Mate operation failed", "error");
1978
2003
  break;
1979
2004
 
@@ -7,8 +7,8 @@ import { refreshIcons, iconHtml } from './icons.js';
7
7
  import { escapeHtml } from './utils.js';
8
8
  import { store } from './store.js';
9
9
  import { getWs } from './ws-ref.js';
10
- import { showHomeHub } from './app-home-hub.js';
11
- import { openHomeChat } from './home-mate-chat.js';
10
+ import { openProjectSession } from './project-session-navigation.js';
11
+ import { openMateWorkspace } from './project-mate-navigation.js';
12
12
  import { getCachedProjects, switchProject, renderProjectList } from './app-projects.js';
13
13
  import { mateAvatarUrl, userAvatarUrl } from './avatar.js';
14
14
  import { openTuiModal } from './tui-attention.js';
@@ -618,11 +618,8 @@ function navigateToNotification(notif) {
618
618
 
619
619
  var mateId = notif.mateId || deriveMateIdFromNotification(notif);
620
620
  if (mateId) {
621
- if (notif.sessionId) {
622
- try { sessionStorage.setItem("pending-notif-session", notif.sessionId); } catch (e) {}
623
- }
624
- showHomeHub();
625
- openHomeChat(mateId);
621
+ if (notif.sessionId) openProjectSession(notif.slug || 'mate-' + mateId, notif.sessionId);
622
+ else openMateWorkspace(mateId);
626
623
  return;
627
624
  }
628
625
 
@@ -17,7 +17,6 @@ import { updateCrossProjectBlink, stopUrgentBlink, setActivity } from './app-fav
17
17
  import { spawnDustParticles } from './sidebar.js';
18
18
  import { isSearchOpen, closeSearch } from './session-search.js';
19
19
  import { exitDmMode } from './app-dm.js';
20
- import { isHomeHubVisible, hideHomeHub, showHomeHub } from './app-home-hub.js';
21
20
  import { resetFileBrowser } from './filebrowser.js';
22
21
  import { closeNotesBrowser } from './sticky-notes-browser.js';
23
22
  import { hideMemory } from './mate-memory.js';
@@ -40,6 +39,7 @@ import { chooseProjectAfterRemoval } from './project-removal-target.js';
40
39
  import { isProjectActivated, isProjectActivationPending, isProjectContextConnected, projectWsPath } from './project-activation.js';
41
40
  import { rememberHomePrimarySurface } from './home-surface.js';
42
41
  import { clearProjectSplitState } from './split-session-boundary.js';
42
+ import { isMateHeaderWorkspace, renderOrdinaryProjectHeader } from './project-header-identity.js';
43
43
 
44
44
  // --- Module-owned state ---
45
45
  var cachedProjects = [];
@@ -273,17 +273,6 @@ export function updateProjectList(msg) {
273
273
  myMessageAvatars[avatarIndex].src = document.body.dataset.myAvatarUrl;
274
274
  }
275
275
  }
276
- // Render my avatar (always present, hidden behind user-island)
277
- var meEl = document.getElementById("icon-strip-me");
278
- if (meEl && !meEl.hasChildNodes()) {
279
- var myUser = st2.cachedAllUsers.find(function (u) { return u.id === st2.myUserId; });
280
- if (myUser) {
281
- var meAvatar = document.createElement("img");
282
- meAvatar.className = "icon-strip-me-avatar";
283
- meAvatar.src = userAvatarUrl(myUser, 34);
284
- meEl.appendChild(meAvatar);
285
- }
286
- }
287
276
  }
288
277
  }
289
278
 
@@ -338,29 +327,8 @@ export function renderProjectList() {
338
327
  var iconStripActiveSlug = (st.mateProjectSlug && st.savedMainSlug) ? st.savedMainSlug : st.currentSlug;
339
328
  renderIconStrip(iconStripProjects, iconStripActiveSlug);
340
329
  // Update title bar project name and icon if it changed
341
- if (!st.mateProjectSlug) {
342
- for (var pi = 0; pi < cachedProjects.length; pi++) {
343
- if (cachedProjects[pi].slug === st.currentSlug) {
344
- var updatedName = cachedProjects[pi].title || cachedProjects[pi].project;
345
- var tbName = document.getElementById("title-bar-project-name");
346
- if (tbName && updatedName) tbName.textContent = updatedName;
347
- var tbIcon = document.getElementById("title-bar-project-icon");
348
- if (tbIcon) {
349
- var pIcon = cachedProjects[pi].icon || null;
350
- if (pIcon) {
351
- tbIcon.textContent = pIcon;
352
- parseEmojis(tbIcon);
353
- tbIcon.classList.add("has-icon");
354
- try { localStorage.setItem("clay-project-icon-" + (st.currentSlug || "default"), pIcon); } catch (e) {}
355
- } else {
356
- tbIcon.textContent = "";
357
- tbIcon.classList.remove("has-icon");
358
- try { localStorage.removeItem("clay-project-icon-" + (st.currentSlug || "default")); } catch (e) {}
359
- }
360
- }
361
- break;
362
- }
363
- }
330
+ if (!st.mateProjectSlug && !isMateHeaderWorkspace(st)) {
331
+ renderOrdinaryProjectHeader(Object.assign({}, st, { projectsHubList: cachedProjects }));
364
332
  }
365
333
  // Re-apply current socket status to the active icon's dot
366
334
  var dot = getStatusDot();
@@ -425,14 +393,13 @@ export function switchProject(slug) {
425
393
  var st = store.snap();
426
394
  var ws = getWs();
427
395
  var targetWsPath = projectWsPath(slug);
428
- var homeVisible = isHomeHubVisible() || store.get('projectsHubVisible');
396
+ var homeVisible = store.get('projectsHubVisible');
429
397
  var alreadyInProject = isProjectActivated(st, slug, ws);
430
398
  var wasDm = st.dmMode;
431
399
  var wasMate = st.dmMode && st.dmTargetUser && st.dmTargetUser.isMate;
432
400
  if (st.dmMode) exitDmMode(wasMate);
433
401
  if (homeVisible && alreadyInProject) {
434
402
  rememberHomePrimarySurface("project", slug);
435
- hideHomeHub();
436
403
  hideProjectsHub();
437
404
  completeProjectsOnboarding();
438
405
  if (document.documentElement.classList.contains("pwa-standalone")) {
@@ -496,7 +463,7 @@ export function confirmCurrentProjectSessionActivation() {
496
463
  export function finishProjectSessionActivation() {
497
464
  var confirmed = confirmCurrentProjectSessionActivation();
498
465
  if (!confirmed) return false;
499
- if (!store.get('pendingHomeProjectSlug')) return !isHomeHubVisible() && !store.get('projectsHubVisible');
466
+ if (!store.get('pendingHomeProjectSlug')) return !store.get('projectsHubVisible');
500
467
  return completePendingProjectActivation();
501
468
  }
502
469
 
@@ -8,7 +8,8 @@ import { refreshIcons } from './icons.js';
8
8
  import { closeToolGroup } from './tools.js';
9
9
  import { sendMessage, hasSendableContent } from './input.js';
10
10
  import { getChatLayout } from './theme.js';
11
- import { addToMessages, scrollToBottom, forceScrollToBottom, getMsgTime, shouldGroupMessage, getTurnCounter, getActivityEl, VENDOR_AVATARS, VENDOR_NAMES } from './chat-render-runtime.js';
11
+ import { addToMessages, scrollToBottom, forceScrollToBottom, getMsgTime, shouldGroupMessage, getTurnCounter, getActivityEl } from './chat-render-runtime.js';
12
+ import { resolveProjectAssistantIdentity, applyProjectAssistantIdentity } from './project-chat-identity.js';
12
13
  export { VENDOR_ORDER, EXPERIMENTAL_VENDORS, isExperimentalVendor } from './vendor-priority.js';
13
14
  export { initRendering, addToMessages, scrollToBottom, forceScrollToBottom, getMsgTime, shouldGroupMessage, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp, getStickyBottom, armStickyBottom, disarmStickyBottom, VENDOR_AVATARS, VENDOR_NAMES, VENDOR_HOMEPAGES } from './chat-render-runtime.js';
14
15
  export { addUserMessage, addSystemMessage, addConflictMessage, addContextOverflowMessage } from './app-message-cards.js';
@@ -22,15 +23,15 @@ var streamDrainTimer = null;
22
23
  export function ensureAssistantBlock() {
23
24
  var _el = store.get('currentMsgEl');
24
25
  if (!_el) {
25
- var _isDm2 = document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl;
26
26
  var vendor = store.get('currentVendor') || "claude";
27
- var dmTarget = store.get('dmTargetUser');
27
+ var identity = resolveProjectAssistantIdentity(store.snap(), vendor);
28
28
  _el = createAssistantBubble({
29
29
  turn: getTurnCounter(),
30
- avatarUrl: _isDm2 ? document.body.dataset.mateAvatarUrl : (VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude),
31
- name: _isDm2 ? ((dmTarget && dmTarget.displayName) || "Mate") : (VENDOR_NAMES[vendor] || VENDOR_NAMES.claude),
30
+ avatarUrl: identity.avatarUrl,
31
+ name: identity.name,
32
32
  time: getMsgTime(),
33
33
  });
34
+ applyProjectAssistantIdentity(_el, identity);
34
35
  if (shouldGroupMessage("msg-assistant")) _el.classList.add("grouped");
35
36
  addToMessages(_el);
36
37
  store.set({ currentMsgEl: _el, currentFullText: "" });
@@ -119,20 +120,17 @@ export function showClaudePreThinking() {
119
120
  if (getChatLayout() !== "channel") return;
120
121
  removeMatePreThinking();
121
122
  var vendor = store.get('currentVendor') || "claude";
122
- var vendorAvatar = VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude;
123
- var vendorName = VENDOR_NAMES[vendor] || VENDOR_NAMES.claude;
124
- doShowMatePreThinking(vendorName, vendorAvatar);
123
+ var identity = resolveProjectAssistantIdentity(store.snap(), vendor);
124
+ doShowMatePreThinking(identity.name, identity.avatarUrl, identity);
125
125
  }
126
126
 
127
127
  export function showMatePreThinking() {
128
128
  removeMatePreThinking();
129
- var dmTarget = store.get('dmTargetUser');
130
- var mateName = dmTarget ? (dmTarget.displayName || "Mate") : "Mate";
131
- var mateAvatar = document.body.dataset.mateAvatarUrl || "";
132
- doShowMatePreThinking(mateName, mateAvatar);
129
+ var identity = resolveProjectAssistantIdentity(store.snap(), store.get('currentVendor'));
130
+ doShowMatePreThinking(identity.name, identity.avatarUrl, identity);
133
131
  }
134
132
 
135
- function doShowMatePreThinking(mateName, mateAvatar) {
133
+ function doShowMatePreThinking(mateName, mateAvatar, identity) {
136
134
  var _el = document.createElement("div");
137
135
  _el.className = "thinking-item mate-thinking mate-pre-thinking";
138
136
  _el.innerHTML =
@@ -141,6 +139,7 @@ function doShowMatePreThinking(mateName, mateAvatar) {
141
139
  '<div class="dm-bubble-header"><span class="dm-bubble-name">' + escapeHtml(mateName) + '</span></div>' +
142
140
  '<div class="mate-thinking-dots"><span></span><span></span><span></span></div>' +
143
141
  '</div>';
142
+ applyProjectAssistantIdentity(_el, identity);
144
143
  store.set({ matePreThinkingEl: _el });
145
144
  var activity = getActivityEl();
146
145
  if (activity && activity.parentNode) {
@@ -1,18 +1,30 @@
1
1
  // Centralized local avatar URL builder for people and Mates.
2
2
  import { imprintDataUrl, mateMarkDataUrl } from './avatar-imprint.js';
3
3
 
4
- var imprintCache = new Map();
5
4
  var mateMarkCache = new Map();
6
5
 
7
- // Legacy style remains part of the identity hash so existing selections map
8
- // deterministically into the local pixel identity system.
6
+ // Historical DiceBear 9.x choices, now generated by Clay's local server.
7
+ export var MATE_AVATAR_STYLES = [
8
+ { id: 'thumbs', name: 'Thumbs' },
9
+ { id: 'bottts', name: 'Bots' },
10
+ { id: 'pixel-art', name: 'Pixel' },
11
+ { id: 'adventurer', name: 'Adventurer' },
12
+ { id: 'micah', name: 'Micah' },
13
+ { id: 'fun-emoji', name: 'Emoji' },
14
+ { id: 'icons', name: 'Icons' },
15
+ ];
16
+
9
17
  export function avatarUrl(style, seed, size) {
10
- var cacheKey = [style || 'imprint', seed || 'anonymous', size || 64].join('|');
11
- if (imprintCache.has(cacheKey)) return imprintCache.get(cacheKey);
12
- var url = imprintDataUrl({ style: style || 'imprint', seed: seed || 'anonymous', size: size || 64 });
13
- if (imprintCache.size >= 512) imprintCache.delete(imprintCache.keys().next().value);
14
- imprintCache.set(cacheKey, url);
15
- return url;
18
+ var normalizedStyle = style || 'imprint';
19
+ var normalizedSeed = seed || 'anonymous';
20
+ var normalizedSize = size || 64;
21
+ var isHistorical = MATE_AVATAR_STYLES.some(function (entry) { return entry.id === normalizedStyle; });
22
+ if (isHistorical) {
23
+ return '/api/generated-avatar?style=' + encodeURIComponent(normalizedStyle)
24
+ + '&seed=' + encodeURIComponent(normalizedSeed)
25
+ + '&size=' + encodeURIComponent(normalizedSize);
26
+ }
27
+ return imprintDataUrl({ style: normalizedStyle, seed: normalizedSeed, size: normalizedSize });
16
28
  }
17
29
 
18
30
  // Use the same bounded account identity for fresh fallbacks across every surface.
@@ -46,5 +58,9 @@ export function mateAvatarUrl(mate, size) {
46
58
  var p = mate.profile || mate;
47
59
  if (p.avatarCustom || mate.avatarCustom) return p.avatarCustom || mate.avatarCustom;
48
60
  var identity = p.displayName || mate.name || mate.displayName || 'Mate';
61
+ var style = p.avatarStyle || mate.avatarStyle || 'imprint';
62
+ if (style !== 'imprint' && style !== 'initial') {
63
+ return avatarUrl(style, p.avatarSeed || mate.avatarSeed || mate.id || identity, size);
64
+ }
49
65
  return mateMarkUrl(identity, size);
50
66
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { store } from './store.js';
4
4
  import { getMessagesEl } from './dom-refs.js';
5
+ import { getProjectAssistantPlaceholder } from './project-chat-identity.js';
5
6
 
6
7
  export var VENDOR_AVATARS = {
7
8
  claude: "/claude-code-avatar.png",
@@ -124,11 +125,22 @@ export function disarmStickyBottom() {
124
125
  }
125
126
 
126
127
  export function initRendering() {
128
+ var lastAssistantPlaceholder = '';
129
+ function updateInputPlaceholder(state) {
130
+ var inputEl = document.getElementById("input");
131
+ if (!inputEl) return;
132
+ var nextPlaceholder = getProjectAssistantPlaceholder(state, state.currentVendor);
133
+ var ownsPlaceholder = !lastAssistantPlaceholder || inputEl.placeholder === lastAssistantPlaceholder;
134
+ lastAssistantPlaceholder = nextPlaceholder;
135
+ if (inputEl.disabled || document.getElementById("input-mention-chip") || !ownsPlaceholder) return;
136
+ inputEl.placeholder = nextPlaceholder;
137
+ }
138
+ updateInputPlaceholder(store.snap());
127
139
  store.subscribe(function (state, prev) {
128
- if (state.currentVendor !== prev.currentVendor) {
129
- var inputEl = document.getElementById("input");
130
- if (inputEl) inputEl.placeholder = "Message " + (VENDOR_NAMES[state.currentVendor] || VENDOR_NAMES.claude) + "...";
131
- }
140
+ if (state.currentVendor !== prev.currentVendor || state.activeSessionMateId !== prev.activeSessionMateId ||
141
+ state.activeSessionMateName !== prev.activeSessionMateName || state.activeProjectMateId !== prev.activeProjectMateId ||
142
+ state.activeProjectMateName !== prev.activeProjectMateName || state.cachedMatesList !== prev.cachedMatesList ||
143
+ state.dmMode !== prev.dmMode || state.dmTargetUser !== prev.dmTargetUser) updateInputPlaceholder(state);
132
144
  });
133
145
  }
134
146
 
@@ -2,8 +2,6 @@ import { mateAvatarUrl } from './avatar.js';
2
2
  import { escapeHtml } from './utils.js';
3
3
  import { refreshIcons } from './icons.js';
4
4
  import { openSearch as openSessionSearch } from './session-search.js';
5
- import { showHomeHub, minimizeHomeHub } from './app-home-hub.js';
6
- import { openHomeConversation } from './home-mate-chat.js';
7
5
  import { startSearchClayChat, attachSearchClayChat, detachSearchClayChat, getSearchClayChatSummary } from './search-clay-chat.js';
8
6
  import { getWs } from './ws-ref.js';
9
7
  import { openProjectLog } from './project-logs.js';
@@ -110,13 +108,7 @@ export function handleClaySessionTarget(msg) {
110
108
  navigateToLog(msg.target);
111
109
  return true;
112
110
  }
113
- if (msg.target.isMate && msg.target.mateId && msg.target.homeSessionId) {
114
- showHomeHub();
115
- openHomeConversation(msg.target.mateId, msg.target.homeSessionId);
116
- } else {
117
- minimizeHomeHub();
118
- navigateToSession({ projectSlug: msg.target.projectSlug, sessionId: msg.target.sessionId }, null);
119
- }
111
+ navigateToSession({ projectSlug: msg.target.projectSlug, sessionId: msg.target.sessionId }, null);
120
112
  return true;
121
113
  }
122
114
 
@@ -166,7 +158,6 @@ export function handlePaletteSessionSwitch() {
166
158
 
167
159
  function navigateToLog(target) {
168
160
  closeCommandPalette();
169
- minimizeHomeHub();
170
161
  if (ctx.currentSlug && ctx.currentSlug() === target.projectSlug) {
171
162
  openProjectLog(target.ref);
172
163
  } else {
@@ -363,11 +354,7 @@ function resumeClayChat() {
363
354
  function activateItem(entry) {
364
355
  if (entry.type === "resume-clay") { resumeClayChat(); return; }
365
356
  if (entry.type === "ask-clay") { beginClayChat(entry.query); return; }
366
- if (entry.type === "mate-session") {
367
- closeCommandPalette();
368
- showHomeHub();
369
- openHomeConversation(entry.data.mateId, entry.data.sessionId);
370
- } else if (entry.type === "session") navigateToSession(entry.data, entry.query);
357
+ if (entry.type === "mate-session" || entry.type === "session") navigateToSession(entry.data, entry.query);
371
358
  }
372
359
 
373
360
  function navigateToSession(item, query) {
@@ -15,18 +15,18 @@ export function handleCursorSharingMessage(msg) {
15
15
  }
16
16
  if (msg.ready !== true || msg.accountAvailable === false || typeof msg.cursorSharing !== "boolean") {
17
17
  if (store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled")) clearPresence();
18
- store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null });
18
+ store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null, cursorSharingPending: null, cursorSharingError: msg.error || "unavailable" });
19
19
  showToast(msg.error || "Cursor sharing is unavailable.", "warn");
20
20
  return true;
21
21
  }
22
22
  var knownUserId = store.get("myUserId");
23
23
  if (knownUserId && msg.accountId && knownUserId !== msg.accountId) {
24
24
  if (store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled")) clearPresence();
25
- store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null });
25
+ store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null, cursorSharingPending: null, cursorSharingError: "account-changed" });
26
26
  return true;
27
27
  }
28
28
  var wasEnabled = store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled");
29
- store.set({ cursorSharingEnabled: msg.cursorSharing, cursorSharingHydrated: true, cursorSharingAccountId: msg.accountId || null });
29
+ store.set({ cursorSharingEnabled: msg.cursorSharing, cursorSharingHydrated: true, cursorSharingAccountId: msg.accountId || null, cursorSharingPending: null, cursorSharingError: null });
30
30
  if (wasEnabled && !msg.cursorSharing) {
31
31
  var ws = getWs();
32
32
  if (ws && ws.readyState === 1) {