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
@@ -1,16 +1,17 @@
1
- import { avatarUrl, userAvatarUrl, mateAvatarUrl } from './avatar.js';
1
+ 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
+ import { startSearchClayChat, attachSearchClayChat, detachSearchClayChat, getSearchClayChatSummary } from './search-clay-chat.js';
8
+ import { getWs } from './ws-ref.js';
5
9
 
6
10
  function formatRelativeDate(ts) {
7
11
  if (!ts) return "";
8
- var now = Date.now();
9
- var diff = now - ts;
10
- if (diff < 0) diff = 0;
11
- var sec = Math.floor(diff / 1000);
12
- if (sec < 60) return "just now";
13
- var min = Math.floor(sec / 60);
12
+ var diff = Math.max(0, Date.now() - ts);
13
+ var min = Math.floor(diff / 60000);
14
+ if (min < 1) return "just now";
14
15
  if (min < 60) return min + "m ago";
15
16
  var hr = Math.floor(min / 60);
16
17
  if (hr < 24) return hr + "h ago";
@@ -23,88 +24,109 @@ function formatRelativeDate(ts) {
23
24
  }
24
25
 
25
26
  var ctx;
26
- var paletteEl = null;
27
- var inputEl = null;
28
- var resultsEl = null;
29
- var footerEl = null;
30
- var activeIndex = -1;
31
- var items = [];
32
- var debounceTimer = null;
33
- var abortCtrl = null;
34
- var pendingNav = null;
35
- var cachedHomeData = null;
36
- var cachedVersion = null;
27
+ var paletteEl = null, inputEl = null, resultsEl = null, footerEl = null;
28
+ var activeIndex = -1, items = [], debounceTimer = null, abortCtrl = null;
29
+ var pendingNav = null, cachedHomeData = [], cachedVersion = null;
30
+ var searchResults = [], searchQuery = "", searchPending = false, chatMode = false;
37
31
 
38
- // --- Commands registry ---
39
- var commands = [
40
- { id: "create-mate", label: "Create Mate", desc: "Create a new AI teammate", icon: "user-plus", action: "createMate" },
41
- { id: "settings", label: "Server settings", desc: "Configure server", icon: "settings", action: "openSettings" },
42
- ];
43
-
44
- export function initCommandPalette(_ctx) {
45
- ctx = _ctx;
32
+ export function initCommandPalette(value) {
33
+ ctx = value;
46
34
  buildDOM();
47
- // Top bar search bar trigger
48
- var hintBtn = document.getElementById("cmd-palette-btn");
49
- if (hintBtn) {
35
+ // The palette dialog stops bubbling so backdrop clicks cannot close it.
36
+ // Capture session controls before that boundary; the same handler also
37
+ // serves links rendered in the full Home transcript.
38
+ document.addEventListener("click", handleClaySessionLinkClick, true);
39
+ var trigger = document.getElementById("cmd-palette-btn");
40
+ if (trigger) {
50
41
  var isMac = navigator.platform.indexOf("Mac") !== -1;
51
- var kbdEl = hintBtn.querySelector(".cmd-palette-searchbar-kbd");
52
- if (kbdEl) kbdEl.textContent = isMac ? "\u2318K" : "Ctrl+K";
53
- hintBtn.addEventListener("click", function () {
54
- if (isCommandPaletteOpen()) {
55
- closeCommandPalette();
56
- } else {
57
- openCommandPalette();
58
- }
59
- });
42
+ var kbd = trigger.querySelector(".cmd-palette-searchbar-kbd");
43
+ if (kbd) kbd.textContent = isMac ? "\u2318K" : "Ctrl+K";
44
+ trigger.addEventListener("click", function () { if (isCommandPaletteOpen()) closeCommandPalette(); else openCommandPalette(); });
60
45
  }
61
46
  document.addEventListener("keydown", function (e) {
62
47
  if ((e.metaKey || e.ctrlKey) && e.key === "k") {
63
48
  e.preventDefault();
64
- if (isCommandPaletteOpen()) {
65
- closeCommandPalette();
66
- } else {
67
- openCommandPalette();
68
- }
49
+ if (isCommandPaletteOpen()) closeCommandPalette(); else openCommandPalette();
69
50
  }
70
51
  });
71
52
  }
72
53
 
73
- export function isCommandPaletteOpen() {
74
- return paletteEl && !paletteEl.classList.contains("hidden");
54
+ function handleClaySessionLinkClick(event) {
55
+ var link = event.target.closest(".clayos-session-link");
56
+ if (!link || link.classList.contains("is-loading")) return;
57
+ var ws = getWs();
58
+ if (!ws || ws.readyState !== 1) {
59
+ link.classList.add("is-error");
60
+ link.title = "Reconnect to open this session";
61
+ return;
62
+ }
63
+ var requestId = "clayos-session-" + Date.now() + "-" + Math.random().toString(36).slice(2, 9);
64
+ link.dataset.sessionRequest = requestId;
65
+ link.classList.remove("is-error");
66
+ link.classList.add("is-loading");
67
+ ws.send(JSON.stringify({
68
+ type: "home_clay_session_resolve",
69
+ requestId: requestId,
70
+ sessionRef: link.dataset.sessionRef,
71
+ surface: link.closest(".search-clay-chat") ? "search" : "home",
72
+ }));
75
73
  }
76
74
 
75
+ export function handleClaySessionTarget(msg) {
76
+ if (!msg || msg.type !== "home_clay_session_target") return false;
77
+ var links = document.querySelectorAll(".clayos-session-link[data-session-request]");
78
+ var link = null;
79
+ for (var i = 0; i < links.length; i++) if (links[i].dataset.sessionRequest === msg.requestId) link = links[i];
80
+ if (link) {
81
+ link.classList.remove("is-loading");
82
+ delete link.dataset.sessionRequest;
83
+ }
84
+ if (msg.status !== "ready" || !msg.target) {
85
+ if (link) {
86
+ link.classList.add("is-error");
87
+ link.title = msg.error || "Session not available";
88
+ }
89
+ return true;
90
+ }
91
+ closeCommandPalette();
92
+ if (msg.target.isMate && msg.target.mateId && msg.target.homeSessionId) {
93
+ showHomeHub();
94
+ openHomeConversation(msg.target.mateId, msg.target.homeSessionId);
95
+ } else {
96
+ minimizeHomeHub();
97
+ navigateToSession({ projectSlug: msg.target.projectSlug, sessionId: msg.target.sessionId }, null);
98
+ }
99
+ return true;
100
+ }
101
+
102
+ export function isCommandPaletteOpen() { return paletteEl && !paletteEl.classList.contains("hidden"); }
103
+
77
104
  export function openCommandPalette() {
78
105
  if (!paletteEl) return;
79
106
  paletteEl.classList.remove("hidden");
80
- var searchbar = document.getElementById("cmd-palette-btn");
81
- if (searchbar) searchbar.style.visibility = "hidden";
82
- inputEl.value = "";
83
- inputEl.placeholder = "Type a command or search...";
84
- activeIndex = -1;
85
- items = [];
86
- resultsEl.innerHTML = '<div class="cmd-palette-loading">Loading...</div>';
107
+ var trigger = document.getElementById("cmd-palette-btn");
108
+ if (trigger) trigger.style.visibility = "hidden";
87
109
  updateFooter();
88
- inputEl.focus();
110
+ if (attachSearchClayChat(resultsEl, showSearch, closeCommandPalette)) {
111
+ chatMode = true;
112
+ paletteEl.classList.add("is-chatting");
113
+ return;
114
+ }
115
+ showSearch();
89
116
  fetchHomeData();
90
117
  }
91
118
 
92
119
  export function closeCommandPalette() {
93
120
  if (!paletteEl) return;
94
121
  paletteEl.classList.add("hidden");
95
- var searchbar = document.getElementById("cmd-palette-btn");
96
- if (searchbar) searchbar.style.visibility = "";
97
- inputEl.value = "";
98
- resultsEl.innerHTML = "";
99
- items = [];
100
- activeIndex = -1;
122
+ var trigger = document.getElementById("cmd-palette-btn");
123
+ if (trigger) trigger.style.visibility = "";
101
124
  if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }
102
125
  if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
126
+ detachSearchClayChat();
103
127
  }
104
128
 
105
- export function setPaletteVersion(version) {
106
- cachedVersion = version;
107
- }
129
+ export function setPaletteVersion(version) { cachedVersion = version; }
108
130
 
109
131
  export function handlePaletteSessionSwitch() {
110
132
  if (!pendingNav) return;
@@ -112,9 +134,7 @@ export function handlePaletteSessionSwitch() {
112
134
  pendingNav = null;
113
135
  if (ctx.currentSlug && ctx.currentSlug() === nav.slug) {
114
136
  ctx.selectSession(nav.sessionId);
115
- if (nav.query) {
116
- setTimeout(function () { openSessionSearch(nav.query); }, 400);
117
- }
137
+ if (nav.query) setTimeout(function () { openSessionSearch(nav.query); }, 400);
118
138
  }
119
139
  }
120
140
 
@@ -123,434 +143,203 @@ function buildDOM() {
123
143
  paletteEl.className = "cmd-palette hidden";
124
144
  paletteEl.innerHTML =
125
145
  '<div class="cmd-palette-backdrop"></div>' +
126
- '<div class="cmd-palette-dialog">' +
146
+ '<div class="cmd-palette-dialog" role="dialog" aria-label="Search or ask Clay">' +
127
147
  '<div class="cmd-palette-input-row">' +
128
- '<i data-lucide="search"></i>' +
129
- '<input class="cmd-palette-input" type="text" placeholder="Type a command or search..." autocomplete="off" spellcheck="false" />' +
130
- '<span class="cmd-palette-kbd" id="cmd-palette-close"><i data-lucide="x"></i></span>' +
148
+ '<img class="cmd-palette-input-brand" src="/clay-studio-symbol.png" width="22" height="22" alt="">' +
149
+ '<i data-lucide="search" aria-hidden="true"></i>' +
150
+ '<input class="cmd-palette-input" type="text" placeholder="Search conversations, or ask Clay…" autocomplete="off" spellcheck="false" />' +
151
+ '<button type="button" class="cmd-palette-kbd" id="cmd-palette-close" aria-label="Close search"><i data-lucide="x"></i></button>' +
131
152
  '</div>' +
132
153
  '<div class="cmd-palette-results"></div>' +
133
154
  '<div class="cmd-palette-footer"></div>' +
134
155
  '</div>';
135
-
136
156
  document.body.appendChild(paletteEl);
137
157
  refreshIcons();
138
-
139
158
  inputEl = paletteEl.querySelector(".cmd-palette-input");
140
159
  resultsEl = paletteEl.querySelector(".cmd-palette-results");
141
160
  footerEl = paletteEl.querySelector(".cmd-palette-footer");
142
-
143
- paletteEl.querySelector(".cmd-palette-backdrop").addEventListener("click", function () {
144
- closeCommandPalette();
145
- });
146
-
147
- paletteEl.querySelector("#cmd-palette-close").addEventListener("click", function () {
148
- closeCommandPalette();
149
- });
150
-
161
+ paletteEl.querySelector(".cmd-palette-backdrop").addEventListener("click", closeCommandPalette);
162
+ paletteEl.querySelector("#cmd-palette-close").addEventListener("click", closeCommandPalette);
151
163
  inputEl.addEventListener("input", function () {
152
- var q = inputEl.value;
164
+ var query = inputEl.value.trim();
165
+ searchQuery = query;
166
+ searchResults = [];
167
+ searchPending = !!query;
168
+ renderSearch();
153
169
  if (debounceTimer) clearTimeout(debounceTimer);
154
- renderHome(q.trim());
155
- if (q.trim()) {
156
- debounceTimer = setTimeout(function () {
157
- fetchHomeSearchResults(q.trim());
158
- }, 300);
159
- }
170
+ if (query) debounceTimer = setTimeout(function () { fetchHomeSearchResults(query); }, 250);
160
171
  });
161
-
162
- inputEl.addEventListener("keydown", function (e) {
163
- if (e.key === "Escape") {
164
- e.preventDefault();
165
- closeCommandPalette();
166
- return;
167
- }
168
- if (e.key === "ArrowDown") {
169
- e.preventDefault();
170
- setActive(activeIndex + 1);
171
- return;
172
- }
173
- if (e.key === "ArrowUp") {
174
- e.preventDefault();
175
- setActive(activeIndex - 1);
176
- return;
177
- }
178
- if (e.key === "Enter") {
179
- e.preventDefault();
180
- if (activeIndex >= 0 && activeIndex < items.length) {
181
- activateItem(items[activeIndex]);
182
- }
183
- return;
172
+ inputEl.addEventListener("keydown", function (event) {
173
+ if (event.key === "Escape") { event.preventDefault(); closeCommandPalette(); return; }
174
+ if (event.key === "ArrowDown") { event.preventDefault(); setActive(activeIndex + 1); return; }
175
+ if (event.key === "ArrowUp") { event.preventDefault(); setActive(activeIndex - 1); return; }
176
+ if (event.key === "Enter") {
177
+ event.preventDefault();
178
+ if (activeIndex >= 0 && activeIndex < items.length) activateItem(items[activeIndex]);
179
+ else if (inputEl.value.trim()) beginClayChat(inputEl.value.trim());
184
180
  }
185
181
  });
182
+ paletteEl.querySelector(".cmd-palette-dialog").addEventListener("click", function (event) { event.stopPropagation(); });
183
+ }
186
184
 
187
- paletteEl.querySelector(".cmd-palette-dialog").addEventListener("click", function (e) {
188
- e.stopPropagation();
189
- });
185
+ function showSearch() {
186
+ chatMode = false;
187
+ paletteEl.classList.remove("is-chatting");
188
+ inputEl.value = searchQuery;
189
+ inputEl.disabled = false;
190
+ inputEl.focus({ preventScroll: true });
191
+ renderSearch();
190
192
  }
191
193
 
192
194
  function updateFooter() {
193
- var shortcuts =
194
- '<span><kbd>&uarr;</kbd> <kbd>&darr;</kbd> navigate</span>' +
195
- '<span><kbd>Enter</kbd> select</span>';
196
- var versionText = cachedVersion ? "v" + cachedVersion : "";
197
- footerEl.innerHTML =
198
- '<a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="cmd-palette-brand"><img src="clay-studio-symbol.png" width="13" height="13" alt="">Clay Studio ' + versionText + '</a>' +
199
- '<span class="cmd-palette-footer-shortcuts">' + shortcuts + '</span>';
195
+ var version = cachedVersion ? " v" + cachedVersion : "";
196
+ footerEl.innerHTML = '<a href="https://github.com/chadbyte/clay" target="_blank" rel="noopener" class="cmd-palette-brand">Clay Studio' + version + '</a><span class="cmd-palette-footer-shortcuts"><span><kbd>&uarr;</kbd> <kbd>&darr;</kbd> navigate</span><span><kbd>Enter</kbd> open or ask</span></span>';
200
197
  }
201
198
 
202
- // ==========================================
203
- // HOME MODE: commands + recent sessions + projects
204
- // ==========================================
205
-
206
199
  function fetchHomeData() {
207
- if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
200
+ if (cachedHomeData.length) { renderSearch(); return; }
201
+ if (abortCtrl) abortCtrl.abort();
208
202
  abortCtrl = new AbortController();
209
- fetch("/api/palette/search", { signal: abortCtrl.signal })
210
- .then(function (res) { return res.json(); })
211
- .then(function (data) {
212
- abortCtrl = null;
213
- cachedHomeData = data.results || [];
214
- renderHome("");
215
- })
216
- .catch(function (err) {
217
- if (err.name === "AbortError") return;
218
- abortCtrl = null;
219
- cachedHomeData = [];
220
- renderHome("");
221
- });
203
+ fetch("/api/palette/search", { signal: abortCtrl.signal }).then(function (res) { return res.json(); }).then(function (data) {
204
+ abortCtrl = null;
205
+ cachedHomeData = data.results || [];
206
+ renderSearch();
207
+ }).catch(function (error) {
208
+ if (error.name === "AbortError") return;
209
+ abortCtrl = null;
210
+ cachedHomeData = [];
211
+ renderSearch();
212
+ });
222
213
  }
223
214
 
224
- function findMateById(mateId) {
225
- if (!mateId || !ctx.matesList) return null;
226
- var mates = ctx.matesList();
227
- for (var i = 0; i < mates.length; i++) {
228
- if (mates[i].id === mateId) return mates[i];
229
- }
230
- return null;
215
+ function fetchHomeSearchResults(query) {
216
+ if (abortCtrl) abortCtrl.abort();
217
+ abortCtrl = new AbortController();
218
+ fetch("/api/palette/search?q=" + encodeURIComponent(query), { signal: abortCtrl.signal }).then(function (res) { return res.json(); }).then(function (data) {
219
+ abortCtrl = null;
220
+ if (searchQuery !== query) return;
221
+ searchResults = data.results || [];
222
+ searchPending = false;
223
+ renderSearch();
224
+ }).catch(function (error) {
225
+ if (error.name === "AbortError") return;
226
+ abortCtrl = null;
227
+ if (searchQuery !== query) return;
228
+ searchPending = false;
229
+ renderSearch();
230
+ });
231
231
  }
232
232
 
233
- function renderHome(filter) {
234
- var f = (filter || "").toLowerCase();
235
- items = [];
236
- var html = "";
237
- var flatIndex = 0;
238
-
239
- // --- Commands ---
240
- var filteredCmds = commands.filter(function (c) {
241
- if (!f) return true;
242
- return c.label.toLowerCase().indexOf(f) !== -1 || c.desc.toLowerCase().indexOf(f) !== -1;
243
- });
244
- if (filteredCmds.length > 0) {
245
- html += '<div class="cmd-palette-group-label">Commands</div>';
246
- for (var i = 0; i < filteredCmds.length; i++) {
247
- var cmd = filteredCmds[i];
248
- items.push({ type: "command", data: cmd });
249
- html += renderItem(flatIndex, '<i data-lucide="' + cmd.icon + '"></i>', cmd.label, cmd.desc, null);
250
- flatIndex++;
251
- }
252
- }
233
+ function findMate(mateId) {
234
+ var mates = ctx.matesList ? ctx.matesList() : [];
235
+ for (var i = 0; i < mates.length; i++) if (mates[i] && mates[i].id === mateId) return mates[i];
236
+ return null;
237
+ }
253
238
 
254
- // --- Recent sessions ---
255
- var recentSessions = (cachedHomeData || []);
256
- if (f) {
257
- recentSessions = recentSessions.filter(function (s) {
258
- return (s.sessionTitle || "").toLowerCase().indexOf(f) !== -1 ||
259
- (s.projectTitle || "").toLowerCase().indexOf(f) !== -1;
260
- });
261
- }
262
- var maxRecent = f ? 10 : 5;
263
- if (recentSessions.length > maxRecent) recentSessions = recentSessions.slice(0, maxRecent);
264
- if (recentSessions.length > 0) {
265
- html += '<div class="cmd-palette-group-label">Recent</div>';
266
- for (var r = 0; r < recentSessions.length; r++) {
267
- var s = recentSessions[r];
268
- items.push({ type: s.isMate ? "mate-session" : "session", data: s });
269
- var iconHtml;
270
- if (s.isMate) {
271
- var mate = findMateById(s.mateId);
272
- if (mate) {
273
- var avUrl = mateAvatarUrl(mate, 28);
274
- iconHtml = '<img src="' + avUrl + '" width="28" height="28" style="border-radius:50%;" alt="">';
275
- } else {
276
- iconHtml = '<i data-lucide="bot"></i>';
277
- }
278
- } else {
279
- iconHtml = s.projectIcon || '<i data-lucide="message-square"></i>';
280
- }
281
- var projLabel = (s.projectIcon || "") + " " + escapeHtml(s.projectTitle || s.projectSlug);
282
- html += renderItem(flatIndex, iconHtml, escapeHtml(s.sessionTitle || "New Session"), projLabel.trim(), null, s.lastActivity);
283
- flatIndex++;
284
- }
285
- }
239
+ function sessionKey(session) { return (session.projectSlug || "") + ":" + (session.sessionId || ""); }
286
240
 
287
- // --- Users (DM) ---
288
- var allUsers = ctx.allUsers ? ctx.allUsers() : [];
289
- var dmConversations = ctx.dmConversations ? ctx.dmConversations() : [];
290
- var myId = ctx.myUserId ? ctx.myUserId() : null;
291
- // Show recent DM conversations first, then filter all users when searching
292
- var userList = [];
293
- if (f) {
294
- userList = allUsers.filter(function (u) {
295
- if (u.id === myId) return false;
296
- var name = (u.displayName || u.username || "").toLowerCase();
297
- return name.indexOf(f) !== -1;
298
- });
299
- } else {
300
- // Recent conversations only
301
- for (var di = 0; di < dmConversations.length && di < 5; di++) {
302
- var dmUserId = dmConversations[di];
303
- for (var ai = 0; ai < allUsers.length; ai++) {
304
- if (allUsers[ai].id === dmUserId && dmUserId !== myId) {
305
- userList.push(allUsers[ai]);
306
- break;
307
- }
308
- }
309
- }
310
- }
311
- if (userList.length > 0) {
312
- html += '<div class="cmd-palette-group-label">' + (f ? "Users" : "Recent conversations") + '</div>';
313
- for (var ui = 0; ui < userList.length; ui++) {
314
- var user = userList[ui];
315
- items.push({ type: "user", data: user });
316
- var userName = escapeHtml(user.displayName || user.username);
317
- var userSub = user.username ? "@" + escapeHtml(user.username) : "";
318
- var uAvatarUrl = userAvatarUrl(user, 28);
319
- var uAvatarHtml = '<img src="' + uAvatarUrl + '" width="28" height="28" style="border-radius:50%;" alt="">';
320
- html += renderItem(flatIndex, uAvatarHtml, userName, userSub, null);
321
- flatIndex++;
322
- }
241
+ function sessionIcon(session) {
242
+ if (session.isMate) {
243
+ var mate = findMate(session.mateId);
244
+ if (mate) return '<img src="' + mateAvatarUrl(mate, 28) + '" width="28" height="28" alt="">';
245
+ return '<i data-lucide="bot"></i>';
323
246
  }
247
+ return session.projectIcon || '<i data-lucide="message-square"></i>';
248
+ }
324
249
 
325
- // --- Mates ---
326
- var matesList = ctx.matesList ? ctx.matesList() : [];
327
- var filteredMates = matesList.filter(function (m) {
328
- if (!f) return true;
329
- var mp = m.profile || {};
330
- var name = (mp.displayName || m.name || "").toLowerCase();
331
- return name.indexOf(f) !== -1;
332
- });
333
- if (filteredMates.length > 0) {
334
- html += '<div class="cmd-palette-group-label">Mates</div>';
335
- for (var mi = 0; mi < filteredMates.length; mi++) {
336
- var mate = filteredMates[mi];
337
- var mp = mate.profile || {};
338
- items.push({ type: "mate", data: mate });
339
- var mateName = escapeHtml(mp.displayName || mate.name || "Mate");
340
- var mateAvUrl = mateAvatarUrl(mate, 28);
341
- var avatarHtml = '<img src="' + mateAvUrl + '" width="28" height="28" style="border-radius:50%;" alt="">';
342
- html += renderItem(flatIndex, avatarHtml, mateName, null, null);
343
- flatIndex++;
344
- }
250
+ function renderSearch() {
251
+ if (chatMode) return;
252
+ var query = searchQuery.toLowerCase();
253
+ var sessions = query ? cachedHomeData.filter(function (item) {
254
+ return (item.sessionTitle || "").toLowerCase().indexOf(query) !== -1 || (item.projectTitle || "").toLowerCase().indexOf(query) !== -1;
255
+ }) : cachedHomeData.slice(0, 5);
256
+ var seen = {};
257
+ for (var i = 0; i < sessions.length; i++) seen[sessionKey(sessions[i])] = true;
258
+ for (var r = 0; r < searchResults.length; r++) if (!seen[sessionKey(searchResults[r])]) { sessions.push(searchResults[r]); seen[sessionKey(searchResults[r])] = true; }
259
+ items = [];
260
+ var html = "", index = 0;
261
+ var clayChat = getSearchClayChatSummary();
262
+ if (clayChat) {
263
+ items.push({ type: "resume-clay" });
264
+ html += '<div class="cmd-palette-group-label">Current Clay chat</div>';
265
+ html += renderItem(index++, '<img src="/clay-studio-symbol.png" width="22" height="22" alt="">', "Return to Clay", escapeHtml(clayChat.processing ? "Clay is responding" : "Continue your current conversation"), clayChat.preview ? escapeHtml(clayChat.preview) : null, clayChat.updatedAt, " is-resume-clay");
345
266
  }
346
-
347
- // --- Projects ---
348
- var projectList = ctx.projectList ? ctx.projectList() : [];
349
- var filteredProjects = projectList.filter(function (p) {
350
- if (p.isMate) return false;
351
- if (p.isWorktree) return false;
352
- if (!f) return true;
353
- var name = (p.title || p.project || p.slug || "").toLowerCase();
354
- return name.indexOf(f) !== -1;
355
- });
356
- if (filteredProjects.length > 0) {
357
- html += '<div class="cmd-palette-group-label">Projects</div>';
358
- for (var j = 0; j < filteredProjects.length; j++) {
359
- var proj = filteredProjects[j];
360
- items.push({ type: "project", data: proj });
361
- var pName = escapeHtml(proj.title || proj.project || proj.slug);
362
- var sessLabel = proj.sessions ? proj.sessions + " sessions" : "";
363
- html += renderItem(flatIndex, proj.icon || '<i data-lucide="box"></i>', pName, sessLabel, null);
364
- flatIndex++;
267
+ if (sessions.length) {
268
+ html += '<div class="cmd-palette-group-label">' + (query ? "Conversations" : "Recent conversations") + '</div>';
269
+ for (var s = 0; s < sessions.length; s++) {
270
+ var session = sessions[s];
271
+ items.push({ type: session.isMate ? "mate-session" : "session", data: session, query: query ? searchQuery : null });
272
+ var project = escapeHtml(session.projectTitle || session.projectSlug || "");
273
+ var snippet = session.snippet ? escapeHtml(session.snippet) : null;
274
+ html += renderItem(index++, sessionIcon(session), escapeHtml(session.sessionTitle || "New Chat"), project, snippet, session.lastActivity, "");
365
275
  }
366
276
  }
367
-
368
- if (items.length === 0 && !f) {
369
- html = '<div class="cmd-palette-empty">No matching results</div>';
277
+ if (query) {
278
+ items.push({ type: "ask-clay", query: searchQuery });
279
+ if (!sessions.length && !searchPending) html += '<div class="cmd-palette-exact-empty">No exact matches. Clay can search by meaning.</div>';
280
+ html += '<div class="cmd-palette-group-label">' + (clayChat ? "New Clay chat" : "Ask Clay") + '</div>';
281
+ html += renderItem(index, '<img src="/clay-studio-symbol.png" width="22" height="22" alt="">', (clayChat ? 'Start a new Clay chat about “' : 'Ask Clay about “') + escapeHtml(searchQuery) + '”', "Search by meaning across your projects and conversations", null, null, " is-ask-clay");
370
282
  }
371
-
283
+ if (!html) html = '<div class="cmd-palette-empty">No conversations yet.</div>';
372
284
  resultsEl.innerHTML = html;
373
285
  activeIndex = -1;
374
286
  refreshIcons();
375
287
  bindItemEvents();
376
288
  }
377
289
 
378
- // ==========================================
379
- // HOME MODE: inline session search (server-side)
380
- // ==========================================
381
-
382
- var homeSearchQuery = "";
383
-
384
- function fetchHomeSearchResults(query) {
385
- homeSearchQuery = query;
386
- if (abortCtrl) { abortCtrl.abort(); abortCtrl = null; }
387
- abortCtrl = new AbortController();
388
- fetch("/api/palette/search?q=" + encodeURIComponent(query), { signal: abortCtrl.signal })
389
- .then(function (res) { return res.json(); })
390
- .then(function (data) {
391
- abortCtrl = null;
392
- if (homeSearchQuery !== query) return;
393
- appendHomeSearchResults(data.results || [], query);
394
- })
395
- .catch(function (err) {
396
- if (err.name === "AbortError") return;
397
- abortCtrl = null;
398
- });
290
+ function renderItem(index, icon, title, desc, snippet, timestamp, extraClass) {
291
+ var date = formatRelativeDate(timestamp);
292
+ return '<button type="button" class="cmd-palette-item' + extraClass + '" data-index="' + index + '"><span class="cmd-palette-item-icon">' + icon + '</span><span class="cmd-palette-item-body"><span class="cmd-palette-item-title-row"><span class="cmd-palette-item-title">' + title + '</span>' + (date ? '<span class="cmd-palette-item-date">' + date + '</span>' : '') + '</span>' + (desc || snippet ? '<span class="cmd-palette-item-meta">' + (desc ? '<span class="cmd-palette-item-project">' + desc + '</span>' : '') + (snippet ? '<span class="cmd-palette-item-snippet">' + snippet + '</span>' : '') + '</span>' : '') + '</span><span class="cmd-palette-item-arrow"><i data-lucide="arrow-right"></i></span></button>';
399
293
  }
400
294
 
401
- function appendHomeSearchResults(results, query) {
402
- if (results.length === 0) return;
403
-
404
- // Deduplicate: exclude sessions already shown in the Recent section
405
- var existingIds = {};
406
- for (var e = 0; e < items.length; e++) {
407
- if (items[e].type === "session" && items[e].data.sessionId) {
408
- existingIds[items[e].data.projectSlug + ":" + items[e].data.sessionId] = true;
409
- }
410
- }
411
- var newResults = results.filter(function (r) {
412
- return !existingIds[r.projectSlug + ":" + r.sessionId];
413
- });
414
- if (newResults.length === 0) return;
415
-
416
- // Remove "No matching results" if present
417
- var emptyEl = resultsEl.querySelector(".cmd-palette-empty");
418
- if (emptyEl) emptyEl.remove();
419
-
420
- // Build HTML and append
421
- var html = '<div class="cmd-palette-group-label cmd-palette-search-results-label">Session search results</div>';
422
- var flatIndex = items.length;
423
- for (var i = 0; i < newResults.length; i++) {
424
- var r = newResults[i];
425
- items.push({ type: r.isMate ? "mate-session" : "search-result", data: r, query: query });
426
- var srIconHtml;
427
- if (r.isMate) {
428
- var srMate = findMateById(r.mateId);
429
- if (srMate) {
430
- var srAvUrl = mateAvatarUrl(srMate, 28);
431
- srIconHtml = '<img src="' + srAvUrl + '" width="28" height="28" style="border-radius:50%;" alt="">';
432
- } else {
433
- srIconHtml = '<i data-lucide="bot"></i>';
434
- }
435
- } else {
436
- srIconHtml = r.projectIcon || '<i data-lucide="message-square"></i>';
437
- }
438
- var projLabel = (r.projectIcon || "") + " " + escapeHtml(r.projectTitle || r.projectSlug);
439
- var snippet = r.snippet ? escapeHtml(r.snippet) : "";
440
- html += renderItem(flatIndex, srIconHtml, escapeHtml(r.sessionTitle || "New Session"), projLabel.trim(), snippet, r.lastActivity);
441
- flatIndex++;
442
- }
443
-
444
- // Append to results
445
- var frag = document.createElement("div");
446
- frag.innerHTML = html;
447
- while (frag.firstChild) {
448
- resultsEl.appendChild(frag.firstChild);
449
- }
450
- refreshIcons();
451
- bindItemEvents();
295
+ function bindItemEvents() {
296
+ var elements = resultsEl.querySelectorAll(".cmd-palette-item");
297
+ for (var i = 0; i < elements.length; i++) (function (element) {
298
+ element.addEventListener("click", function () { var index = parseInt(element.dataset.index, 10); if (items[index]) activateItem(items[index]); });
299
+ element.addEventListener("mouseenter", function () { setActive(parseInt(element.dataset.index, 10), true); });
300
+ })(elements[i]);
452
301
  }
453
302
 
454
- // ==========================================
455
- // Shared rendering / interaction helpers
456
- // ==========================================
457
-
458
- function renderItem(index, iconContent, title, desc, snippet, timestamp) {
459
- var dateStr = formatRelativeDate(timestamp);
460
- return '<div class="cmd-palette-item" data-index="' + index + '">' +
461
- '<div class="cmd-palette-item-icon">' + iconContent + '</div>' +
462
- '<div class="cmd-palette-item-body">' +
463
- '<div class="cmd-palette-item-title-row">' +
464
- '<span class="cmd-palette-item-title">' + title + '</span>' +
465
- (dateStr ? '<span class="cmd-palette-item-date">' + dateStr + '</span>' : '') +
466
- '</div>' +
467
- (desc || snippet ?
468
- '<div class="cmd-palette-item-meta">' +
469
- (desc ? '<span class="cmd-palette-item-project">' + desc + '</span>' : '') +
470
- (snippet ? '<span class="cmd-palette-item-snippet">' + snippet + '</span>' : '') +
471
- '</div>'
472
- : '') +
473
- '</div>' +
474
- '<div class="cmd-palette-item-arrow"><i data-lucide="arrow-right"></i></div>' +
475
- '</div>';
303
+ function setActive(index, skipScroll) {
304
+ if (!items.length) return;
305
+ if (index < 0) index = items.length - 1;
306
+ if (index >= items.length) index = 0;
307
+ activeIndex = index;
308
+ var elements = resultsEl.querySelectorAll(".cmd-palette-item");
309
+ for (var i = 0; i < elements.length; i++) elements[i].classList.toggle("active", i === index);
310
+ if (!skipScroll && elements[index]) elements[index].scrollIntoView({ block: "nearest" });
476
311
  }
477
312
 
478
- function bindItemEvents() {
479
- var itemEls = resultsEl.querySelectorAll(".cmd-palette-item");
480
- for (var k = 0; k < itemEls.length; k++) {
481
- (function (el) {
482
- el.addEventListener("click", function () {
483
- var idx = parseInt(el.getAttribute("data-index"), 10);
484
- if (idx >= 0 && idx < items.length) activateItem(items[idx]);
485
- });
486
- el.addEventListener("mouseenter", function () {
487
- var idx = parseInt(el.getAttribute("data-index"), 10);
488
- setActive(idx, true);
489
- });
490
- })(itemEls[k]);
491
- }
313
+ function beginClayChat(query) {
314
+ if (chatMode) return;
315
+ chatMode = true;
316
+ paletteEl.classList.add("is-chatting");
317
+ startSearchClayChat(query, resultsEl, showSearch, closeCommandPalette);
492
318
  }
493
319
 
494
- function setActive(idx, skipScroll) {
495
- if (items.length === 0) return;
496
- if (idx < 0) idx = items.length - 1;
497
- if (idx >= items.length) idx = 0;
498
- activeIndex = idx;
499
-
500
- var els = resultsEl.querySelectorAll(".cmd-palette-item");
501
- for (var i = 0; i < els.length; i++) {
502
- els[i].classList.toggle("active", i === idx);
503
- }
504
- if (!skipScroll && els[idx]) {
505
- els[idx].scrollIntoView({ block: "nearest" });
506
- }
320
+ function resumeClayChat() {
321
+ if (!attachSearchClayChat(resultsEl, showSearch, closeCommandPalette)) return;
322
+ chatMode = true;
323
+ paletteEl.classList.add("is-chatting");
507
324
  }
508
325
 
509
326
  function activateItem(entry) {
510
- if (entry.type === "command") {
511
- executeCommand(entry.data);
512
- } else if (entry.type === "mate-session") {
513
- closeCommandPalette();
514
- // Open mate DM, then select the specific session after connection
515
- if (entry.data.mateId && ctx.openDm) {
516
- pendingNav = { slug: entry.data.projectSlug, sessionId: entry.data.sessionId, query: entry.query || null };
517
- ctx.openDm(entry.data.mateId);
518
- }
519
- } else if (entry.type === "session" || entry.type === "search-result") {
520
- navigateToSession(entry.data, entry.query || null);
521
- } else if (entry.type === "project") {
522
- closeCommandPalette();
523
- ctx.switchProject(entry.data.slug);
524
- } else if (entry.type === "mate" || entry.type === "user") {
327
+ if (entry.type === "resume-clay") { resumeClayChat(); return; }
328
+ if (entry.type === "ask-clay") { beginClayChat(entry.query); return; }
329
+ if (entry.type === "mate-session") {
525
330
  closeCommandPalette();
526
- ctx.openDm(entry.data.id);
527
- }
528
- }
529
-
530
- function executeCommand(cmd) {
531
- closeCommandPalette();
532
- switch (cmd.action) {
533
- case "createMate":
534
- ctx.runAction("createMate");
535
- break;
536
- case "openSettings":
537
- ctx.runAction("openSettings");
538
- break;
539
- }
331
+ showHomeHub();
332
+ openHomeConversation(entry.data.mateId, entry.data.sessionId);
333
+ } else if (entry.type === "session") navigateToSession(entry.data, entry.query);
540
334
  }
541
335
 
542
336
  function navigateToSession(item, query) {
543
337
  closeCommandPalette();
544
- var slug = item.projectSlug;
545
- var sessionId = item.sessionId;
546
-
547
- if (ctx.currentSlug && ctx.currentSlug() === slug) {
548
- ctx.selectSession(sessionId);
549
- if (query) {
550
- setTimeout(function () { openSessionSearch(query); }, 400);
551
- }
338
+ if (ctx.currentSlug && ctx.currentSlug() === item.projectSlug) {
339
+ ctx.selectSession(item.sessionId);
340
+ if (query) setTimeout(function () { openSessionSearch(query); }, 400);
552
341
  } else {
553
- pendingNav = { slug: slug, sessionId: sessionId, query: query };
554
- ctx.switchProject(slug);
342
+ pendingNav = { slug: item.projectSlug, sessionId: item.sessionId, query: query };
343
+ ctx.switchProject(item.projectSlug);
555
344
  }
556
345
  }