clay-server 5.1.0-beta.1 → 5.1.0-beta.3
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.
- package/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/bin/cli.js +9 -91
- package/lib/builtin-mates.js +7 -7
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon-settings.js +11 -0
- package/lib/daemon.js +10 -37
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/linear-store.js +35 -8
- package/lib/mate-identity-file.js +39 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +37 -22
- package/lib/mate-ready-creation.js +2 -1
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates-identity.js +4 -4
- package/lib/mates-prompts.js +4 -3
- package/lib/mates.js +30 -11
- package/lib/os-users.js +5 -16
- package/lib/project-connection.js +36 -9
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +4 -2
- package/lib/project-filesystem.js +21 -39
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-mate-interaction.js +7 -6
- package/lib/project-server-settings.js +31 -0
- package/lib/project-sessions.js +92 -182
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +62 -21
- package/lib/public/app.js +79 -71
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/input.css +3 -1
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/menus.css +3 -0
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +15 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/project-settings-modal.css +56 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/server-settings-system.css +125 -0
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/session-github.css +25 -16
- package/lib/public/css/settings-ui.css +247 -22
- package/lib/public/css/shared-browser.css +7 -3
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +156 -1
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +206 -548
- package/lib/public/modules/account-island.js +232 -0
- package/lib/public/modules/admin-settings-email.js +197 -0
- package/lib/public/modules/admin-settings-invitations.js +183 -0
- package/lib/public/modules/admin-settings-projects.js +198 -0
- package/lib/public/modules/admin-settings-ui.js +100 -0
- package/lib/public/modules/admin-settings-users.js +331 -0
- package/lib/public/modules/admin.js +19 -949
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +47 -61
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rate-limit.js +70 -12
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +30 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/context-sources.js +27 -18
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +88 -65
- package/lib/public/modules/header-tui-font.js +10 -20
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/linear-settings.js +3 -2
- package/lib/public/modules/markdown.js +5 -6
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/notification-settings.js +81 -0
- package/lib/public/modules/notifications.js +44 -28
- package/lib/public/modules/personal-settings-dialog.js +51 -0
- package/lib/public/modules/profile.js +66 -24
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-settings-environment.js +106 -0
- package/lib/public/modules/project-settings.js +72 -628
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/server-settings-controls.js +316 -0
- package/lib/public/modules/server-settings-environment.js +194 -0
- package/lib/public/modules/server-settings-navigation.js +39 -0
- package/lib/public/modules/server-settings-state.js +54 -0
- package/lib/public/modules/server-settings.js +116 -788
- package/lib/public/modules/server-storage-settings.js +84 -0
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-github.js +2 -1
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +3 -0
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/settings-env-values.js +34 -0
- package/lib/public/modules/settings-select.js +121 -0
- package/lib/public/modules/shared-browser.js +22 -12
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/stt-picker.js +14 -5
- package/lib/public/modules/terminal-prefs.js +22 -0
- package/lib/public/modules/theme.js +88 -52
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/user-settings-account.js +318 -0
- package/lib/public/modules/user-settings-appearance.js +55 -0
- package/lib/public/modules/user-settings-editors.js +24 -0
- package/lib/public/modules/user-settings-integrations.js +104 -0
- package/lib/public/modules/user-settings-layout.js +80 -0
- package/lib/public/modules/user-settings-preferences.js +48 -0
- package/lib/public/modules/user-settings-profile.js +53 -0
- package/lib/public/modules/user-settings-themes.js +38 -0
- package/lib/public/modules/user-settings-voice.js +75 -0
- package/lib/public/modules/user-settings.js +53 -480
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +20 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/sdk-message-processor.js +16 -4
- package/lib/sdk-quota-snapshot.js +37 -0
- package/lib/server-admin.js +11 -0
- package/lib/server-appearance-settings.js +71 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-linear.js +14 -8
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +14 -4
- package/lib/server-notification-settings.js +67 -0
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +69 -1
- package/lib/server-storage.js +57 -0
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +31 -3
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +35 -10
- package/lib/startup-projects.js +40 -0
- package/lib/storage-native-walk.js +85 -0
- package/lib/storage-usage.js +144 -0
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-preferences.js +0 -74
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -4
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +52 -4
- package/lib/yoke/acp-process-manager.js +2 -2
- package/lib/yoke/adapters/codex.js +12 -52
- package/lib/yoke/codex-app-server.js +2 -2
- package/lib/yoke/codex-model-catalog.js +52 -0
- package/lib/yoke/codex-rate-limits.js +26 -0
- package/package.json +12 -3
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { confirmSettingsAction } from './server-settings-state.js';
|
|
2
|
+
import { enhanceSettingsSelects } from './settings-select.js';
|
|
1
3
|
// User-island Default AI picker. Canonical state and the unsaved draft are separate.
|
|
2
4
|
|
|
3
5
|
import { store } from './store.js';
|
|
@@ -7,7 +9,9 @@ import { refreshIcons } from './icons.js';
|
|
|
7
9
|
|
|
8
10
|
var sequence = 0;
|
|
9
11
|
var opener = null;
|
|
12
|
+
var preferredOpener = null;
|
|
10
13
|
var popover = null;
|
|
14
|
+
var inlineTarget = null;
|
|
11
15
|
|
|
12
16
|
function nextRequestId() {
|
|
13
17
|
sequence += 1;
|
|
@@ -49,6 +53,7 @@ function close() {
|
|
|
49
53
|
|
|
50
54
|
function position() {
|
|
51
55
|
if (!popover || !opener) return;
|
|
56
|
+
if (inlineTarget) return;
|
|
52
57
|
var rect = opener.getBoundingClientRect();
|
|
53
58
|
var width = Math.min(390, Math.max(0, window.innerWidth - 24));
|
|
54
59
|
popover.style.width = width + "px";
|
|
@@ -101,6 +106,41 @@ function addFieldLabel(text, control) {
|
|
|
101
106
|
popover.appendChild(label);
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
function inlineCurrentSelection(state, draft) {
|
|
110
|
+
return state.preference || state.selection || draft || {};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function renderInlineSummary() {
|
|
114
|
+
var state = store.get("defaultAiState") || {};
|
|
115
|
+
var draft = store.get("defaultAiDraft") || {};
|
|
116
|
+
var current = inlineCurrentSelection(state, draft);
|
|
117
|
+
var vendor = current.vendor ? (VENDOR_NAMES[current.vendor] || current.vendor) : "Loading default…";
|
|
118
|
+
var model = current.model || "Model unavailable";
|
|
119
|
+
var effort = current.effort || "Provider default";
|
|
120
|
+
popover.innerHTML = '';
|
|
121
|
+
var summary = document.createElement('button');
|
|
122
|
+
summary.type = 'button';
|
|
123
|
+
summary.className = 'default-ai-summary';
|
|
124
|
+
summary.id = 'account-ai-summary';
|
|
125
|
+
summary.setAttribute('aria-label', 'Default AI: ' + vendor + ', ' + model + ', ' + effort);
|
|
126
|
+
var label = document.createElement('span');
|
|
127
|
+
label.className = 'default-ai-summary-label';
|
|
128
|
+
label.textContent = 'Default AI';
|
|
129
|
+
var value = document.createElement('span');
|
|
130
|
+
value.className = 'default-ai-summary-value';
|
|
131
|
+
value.textContent = vendor + ' · ' + model + ' · ' + effort;
|
|
132
|
+
var icon = document.createElement('i');
|
|
133
|
+
icon.setAttribute('data-lucide', 'chevron-right');
|
|
134
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
135
|
+
summary.appendChild(label);
|
|
136
|
+
summary.appendChild(value);
|
|
137
|
+
summary.appendChild(icon);
|
|
138
|
+
popover.appendChild(summary);
|
|
139
|
+
summary.addEventListener('click', function () { store.set({ defaultAiInlineEditing: true }); });
|
|
140
|
+
if(state.error)addStatus(state.error,true);
|
|
141
|
+
refreshIcons();
|
|
142
|
+
}
|
|
143
|
+
|
|
104
144
|
function render() {
|
|
105
145
|
if (!popover) return;
|
|
106
146
|
var state = store.get("defaultAiState") || {};
|
|
@@ -109,7 +149,27 @@ function render() {
|
|
|
109
149
|
var catalog = (state.catalogs || {})[draft.vendor] || null;
|
|
110
150
|
var models = catalog && catalog.models || [];
|
|
111
151
|
|
|
112
|
-
|
|
152
|
+
if (inlineTarget && store.get("defaultAiInlineEditing") !== true) {
|
|
153
|
+
renderInlineSummary();
|
|
154
|
+
position();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (inlineTarget) {
|
|
159
|
+
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>';
|
|
160
|
+
} else {
|
|
161
|
+
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>';
|
|
162
|
+
}
|
|
163
|
+
if (inlineTarget) {
|
|
164
|
+
var cancel = popover.querySelector(".default-ai-cancel");
|
|
165
|
+
cancel.addEventListener("click", function () {
|
|
166
|
+
function discard() {
|
|
167
|
+
var canonical = inlineCurrentSelection(store.get("defaultAiState") || {}, store.get("defaultAiDraft") || {});
|
|
168
|
+
store.set({ defaultAiDraft: Object.assign({}, canonical), defaultAiDraftDirty: false, defaultAiInlineEditing: false });
|
|
169
|
+
}
|
|
170
|
+
if(store.get("defaultAiDraftDirty"))confirmSettingsAction("Discard unsaved AI defaults?", "Discard", discard);else discard();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
113
173
|
if (state.loading && !vendors.length) {
|
|
114
174
|
addStatus("Loading available AI providers…", false);
|
|
115
175
|
position();
|
|
@@ -170,8 +230,8 @@ function render() {
|
|
|
170
230
|
var save = document.createElement("button");
|
|
171
231
|
save.type = "button";
|
|
172
232
|
save.className = "default-ai-save";
|
|
173
|
-
save.textContent = state.saving ? "
|
|
174
|
-
save.disabled = state.saving === true || vendors.indexOf(vendor.value) === -1 || !selectedModel || !selectedEffort;
|
|
233
|
+
save.textContent = state.saving ? "Applying…" : "Apply";
|
|
234
|
+
save.disabled = state.saving === true || store.get("defaultAiDraftDirty") !== true || vendors.indexOf(vendor.value) === -1 || !selectedModel || !selectedEffort;
|
|
175
235
|
save.addEventListener("click", function () {
|
|
176
236
|
var id = nextRequestId();
|
|
177
237
|
var latest = store.get("defaultAiState") || {};
|
|
@@ -182,6 +242,7 @@ function render() {
|
|
|
182
242
|
render();
|
|
183
243
|
});
|
|
184
244
|
popover.appendChild(save);
|
|
245
|
+
enhanceSettingsSelects(popover);
|
|
185
246
|
if (state.error) addStatus(state.error, true);
|
|
186
247
|
position();
|
|
187
248
|
refreshIcons();
|
|
@@ -293,71 +354,25 @@ export function handleDefaultAiMessage(msg) {
|
|
|
293
354
|
}
|
|
294
355
|
|
|
295
356
|
export function initDefaultAi() {
|
|
296
|
-
|
|
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();
|
|
357
|
+
return;
|
|
338
358
|
}
|
|
339
359
|
|
|
340
|
-
export function openDefaultAi() {
|
|
341
|
-
|
|
342
|
-
if (button && popover && popover.classList.contains("hidden")) button.click();
|
|
360
|
+
export function openDefaultAi(openerElement) {
|
|
361
|
+
document.dispatchEvent(new CustomEvent('clay:open-account-default-ai', { detail: { opener: openerElement || null } }));
|
|
343
362
|
}
|
|
344
363
|
|
|
345
|
-
function
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
image.alt = "";
|
|
358
|
-
avatar.appendChild(image);
|
|
359
|
-
}
|
|
360
|
-
if (image.getAttribute("src") !== source) image.setAttribute("src", source);
|
|
364
|
+
export function mountDefaultAi(target) {
|
|
365
|
+
inlineTarget = target;
|
|
366
|
+
popover = target;
|
|
367
|
+
opener = target;
|
|
368
|
+
render();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function unmountDefaultAi(target) {
|
|
372
|
+
if (inlineTarget !== target) return;
|
|
373
|
+
inlineTarget = null;
|
|
374
|
+
opener = null;
|
|
375
|
+
popover = null;
|
|
361
376
|
}
|
|
362
377
|
|
|
363
378
|
store.subscribe(function (state, previous) {
|
|
@@ -371,7 +386,15 @@ store.subscribe(function (state, previous) {
|
|
|
371
386
|
if (accountId && state.connected) requestDefaultAi();
|
|
372
387
|
return;
|
|
373
388
|
}
|
|
389
|
+
if (state.defaultAiInlineEditing !== previous.defaultAiInlineEditing) {
|
|
390
|
+
if (popover) render();
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
374
393
|
if (state.defaultAiState === previous.defaultAiState) return;
|
|
375
|
-
|
|
394
|
+
if (inlineTarget && previous.defaultAiState && previous.defaultAiState.saving === true && state.defaultAiState && state.defaultAiState.saving === false && state.defaultAiDraftDirty !== true && state.defaultAiInlineEditing === true) {
|
|
395
|
+
store.set({ defaultAiInlineEditing: false });
|
|
396
|
+
render();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
376
399
|
if (popover && !popover.classList.contains("hidden")) render();
|
|
377
400
|
});
|
|
@@ -7,23 +7,14 @@
|
|
|
7
7
|
// PUT /api/user/terminal-font.
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
saveTerminalFont,
|
|
11
|
+
TERMINAL_FONT_OPTIONS,
|
|
11
12
|
getTerminalFontFamily,
|
|
12
13
|
getTerminalFontSize,
|
|
13
14
|
onTerminalFontChange,
|
|
14
15
|
} from './terminal-prefs.js';
|
|
15
16
|
|
|
16
|
-
var FONT_OPTIONS =
|
|
17
|
-
{ label: "SF Mono", family: "'SF Mono', Menlo, Monaco, 'Courier New', monospace" },
|
|
18
|
-
{ label: "JetBrains Mono", family: "'JetBrains Mono', 'SF Mono', Menlo, monospace" },
|
|
19
|
-
{ label: "Fira Code", family: "'Fira Code', 'SF Mono', Menlo, monospace" },
|
|
20
|
-
{ label: "Cascadia Code", family: "'Cascadia Code', 'SF Mono', Menlo, monospace" },
|
|
21
|
-
{ label: "IBM Plex Mono", family: "'IBM Plex Mono', 'SF Mono', Menlo, monospace" },
|
|
22
|
-
{ label: "Source Code Pro", family: "'Source Code Pro', 'SF Mono', Menlo, monospace" },
|
|
23
|
-
{ label: "Roboto Mono", family: "'Roboto Mono', 'SF Mono', Menlo, monospace" },
|
|
24
|
-
{ label: "D2 Coding", family: "'D2 coding', 'D2Coding', 'SF Mono', Menlo, monospace" },
|
|
25
|
-
{ label: "System mono", family: "ui-monospace, monospace" },
|
|
26
|
-
];
|
|
17
|
+
var FONT_OPTIONS = TERMINAL_FONT_OPTIONS;
|
|
27
18
|
|
|
28
19
|
var MIN_SIZE = 9;
|
|
29
20
|
var MAX_SIZE = 32;
|
|
@@ -48,11 +39,12 @@ function escapeHtml(s) {
|
|
|
48
39
|
}
|
|
49
40
|
|
|
50
41
|
function persistTermFont(family, size) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
var status = popoverEl.querySelector('[role=status]');
|
|
43
|
+
status.textContent = 'Saving…';
|
|
44
|
+
popoverEl.querySelectorAll('button').forEach(function (button) {button.disabled = true;});
|
|
45
|
+
saveTerminalFont(family, size).then(function () {status.textContent = 'Saved.';})
|
|
46
|
+
.catch(function (error) {status.textContent = error.message;})
|
|
47
|
+
.finally(function () {popoverEl.querySelectorAll('button').forEach(function (button) {button.disabled = false;});syncSize();});
|
|
56
48
|
}
|
|
57
49
|
|
|
58
50
|
function syncSize() {
|
|
@@ -96,7 +88,6 @@ function buildPopover() {
|
|
|
96
88
|
(function (family) {
|
|
97
89
|
item.addEventListener('click', function (e) {
|
|
98
90
|
e.stopPropagation();
|
|
99
|
-
applyTerminalFont(family, undefined);
|
|
100
91
|
persistTermFont(family, undefined);
|
|
101
92
|
});
|
|
102
93
|
})(opt.family);
|
|
@@ -127,16 +118,15 @@ function buildPopover() {
|
|
|
127
118
|
sizeDecEl.addEventListener('click', function (e) {
|
|
128
119
|
e.stopPropagation();
|
|
129
120
|
var next = Math.max(MIN_SIZE, getTerminalFontSize() - 1);
|
|
130
|
-
applyTerminalFont(undefined, next);
|
|
131
121
|
persistTermFont(undefined, next);
|
|
132
122
|
});
|
|
133
123
|
sizeIncEl.addEventListener('click', function (e) {
|
|
134
124
|
e.stopPropagation();
|
|
135
125
|
var next = Math.min(MAX_SIZE, getTerminalFontSize() + 1);
|
|
136
|
-
applyTerminalFont(undefined, next);
|
|
137
126
|
persistTermFont(undefined, next);
|
|
138
127
|
});
|
|
139
128
|
|
|
129
|
+
var status = document.createElement('p');status.setAttribute('role','status');status.className='settings-status';popoverEl.appendChild(status);
|
|
140
130
|
document.body.appendChild(popoverEl);
|
|
141
131
|
return popoverEl;
|
|
142
132
|
}
|
|
@@ -1,295 +1,24 @@
|
|
|
1
1
|
import { store } from './store.js';
|
|
2
2
|
import { getWs } from './ws-ref.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
var composing = false;
|
|
20
|
-
|
|
21
|
-
function textElement(tag, className, text) {
|
|
22
|
-
var element = document.createElement(tag);
|
|
23
|
-
element.className = className;
|
|
24
|
-
element.textContent = text || "";
|
|
25
|
-
return element;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function findHeader(messages) {
|
|
29
|
-
for (var i = (messages || []).length - 1; i >= 0; i--) if (messages[i] && messages[i].role === "debate_header") return messages[i];
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function findActiveTurn(messages) {
|
|
34
|
-
for (var i = (messages || []).length - 1; i >= 0; i--) {
|
|
35
|
-
if (messages[i] && messages[i].role === "debate_turn" && messages[i].status === "active") return messages[i];
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function homeDebateControlState(messages) {
|
|
41
|
-
var header = findHeader(messages);
|
|
42
|
-
if (!header || ["live", "ended", "interrupted"].indexOf(header.phase) === -1) return null;
|
|
43
|
-
var mode = header.phase === "live" ? (header.interaction || "default") : "terminal";
|
|
44
|
-
return { mode: mode, header: header, turn: findActiveTurn(messages), phase: header.phase };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function ensureElements() {
|
|
48
|
-
var nextSlot = document.getElementById("home-debate-controls-slot");
|
|
49
|
-
if (slotEl === nextSlot) return !!slotEl;
|
|
50
|
-
slotEl = nextSlot;
|
|
51
|
-
normalComposerEl = document.getElementById("home-mate-chat-composer");
|
|
52
|
-
modelEl = document.getElementById("home-mate-chat-session-model");
|
|
53
|
-
controlEl = null;
|
|
54
|
-
controlMode = null;
|
|
55
|
-
controlStateKey = null;
|
|
56
|
-
return !!slotEl;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function clearControls() {
|
|
60
|
-
if (slotEl) slotEl.innerHTML = "";
|
|
61
|
-
controlEl = null;
|
|
62
|
-
controlMode = null;
|
|
63
|
-
controlStateKey = null;
|
|
64
|
-
currentState = null;
|
|
65
|
-
inputEl = null;
|
|
66
|
-
primaryEl = null;
|
|
67
|
-
secondaryEl = null;
|
|
68
|
-
activityEl = null;
|
|
69
|
-
handEl = null;
|
|
70
|
-
stopEl = null;
|
|
71
|
-
composing = false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function setSpecialMode(active) {
|
|
75
|
-
if (normalComposerEl) normalComposerEl.hidden = active;
|
|
76
|
-
if (modelEl) modelEl.hidden = active;
|
|
77
|
-
if (slotEl) slotEl.hidden = !active;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function sendControl(action, data) {
|
|
81
|
-
var ws = getWs();
|
|
82
|
-
if (!ws || ws.readyState !== 1 || !currentState) return false;
|
|
83
|
-
ws.send(JSON.stringify({
|
|
84
|
-
type: "home_debate_control",
|
|
85
|
-
action: action,
|
|
86
|
-
mateId: store.get('homeChatMateId'),
|
|
87
|
-
sessionId: store.get('homeChatSessionId'),
|
|
88
|
-
requestId: currentRequestId,
|
|
89
|
-
text: data && data.text ? data.text : "",
|
|
90
|
-
response: data && data.response ? data.response : null,
|
|
91
|
-
}));
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function button(label, className) {
|
|
96
|
-
var element = textElement("button", className, label);
|
|
97
|
-
element.type = "button";
|
|
98
|
-
return element;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function dots() {
|
|
102
|
-
var group = document.createElement("span");
|
|
103
|
-
group.className = "home-debate-control-dots";
|
|
104
|
-
group.setAttribute("aria-hidden", "true");
|
|
105
|
-
for (var i = 0; i < 3; i++) group.appendChild(document.createElement("i"));
|
|
106
|
-
return group;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function activityLabel(state) {
|
|
110
|
-
if (state.header.stopping) return state.turn ? "Stopping after " + (state.turn.mateName || "the current speaker") + " finishes" : "Stopping debate";
|
|
111
|
-
if (!state.turn) return state.header.handRaised ? "Your hand is raised" : "Debate is live";
|
|
112
|
-
var name = state.turn.mateName || "Mate";
|
|
113
|
-
var activity = state.turn.activity || (state.turn.text ? "speaking" : "preparing");
|
|
114
|
-
return name + " is " + activity.toLowerCase();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function lockSubmission(label) {
|
|
118
|
-
if (inputEl) inputEl.disabled = true;
|
|
119
|
-
if (primaryEl) { primaryEl.disabled = true; primaryEl.textContent = label; }
|
|
120
|
-
if (secondaryEl) secondaryEl.disabled = true;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function submitInput(action, response) {
|
|
124
|
-
var text = inputEl ? inputEl.value.trim() : "";
|
|
125
|
-
if (action === "user_floor" && !text) return false;
|
|
126
|
-
if (!sendControl(action, { text: text, response: response })) return false;
|
|
127
|
-
lockSubmission(action === "user_floor" ? "Sending…" : "Continuing…");
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function bindInput(submit) {
|
|
132
|
-
inputEl.addEventListener("compositionstart", function () { composing = true; });
|
|
133
|
-
inputEl.addEventListener("compositionend", function () { composing = false; });
|
|
134
|
-
inputEl.addEventListener("input", function () {
|
|
135
|
-
if (controlMode === "user_floor" && primaryEl) primaryEl.disabled = !inputEl.value.trim();
|
|
136
|
-
});
|
|
137
|
-
inputEl.addEventListener("keydown", function (event) {
|
|
138
|
-
if (event.key !== "Enter" || event.shiftKey || event.isComposing || composing || event.keyCode === 229) return;
|
|
139
|
-
event.preventDefault();
|
|
140
|
-
submit();
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function focusInputOnce() {
|
|
145
|
-
var target = inputEl;
|
|
146
|
-
if (!target) return;
|
|
147
|
-
var focus = function () {
|
|
148
|
-
if (target === inputEl && !target.disabled && target.isConnected !== false) target.focus({ preventScroll: true });
|
|
149
|
-
};
|
|
150
|
-
if (typeof requestAnimationFrame === "function") requestAnimationFrame(focus);
|
|
151
|
-
else focus();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function buildDefault(state) {
|
|
155
|
-
var context = document.createElement("div");
|
|
156
|
-
context.className = "home-debate-control-context";
|
|
157
|
-
context.appendChild(dots());
|
|
158
|
-
activityEl = textElement("span", "home-debate-control-activity", activityLabel(state));
|
|
159
|
-
activityEl.setAttribute("role", "status");
|
|
160
|
-
activityEl.setAttribute("aria-live", "polite");
|
|
161
|
-
context.appendChild(activityEl);
|
|
162
|
-
controlEl.appendChild(context);
|
|
163
|
-
var actions = document.createElement("div");
|
|
164
|
-
actions.className = "home-debate-control-actions";
|
|
165
|
-
handEl = button(state.header.handRaised ? "Hand raised" : "Raise hand", "home-debate-control-secondary");
|
|
166
|
-
handEl.setAttribute("aria-pressed", state.header.handRaised ? "true" : "false");
|
|
167
|
-
handEl.disabled = state.header.handRaised === true;
|
|
168
|
-
handEl.addEventListener("click", function () {
|
|
169
|
-
if (!sendControl("hand_raise")) return;
|
|
170
|
-
handEl.disabled = true;
|
|
171
|
-
handEl.textContent = "Raising hand…";
|
|
172
|
-
});
|
|
173
|
-
stopEl = button(state.header.stopping ? "Cancel stop" : "Stop debate", state.header.stopping ? "home-debate-control-secondary" : "home-debate-control-stop");
|
|
174
|
-
stopEl.addEventListener("click", function () {
|
|
175
|
-
var cancelling = currentState && currentState.header && currentState.header.stopping === true;
|
|
176
|
-
if (!sendControl(cancelling ? "cancel_stop" : "stop")) return;
|
|
177
|
-
stopEl.disabled = true;
|
|
178
|
-
stopEl.textContent = cancelling ? "Cancelling…" : "Stopping…";
|
|
179
|
-
});
|
|
180
|
-
actions.appendChild(handEl);
|
|
181
|
-
actions.appendChild(stopEl);
|
|
182
|
-
controlEl.appendChild(actions);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function buildInputMode(state) {
|
|
186
|
-
var isFloor = state.mode === "user_floor";
|
|
187
|
-
var heading = textElement("div", "home-debate-control-heading", isFloor ? "You have the floor" : "The moderator is ready to conclude");
|
|
188
|
-
heading.id = "home-debate-control-heading";
|
|
189
|
-
controlEl.appendChild(heading);
|
|
190
|
-
inputEl = document.createElement("textarea");
|
|
191
|
-
inputEl.rows = 2;
|
|
192
|
-
inputEl.placeholder = isFloor ? "Share your thoughts with the panel" : "Add an optional direction to continue";
|
|
193
|
-
inputEl.setAttribute("aria-labelledby", heading.id);
|
|
194
|
-
controlEl.appendChild(inputEl);
|
|
195
|
-
var actions = document.createElement("div");
|
|
196
|
-
actions.className = "home-debate-control-actions";
|
|
197
|
-
if (isFloor) {
|
|
198
|
-
primaryEl = button("Send", "home-debate-control-primary");
|
|
199
|
-
primaryEl.disabled = true;
|
|
200
|
-
primaryEl.addEventListener("click", function () { submitInput("user_floor"); });
|
|
201
|
-
secondaryEl = button("Pass", "home-debate-control-secondary");
|
|
202
|
-
secondaryEl.addEventListener("click", function () {
|
|
203
|
-
if (!sendControl("user_floor", { text: "(The user passed without speaking)" })) return;
|
|
204
|
-
lockSubmission("Sending…");
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
primaryEl = button("Continue", "home-debate-control-primary");
|
|
208
|
-
primaryEl.addEventListener("click", function () { submitInput("conclude", "continue"); });
|
|
209
|
-
secondaryEl = button("End debate", "home-debate-control-stop");
|
|
210
|
-
secondaryEl.addEventListener("click", function () {
|
|
211
|
-
if (!sendControl("conclude", { response: "end" })) return;
|
|
212
|
-
lockSubmission("Ending…");
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
actions.appendChild(primaryEl);
|
|
216
|
-
actions.appendChild(secondaryEl);
|
|
217
|
-
controlEl.appendChild(actions);
|
|
218
|
-
bindInput(function () { submitInput(isFloor ? "user_floor" : "conclude", isFloor ? null : "continue"); });
|
|
219
|
-
focusInputOnce();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function terminalLabel(state) {
|
|
223
|
-
if (state.phase === "interrupted") return "Debate interrupted when Clay restarted";
|
|
224
|
-
if (state.header.reason === "error") return "The debate stopped after an error";
|
|
225
|
-
if (state.header.reason === "stopped" || state.header.reason === "user_stopped") return "Debate stopped";
|
|
226
|
-
return "Debate ended";
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function buildTerminal(state) {
|
|
230
|
-
var status = textElement("div", "home-debate-control-terminal-status", terminalLabel(state));
|
|
231
|
-
status.setAttribute("role", "status");
|
|
232
|
-
controlEl.appendChild(status);
|
|
233
|
-
var actions = document.createElement("div");
|
|
234
|
-
actions.className = "home-debate-control-actions";
|
|
235
|
-
primaryEl = button("Resume debate", "home-debate-control-primary");
|
|
236
|
-
primaryEl.addEventListener("click", function () {
|
|
237
|
-
if (!sendControl("resume")) return;
|
|
238
|
-
lockSubmission("Resuming…");
|
|
239
|
-
});
|
|
240
|
-
actions.appendChild(primaryEl);
|
|
241
|
-
if (typeof startNewDebate === "function") {
|
|
242
|
-
secondaryEl = button("New debate", "home-debate-control-secondary");
|
|
243
|
-
secondaryEl.addEventListener("click", function () { startNewDebate(); });
|
|
244
|
-
actions.appendChild(secondaryEl);
|
|
245
|
-
}
|
|
246
|
-
controlEl.appendChild(actions);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function buildControls(state) {
|
|
250
|
-
slotEl.innerHTML = "";
|
|
251
|
-
controlEl = document.createElement("section");
|
|
252
|
-
controlEl.className = "home-debate-control-surface home-debate-control-" + state.mode;
|
|
253
|
-
controlEl.setAttribute("role", state.mode === "default" ? "toolbar" : "region");
|
|
254
|
-
controlEl.setAttribute("aria-label", state.mode === "terminal" ? "Debate status" : "Live debate controls");
|
|
255
|
-
slotEl.appendChild(controlEl);
|
|
256
|
-
if (state.mode === "default") buildDefault(state);
|
|
257
|
-
else if (state.mode === "user_floor" || state.mode === "conclude") buildInputMode(state);
|
|
258
|
-
else buildTerminal(state);
|
|
259
|
-
controlMode = state.mode;
|
|
260
|
-
controlStateKey = state.mode + ":" + state.phase + ":" + (state.header.reason || "");
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function updateControls(state) {
|
|
264
|
-
if (state.mode !== "default") return;
|
|
265
|
-
var label = activityLabel(state);
|
|
266
|
-
if (activityEl && activityEl.textContent !== label) activityEl.textContent = label;
|
|
267
|
-
if (state.header.handRaised && handEl) {
|
|
268
|
-
handEl.textContent = "Hand raised";
|
|
269
|
-
handEl.disabled = true;
|
|
270
|
-
handEl.setAttribute("aria-pressed", "true");
|
|
3
|
+
import { createDebateControls } from './debate-controls.js';
|
|
4
|
+
export { homeDebateControlState } from './debate-controls.js';
|
|
5
|
+
|
|
6
|
+
var controls = createDebateControls({
|
|
7
|
+
slotId: "home-debate-controls-slot",
|
|
8
|
+
composerId: "home-mate-chat-composer",
|
|
9
|
+
modelId: "home-mate-chat-session-model",
|
|
10
|
+
send: function (action, data, requestId) {
|
|
11
|
+
var ws = getWs();
|
|
12
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
13
|
+
ws.send(JSON.stringify({
|
|
14
|
+
type: "home_debate_control", action: action,
|
|
15
|
+
mateId: store.get('homeChatMateId'), sessionId: store.get('homeChatSessionId'),
|
|
16
|
+
requestId: requestId, text: data.text || "", response: data.response || null
|
|
17
|
+
}));
|
|
18
|
+
return true;
|
|
271
19
|
}
|
|
272
|
-
|
|
273
|
-
stopEl.disabled = false;
|
|
274
|
-
stopEl.textContent = state.header.stopping ? "Cancel stop" : "Stop debate";
|
|
275
|
-
stopEl.className = state.header.stopping ? "home-debate-control-secondary" : "home-debate-control-stop";
|
|
276
|
-
}
|
|
277
|
-
}
|
|
20
|
+
});
|
|
278
21
|
|
|
279
22
|
export function renderHomeDebateControls(messages, requestId, onStartNewDebate) {
|
|
280
|
-
|
|
281
|
-
var state = homeDebateControlState(messages);
|
|
282
|
-
currentRequestId = requestId || null;
|
|
283
|
-
startNewDebate = onStartNewDebate || null;
|
|
284
|
-
if (!state) {
|
|
285
|
-
setSpecialMode(false);
|
|
286
|
-
clearControls();
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
289
|
-
currentState = state;
|
|
290
|
-
setSpecialMode(true);
|
|
291
|
-
var nextStateKey = state.mode + ":" + state.phase + ":" + (state.header.reason || "");
|
|
292
|
-
if (!controlEl || controlMode !== state.mode || controlStateKey !== nextStateKey) buildControls(state);
|
|
293
|
-
else updateControls(state);
|
|
294
|
-
return true;
|
|
23
|
+
return controls.render(messages, requestId, onStartNewDebate);
|
|
295
24
|
}
|