clay-server 5.1.0-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 (157) 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-knowledge.js +315 -136
  22. package/lib/project-mate-creation-proposal.js +1 -0
  23. package/lib/project-sessions.js +39 -2
  24. package/lib/project-user-knowledge.js +60 -0
  25. package/lib/project.js +59 -18
  26. package/lib/public/app.js +73 -34
  27. package/lib/public/clay-studio-wordmark-bold.svg +20 -0
  28. package/lib/public/css/clay-workspace.css +105 -0
  29. package/lib/public/css/debates-workbench.css +47 -0
  30. package/lib/public/css/home-debate-live.css +26 -0
  31. package/lib/public/css/home-hub.css +3 -1
  32. package/lib/public/css/home-mate-model-picker.css +15 -131
  33. package/lib/public/css/home-mate-settings.css +168 -16
  34. package/lib/public/css/icon-strip.css +249 -32
  35. package/lib/public/css/mate-conversation.css +176 -0
  36. package/lib/public/css/mate-knowledge-workbench.css +118 -0
  37. package/lib/public/css/mate-workspace-color.css +16 -0
  38. package/lib/public/css/mates.css +28 -28
  39. package/lib/public/css/messages.css +1 -114
  40. package/lib/public/css/mobile-nav.css +16 -16
  41. package/lib/public/css/overlays.css +8 -0
  42. package/lib/public/css/project-logs.css +7 -0
  43. package/lib/public/css/project-mate-creation.css +105 -0
  44. package/lib/public/css/right-workbench.css +3 -3
  45. package/lib/public/css/session-folders.css +80 -21
  46. package/lib/public/css/sidebar.css +183 -107
  47. package/lib/public/css/title-bar.css +151 -0
  48. package/lib/public/css/worker-delegation.css +47 -0
  49. package/lib/public/css/worker-proposal.css +72 -150
  50. package/lib/public/css/you.css +74 -0
  51. package/lib/public/index.html +33 -101
  52. package/lib/public/modules/account-island.js +230 -0
  53. package/lib/public/modules/app-cursors.js +19 -43
  54. package/lib/public/modules/app-debate-ui.js +4 -3
  55. package/lib/public/modules/app-header.js +106 -0
  56. package/lib/public/modules/app-message-router.js +12 -3
  57. package/lib/public/modules/app-messages.js +34 -9
  58. package/lib/public/modules/app-notifications.js +4 -7
  59. package/lib/public/modules/app-projects.js +5 -38
  60. package/lib/public/modules/app-rendering.js +12 -13
  61. package/lib/public/modules/avatar.js +25 -9
  62. package/lib/public/modules/chat-render-runtime.js +16 -4
  63. package/lib/public/modules/command-palette.js +2 -15
  64. package/lib/public/modules/cursor-sharing-preference.js +3 -3
  65. package/lib/public/modules/debate-controls.js +299 -0
  66. package/lib/public/modules/debate.js +2 -0
  67. package/lib/public/modules/debates-workbench.js +339 -0
  68. package/lib/public/modules/default-ai.js +81 -65
  69. package/lib/public/modules/home-debate-controls.js +18 -289
  70. package/lib/public/modules/home-mate-avatar-editor.js +228 -0
  71. package/lib/public/modules/home-mate-color-picker.js +66 -0
  72. package/lib/public/modules/home-mate-creation.js +1 -1
  73. package/lib/public/modules/home-mate-instructions.js +90 -0
  74. package/lib/public/modules/home-mate-model-picker.js +80 -271
  75. package/lib/public/modules/home-mate-profile-editor.js +72 -0
  76. package/lib/public/modules/home-mate-settings.js +118 -125
  77. package/lib/public/modules/home-shell.js +3 -0
  78. package/lib/public/modules/home-surface-boot.js +1 -9
  79. package/lib/public/modules/icon-strip-tooltip.js +95 -0
  80. package/lib/public/modules/knowledge-db-edit-state.js +35 -0
  81. package/lib/public/modules/knowledge-db-workbench.js +234 -0
  82. package/lib/public/modules/knowledge-history-state.js +55 -0
  83. package/lib/public/modules/knowledge-markdown-editor.js +57 -0
  84. package/lib/public/modules/knowledge-preview-links.js +70 -0
  85. package/lib/public/modules/knowledge-workbench-shell.js +21 -0
  86. package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
  87. package/lib/public/modules/mate-knowledge-workbench.js +500 -0
  88. package/lib/public/modules/mate-knowledge.js +11 -3
  89. package/lib/public/modules/mate-management.js +54 -10
  90. package/lib/public/modules/mate-sidebar.js +11 -1
  91. package/lib/public/modules/mate-workspace-color.js +33 -0
  92. package/lib/public/modules/mention.js +5 -13
  93. package/lib/public/modules/profile.js +51 -18
  94. package/lib/public/modules/project-chat-identity.js +79 -0
  95. package/lib/public/modules/project-debate-planning-workspace.js +250 -0
  96. package/lib/public/modules/project-debate-workspace.js +185 -0
  97. package/lib/public/modules/project-header-identity.js +127 -0
  98. package/lib/public/modules/project-logs-render.js +9 -4
  99. package/lib/public/modules/project-mate-creation-workspace.js +414 -0
  100. package/lib/public/modules/project-mate-navigation.js +238 -0
  101. package/lib/public/modules/project-session-navigation.js +29 -0
  102. package/lib/public/modules/project-switcher.js +6 -8
  103. package/lib/public/modules/projects-hub-view.js +5 -6
  104. package/lib/public/modules/projects-hub.js +2 -6
  105. package/lib/public/modules/qrcode.js +27 -8
  106. package/lib/public/modules/search-clay-chat.js +8 -11
  107. package/lib/public/modules/session-activity-tooltip.js +12 -0
  108. package/lib/public/modules/session-create-form.js +86 -14
  109. package/lib/public/modules/session-create.js +50 -7
  110. package/lib/public/modules/session-list-visibility.js +41 -0
  111. package/lib/public/modules/session-presence-ui.js +4 -1
  112. package/lib/public/modules/session-title-marquee.js +51 -0
  113. package/lib/public/modules/sidebar-mates.js +3 -50
  114. package/lib/public/modules/sidebar-mobile.js +63 -60
  115. package/lib/public/modules/sidebar-projects.js +84 -97
  116. package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
  117. package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
  118. package/lib/public/modules/sidebar-sessions.js +49 -50
  119. package/lib/public/modules/sidebar.js +11 -13
  120. package/lib/public/modules/thinking-lifecycle.js +7 -6
  121. package/lib/public/modules/tool-palette-order.js +4 -3
  122. package/lib/public/modules/tool-palette.js +13 -3
  123. package/lib/public/modules/tools.js +22 -22
  124. package/lib/public/modules/worker-proposal.js +42 -8
  125. package/lib/public/modules/worker-runtime-picker.js +115 -0
  126. package/lib/public/modules/you-activity.js +121 -0
  127. package/lib/public/modules/you.js +251 -0
  128. package/lib/public/style.css +16 -8
  129. package/lib/public/vendor/codemirror/LICENSE +21 -0
  130. package/lib/public/vendor/codemirror/codemirror.css +344 -0
  131. package/lib/public/vendor/codemirror/codemirror.js +9884 -0
  132. package/lib/public/vendor/codemirror/continuelist.js +101 -0
  133. package/lib/public/vendor/codemirror/markdown.js +886 -0
  134. package/lib/public/vendor/codemirror/show-hint.css +37 -0
  135. package/lib/public/vendor/codemirror/show-hint.js +523 -0
  136. package/lib/sdk-bridge.js +15 -3
  137. package/lib/server-admin.js +11 -0
  138. package/lib/server-home-chat-events.js +1 -1
  139. package/lib/server-home-chat.js +25 -3
  140. package/lib/server-home-debate-planning.js +4 -1
  141. package/lib/server-home-debates.js +2 -0
  142. package/lib/server-home-mate-creation.js +4 -1
  143. package/lib/server-mate-instructions.js +44 -0
  144. package/lib/server-mates.js +12 -3
  145. package/lib/server-palette.js +1 -1
  146. package/lib/server-settings.js +65 -1
  147. package/lib/server-user-knowledge.js +119 -0
  148. package/lib/server.js +21 -1
  149. package/lib/session-visibility.js +7 -2
  150. package/lib/sessions.js +32 -6
  151. package/lib/user-knowledge-service.js +167 -0
  152. package/lib/users-permissions.js +7 -0
  153. package/lib/users-project-mate-filter-preferences.js +39 -0
  154. package/lib/users.js +6 -0
  155. package/lib/workspace-query-access.js +4 -1
  156. package/lib/ws-schema.js +50 -0
  157. package/package.json +10 -1
@@ -0,0 +1,339 @@
1
+ // Cross-Mate debate archive and launcher. Conversation content remains in the
2
+ // owning Mate project; this panel is only an authorized index and launch pad.
3
+
4
+ import { store } from './store.js';
5
+ import { getWs } from './ws-ref.js';
6
+ import { iconHtml, refreshIcons } from './icons.js';
7
+ import { switchProject } from './app-projects.js';
8
+ import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench } from './right-workbench.js';
9
+ import { startProjectDebatePlanning } from './project-debate-planning-workspace.js';
10
+ import { isMateWorkspace } from './project-mate-navigation.js';
11
+
12
+ var panel = null;
13
+ var requestSequence = 0;
14
+ var opener = null;
15
+ var backgroundState = [];
16
+
17
+ function narrowLayout() {
18
+ return typeof window !== 'undefined' && window.matchMedia && window.matchMedia('(max-width: 1023px)').matches;
19
+ }
20
+
21
+ function isMateDebateSurface(state) {
22
+ return isMateWorkspace(state) || (state.dmMode === true && state.dmTargetUser && state.dmTargetUser.isMate === true);
23
+ }
24
+
25
+ function setNarrowBackground(hidden) {
26
+ var selectors = ['#app', '#sidebar-column', '#icon-strip', '#top-bar', '#main-column > .title-bar-content', '#dm-header-bar'];
27
+ if (hidden) {
28
+ backgroundState = [];
29
+ for (var i = 0; i < selectors.length; i++) {
30
+ var element = document.querySelector(selectors[i]);
31
+ if (!element) continue;
32
+ backgroundState.push({ element: element, inert: element.inert === true, ariaHidden: element.getAttribute('aria-hidden') });
33
+ element.inert = true;
34
+ element.setAttribute('aria-hidden', 'true');
35
+ }
36
+ return;
37
+ }
38
+ for (var j = 0; j < backgroundState.length; j++) {
39
+ backgroundState[j].element.inert = backgroundState[j].inert;
40
+ if (backgroundState[j].ariaHidden == null) backgroundState[j].element.removeAttribute('aria-hidden');
41
+ else backgroundState[j].element.setAttribute('aria-hidden', backgroundState[j].ariaHidden);
42
+ }
43
+ backgroundState = [];
44
+ }
45
+
46
+ function send(message) {
47
+ var ws = getWs();
48
+ if (!ws || ws.readyState !== 1) return false;
49
+ ws.send(JSON.stringify(message));
50
+ return true;
51
+ }
52
+
53
+ function phaseLabel(phase) {
54
+ if (phase === 'live') return 'Live';
55
+ if (phase === 'ended') return 'Ended';
56
+ if (phase === 'interrupted') return 'Interrupted';
57
+ return 'Planning';
58
+ }
59
+
60
+ function dateLabel(value) {
61
+ if (typeof value !== 'number' || !isFinite(value) || value <= 0) return 'Date unavailable';
62
+ try { return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium' }).format(new Date(value)); }
63
+ catch (error) { return new Date(value).toLocaleDateString(); }
64
+ }
65
+
66
+ function participantsLabel(participants) {
67
+ var source = Array.isArray(participants) ? participants : [];
68
+ var names = [];
69
+ for (var i = 0; i < source.length; i++) if (source[i] && source[i].name) names.push(source[i].name);
70
+ return names.length ? names.join(', ') : 'Panel not selected';
71
+ }
72
+
73
+ function ensurePanel() {
74
+ if (panel) return panel;
75
+ var host = document.getElementById('main-panels');
76
+ if (!host) return null;
77
+ panel = document.createElement('section');
78
+ panel.id = 'debates-workbench';
79
+ panel.className = 'hidden';
80
+ panel.setAttribute('role', 'region');
81
+ panel.setAttribute('aria-label', 'Debates');
82
+ panel.innerHTML =
83
+ '<header class="debates-workbench-topbar">' +
84
+ '<span class="debates-workbench-title">' + iconHtml('messages-square') + 'Debates</span>' +
85
+ '<button class="debates-workbench-new" type="button" data-debates-action="new">' + iconHtml('plus') + 'New debate</button>' +
86
+ '<div class="debates-workbench-actions">' +
87
+ '<button class="debates-workbench-icon" type="button" data-debates-action="wide" title="Widen panel" aria-label="Widen Debates panel" aria-pressed="false">' + iconHtml('chevrons-left-right') + '</button>' +
88
+ '<button class="debates-workbench-icon" type="button" data-debates-action="fullscreen" title="Toggle fullscreen" aria-label="Toggle Debates fullscreen" aria-pressed="false">' + iconHtml('maximize-2') + '</button>' +
89
+ '<button class="debates-workbench-icon" type="button" data-debates-action="close" title="Close" aria-label="Close Debates">' + iconHtml('x') + '</button>' +
90
+ '</div>' +
91
+ '</header>' +
92
+ '<div class="debates-workbench-filters" role="group" aria-label="Filter debates"></div>' +
93
+ '<form class="debates-workbench-form hidden"><label for="debates-workbench-topic">What should the debate be about?</label><textarea id="debates-workbench-topic" maxlength="1000" required placeholder="Enter a question or topic"></textarea><p class="debates-workbench-launch-status" role="alert"></p><div class="debates-workbench-form-actions"><button type="button" data-debates-action="cancel-new">Cancel</button><button type="submit">Continue in chat</button></div></form>' +
94
+ '<p class="debates-workbench-summary" role="status" aria-live="polite"></p>' +
95
+ '<div class="debates-workbench-list" role="list"></div>';
96
+ host.appendChild(panel);
97
+ panel.addEventListener('click', handleClick);
98
+ panel.addEventListener('keydown', handleKeydown);
99
+ panel.querySelector('form').addEventListener('submit', submitNewDebate);
100
+ refreshIcons();
101
+ return panel;
102
+ }
103
+
104
+ function ensureMateProjectDebatesButton() {
105
+ var button = document.getElementById('mate-project-debates-btn');
106
+ if (button) return button;
107
+ var tools = document.getElementById('session-actions');
108
+ if (!tools) return null;
109
+ button = document.createElement('button');
110
+ button.id = 'mate-project-debates-btn';
111
+ button.type = 'button';
112
+ button.className = 'palette-tile';
113
+ button.title = 'Debates';
114
+ button.setAttribute('aria-label', 'Debates');
115
+ button.innerHTML = iconHtml('messages-square') + '<span class="tool-btn-label">Debates</span>';
116
+ tools.appendChild(button);
117
+ refreshIcons(button);
118
+ return button;
119
+ }
120
+
121
+ function requestDebates() {
122
+ requestSequence += 1;
123
+ var requestId = 'debates-workbench-' + requestSequence;
124
+ store.set({ debatesWorkbenchStatus: 'loading', debatesWorkbenchRequestId: requestId, debatesWorkbenchError: '' });
125
+ if (!send({ type: 'home_debates_list', requestId: requestId })) {
126
+ store.set({ debatesWorkbenchStatus: 'error', debatesWorkbenchError: 'Reconnect to load your debates.' });
127
+ render();
128
+ return;
129
+ }
130
+ render();
131
+ }
132
+
133
+ function renderFilters() {
134
+ var filters = panel.querySelector('.debates-workbench-filters');
135
+ var active = store.get('debatesWorkbenchFilter') || 'all';
136
+ var specs = [{ key: 'all', label: 'All' }, { key: 'planning', label: 'Planning' }, { key: 'live', label: 'Live' }, { key: 'ended', label: 'Ended' }, { key: 'interrupted', label: 'Interrupted' }];
137
+ filters.innerHTML = '';
138
+ for (var i = 0; i < specs.length; i++) {
139
+ var button = document.createElement('button');
140
+ button.type = 'button';
141
+ button.className = 'debates-workbench-filter';
142
+ button.dataset.debatesFilter = specs[i].key;
143
+ button.setAttribute('aria-pressed', specs[i].key === active ? 'true' : 'false');
144
+ button.textContent = specs[i].label;
145
+ filters.appendChild(button);
146
+ }
147
+ }
148
+
149
+ function debateRow(debate) {
150
+ var row = document.createElement('button');
151
+ row.type = 'button';
152
+ row.className = 'debates-workbench-row';
153
+ row.dataset.projectSlug = debate.projectSlug || '';
154
+ row.dataset.sessionId = String(debate.localId == null ? '' : debate.localId);
155
+ row.setAttribute('role', 'listitem');
156
+ var title = document.createElement('strong');
157
+ title.textContent = debate.topic || debate.title || 'Debate planning';
158
+ var panelists = document.createElement('span');
159
+ panelists.className = 'debates-workbench-row-panel';
160
+ panelists.textContent = participantsLabel(debate.participants);
161
+ var meta = document.createElement('span');
162
+ meta.className = 'debates-workbench-row-meta';
163
+ var phase = document.createElement('span');
164
+ phase.className = 'debates-workbench-phase';
165
+ phase.textContent = phaseLabel(debate.phase);
166
+ var date = document.createElement('span');
167
+ date.textContent = dateLabel(debate.lastActivity);
168
+ meta.appendChild(phase);
169
+ meta.appendChild(date);
170
+ row.appendChild(title);
171
+ row.appendChild(panelists);
172
+ row.appendChild(meta);
173
+ return row;
174
+ }
175
+
176
+ function render() {
177
+ if (!panel || panel.classList.contains('hidden')) return;
178
+ renderFilters();
179
+ panel.querySelector('form').classList.toggle('hidden', !store.get('debatesWorkbenchCreating'));
180
+ var summary = panel.querySelector('.debates-workbench-summary');
181
+ var list = panel.querySelector('.debates-workbench-list');
182
+ var status = store.get('debatesWorkbenchStatus') || 'idle';
183
+ var filter = store.get('debatesWorkbenchFilter') || 'all';
184
+ var debates = (store.get('debatesWorkbenchItems') || []).filter(function (item) { return filter === 'all' || item.phase === filter; });
185
+ list.innerHTML = '';
186
+ if (status === 'loading' || status === 'idle') {
187
+ summary.textContent = 'Loading debates…';
188
+ list.innerHTML = '<div class="debates-workbench-empty"><strong>Gathering your debates</strong>Planning sessions and completed debates will appear here.</div>';
189
+ } else if (status === 'error') {
190
+ summary.textContent = 'Debates could not be loaded.';
191
+ var failure = document.createElement('div');
192
+ failure.className = 'debates-workbench-empty';
193
+ var failureTitle = document.createElement('strong');
194
+ failureTitle.textContent = 'Could not load debates';
195
+ var failureText = document.createElement('span');
196
+ failureText.textContent = store.get('debatesWorkbenchError') || 'Try again when the connection is available.';
197
+ failure.appendChild(failureTitle);
198
+ failure.appendChild(failureText);
199
+ list.appendChild(failure);
200
+ } else if (!debates.length) {
201
+ summary.textContent = filter === 'all' ? 'No debates yet' : 'No ' + filter + ' debates';
202
+ list.innerHTML = '<div class="debates-workbench-empty"><strong>Nothing here yet</strong>Use New debate to plan one with Clay in the main chat.</div>';
203
+ } else {
204
+ summary.textContent = debates.length + (debates.length === 1 ? ' debate' : ' debates');
205
+ for (var i = 0; i < debates.length; i++) list.appendChild(debateRow(debates[i]));
206
+ }
207
+ list.scrollTop = Number(store.get('debatesWorkbenchScrollTop')) || 0;
208
+ refreshIcons();
209
+ }
210
+
211
+ function handleKeydown(event) {
212
+ if (event.key === 'Escape') {
213
+ event.preventDefault();
214
+ closeDebatesWorkbench(true);
215
+ return;
216
+ }
217
+ if (event.key !== 'Tab' || !narrowLayout()) return;
218
+ var controls = panel.querySelectorAll('button:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])');
219
+ if (!controls.length) return;
220
+ var first = controls[0];
221
+ var last = controls[controls.length - 1];
222
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
223
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
224
+ }
225
+
226
+ function applyWindowState(wide, fullscreen) {
227
+ store.set({ debatesWorkbenchWide: !!wide, debatesWorkbenchFullscreen: !!fullscreen });
228
+ panel.classList.toggle('debates-workbench-wide', !!wide && !fullscreen);
229
+ panel.classList.toggle('panel-fullscreen', !!fullscreen);
230
+ panel.querySelector('[data-debates-action="wide"]').setAttribute('aria-pressed', wide ? 'true' : 'false');
231
+ panel.querySelector('[data-debates-action="fullscreen"]').setAttribute('aria-pressed', fullscreen ? 'true' : 'false');
232
+ }
233
+
234
+ function handleClick(event) {
235
+ var filter = event.target.closest('[data-debates-filter]');
236
+ if (filter) { store.set({ debatesWorkbenchFilter: filter.dataset.debatesFilter }); render(); return; }
237
+ var row = event.target.closest('.debates-workbench-row');
238
+ if (row) {
239
+ var localId = Number(row.dataset.sessionId);
240
+ if (!row.dataset.projectSlug || !Number.isSafeInteger(localId) || localId < 1) return;
241
+ store.set({ pendingDebateNavigation: { projectSlug: row.dataset.projectSlug, sessionId: localId } });
242
+ if (narrowLayout()) closeDebatesWorkbench(false);
243
+ switchProject(row.dataset.projectSlug);
244
+ flushPendingNavigation();
245
+ return;
246
+ }
247
+ var action = event.target.closest('[data-debates-action]');
248
+ if (!action) return;
249
+ if (action.dataset.debatesAction === 'close') closeDebatesWorkbench(true);
250
+ if (action.dataset.debatesAction === 'new') {
251
+ store.set({ debatesWorkbenchCreating: true }); render();
252
+ panel.querySelector('textarea').focus({ preventScroll: true });
253
+ }
254
+ if (action.dataset.debatesAction === 'cancel-new') { store.set({ debatesWorkbenchCreating: false }); render(); }
255
+ if (action.dataset.debatesAction === 'wide') applyWindowState(!store.get('debatesWorkbenchWide'), false);
256
+ if (action.dataset.debatesAction === 'fullscreen') applyWindowState(false, !store.get('debatesWorkbenchFullscreen'));
257
+ }
258
+
259
+ function submitNewDebate(event) {
260
+ event.preventDefault();
261
+ var input = panel.querySelector('textarea');
262
+ var topic = input.value.trim();
263
+ if (!topic) { input.focus(); return; }
264
+ var status = panel.querySelector('.debates-workbench-launch-status');
265
+ status.textContent = 'Opening Clay in the main chat…';
266
+ if (!startProjectDebatePlanning(topic)) {
267
+ status.textContent = store.get('projectDebatePlanningError') || 'Clay is unavailable. Refresh and try again.';
268
+ input.focus();
269
+ return;
270
+ }
271
+ input.value = '';
272
+ store.set({ debatesWorkbenchCreating: false });
273
+ closeDebatesWorkbench();
274
+ }
275
+
276
+ function flushPendingNavigation() {
277
+ var pending = store.get('pendingDebateNavigation');
278
+ var ws = getWs();
279
+ if (!pending || store.get('activeProjectSlug') !== pending.projectSlug || !ws || ws.readyState !== 1) return;
280
+ store.set({ pendingDebateNavigation: null });
281
+ ws.send(JSON.stringify({ type: 'switch_session', id: pending.sessionId }));
282
+ }
283
+
284
+ export function handleDebatesWorkbenchState(msg) {
285
+ if (!msg || msg.type !== 'home_debates_state') return false;
286
+ if (!isMateDebateSurface(store.snap())) return true;
287
+ if (msg.requestId && msg.requestId !== store.get('debatesWorkbenchRequestId')) return true;
288
+ store.set({ debatesWorkbenchStatus: msg.status === 'error' || msg.error ? 'error' : 'ready', debatesWorkbenchItems: Array.isArray(msg.debates) ? msg.debates : [], debatesWorkbenchError: msg.error || '' });
289
+ render();
290
+ return true;
291
+ }
292
+
293
+ export function openDebatesWorkbench(trigger) {
294
+ if (!isMateDebateSurface(store.snap())) return false;
295
+ if (!ensurePanel()) return;
296
+ opener = trigger && trigger.focus ? trigger : document.activeElement;
297
+ claimRightWorkbench('debates');
298
+ panel.classList.remove('hidden');
299
+ var narrow = narrowLayout();
300
+ panel.setAttribute('role', narrow ? 'dialog' : 'region');
301
+ panel.setAttribute('aria-modal', narrow ? 'true' : 'false');
302
+ setNarrowBackground(narrow);
303
+ applyWindowState(store.get('debatesWorkbenchWide'), store.get('debatesWorkbenchFullscreen'));
304
+ requestDebates();
305
+ requestAnimationFrame(function () { panel.querySelector('[data-debates-action="new"]').focus({ preventScroll: true }); });
306
+ }
307
+
308
+ export function closeDebatesWorkbench(restoreFocus) {
309
+ if (panel) {
310
+ var list = panel.querySelector('.debates-workbench-list');
311
+ if (list) store.set({ debatesWorkbenchScrollTop: list.scrollTop });
312
+ panel.classList.add('hidden');
313
+ }
314
+ setNarrowBackground(false);
315
+ releaseRightWorkbench('debates');
316
+ if (restoreFocus && opener && opener.isConnected) opener.focus({ preventScroll: true });
317
+ }
318
+
319
+ export function initDebatesWorkbench() {
320
+ registerRightWorkbench('debates', function () { closeDebatesWorkbench(false); });
321
+ var buttons = [ensureMateProjectDebatesButton(), document.getElementById('debates-btn'), document.getElementById('mate-debates-btn')];
322
+ for (var i = 0; i < buttons.length; i++) if (buttons[i]) buttons[i].addEventListener('click', function (event) {
323
+ if (panel && !panel.classList.contains('hidden')) closeDebatesWorkbench(true);
324
+ else openDebatesWorkbench(event.currentTarget);
325
+ });
326
+ store.subscribe(function (state, previous) {
327
+ if (state.activeProjectSlug !== previous.activeProjectSlug || state.connected !== previous.connected) flushPendingNavigation();
328
+ var wasMateWorkspace = isMateDebateSurface(previous);
329
+ var isMate = isMateDebateSurface(state);
330
+ if (wasMateWorkspace && !isMate) {
331
+ requestSequence += 1;
332
+ store.set({ debatesWorkbenchRequestId: null });
333
+ if (panel && !panel.classList.contains('hidden')) closeDebatesWorkbench(false);
334
+ } else if (state.currentSlug !== previous.currentSlug && panel && !panel.classList.contains('hidden')) {
335
+ if (isMate) requestDebates();
336
+ else closeDebatesWorkbench(false);
337
+ }
338
+ });
339
+ }
@@ -7,7 +7,9 @@ import { refreshIcons } from './icons.js';
7
7
 
8
8
  var sequence = 0;
9
9
  var opener = null;
10
+ var preferredOpener = null;
10
11
  var popover = null;
12
+ var inlineTarget = null;
11
13
 
12
14
  function nextRequestId() {
13
15
  sequence += 1;
@@ -49,6 +51,7 @@ function close() {
49
51
 
50
52
  function position() {
51
53
  if (!popover || !opener) return;
54
+ if (inlineTarget) return;
52
55
  var rect = opener.getBoundingClientRect();
53
56
  var width = Math.min(390, Math.max(0, window.innerWidth - 24));
54
57
  popover.style.width = width + "px";
@@ -101,6 +104,40 @@ function addFieldLabel(text, control) {
101
104
  popover.appendChild(label);
102
105
  }
103
106
 
107
+ function inlineCurrentSelection(state, draft) {
108
+ return state.preference || state.selection || draft || {};
109
+ }
110
+
111
+ function renderInlineSummary() {
112
+ var state = store.get("defaultAiState") || {};
113
+ var draft = store.get("defaultAiDraft") || {};
114
+ var current = inlineCurrentSelection(state, draft);
115
+ var vendor = current.vendor ? (VENDOR_NAMES[current.vendor] || current.vendor) : "Loading default…";
116
+ var model = current.model || "Model unavailable";
117
+ var effort = current.effort || "Provider default";
118
+ popover.innerHTML = '';
119
+ var summary = document.createElement('button');
120
+ summary.type = 'button';
121
+ summary.className = 'default-ai-summary';
122
+ summary.id = 'account-ai-summary';
123
+ summary.setAttribute('aria-label', 'Default AI: ' + vendor + ', ' + model + ', ' + effort);
124
+ var label = document.createElement('span');
125
+ label.className = 'default-ai-summary-label';
126
+ label.textContent = 'Default AI';
127
+ var value = document.createElement('span');
128
+ value.className = 'default-ai-summary-value';
129
+ value.textContent = vendor + ' · ' + model + ' · ' + effort;
130
+ var icon = document.createElement('i');
131
+ icon.setAttribute('data-lucide', 'chevron-right');
132
+ icon.setAttribute('aria-hidden', 'true');
133
+ summary.appendChild(label);
134
+ summary.appendChild(value);
135
+ summary.appendChild(icon);
136
+ popover.appendChild(summary);
137
+ summary.addEventListener('click', function () { store.set({ defaultAiInlineEditing: true }); });
138
+ refreshIcons();
139
+ }
140
+
104
141
  function render() {
105
142
  if (!popover) return;
106
143
  var state = store.get("defaultAiState") || {};
@@ -109,7 +146,17 @@ function render() {
109
146
  var catalog = (state.catalogs || {})[draft.vendor] || null;
110
147
  var models = catalog && catalog.models || [];
111
148
 
112
- popover.innerHTML = '<div class="default-ai-title">Default AI</div><div class="default-ai-copy">Used for new Clay interviews and built-in AI assistance.</div>';
149
+ if (inlineTarget && store.get("defaultAiInlineEditing") !== true) {
150
+ renderInlineSummary();
151
+ position();
152
+ return;
153
+ }
154
+
155
+ if (inlineTarget) {
156
+ popover.innerHTML = '<div class="default-ai-edit-heading"><strong>Default AI</strong><button type="button" class="default-ai-cancel" aria-label="Cancel Default AI editing">Cancel</button></div>';
157
+ } else {
158
+ popover.innerHTML = '<div class="default-ai-title">Default AI</div><div class="default-ai-copy">Used for new Clay interviews and built-in AI assistance.</div>';
159
+ }
113
160
  if (state.loading && !vendors.length) {
114
161
  addStatus("Loading available AI providers…", false);
115
162
  position();
@@ -170,8 +217,8 @@ function render() {
170
217
  var save = document.createElement("button");
171
218
  save.type = "button";
172
219
  save.className = "default-ai-save";
173
- save.textContent = state.saving ? "Saving…" : "Save default";
174
- save.disabled = state.saving === true || vendors.indexOf(vendor.value) === -1 || !selectedModel || !selectedEffort;
220
+ save.textContent = state.saving ? "Applying…" : "Apply";
221
+ save.disabled = state.saving === true || store.get("defaultAiDraftDirty") !== true || vendors.indexOf(vendor.value) === -1 || !selectedModel || !selectedEffort;
175
222
  save.addEventListener("click", function () {
176
223
  var id = nextRequestId();
177
224
  var latest = store.get("defaultAiState") || {};
@@ -181,6 +228,13 @@ function render() {
181
228
  }
182
229
  render();
183
230
  });
231
+ if (inlineTarget) {
232
+ var cancel = popover.querySelector(".default-ai-cancel");
233
+ cancel.addEventListener("click", function () {
234
+ var canonical = inlineCurrentSelection(store.get("defaultAiState") || {}, store.get("defaultAiDraft") || {});
235
+ store.set({ defaultAiDraft: Object.assign({}, canonical), defaultAiDraftDirty: false, defaultAiInlineEditing: false });
236
+ });
237
+ }
184
238
  popover.appendChild(save);
185
239
  if (state.error) addStatus(state.error, true);
186
240
  position();
@@ -293,71 +347,25 @@ export function handleDefaultAiMessage(msg) {
293
347
  }
294
348
 
295
349
  export function initDefaultAi() {
296
- var actions = document.querySelector(".user-island-actions");
297
- if (!actions || document.getElementById("default-ai-btn")) return;
298
- var button = document.createElement("button");
299
- button.id = "default-ai-btn";
300
- button.className = "default-ai-button";
301
- button.title = "Default AI";
302
- button.setAttribute("aria-label", "Default AI");
303
- button.setAttribute("aria-haspopup", "dialog");
304
- button.setAttribute("aria-expanded", "false");
305
- button.innerHTML = '<span class="default-ai-avatar"></span>';
306
- var settings = document.getElementById("user-settings-btn");
307
- if (settings) actions.insertBefore(button, settings);
308
- else actions.appendChild(button);
309
- popover = document.createElement("section");
310
- popover.id = "default-ai-popover";
311
- popover.className = "default-ai-popover hidden";
312
- popover.setAttribute("role", "dialog");
313
- popover.setAttribute("aria-label", "Default AI settings");
314
- document.body.appendChild(popover);
315
- button.addEventListener("click", function () {
316
- if (!popover.classList.contains("hidden")) { close(); return; }
317
- opener = button;
318
- button.setAttribute("aria-expanded", "true");
319
- popover.classList.remove("hidden");
320
- requestDefaultAi();
321
- render();
322
- });
323
- document.addEventListener("click", function (event) {
324
- var path = typeof event.composedPath === "function" ? event.composedPath() : [];
325
- var clickedButton = path.indexOf(button) !== -1 || button.contains(event.target);
326
- var clickedPopover = path.indexOf(popover) !== -1 || popover.contains(event.target);
327
- if (!popover || popover.classList.contains("hidden") || clickedPopover || clickedButton) return;
328
- close();
329
- });
330
- document.addEventListener("keydown", function (event) {
331
- if (event.key !== "Escape" || !popover || popover.classList.contains("hidden")) return;
332
- event.preventDefault();
333
- close();
334
- });
335
- window.addEventListener("resize", position);
336
- window.addEventListener("scroll", position, true);
337
- updateBadge();
350
+ return;
338
351
  }
339
352
 
340
- export function openDefaultAi() {
341
- var button = document.getElementById("default-ai-btn");
342
- if (button && popover && popover.classList.contains("hidden")) button.click();
353
+ export function openDefaultAi(openerElement) {
354
+ document.dispatchEvent(new CustomEvent('clay:open-account-default-ai', { detail: { opener: openerElement || null } }));
343
355
  }
344
356
 
345
- function updateBadge() {
346
- var avatar = document.querySelector("#default-ai-btn .default-ai-avatar");
347
- var selection = (store.get("defaultAiState") || {}).selection;
348
- if (!avatar) return;
349
- var source = selection && VENDOR_AVATARS[selection.vendor];
350
- var image = avatar.querySelector("img");
351
- if (!source) {
352
- if (image) image.remove();
353
- return;
354
- }
355
- if (!image) {
356
- image = document.createElement("img");
357
- image.alt = "";
358
- avatar.appendChild(image);
359
- }
360
- if (image.getAttribute("src") !== source) image.setAttribute("src", source);
357
+ export function mountDefaultAi(target) {
358
+ inlineTarget = target;
359
+ popover = target;
360
+ opener = target;
361
+ render();
362
+ }
363
+
364
+ export function unmountDefaultAi(target) {
365
+ if (inlineTarget !== target) return;
366
+ inlineTarget = null;
367
+ opener = null;
368
+ popover = null;
361
369
  }
362
370
 
363
371
  store.subscribe(function (state, previous) {
@@ -371,7 +379,15 @@ store.subscribe(function (state, previous) {
371
379
  if (accountId && state.connected) requestDefaultAi();
372
380
  return;
373
381
  }
382
+ if (state.defaultAiInlineEditing !== previous.defaultAiInlineEditing) {
383
+ if (popover) render();
384
+ return;
385
+ }
374
386
  if (state.defaultAiState === previous.defaultAiState) return;
375
- updateBadge();
387
+ if (inlineTarget && previous.defaultAiState && previous.defaultAiState.saving === true && state.defaultAiState && state.defaultAiState.saving === false && state.defaultAiDraftDirty !== true && state.defaultAiInlineEditing === true) {
388
+ store.set({ defaultAiInlineEditing: false });
389
+ render();
390
+ return;
391
+ }
376
392
  if (popover && !popover.classList.contains("hidden")) render();
377
393
  });