clay-server 5.2.0-beta.5 → 5.2.0-beta.7

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 (246) hide show
  1. package/lib/claude-hook-installer.js +1 -267
  2. package/lib/claude-jsonl-watcher.js +1 -204
  3. package/lib/clay-control-presentation-binding.js +96 -0
  4. package/lib/clay-control-presentation.js +128 -0
  5. package/lib/clay-control-target-projection.js +26 -0
  6. package/lib/clay-mate-chat.js +1 -0
  7. package/lib/clay-mate-knowledge.js +1 -1
  8. package/lib/clay-product-control-tools.js +1 -1
  9. package/lib/clay-product-control.js +22 -12
  10. package/lib/clay-project-records.js +2 -1
  11. package/lib/clay-scheduling.js +1 -1
  12. package/lib/clay-screen-controls.js +13 -5
  13. package/lib/clay-skill-install.js +1 -33
  14. package/lib/clay-workspace-controls.js +2 -1
  15. package/lib/cli-sessions.js +1 -300
  16. package/lib/codex-defaults.js +1 -28
  17. package/lib/context-usage.js +3 -2
  18. package/lib/contextual-screen-snapshot.js +38 -0
  19. package/lib/daemon.js +5 -55
  20. package/lib/default-ai-runtime.js +4 -8
  21. package/lib/email-mcp-server.js +1 -1
  22. package/lib/kiro-defaults.js +1 -22
  23. package/lib/mate-context-service.js +138 -0
  24. package/lib/mate-context-tools.js +21 -0
  25. package/lib/mcp-proxy.js +2 -32
  26. package/lib/mcp-query-bridge.js +1 -1
  27. package/lib/mcp-source-adapters.js +1 -91
  28. package/lib/mcp-source-context.js +1 -42
  29. package/lib/mcp-source-discovery.js +1 -169
  30. package/lib/mcp-source-plugins.js +1 -68
  31. package/lib/mcp-source-restrictions.js +1 -47
  32. package/lib/mcp-tool-policy.js +1 -26
  33. package/lib/os-user-diagnostics.js +2 -4
  34. package/lib/os-users.js +4 -65
  35. package/lib/project-connection.js +14 -10
  36. package/lib/project-control-git-view.js +12 -0
  37. package/lib/project-filesystem.js +5 -1
  38. package/lib/project-http.js +7 -4
  39. package/lib/project-mcp.js +2 -2
  40. package/lib/project-notifications.js +5 -4
  41. package/lib/project-pair-result-delivery.js +2 -2
  42. package/lib/project-pair-usage.js +12 -13
  43. package/lib/project-pending-message-queue.js +3 -1
  44. package/lib/project-product-control.js +3 -1
  45. package/lib/project-scheduled-messages.js +4 -4
  46. package/lib/project-scheduled-task-control.js +1 -1
  47. package/lib/project-session-document.js +20 -5
  48. package/lib/project-session-history-actions.js +5 -3
  49. package/lib/project-session-pair.js +1 -1
  50. package/lib/project-session-runtime-actions.js +2 -1
  51. package/lib/project-session-spawn.js +2 -3
  52. package/lib/project-session-vendor.js +2 -1
  53. package/lib/project-sessions.js +18 -26
  54. package/lib/project-shared-browser.js +22 -5
  55. package/lib/project-studio-presentation.js +58 -0
  56. package/lib/project-user-message.js +37 -0
  57. package/lib/project-vendor-login.js +6 -36
  58. package/lib/project-workspace-query.js +11 -1
  59. package/lib/project.js +24 -7
  60. package/lib/public/app.js +25 -0
  61. package/lib/public/appearance-bootstrap.js +2 -0
  62. package/lib/public/css/contextual-clay.css +240 -0
  63. package/lib/public/css/messages.css +6 -2
  64. package/lib/public/modules/app-favicon.js +18 -9
  65. package/lib/public/modules/app-header.js +4 -2
  66. package/lib/public/modules/app-loop-ui.js +2 -0
  67. package/lib/public/modules/app-message-router.js +5 -1
  68. package/lib/public/modules/app-messages.js +50 -6
  69. package/lib/public/modules/app-notifications.js +11 -5
  70. package/lib/public/modules/app-panels.js +61 -123
  71. package/lib/public/modules/app-projects.js +3 -0
  72. package/lib/public/modules/app-rate-limit.js +7 -27
  73. package/lib/public/modules/chat-render-runtime.js +3 -0
  74. package/lib/public/modules/clay-control-activity.js +214 -0
  75. package/lib/public/modules/clay-control-copy.js +36 -0
  76. package/lib/public/modules/clay-control-detail-targets.js +44 -0
  77. package/lib/public/modules/clay-control-object-targets.js +52 -0
  78. package/lib/public/modules/clay-control-target-visibility.js +12 -0
  79. package/lib/public/modules/clay-control-targets.js +44 -0
  80. package/lib/public/modules/clay-navigation-render.js +52 -0
  81. package/lib/public/modules/clay-owner-navigation.js +11 -2
  82. package/lib/public/modules/clay-session-links.js +31 -0
  83. package/lib/public/modules/clay-studio-bridge.js +20 -0
  84. package/lib/public/modules/clay-studio-document.js +67 -0
  85. package/lib/public/modules/clay-studio-render.js +144 -0
  86. package/lib/public/modules/clay-tool-presentation.js +4 -0
  87. package/lib/public/modules/command-palette.js +26 -31
  88. package/lib/public/modules/contextual-ask-session.js +26 -0
  89. package/lib/public/modules/contextual-clay-geometry.js +155 -0
  90. package/lib/public/modules/contextual-clay-session.js +130 -0
  91. package/lib/public/modules/contextual-clay-workspace.js +157 -0
  92. package/lib/public/modules/contextual-clay.js +237 -0
  93. package/lib/public/modules/contextual-composer.js +91 -0
  94. package/lib/public/modules/contextual-mate-context.js +115 -0
  95. package/lib/public/modules/contextual-mate-hint.js +40 -0
  96. package/lib/public/modules/contextual-mate-identity.js +23 -0
  97. package/lib/public/modules/contextual-mate-sessions.js +134 -0
  98. package/lib/public/modules/contextual-search.js +137 -0
  99. package/lib/public/modules/contextual-session-citations.js +58 -0
  100. package/lib/public/modules/filebrowser.js +20 -1
  101. package/lib/public/modules/generation-stop.js +8 -5
  102. package/lib/public/modules/git-panel.js +3 -1
  103. package/lib/public/modules/icon-strip-tooltip.js +2 -1
  104. package/lib/public/modules/input.js +35 -1
  105. package/lib/public/modules/issues-render.js +3 -2
  106. package/lib/public/modules/knowledge-db-workbench.js +4 -4
  107. package/lib/public/modules/markdown.js +2 -34
  108. package/lib/public/modules/mate-knowledge-workbench.js +1 -1
  109. package/lib/public/modules/mcp-connection-view.js +1 -1
  110. package/lib/public/modules/message-delivery.js +10 -0
  111. package/lib/public/modules/pane-bridge.js +2 -2
  112. package/lib/public/modules/pending-message-queue.js +1 -0
  113. package/lib/public/modules/permission-control.js +5 -4
  114. package/lib/public/modules/product-review.js +26 -0
  115. package/lib/public/modules/project-chat-identity.js +13 -4
  116. package/lib/public/modules/project-logs-render.js +3 -0
  117. package/lib/public/modules/project-mate-navigation.js +58 -21
  118. package/lib/public/modules/scheduled-tasks.js +2 -0
  119. package/lib/public/modules/scheduler.js +2 -0
  120. package/lib/public/modules/search-clay-chat.js +5 -454
  121. package/lib/public/modules/session-create-form.js +10 -10
  122. package/lib/public/modules/settings-defaults.js +27 -28
  123. package/lib/public/modules/shared-browser.js +2 -0
  124. package/lib/public/modules/sidebar-mobile.js +4 -3
  125. package/lib/public/modules/sidebar-projects.js +1 -0
  126. package/lib/public/modules/sidebar-sessions.js +1 -0
  127. package/lib/public/modules/split-view.js +7 -16
  128. package/lib/public/modules/terminal.js +9 -0
  129. package/lib/public/modules/tools.js +6 -2
  130. package/lib/public/modules/tui-grab.js +1 -2
  131. package/lib/public/modules/vendor-login-browser.js +5 -3
  132. package/lib/public/modules/vendor-login.js +2 -2
  133. package/lib/public/modules/vendor-priority.js +15 -1
  134. package/lib/public/modules/wireframe-workbench.js +5 -2
  135. package/lib/public/muse-avatar.svg +4 -0
  136. package/lib/public/style.css +2 -0
  137. package/lib/safe-bash-commands.js +3 -45
  138. package/lib/sdk-bridge.js +131 -395
  139. package/lib/sdk-foreground-admission.js +16 -0
  140. package/lib/sdk-mcp-descriptors.js +2 -37
  141. package/lib/sdk-message-processor.js +50 -17
  142. package/lib/sdk-quota-snapshot.js +1 -1
  143. package/lib/sdk-response-recovery.js +1 -155
  144. package/lib/sdk-worker.js +2 -677
  145. package/lib/server-contextual-clay-settings.js +40 -0
  146. package/lib/server-contextual-mate-sessions.js +70 -0
  147. package/lib/server-home-chat.js +7 -1
  148. package/lib/server-home-clay-entry.js +23 -4
  149. package/lib/server-home-clay-session-links.js +12 -0
  150. package/lib/server-owner-ui.js +49 -8
  151. package/lib/server-settings.js +2 -0
  152. package/lib/server.js +18 -1
  153. package/lib/session-fork-history.js +21 -0
  154. package/lib/session-hygiene.js +3 -35
  155. package/lib/session-permission-mode.js +4 -3
  156. package/lib/session-skill-scope.js +11 -0
  157. package/lib/sessions.js +24 -89
  158. package/lib/terminal-manager.js +18 -11
  159. package/lib/tool-llm.js +1 -1
  160. package/lib/tui-transcript-index.js +1 -132
  161. package/lib/users-contextual-clay-preferences.js +31 -0
  162. package/lib/users.js +3 -0
  163. package/lib/vendor-login-browser.js +1 -11
  164. package/lib/workspace-assignment-service.js +25 -0
  165. package/lib/workspace-query-mcp-server.js +1 -1
  166. package/lib/ws-request.js +1 -0
  167. package/lib/ws-schema.js +10 -0
  168. package/lib/yoke/acp-agent-profiles.js +5 -3
  169. package/lib/yoke/adapters/antigravity.js +3 -14
  170. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  171. package/lib/yoke/adapters/claude.js +7 -42
  172. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  173. package/lib/yoke/adapters/codex.js +1 -0
  174. package/lib/yoke/adapters/kiro.js +3 -1
  175. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  176. package/lib/yoke/adapters/muse.js +122 -0
  177. package/lib/yoke/auth-events.js +17 -0
  178. package/lib/yoke/claude-hook-installer.js +271 -0
  179. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  180. package/lib/yoke/claude-maintenance.js +55 -0
  181. package/lib/yoke/claude-permission-patterns.js +53 -0
  182. package/lib/yoke/claude-response-recovery.js +155 -0
  183. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  184. package/lib/yoke/clay-skill-install.js +33 -0
  185. package/lib/yoke/cli-sessions.js +300 -0
  186. package/lib/yoke/codex-app-server.js +7 -12
  187. package/lib/yoke/configuration.js +13 -0
  188. package/lib/yoke/discovery.js +70 -0
  189. package/lib/yoke/errors.js +8 -0
  190. package/lib/yoke/host-environment.js +7 -0
  191. package/lib/yoke/index.js +9 -51
  192. package/lib/yoke/interface.js +116 -0
  193. package/lib/yoke/kiro-acp-server.js +5 -5
  194. package/lib/yoke/legacy-sessions.js +89 -0
  195. package/lib/yoke/login-protocol.js +25 -0
  196. package/lib/yoke/maintenance.js +12 -0
  197. package/lib/yoke/mcp-proxy.js +32 -0
  198. package/lib/yoke/mcp-source-adapters.js +91 -0
  199. package/lib/yoke/mcp-source-context.js +42 -0
  200. package/lib/yoke/mcp-source-discovery.js +169 -0
  201. package/lib/yoke/mcp-source-plugins.js +68 -0
  202. package/lib/yoke/mcp-source-restrictions.js +47 -0
  203. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  204. package/lib/yoke/model-preferences.js +6 -0
  205. package/lib/yoke/muse-artifacts.js +36 -0
  206. package/lib/yoke/muse-controls.js +50 -0
  207. package/lib/yoke/muse-input.js +64 -0
  208. package/lib/yoke/muse-items.js +157 -0
  209. package/lib/yoke/muse-policy.js +52 -0
  210. package/lib/yoke/muse-query.js +428 -0
  211. package/lib/yoke/muse-runtime.js +211 -0
  212. package/lib/yoke/muse-services.js +79 -0
  213. package/lib/yoke/muse-skills.js +79 -0
  214. package/lib/yoke/muse-turns.js +71 -0
  215. package/lib/yoke/options/acp.js +2 -0
  216. package/lib/yoke/options/antigravity.js +2 -0
  217. package/lib/yoke/options/claude.js +21 -0
  218. package/lib/yoke/options/codex-defaults.js +29 -0
  219. package/lib/yoke/options/codex-settings.js +21 -0
  220. package/lib/yoke/options/codex.js +6 -0
  221. package/lib/yoke/options/kiro-defaults.js +22 -0
  222. package/lib/yoke/options/kiro.js +5 -0
  223. package/lib/yoke/options/muse.js +5 -0
  224. package/lib/yoke/provider-contract.js +5 -0
  225. package/lib/yoke/providers/antigravity-executable.js +8 -0
  226. package/lib/yoke/providers/claude-executable.js +40 -0
  227. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  228. package/lib/yoke/providers/claude-process.js +97 -0
  229. package/lib/yoke/providers/claude-provision.js +75 -0
  230. package/lib/yoke/providers/codex-errors.js +8 -0
  231. package/lib/yoke/providers/muse-executable.js +17 -0
  232. package/lib/yoke/provisioning.js +6 -0
  233. package/lib/yoke/query-options.js +10 -0
  234. package/lib/yoke/response-recovery.js +41 -0
  235. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  236. package/lib/yoke/sdk-server-factory.js +7 -0
  237. package/lib/yoke/session-history.js +8 -0
  238. package/lib/yoke/session-tool-transport.js +31 -13
  239. package/lib/yoke/settings.js +23 -0
  240. package/lib/yoke/source-locations.js +4 -0
  241. package/lib/yoke/title-query.js +18 -7
  242. package/lib/yoke/tui-transcript-index.js +132 -0
  243. package/lib/yoke/usage.js +48 -0
  244. package/lib/yoke/user-input.js +13 -0
  245. package/lib/yoke/vendor-registry.js +81 -1
  246. package/package.json +3 -2
@@ -1,454 +1,5 @@
1
- import { createHomeDebateQuestionCard, applyHomeDebateQuestion, resolveHomeDebateQuestion, markHomeDebateQuestionSubmitting } from './home-debate-planning.js';
2
- // Compact Clay conversation hosted inside the global search drawer.
3
- import { getWs } from './ws-ref.js';
4
- import { openProjectSession } from './project-session-navigation.js';
5
- import { refreshIcons } from './icons.js';
6
- import { store } from './store.js';
7
- import { mateAvatarUrl } from './avatar.js';
8
- import { createAssistantBubble, createUserBubble, finalizeAssistantBubble, renderAssistantBubbleText } from './chat-bubble-renderer.js';
9
- import { isExactSearchControlMessage, replaceSearchPermissions, applySearchPermissionMessage, createSearchPermissionCard } from './search-clay-controls.js';
10
-
11
- var state = store.get('searchClayChatState') || null;
12
- var hostEl = null;
13
- var backHandler = null;
14
- var closeHandler = null;
15
- var sequence = 0;
16
- var progressTimer = null;
17
-
18
- function send(payload) {
19
- var ws = getWs();
20
- if (!ws || ws.readyState !== 1) return false;
21
- ws.send(JSON.stringify(payload));
22
- return true;
23
- }
24
-
25
- function requestId() {
26
- sequence++;
27
- return "search-clay-" + Date.now() + "-" + sequence;
28
- }
29
-
30
- function stopProgressTimer() {
31
- if (!progressTimer) return;
32
- clearInterval(progressTimer);
33
- progressTimer = null;
34
- }
35
-
36
- function startProgressTimer() {
37
- if (progressTimer) return;
38
- progressTimer = setInterval(function () { if (state && state.processing) updateProgressDom(); else stopProgressTimer(); }, 1000);
39
- }
40
-
41
- function progressCopy() {
42
- var elapsed = state && state.startedAt ? Math.max(0, Math.floor((Date.now() - state.startedAt) / 1000)) : 0;
43
- var label = state && state.step ? "Considering what was found" : "Understanding what to look for";
44
- if (state.activity === "searching") label = state.step > 1 ? "Checking another lead" : "Searching your conversations";
45
- else if (state.activity === "reviewing") label = "Reviewing what Clay found";
46
- else if (state.activity === "reconsidering") label = "Trying another search route";
47
- else if (elapsed >= 12) label = "Following related context";
48
- else if (elapsed >= 4) label = "Searching your conversations";
49
- var detail = (state.step ? "Search pass " + state.step + " · " : "") + elapsed + "s";
50
- return { label: label, detail: detail };
51
- }
52
-
53
- function updateProgressDom() {
54
- if (!hostEl) return;
55
- var progress = progressCopy();
56
- var label = hostEl.querySelector(".search-clay-pending-copy strong");
57
- var detail = hostEl.querySelector(".search-clay-pending-copy small");
58
- if (label) label.textContent = progress.label;
59
- if (detail) detail.textContent = progress.detail;
60
- var activeDetails = hostEl.querySelectorAll(".search-clay-activity-item.is-active small");
61
- var activeIndex = 0;
62
- for (var i = 0; state && i < state.activities.length; i++) {
63
- if (state.activities[i].status !== "active") continue;
64
- var elapsed = Math.max(0, Math.floor((Date.now() - state.activities[i].startedAt) / 1000));
65
- state.activities[i].detail = elapsed + "s elapsed";
66
- if (activeDetails[activeIndex]) activeDetails[activeIndex].textContent = state.activities[i].detail;
67
- activeIndex++;
68
- }
69
- }
70
-
71
- function button(icon, label, title, handler) {
72
- var el = document.createElement("button");
73
- el.type = "button";
74
- el.className = "search-clay-icon-button";
75
- el.title = title;
76
- el.setAttribute("aria-label", title);
77
- el.innerHTML = '<i data-lucide="' + icon + '" aria-hidden="true"></i><span>' + label + '</span>';
78
- el.addEventListener("click", handler);
79
- return el;
80
- }
81
-
82
- function clayMate() {
83
- var mates = store.get('cachedMatesList') || [];
84
- for (var i = 0; i < mates.length; i++) {
85
- if (mates[i] && (mates[i].id === state.mateId || mates[i].builtinKey === "clay")) return mates[i];
86
- }
87
- return { name: "Clay", profile: { displayName: "Clay", avatarCustom: "/clay-studio-symbol.png" } };
88
- }
89
-
90
- function appendActivityList(content, items, expanded, onToggle) {
91
- var panel = document.createElement("div");
92
- panel.className = "search-clay-activity-panel " + (expanded ? "is-expanded" : "is-collapsed");
93
- var toggle = document.createElement("button");
94
- toggle.type = "button";
95
- toggle.className = "search-clay-activity-toggle";
96
- toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
97
- toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Clay activity, " + items.length + (items.length === 1 ? " step" : " steps"));
98
- toggle.innerHTML = '<i data-lucide="activity" aria-hidden="true"></i><span><strong>Activity</strong><small></small></span><i class="search-clay-activity-chevron" data-lucide="chevron-down" aria-hidden="true"></i>';
99
- toggle.querySelector("small").textContent = items.length + (items.length === 1 ? " step" : " steps");
100
- if (items.length <= 2) {
101
- toggle.disabled = true;
102
- toggle.setAttribute("aria-label", "Clay activity, " + items.length + (items.length === 1 ? " step" : " steps"));
103
- } else {
104
- toggle.addEventListener("click", function () {
105
- expanded = !expanded;
106
- panel.classList.toggle("is-expanded", expanded);
107
- panel.classList.toggle("is-collapsed", !expanded);
108
- toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
109
- toggle.setAttribute("aria-label", (expanded ? "Collapse" : "Expand") + " Clay activity, " + items.length + " steps");
110
- onToggle(expanded);
111
- });
112
- }
113
- panel.appendChild(toggle);
114
- var list = document.createElement("div");
115
- list.className = "search-clay-activity-list";
116
- for (var i = 0; i < items.length; i++) {
117
- var item = document.createElement("div");
118
- item.className = "search-clay-activity-item is-" + items[i].status;
119
- item.innerHTML = '<i data-lucide="' + activityIcon(items[i].status) + '" aria-hidden="true"></i>';
120
- var copy = document.createElement("span");
121
- var label = document.createElement("strong");
122
- label.textContent = items[i].label;
123
- copy.appendChild(label);
124
- var detail = document.createElement("small");
125
- detail.textContent = items[i].detail || "";
126
- copy.appendChild(detail);
127
- item.appendChild(copy);
128
- list.appendChild(item);
129
- }
130
- panel.appendChild(list);
131
- content.appendChild(panel);
132
- }
133
-
134
- function renderMessage(message, streaming) {
135
- if (message.role === "question" && message.flow === "mcp_import") return createHomeDebateQuestionCard(message, respondToImport);
136
- var row;
137
- if (message.role === "user") {
138
- row = createUserBubble({ text: message.text || "" });
139
- row.classList.add("search-clay-message", "search-clay-message-user");
140
- } else {
141
- row = createAssistantBubble({ name: "Clay", avatarUrl: mateAvatarUrl(clayMate(), 28) });
142
- row.classList.add("search-clay-message", "search-clay-message-assistant");
143
- if (streaming) renderAssistantBubbleText(row, message.text || "", false);
144
- else finalizeAssistantBubble(row, message.text || "", false);
145
- if (message.activities && message.activities.length) {
146
- appendActivityList(row.querySelector(".dm-bubble-content"), message.activities, message.activitiesExpanded === true, message.toggleActivities || function (expanded) { message.activitiesExpanded = expanded; });
147
- row.classList.add("search-clay-activity-message");
148
- }
149
- }
150
- row.setAttribute("role", "article");
151
- row.setAttribute("aria-label", message.role === "user" ? "Your message" : "Message from Clay");
152
- return row;
153
- }
154
-
155
- function activityIcon(status) {
156
- if (status === "done") return "circle-check";
157
- if (status === "error") return "circle-alert";
158
- return "loader-circle";
159
- }
160
-
161
- function updateActivity(message) {
162
- var id = message.activityId || message.phase + ":" + (message.step || 0);
163
- var activity = null;
164
- for (var i = 0; i < state.activities.length; i++) if (state.activities[i].id === id) activity = state.activities[i];
165
- if (!activity) {
166
- activity = { id: id, label: message.label || "Working", detail: "0s elapsed", status: message.status || "active", startedAt: Date.now() };
167
- state.activities.push(activity);
168
- } else if (message.status === "active") {
169
- activity.label = message.label || activity.label;
170
- activity.status = "active";
171
- } else {
172
- var elapsed = Math.max(0, Math.floor((Date.now() - activity.startedAt) / 1000));
173
- activity.detail = (message.label || "Complete") + (elapsed ? " \u00b7 " + elapsed + "s" : "");
174
- activity.status = message.status || "done";
175
- }
176
- if (state.activities.length > 12) state.activities = state.activities.slice(state.activities.length - 12);
177
- }
178
-
179
- function takeActivities(finalLabel, finalStatus) {
180
- var now = Date.now();
181
- for (var i = 0; i < state.activities.length; i++) {
182
- if (state.activities[i].status !== "active") continue;
183
- var elapsed = Math.max(0, Math.floor((now - state.activities[i].startedAt) / 1000));
184
- state.activities[i].status = finalStatus || "done";
185
- state.activities[i].detail = finalLabel + (elapsed ? " \u00b7 " + elapsed + "s" : "");
186
- }
187
- var items = state.activities.slice();
188
- state.activities = [];
189
- return items;
190
- }
191
-
192
- function submit(input, sendButton) {
193
- var text = input.value.trim();
194
- if (!state || !text || !state.sessionId) return;
195
- if (!send({ type: "home_mate_send", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, text: text })) return;
196
- if (state.processing) {
197
- state.queuedUsers.push({ role: "user", text: text });
198
- } else {
199
- state.messages.push({ role: "user", text: text });
200
- state.processing = true;
201
- state.awaitingCompletion = true;
202
- state.stream = "";
203
- state.activity = "thinking";
204
- state.step = 0;
205
- state.activities = [];
206
- state.activityExpanded = false;
207
- state.startedAt = Date.now();
208
- }
209
- state.pendingTurns++;
210
- state.updatedAt = Date.now();
211
- startProgressTimer();
212
- state.draft = "";
213
- input.value = "";
214
- sendButton.disabled = true;
215
- render();
216
- }
217
-
218
- function stopSearchClayChat() {
219
- if (!state || !state.processing || state.stopping || !state.mateId || !state.sessionId) return false;
220
- if (!send({ type: "home_mate_stop", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId })) return false;
221
- state.stopping = true;
222
- render();
223
- return true;
224
- }
225
-
226
- function respondToImport(message, action, opener, answers) {
227
- if (!state || message.status !== 'pending') return;
228
- if (!send({ type: 'home_mcp_import_response', mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, toolId: message.toolId, answers: answers || {} })) return;
229
- markHomeDebateQuestionSubmitting(message, opener);
230
- store.set({ searchClayChatState: state }); render();
231
- }
232
-
233
- function respondToPermission(permission, decision) {
234
- if (!state || permission.status !== "pending") return false;
235
- if (!send({ type: "home_mate_permission_response", mateId: state.mateId, sessionId: state.sessionId, requestId: state.requestId, permissionRequestId: permission.permissionRequestId, decision: decision })) return false;
236
- permission.status = "answering";
237
- render();
238
- return true;
239
- }
240
-
241
- function expand() {
242
- if (!state || !state.mateId || !state.localId) return;
243
- if (closeHandler) closeHandler();
244
- openProjectSession('mate-' + state.mateId, state.localId);
245
- }
246
-
247
- function render() {
248
- if (!hostEl || !state) return;
249
- var shell = hostEl.querySelector(".search-clay-chat");
250
- var transcript = shell ? shell.querySelector(".search-clay-transcript") : null;
251
- var previousTop = transcript ? transcript.scrollTop : 0;
252
- var follow = !transcript || transcript.scrollHeight - transcript.scrollTop - transcript.clientHeight < 40;
253
- if (!shell) {
254
- hostEl.innerHTML = "";
255
- shell = document.createElement("section");
256
- shell.className = "search-clay-chat";
257
- shell.setAttribute("aria-label", "Chat with Clay");
258
- var header = document.createElement("header");
259
- header.className = "search-clay-header";
260
- var identity = document.createElement("div");
261
- identity.className = "search-clay-identity";
262
- identity.innerHTML = '<span><strong>Clay</strong><small>Workspace search</small></span>';
263
- header.appendChild(identity);
264
- var actions = document.createElement("div");
265
- actions.className = "search-clay-header-actions";
266
- actions.appendChild(button("search", "Search", "Back to search", function () { detachSearchClayChat(); if (backHandler) backHandler(); }));
267
- actions.appendChild(button("maximize-2", "Expand", "Open this conversation in project chat", expand));
268
- header.appendChild(actions);
269
- shell.appendChild(header);
270
- transcript = document.createElement("div");
271
- transcript.className = "search-clay-transcript";
272
- transcript.setAttribute("aria-live", "polite");
273
- shell.appendChild(transcript);
274
- var composer = document.createElement("div");
275
- composer.className = "search-clay-composer";
276
- var freshInput = document.createElement("textarea");
277
- freshInput.rows = 1;
278
- freshInput.value = state.draft || "";
279
- freshInput.setAttribute("aria-label", "Message Clay");
280
- var freshSendButton = document.createElement("button");
281
- freshSendButton.type = "button";
282
- freshSendButton.className = "search-clay-send";
283
- freshSendButton.setAttribute("aria-label", "Send to Clay");
284
- freshSendButton.innerHTML = '<i data-lucide="arrow-up" aria-hidden="true"></i>';
285
- freshInput.addEventListener("input", function () { state.draft = freshInput.value; freshSendButton.disabled = state.processing ? (!state.sessionId || state.stopping) : (!state.sessionId || !freshInput.value.trim()); });
286
- freshInput.addEventListener("keydown", function (event) { if (event.key === "Enter" && !event.shiftKey && !event.isComposing) { event.preventDefault(); submit(freshInput, freshSendButton); } });
287
- freshSendButton.addEventListener("click", function () { if (state.processing) stopSearchClayChat(); else submit(freshInput, freshSendButton); });
288
- composer.appendChild(freshInput);
289
- composer.appendChild(freshSendButton);
290
- shell.appendChild(composer);
291
- hostEl.appendChild(shell);
292
- }
293
- transcript.innerHTML = "";
294
- for (var i = 0; i < state.messages.length; i++) transcript.appendChild(renderMessage(state.messages[i], false));
295
- if (state.activities.length || state.stream) transcript.appendChild(renderMessage({ role: "assistant", text: state.stream, activities: state.activities, activitiesExpanded: state.activityExpanded, toggleActivities: function (expanded) { state.activityExpanded = expanded; } }, true));
296
- for (var p = 0; p < state.permissions.length; p++) transcript.appendChild(createSearchPermissionCard(state.permissions[p], respondToPermission));
297
- if (state.processing && !state.stream && !state.activities.length) {
298
- var progress = progressCopy();
299
- var pending = document.createElement("div");
300
- pending.className = "search-clay-pending";
301
- pending.setAttribute("role", "status");
302
- var pendingCopy = document.createElement("span");
303
- pendingCopy.className = "search-clay-pending-copy";
304
- var pendingLabel = document.createElement("strong");
305
- pendingLabel.textContent = progress.label;
306
- var pendingDetail = document.createElement("small");
307
- pendingDetail.textContent = progress.detail;
308
- pendingCopy.appendChild(pendingLabel);
309
- pendingCopy.appendChild(pendingDetail);
310
- pending.appendChild(pendingCopy);
311
- var dots = document.createElement("span");
312
- dots.className = "search-clay-dots";
313
- dots.setAttribute("aria-hidden", "true");
314
- dots.innerHTML = "<i></i><i></i><i></i>";
315
- pending.appendChild(dots);
316
- transcript.appendChild(pending);
317
- }
318
- for (var q = 0; q < state.queuedUsers.length; q++) transcript.appendChild(renderMessage(state.queuedUsers[q], false));
319
- var input = shell.querySelector(".search-clay-composer textarea");
320
- var sendButton = shell.querySelector(".search-clay-send");
321
- input.placeholder = state.sessionId ? "Message Clay…" : "Starting Clay…";
322
- input.disabled = !state.sessionId;
323
- sendButton.disabled = state.processing ? (!state.sessionId || state.stopping) : (!state.sessionId || !input.value.trim());
324
- sendButton.setAttribute("aria-label", state.processing ? (state.stopping ? "Stopping Clay" : "Stop Clay") : "Send to Clay");
325
- sendButton.innerHTML = state.processing ? '<i data-lucide="square" aria-hidden="true"></i>' : '<i data-lucide="arrow-up" aria-hidden="true"></i>';
326
- var expandButton = shell.querySelector('.search-clay-icon-button[aria-label="Open this conversation in project chat"]');
327
- if (expandButton) expandButton.disabled = !state.localId;
328
- refreshIcons();
329
- transcript.scrollTop = follow ? transcript.scrollHeight : previousTop;
330
- }
331
-
332
- export function startSearchClayChat(query, host, onBack, onClose) {
333
- var clean = typeof query === "string" ? query.trim().slice(0, 12000) : "";
334
- if (!clean) return false;
335
- hostEl = host;
336
- backHandler = onBack;
337
- closeHandler = onClose;
338
- var startedAt = Date.now();
339
- state = { requestId: requestId(), mateId: null, sessionId: null, localId: null, messages: [{ role: "user", text: clean }], queuedUsers: [], pendingTurns: 1, activities: [], permissions: [], activityExpanded: false, stream: "", draft: "", processing: true, stopping: false, awaitingCompletion: true, activity: "thinking", step: 0, startedAt: startedAt, updatedAt: startedAt, query: clean };
340
- store.set({ searchClayChatState: state });
341
- startProgressTimer();
342
- render();
343
- if (!send({ type: "home_clay_ask", requestId: state.requestId, text: clean })) {
344
- state.processing = false;
345
- state.awaitingCompletion = false;
346
- state.pendingTurns = 0;
347
- stopProgressTimer();
348
- state.messages.push({ role: "assistant", text: "Clay is offline. Reconnect and try again." });
349
- render();
350
- }
351
- return true;
352
- }
353
-
354
- export function attachSearchClayChat(host, onBack, onClose) {
355
- if (!state) return false;
356
- hostEl = host;
357
- backHandler = onBack;
358
- closeHandler = onClose;
359
- if (state.processing) send({ type: "home_clay_ask", requestId: state.requestId, text: state.query });
360
- render();
361
- return true;
362
- }
363
-
364
- export function getSearchClayChatSummary() {
365
- if (!state) return null;
366
- var preview = "";
367
- var candidates = state.queuedUsers.length ? state.queuedUsers : state.messages;
368
- for (var i = candidates.length - 1; i >= 0; i--) {
369
- if (!candidates[i] || typeof candidates[i].text !== "string" || !candidates[i].text.trim()) continue;
370
- preview = candidates[i].text.replace(/\s+/g, " ").trim().slice(0, 120);
371
- break;
372
- }
373
- return { sessionId: state.sessionId, processing: state.processing === true, preview: preview, updatedAt: state.updatedAt || state.startedAt || null };
374
- }
375
-
376
- export function detachSearchClayChat() { hostEl = null; }
377
-
378
- export function handleSearchClayMessage(msg) {
379
- if (!isExactSearchControlMessage(state, msg)) return false;
380
- state.updatedAt = Date.now();
381
- if (msg.mateId) state.mateId = msg.mateId;
382
- if (msg.type === "home_mate_session_identity" && msg.sessionId) state.sessionId = msg.sessionId;
383
- if (msg.type === 'home_mcp_import_question') {
384
- if (state.stream) { state.messages.push({ role: 'assistant', text: state.stream }); state.stream = ''; }
385
- state.messages = applyHomeDebateQuestion(state.messages, msg);
386
- } else if (msg.type === 'home_mcp_import_question_resolved') {
387
- state.messages = resolveHomeDebateQuestion(state.messages, msg);
388
- } else if (msg.type === "home_clay_activity") {
389
- if (!state.awaitingCompletion) return true;
390
- state.activity = msg.phase || state.activity;
391
- state.step = typeof msg.step === "number" ? msg.step : state.step;
392
- updateActivity(msg);
393
- } else if (msg.type === "home_mate_history") {
394
- state.sessionId = msg.sessionId || state.sessionId;
395
- state.localId = typeof msg.localId === "number" ? msg.localId : state.localId;
396
- state.messages = Array.isArray(msg.messages) ? msg.messages.filter(function (item) { return item && (item.role === "user" || item.role === "assistant" || item.role === "question" && item.flow === "mcp_import"); }).map(function (item) { return item.role === "question" ? Object.assign({}, item) : { role: item.role, text: item.text || "" }; }) : state.messages;
397
- state.processing = msg.isProcessing === true;
398
- state.awaitingCompletion = state.processing;
399
- state.pendingTurns = state.processing ? Math.max(1, state.pendingTurns) : 0;
400
- if (state.processing) startProgressTimer();
401
- state.stream = "";
402
- state.stopping = false;
403
- replaceSearchPermissions(state, msg.pendingPermissions);
404
- } else if (msg.type === "home_mate_permission_request" || msg.type === "home_mate_permission_resolved" || msg.type === "home_mate_permission_cancelled") {
405
- applySearchPermissionMessage(state, msg);
406
- } else if (msg.type === "home_mate_stopping") {
407
- state.stopping = true;
408
- } else if (msg.type === "home_mate_delta") {
409
- if (!state.awaitingCompletion) return true;
410
- state.sessionId = msg.sessionId || state.sessionId;
411
- state.processing = true;
412
- state.pendingTurns = Math.max(1, state.pendingTurns);
413
- state.stream += msg.text || "";
414
- } else if (msg.type === "home_mate_done") {
415
- if (!state.awaitingCompletion) return true;
416
- var completedActivities = takeActivities("Response complete", "done");
417
- if (state.stream || msg.text || completedActivities.length) state.messages.push({ role: "assistant", text: state.stream || msg.text || "", activities: completedActivities, activitiesExpanded: state.activityExpanded });
418
- if (state.queuedUsers.length) state.messages.push(state.queuedUsers.shift());
419
- state.stream = "";
420
- state.activityExpanded = false;
421
- state.pendingTurns = Math.max(0, state.pendingTurns - 1);
422
- state.processing = state.pendingTurns > 0;
423
- state.stopping = false;
424
- state.awaitingCompletion = state.processing;
425
- state.startedAt = Date.now();
426
- if (!state.processing) stopProgressTimer();
427
- } else if (msg.type === "home_mate_error") {
428
- if (!state.awaitingCompletion) return true;
429
- var failedActivities = takeActivities("Stopped", "error");
430
- state.stream = "";
431
- state.messages.push({ role: "assistant", text: msg.text || "Clay could not complete that search.", activities: failedActivities, activitiesExpanded: state.activityExpanded });
432
- if (state.queuedUsers.length) state.messages.push(state.queuedUsers.shift());
433
- state.pendingTurns = Math.max(0, state.pendingTurns - 1);
434
- state.activityExpanded = false;
435
- state.processing = state.pendingTurns > 0;
436
- state.stopping = false;
437
- state.awaitingCompletion = state.processing;
438
- state.startedAt = Date.now();
439
- if (!state.processing) stopProgressTimer();
440
- }
441
- render();
442
- return true;
443
- }
444
-
445
- store.subscribe(function (appState, previous) {
446
- if (!state || appState.connected === previous.connected) return;
447
- if (!appState.connected) {
448
- replaceSearchPermissions(state, []);
449
- state.stopping = false;
450
- render();
451
- return;
452
- }
453
- if (state.processing) send({ type: "home_clay_ask", requestId: state.requestId, text: state.query });
454
- });
1
+ // Search is an entry point. The sole chat renderer is the contextual Mate pane.
2
+ import { startContextualSearch, handleContextualSearchMessage, retryContextualSearch } from './contextual-search.js';
3
+ export function startSearchClayChat(query) { return startContextualSearch(query); }
4
+ export function handleSearchClayMessage(message) { return handleContextualSearchMessage(message); }
5
+ export function retrySearchClayAsk() { return retryContextualSearch(); }
@@ -8,6 +8,7 @@
8
8
  import { store } from './store.js';
9
9
  import { iconHtml, refreshIcons } from './icons.js';
10
10
  import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, isExperimentalVendor } from './app-rendering.js';
11
+ import { sortVendorEntries } from './vendor-priority.js';
11
12
  import { startNewSession } from './sidebar-sessions.js';
12
13
  import { closeMobileSheet } from './sidebar-mobile.js';
13
14
  import {
@@ -15,20 +16,19 @@ import {
15
16
  beginSessionCreate, closeSessionCreate, chooseVendor, setCreateMenu, submitSessionCreate, submitMateSessionCreate, saveProjectDefault, retryOptions
16
17
  } from './session-create.js';
17
18
 
18
- // Every registered provider, in the established order, followed by any the
19
- // server reports that this client does not know. Installed state is the
19
+ // Installed providers first, each group in the established priority order,
20
+ // followed by unknown providers in server order. Installed state is the
20
21
  // server's, per user; the dropdown never invents or hardcodes availability.
21
22
  function vendorEntries(options) {
22
23
  var byId = {};
23
24
  options.vendors.forEach(function (v) { byId[v.id] = v; });
24
25
  var ids = VENDOR_ORDER.slice();
25
26
  options.vendors.forEach(function (v) { if (ids.indexOf(v.id) === -1) ids.push(v.id); });
26
- return ids.map(function (id) {
27
+ return sortVendorEntries(ids.map(function (id) {
27
28
  var known = byId[id];
28
29
  return { id: id, name: VENDOR_NAMES[id] || (known && known.displayName) || id, installed: !!(known && known.installed) };
29
- });
30
+ }));
30
31
  }
31
-
32
32
  function vendorLabel(id) {
33
33
  return VENDOR_NAMES[id] || id;
34
34
  }
@@ -69,7 +69,6 @@ function focusCreateRow(folderId) {
69
69
  if (target && !target.disabled) { target.focus({ preventScroll: true }); return; }
70
70
  }
71
71
  }
72
-
73
72
  function prefersReducedMotion() {
74
73
  return typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
75
74
  }
@@ -381,7 +380,8 @@ function paintRow(root) {
381
380
  }
382
381
  placeMenu(root);
383
382
  if (form.menuOpen && form.menuFocus && root.getClientRects().length) {
384
- var first = root.querySelector('[data-focus-key="item:' + (form.menuIndex || 0) + '"]');
383
+ var entry = entries[form.menuIndex || 0];
384
+ var first = entry && root.querySelector('[data-focus-key="item:' + encodeURIComponent(entry.id) + '"]');
385
385
  if (first) { first.focus({ preventScroll: true }); store.set({ sessionCreate: Object.assign({}, createState(), { menuFocus: false }) }); }
386
386
  }
387
387
  }
@@ -406,14 +406,14 @@ function renderMenu(entries, form, options, installed) {
406
406
  menu.className = "session-create-menu";
407
407
  menu.setAttribute("role", "menu");
408
408
  menu.setAttribute("aria-label", "Providers");
409
- entries.forEach(function (entry, index) {
409
+ entries.forEach(function (entry) {
410
410
  var row = document.createElement("div");
411
411
  row.className = "session-create-menu-provider";
412
412
  var html = '<img src="' + (VENDOR_AVATARS[entry.id] || VENDOR_AVATARS.claude) + '" class="session-create-icon" alt="">' +
413
413
  '<span class="session-create-menu-name"></span>' +
414
414
  (entry.installed && isExperimentalVendor(entry.id) ? '<span class="vendor-experimental-badge" aria-label="Experimental integration" title="Experimental integration; not yet validated through direct use testing">🧪</span>' : "") +
415
415
  (entry.installed ? (options.projectDefault === entry.id ? '<span class="session-create-menu-note">Default</span>' : "") : '<span class="session-create-menu-note">Not installed</span>');
416
- var item = menuItem("item:" + index, (entry.installed ? "" : "unavailable ") + (entry.id === form.vendor ? "selected" : ""), html, function () {
416
+ var item = menuItem("item:" + encodeURIComponent(entry.id), (entry.installed ? "" : "unavailable ") + (entry.id === form.vendor ? "selected" : ""), html, function () {
417
417
  if (entry.installed) { chooseVendor(entry.id); var live = createState(); store.set({ sessionCreate: Object.assign({}, live, { focusKey: "vendor", wantFocus: true }) }); }
418
418
  }, entry.installed ? "New " + entry.name + " session" : entry.name + " is not installed");
419
419
  item.querySelector(".session-create-menu-name").textContent = entry.name;
@@ -423,7 +423,7 @@ function renderMenu(entries, form, options, installed) {
423
423
  row.appendChild(item);
424
424
  if (entry.installed && options.canSetProjectDefault && options.projectDefault !== entry.id) {
425
425
  var savingThis = form.defaultSaving && form.defaultVendor === entry.id;
426
- var setDefault = menuItem("default:" + index, "session-create-default-btn", "<span></span>", function () { saveProjectDefault(entry.id); }, "Set " + entry.name + " as the project default");
426
+ var setDefault = menuItem("default:" + encodeURIComponent(entry.id), "session-create-default-btn", "<span></span>", function () { saveProjectDefault(entry.id); }, "Set " + entry.name + " as the project default");
427
427
  setDefault.firstChild.textContent = savingThis ? "Saving" : "Set default";
428
428
  setDefault.disabled = !!form.defaultSaving;
429
429
  row.appendChild(setDefault);