clay-server 5.0.2-beta.1 → 5.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon.js +2 -0
- 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/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +36 -21
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates.js +18 -0
- package/lib/project-connection.js +36 -2
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +1 -0
- package/lib/project-file-path.js +2 -3
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-request-access.js +13 -1
- package/lib/project-sessions.js +39 -2
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +59 -18
- package/lib/public/app.js +73 -34
- 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/filebrowser.css +10 -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/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/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +8 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +151 -0
- 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 +33 -101
- package/lib/public/modules/account-island.js +230 -0
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- 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 +34 -9
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +25 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- 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 +81 -65
- package/lib/public/modules/filebrowser.js +28 -8
- 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/html-preview.js +19 -0
- 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/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/profile.js +51 -18
- 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-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/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-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +4 -1
- package/lib/public/modules/session-title-marquee.js +51 -0
- 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/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/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 +16 -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/server-admin.js +11 -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-mate-instructions.js +44 -0
- package/lib/server-mates.js +12 -3
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +65 -1
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +21 -1
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +32 -6
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +50 -0
- package/package.json +10 -1
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { mountDefaultAi, unmountDefaultAi } from './default-ai.js';
|
|
3
|
+
import { openUserSettings } from './user-settings.js';
|
|
4
|
+
import { getProfile, updateProfileName, regenerateProfileAvatar, showAvatarPositioner, uploadAvatarBlob } from './profile.js';
|
|
5
|
+
import { requestCursorSharingState, setCursorSharing } from './app-cursors.js';
|
|
6
|
+
import { registerTooltip } from './tooltip.js';
|
|
7
|
+
|
|
8
|
+
var popover = null;
|
|
9
|
+
var trigger = null;
|
|
10
|
+
var lastFocus = null;
|
|
11
|
+
|
|
12
|
+
function accountName() { return document.body.dataset.myDisplayName || 'Clay user'; }
|
|
13
|
+
|
|
14
|
+
function close(returnFocus) {
|
|
15
|
+
if (!popover) return;
|
|
16
|
+
var aiSection = popover.querySelector('#account-ai-section');
|
|
17
|
+
if (aiSection) unmountDefaultAi(aiSection);
|
|
18
|
+
popover.remove();
|
|
19
|
+
popover = null;
|
|
20
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
21
|
+
trigger.setAttribute('aria-label', 'Open account menu for ' + accountName());
|
|
22
|
+
document.removeEventListener('pointerdown', onOutside);
|
|
23
|
+
document.removeEventListener('focusin', onFocusOutside);
|
|
24
|
+
document.removeEventListener('keydown', onKeydown);
|
|
25
|
+
window.removeEventListener('resize', position);
|
|
26
|
+
store.set({ defaultAiInlineEditing: false });
|
|
27
|
+
if (returnFocus && lastFocus && document.contains(lastFocus)) lastFocus.focus({ preventScroll: true });
|
|
28
|
+
lastFocus = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isAvatarPositionerTarget(target) { return target && target.closest && target.closest('.avatar-positioner-overlay'); }
|
|
32
|
+
function onOutside(event) { if (!popover || popover.contains(event.target) || trigger.contains(event.target) || isAvatarPositionerTarget(event.target)) return; close(false); }
|
|
33
|
+
function onFocusOutside(event) { if (!popover || popover.contains(event.target) || trigger.contains(event.target) || isAvatarPositionerTarget(event.target)) return; close(false); }
|
|
34
|
+
function onKeydown(event) {
|
|
35
|
+
if (event.key !== 'Escape') return;
|
|
36
|
+
if (isAvatarPositionerTarget(event.target) || document.querySelector('.avatar-positioner-overlay')) return;
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
close(true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function position() {
|
|
43
|
+
if (!popover || !trigger) return;
|
|
44
|
+
var rect = trigger.getBoundingClientRect();
|
|
45
|
+
var width = Math.min(280, window.innerWidth - 24);
|
|
46
|
+
var left = Math.max(12, Math.min(window.innerWidth - width - 12, rect.left));
|
|
47
|
+
popover.style.width = width + 'px';
|
|
48
|
+
popover.style.left = left + 'px';
|
|
49
|
+
popover.style.top = Math.max(12, rect.top - popover.offsetHeight - 8) + 'px';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function renderNameResting(restoreFocus) {
|
|
53
|
+
var section = popover && popover.querySelector('.account-identity-copy');
|
|
54
|
+
if (!section) return;
|
|
55
|
+
section.innerHTML = '<button type="button" id="account-name-edit" class="account-name-display"><span></span><i data-lucide="pencil" aria-hidden="true"></i></button><small>Personal account</small>';
|
|
56
|
+
section.querySelector('span').textContent = accountName();
|
|
57
|
+
section.querySelector('#account-name-edit').addEventListener('click', startNameEdit);
|
|
58
|
+
if (window.lucide) window.lucide.createIcons({ nodes: [section] });
|
|
59
|
+
if (restoreFocus) section.querySelector('#account-name-edit').focus();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function startNameEdit() {
|
|
63
|
+
var section = popover && popover.querySelector('.account-identity-copy');
|
|
64
|
+
if (!section) return;
|
|
65
|
+
var input = document.createElement('input');
|
|
66
|
+
input.id = 'account-profile-name';
|
|
67
|
+
input.setAttribute('aria-label', 'Display name');
|
|
68
|
+
input.className = 'account-name-input';
|
|
69
|
+
input.type = 'text';
|
|
70
|
+
input.maxLength = 50;
|
|
71
|
+
input.autocomplete = 'name';
|
|
72
|
+
input.value = getProfile().name || '';
|
|
73
|
+
section.innerHTML = '';
|
|
74
|
+
section.appendChild(input);
|
|
75
|
+
var hint = document.createElement('small');
|
|
76
|
+
hint.textContent = 'Enter to save · Escape to cancel';
|
|
77
|
+
section.appendChild(hint);
|
|
78
|
+
input.addEventListener('keydown', function(event) {
|
|
79
|
+
if (event.key === 'Enter') {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
updateProfileName(input.value);
|
|
82
|
+
renderNameResting(true);
|
|
83
|
+
} else if (event.key === 'Escape') {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
renderNameResting(true);
|
|
86
|
+
}
|
|
87
|
+
event.stopPropagation();
|
|
88
|
+
});
|
|
89
|
+
input.focus();
|
|
90
|
+
input.select();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function toggleAvatarEditor() {
|
|
94
|
+
var editor = popover && popover.querySelector('#account-avatar-editor');
|
|
95
|
+
if (!editor) return;
|
|
96
|
+
editor.hidden = !editor.hidden;
|
|
97
|
+
if (!editor.hidden) editor.querySelector('#account-avatar-upload').focus();
|
|
98
|
+
position();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function bindAvatarEditor() {
|
|
102
|
+
var avatar = popover.querySelector('#account-avatar-edit');
|
|
103
|
+
var editor = popover.querySelector('#account-avatar-editor');
|
|
104
|
+
var upload = editor.querySelector('#account-avatar-upload');
|
|
105
|
+
var file = editor.querySelector('#account-avatar-file');
|
|
106
|
+
var generate = editor.querySelector('#account-avatar-generate');
|
|
107
|
+
avatar.addEventListener('click', function(event) { event.stopPropagation(); toggleAvatarEditor(); });
|
|
108
|
+
editor.addEventListener('click', function(event) { event.stopPropagation(); });
|
|
109
|
+
upload.addEventListener('click', function() { file.click(); });
|
|
110
|
+
file.addEventListener('change', function() {
|
|
111
|
+
var selected = file.files && file.files[0];
|
|
112
|
+
if (!selected) return;
|
|
113
|
+
var image = new Image();
|
|
114
|
+
var objectUrl = URL.createObjectURL(selected);
|
|
115
|
+
image.onload = function() {
|
|
116
|
+
showAvatarPositioner(image, objectUrl, function(blob) {
|
|
117
|
+
URL.revokeObjectURL(objectUrl);
|
|
118
|
+
uploadAvatarBlob(blob).then(function() { editor.hidden = true; }).catch(function() { editor.dataset.error = 'true'; });
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
image.src = objectUrl;
|
|
122
|
+
});
|
|
123
|
+
generate.addEventListener('click', function() { regenerateProfileAvatar(); editor.hidden = true; });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function render() {
|
|
127
|
+
popover = document.createElement('div');
|
|
128
|
+
popover.id = 'account-popover';
|
|
129
|
+
popover.className = 'account-popover';
|
|
130
|
+
popover.setAttribute('role', 'dialog');
|
|
131
|
+
popover.setAttribute('aria-label', 'Account');
|
|
132
|
+
var profile = getProfile();
|
|
133
|
+
var identity = document.createElement('div');
|
|
134
|
+
identity.className = 'account-menu-identity';
|
|
135
|
+
identity.innerHTML = '<button type="button" id="account-avatar-edit" class="account-avatar-edit" aria-label="Edit avatar"><img src="' + (document.body.dataset.myAvatarUrl || '') + '" alt=""></button><div class="account-identity-copy"></div><button type="button" class="account-settings-button" aria-label="User Settings" title="User Settings"><i data-lucide="settings" aria-hidden="true"></i></button>';
|
|
136
|
+
identity.querySelector('#account-avatar-edit img').alt = profile.name || 'Clay user';
|
|
137
|
+
var editor = document.createElement('div');
|
|
138
|
+
editor.id = 'account-avatar-editor';
|
|
139
|
+
editor.className = 'account-avatar-editor';
|
|
140
|
+
editor.hidden = true;
|
|
141
|
+
editor.innerHTML = '<button type="button" id="account-avatar-upload">Upload photo</button><button type="button" id="account-avatar-generate">Generate avatar</button><input id="account-avatar-file" type="file" accept="image/*">';
|
|
142
|
+
popover.appendChild(identity);
|
|
143
|
+
popover.appendChild(editor);
|
|
144
|
+
var aiSection = document.createElement('section');
|
|
145
|
+
aiSection.id = 'account-ai-section';
|
|
146
|
+
aiSection.className = 'account-inline-section account-ai-section';
|
|
147
|
+
aiSection.setAttribute('aria-label', 'Default AI');
|
|
148
|
+
popover.appendChild(aiSection);
|
|
149
|
+
mountDefaultAi(aiSection);
|
|
150
|
+
identity.querySelector('.account-settings-button').addEventListener('click', onSettings);
|
|
151
|
+
document.body.appendChild(popover);
|
|
152
|
+
renderNameResting();
|
|
153
|
+
bindAvatarEditor();
|
|
154
|
+
updateCursorAction();
|
|
155
|
+
if (window.lucide) window.lucide.createIcons({ nodes: [popover] });
|
|
156
|
+
position();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function updateCursorAction() {
|
|
160
|
+
var button = document.getElementById('cursor-share-toggle');
|
|
161
|
+
if (!button) return;
|
|
162
|
+
var hydrated = store.get('cursorSharingHydrated') === true;
|
|
163
|
+
var enabled = hydrated && store.get('cursorSharingEnabled') === true;
|
|
164
|
+
var pending = store.get('cursorSharingPending') !== null && store.get('cursorSharingPending') !== undefined;
|
|
165
|
+
var connected = store.get('connected') !== false;
|
|
166
|
+
var error = store.get('cursorSharingError');
|
|
167
|
+
var canRetry = !!error && !hydrated && connected;
|
|
168
|
+
var showOff = hydrated && !enabled && !pending && !error && connected;
|
|
169
|
+
button.hidden = store.get('isMultiUserMode') !== true;
|
|
170
|
+
button.removeAttribute('role');
|
|
171
|
+
button.removeAttribute('aria-checked');
|
|
172
|
+
button.setAttribute('aria-pressed', enabled ? 'true' : 'false');
|
|
173
|
+
button.classList.toggle('on', enabled);
|
|
174
|
+
button.classList.toggle('off', showOff);
|
|
175
|
+
button.classList.toggle('pending', pending);
|
|
176
|
+
button.disabled = pending || !connected || (!hydrated && !canRetry);
|
|
177
|
+
var stateLabel = pending ? 'waiting' : !connected ? 'offline' : error ? (canRetry ? 'error; activate to retry' : 'error') : !hydrated ? 'unavailable' : enabled ? 'on' : 'off';
|
|
178
|
+
button.setAttribute('aria-label', 'Cursor sharing ' + stateLabel);
|
|
179
|
+
var tooltipText = pending ? 'Cursor sharing is waiting for confirmation.' : !connected ? 'Cursor sharing is offline.' : error ? (canRetry ? 'Cursor sharing is unavailable. Click to retry.' : 'Cursor sharing is unavailable.') : !hydrated ? 'Cursor sharing is unavailable.' : enabled ? 'Your cursor is visible to others. Click to stop sharing.' : 'Cursor sharing is off. Click to share your cursor.';
|
|
180
|
+
registerTooltip(button, tooltipText);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function onSettings(event) { event.stopPropagation(); close(false); openUserSettings(); }
|
|
184
|
+
function onCursorAction(event) {
|
|
185
|
+
event.stopPropagation();
|
|
186
|
+
if (event.currentTarget.disabled) return;
|
|
187
|
+
if (store.get('cursorSharingError') && store.get('cursorSharingHydrated') !== true) {
|
|
188
|
+
requestCursorSharingState();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
setCursorSharing(!(store.get('cursorSharingEnabled') === true));
|
|
192
|
+
}
|
|
193
|
+
function focusAi() { var control = popover && popover.querySelector('#account-ai-section select'); if (control) control.focus({ preventScroll: true }); }
|
|
194
|
+
function onOpenDefaultAi() { if (!popover) open(); store.set({ defaultAiInlineEditing: true }); focusAi(); }
|
|
195
|
+
|
|
196
|
+
function open() {
|
|
197
|
+
if (popover) { close(true); return; }
|
|
198
|
+
lastFocus = document.activeElement;
|
|
199
|
+
render();
|
|
200
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
201
|
+
trigger.setAttribute('aria-label', 'Close account menu for ' + accountName());
|
|
202
|
+
document.addEventListener('pointerdown', onOutside);
|
|
203
|
+
document.addEventListener('focusin', onFocusOutside);
|
|
204
|
+
document.addEventListener('keydown', onKeydown);
|
|
205
|
+
window.addEventListener('resize', position);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function initAccountIsland() {
|
|
209
|
+
trigger = document.getElementById('user-account-trigger');
|
|
210
|
+
if (!trigger) return;
|
|
211
|
+
trigger.addEventListener('click', open);
|
|
212
|
+
document.addEventListener('clay:open-account-default-ai', onOpenDefaultAi);
|
|
213
|
+
var cursorToggle = document.getElementById('cursor-share-toggle');
|
|
214
|
+
if (cursorToggle) cursorToggle.addEventListener('click', onCursorAction);
|
|
215
|
+
updateCursorAction();
|
|
216
|
+
trigger.setAttribute('aria-label', 'Open account menu for ' + accountName());
|
|
217
|
+
store.subscribe(function(state, previous) {
|
|
218
|
+
if (state.myUserId !== previous.myUserId || state.connected === false) close(false);
|
|
219
|
+
updateCursorAction();
|
|
220
|
+
if (popover) position();
|
|
221
|
+
});
|
|
222
|
+
document.addEventListener('clay:profile-updated', function() {
|
|
223
|
+
if (!popover) return;
|
|
224
|
+
var identityName = popover.querySelector('.account-name-display span');
|
|
225
|
+
if (identityName) identityName.textContent = accountName();
|
|
226
|
+
var avatar = popover.querySelector('#account-avatar-edit img');
|
|
227
|
+
if (avatar) avatar.src = document.body.dataset.myAvatarUrl || avatar.src;
|
|
228
|
+
});
|
|
229
|
+
window.addEventListener('resize', position);
|
|
230
|
+
}
|
|
@@ -199,50 +199,26 @@ function findClosestTurn(clientY) {
|
|
|
199
199
|
|
|
200
200
|
// Cursor sharing toggle button in user island (multi-user only)
|
|
201
201
|
export function initCursorToggle() {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (document.getElementById("cursor-share-toggle")) return;
|
|
206
|
-
|
|
207
|
-
var btn = document.createElement("button");
|
|
208
|
-
btn.id = "cursor-share-toggle";
|
|
209
|
-
btn.className = "cursor-share-btn";
|
|
210
|
-
btn.innerHTML = '<i data-lucide="mouse-pointer-2"></i>';
|
|
211
|
-
var settingsBtn = document.getElementById("user-settings-btn");
|
|
212
|
-
if (settingsBtn) {
|
|
213
|
-
actionsEl.insertBefore(btn, settingsBtn);
|
|
214
|
-
} else {
|
|
215
|
-
actionsEl.appendChild(btn);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function updateToggleStyle() {
|
|
219
|
-
if (store.get("cursorSharingHydrated") && store.get("cursorSharingEnabled")) {
|
|
220
|
-
btn.classList.remove("off");
|
|
221
|
-
btn.classList.add("on");
|
|
222
|
-
registerTooltip(btn, "Cursor sharing on");
|
|
223
|
-
} else {
|
|
224
|
-
btn.classList.remove("on");
|
|
225
|
-
btn.classList.add("off");
|
|
226
|
-
registerTooltip(btn, "Cursor sharing off");
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
store.subscribe(function (state, prev) {
|
|
231
|
-
if (state.cursorSharingEnabled !== prev.cursorSharingEnabled || state.cursorSharingHydrated !== prev.cursorSharingHydrated) {
|
|
232
|
-
updateToggleStyle();
|
|
233
|
-
}
|
|
234
|
-
});
|
|
202
|
+
// The labeled rail control is owned by account-island.js.
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
235
205
|
|
|
236
|
-
|
|
237
|
-
|
|
206
|
+
export function setCursorSharing(enabled) {
|
|
207
|
+
if (!store.get('cursorSharingHydrated') || store.get('cursorSharingPending') !== null && store.get('cursorSharingPending') !== undefined) return false;
|
|
208
|
+
if (enabled === true && store.get('isMultiUserMode') !== true) return false;
|
|
209
|
+
var ws = getWs();
|
|
210
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
211
|
+
store.set({ cursorSharingPending: enabled });
|
|
212
|
+
ws.send(JSON.stringify({ type: 'cursor_sharing_set', enabled: enabled === true, requestId: 'cursor-sharing-' + Date.now() }));
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
238
215
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
});
|
|
216
|
+
export function requestCursorSharingState() {
|
|
217
|
+
var ws = getWs();
|
|
218
|
+
if (!ws || ws.readyState !== 1) return false;
|
|
219
|
+
store.set({ cursorSharingPending: 'refresh' });
|
|
220
|
+
ws.send(JSON.stringify({ type: 'cursor_sharing_get', requestId: 'cursor-sharing-refresh-' + Date.now() }));
|
|
221
|
+
return true;
|
|
246
222
|
}
|
|
247
223
|
|
|
248
224
|
// --- Exported functions ---
|
|
@@ -393,7 +369,7 @@ export function initCursors() {
|
|
|
393
369
|
if (cursorThrottleTimer) { clearTimeout(cursorThrottleTimer); cursorThrottleTimer = null; }
|
|
394
370
|
if (selectionThrottleTimer) { clearTimeout(selectionThrottleTimer); selectionThrottleTimer = null; }
|
|
395
371
|
lastSelectionKey = "";
|
|
396
|
-
store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null });
|
|
372
|
+
store.set({ cursorSharingEnabled: false, cursorSharingHydrated: false, cursorSharingAccountId: null, cursorSharingPending: null, cursorSharingError: disconnected ? "disconnected" : "account-changed" });
|
|
397
373
|
if (identityChanged && state.myUserId && state.connected) {
|
|
398
374
|
var ws = getWs();
|
|
399
375
|
if (ws && ws.readyState === 1) ws.send(JSON.stringify({ type: "cursor_sharing_get", requestId: "cursor-sharing-refresh-" + Date.now() }));
|
|
@@ -6,6 +6,7 @@ import { store } from './store.js';
|
|
|
6
6
|
import { getWs } from './ws-ref.js';
|
|
7
7
|
import { scrollToBottom } from './app-rendering.js';
|
|
8
8
|
import { exportDebateAsPdf } from './debate.js';
|
|
9
|
+
import { getProjectAssistantPlaceholder } from './project-chat-identity.js';
|
|
9
10
|
|
|
10
11
|
// Module-internal UI var (not in store)
|
|
11
12
|
var debateHandRaiseOpen = false;
|
|
@@ -64,7 +65,7 @@ export function exitDebateConcludeMode() {
|
|
|
64
65
|
if (banner) banner.remove();
|
|
65
66
|
var inputEl = document.getElementById("input");
|
|
66
67
|
if (inputEl && inputEl._origPlaceholder) {
|
|
67
|
-
inputEl.placeholder =
|
|
68
|
+
inputEl.placeholder = getProjectAssistantPlaceholder(store.snap(), store.get('currentVendor'));
|
|
68
69
|
delete inputEl._origPlaceholder;
|
|
69
70
|
}
|
|
70
71
|
}
|
|
@@ -129,7 +130,7 @@ export function exitDebateEndedMode() {
|
|
|
129
130
|
if (banner) banner.remove();
|
|
130
131
|
var inputEl2 = document.getElementById("input");
|
|
131
132
|
if (inputEl2 && inputEl2._origPlaceholder) {
|
|
132
|
-
inputEl2.placeholder =
|
|
133
|
+
inputEl2.placeholder = getProjectAssistantPlaceholder(store.snap(), store.get('currentVendor'));
|
|
133
134
|
delete inputEl2._origPlaceholder;
|
|
134
135
|
}
|
|
135
136
|
}
|
|
@@ -191,7 +192,7 @@ export function exitDebateFloorMode() {
|
|
|
191
192
|
if (banner) banner.remove();
|
|
192
193
|
var inputEl = document.getElementById("input");
|
|
193
194
|
if (inputEl && inputEl._origPlaceholder) {
|
|
194
|
-
inputEl.placeholder =
|
|
195
|
+
inputEl.placeholder = getProjectAssistantPlaceholder(store.snap(), store.get('currentVendor'));
|
|
195
196
|
delete inputEl._origPlaceholder;
|
|
196
197
|
}
|
|
197
198
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { beginProjectDebatePrepend, endProjectDebatePrepend } from './project-debate-workspace.js';
|
|
1
2
|
// app-header.js - Session rename, session info popover, progressive history loading
|
|
2
3
|
// Extracted from app.js (PR-34)
|
|
3
4
|
|
|
@@ -12,6 +13,9 @@ import { saveToolState, resetToolState, restoreToolState } from './tools.js';
|
|
|
12
13
|
import { getSessionUsage, setSessionUsage, getContextData, setContextData, updateContextPanel, updateUsagePanel } from './app-panels.js';
|
|
13
14
|
import { onHistoryPrepended as onSessionSearchHistoryPrepended } from './session-search.js';
|
|
14
15
|
import { getCachedSessions } from './sidebar-sessions.js';
|
|
16
|
+
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
17
|
+
import { splitGroupRoles } from './split-group-helpers.js';
|
|
18
|
+
import { createWorkerHistoryControl } from './sidebar-session-hierarchy.js';
|
|
15
19
|
import { bindPermissionControl, renderPermissionControl } from './permission-control.js';
|
|
16
20
|
import { startHeaderSessionInlineRename } from './session-context-menu.js';
|
|
17
21
|
|
|
@@ -19,11 +23,104 @@ import { startHeaderSessionInlineRename } from './session-context-menu.js';
|
|
|
19
23
|
var sessionInfoPopover = null;
|
|
20
24
|
var historySentinelObserver = null;
|
|
21
25
|
|
|
26
|
+
function splitHistoryOwner(state, sessions) {
|
|
27
|
+
var split = state.splitPanes;
|
|
28
|
+
if (!split || !Array.isArray(split.panes)) return null;
|
|
29
|
+
var groups = state.splitGroups || [];
|
|
30
|
+
var group = null;
|
|
31
|
+
var roles = null;
|
|
32
|
+
for (var gi = 0; gi < groups.length; gi++) {
|
|
33
|
+
var candidateRoles = splitGroupRoles(groups[gi]);
|
|
34
|
+
if (!candidateRoles) continue;
|
|
35
|
+
var matches = false;
|
|
36
|
+
for (var pi = 0; pi < split.panes.length; pi++) {
|
|
37
|
+
if (candidateRoles.orderedIds.indexOf(split.panes[pi].sessionId) !== -1) matches = true;
|
|
38
|
+
}
|
|
39
|
+
if (matches) { group = groups[gi]; roles = candidateRoles; break; }
|
|
40
|
+
}
|
|
41
|
+
if (!group || !roles) return null;
|
|
42
|
+
var hierarchy = buildSessionHierarchy(sessions || []);
|
|
43
|
+
for (var hi = 0; hi < hierarchy.roots.length; hi++) {
|
|
44
|
+
var root = hierarchy.roots[hi];
|
|
45
|
+
if (root.driver.id === roles.driverId && root.workers.length) return { root: root, group: group, roles: roles };
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function splitPaneHistoryUrl(slug, sessionId) {
|
|
51
|
+
return "/p/" + encodeURIComponent(slug) + "/?pane=1&session=" + encodeURIComponent(sessionId);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function createHeaderWorkerHistoryControl(root, context) {
|
|
55
|
+
var capturedWs = context.ws;
|
|
56
|
+
var capturedSlug = context.slug;
|
|
57
|
+
var capturedMateId = context.mateId;
|
|
58
|
+
var capturedActiveSessionId = context.activeSessionId;
|
|
59
|
+
var capturedSplit = context.split;
|
|
60
|
+
var historyControl = createWorkerHistoryControl(root.driver, root.workers, {
|
|
61
|
+
className: "header-worker-history-btn",
|
|
62
|
+
label: "Show Split Worker history",
|
|
63
|
+
validate: function (driver) {
|
|
64
|
+
var current = store.snap();
|
|
65
|
+
var ws = getWs();
|
|
66
|
+
if (!ws || ws !== capturedWs || ws.readyState !== 1 || !current.connected || current.currentSlug !== capturedSlug ||
|
|
67
|
+
(current.activeProjectMateId || null) !== capturedMateId || current.dmMode) return false;
|
|
68
|
+
if (!capturedSplit) return current.activeSessionId === driver.id && !current.splitPanes;
|
|
69
|
+
var split = current.splitPanes;
|
|
70
|
+
if (!split || split.groupId !== capturedSplit.groupId || !Array.isArray(split.panes) || split.panes.length !== capturedSplit.panes.length) return false;
|
|
71
|
+
if (current.activeSessionId !== capturedActiveSessionId) return false;
|
|
72
|
+
for (var i = 0; i < split.panes.length; i++) {
|
|
73
|
+
if (split.panes[i].sessionId !== capturedSplit.panes[i].sessionId || split.panes[i].slug !== capturedSplit.panes[i].slug) return false;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
},
|
|
77
|
+
navigate: capturedSplit ? function (worker) {
|
|
78
|
+
var opened = window.open(splitPaneHistoryUrl(capturedSlug, worker.id), "_blank", "noopener");
|
|
79
|
+
return !!opened;
|
|
80
|
+
} : null,
|
|
81
|
+
});
|
|
82
|
+
return historyControl;
|
|
83
|
+
}
|
|
84
|
+
|
|
22
85
|
export function initHeader() {
|
|
23
86
|
var headerRenameBtn = document.getElementById("header-rename-btn");
|
|
24
87
|
var headerTitleEl = document.getElementById("header-title");
|
|
25
88
|
var headerInfoBtn = document.getElementById("header-info-btn");
|
|
26
89
|
var headerFullAccessBtn = document.getElementById("header-full-access-btn");
|
|
90
|
+
var headerSearchBtn = document.getElementById("find-in-session-btn");
|
|
91
|
+
var headerWorkerHistoryBtn = null;
|
|
92
|
+
|
|
93
|
+
function refreshHeaderWorkerHistory() {
|
|
94
|
+
if (!headerSearchBtn) return;
|
|
95
|
+
if (headerWorkerHistoryBtn) {
|
|
96
|
+
headerWorkerHistoryBtn.remove();
|
|
97
|
+
headerWorkerHistoryBtn = null;
|
|
98
|
+
}
|
|
99
|
+
var state = store.snap();
|
|
100
|
+
var sessions = getCachedSessions() || [];
|
|
101
|
+
var hierarchy = buildSessionHierarchy(sessions);
|
|
102
|
+
var owner = null;
|
|
103
|
+
var context = null;
|
|
104
|
+
if (state.splitPanes && state.splitPanes.panes) {
|
|
105
|
+
var splitOwner = splitHistoryOwner(state, sessions);
|
|
106
|
+
owner = splitOwner ? splitOwner.root : null;
|
|
107
|
+
if (owner) {
|
|
108
|
+
context = {
|
|
109
|
+
ws: getWs(), slug: state.currentSlug, mateId: state.activeProjectMateId || null,
|
|
110
|
+
activeSessionId: state.activeSessionId,
|
|
111
|
+
split: { groupId: state.splitPanes.groupId, panes: state.splitPanes.panes.map(function (pane) { return { sessionId: pane.sessionId, slug: pane.slug }; }) },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
for (var hi = 0; hi < hierarchy.roots.length; hi++) {
|
|
116
|
+
if (hierarchy.roots[hi].driver.id === state.activeSessionId && hierarchy.roots[hi].workers.length) { owner = hierarchy.roots[hi]; break; }
|
|
117
|
+
}
|
|
118
|
+
if (owner) context = { ws: getWs(), slug: state.currentSlug, mateId: state.activeProjectMateId || null, activeSessionId: state.activeSessionId, split: null };
|
|
119
|
+
}
|
|
120
|
+
if (!owner || !context) return;
|
|
121
|
+
headerWorkerHistoryBtn = createHeaderWorkerHistoryControl(owner, context);
|
|
122
|
+
if (headerWorkerHistoryBtn) headerSearchBtn.insertAdjacentElement("afterend", headerWorkerHistoryBtn);
|
|
123
|
+
}
|
|
27
124
|
|
|
28
125
|
function permissionControlState() {
|
|
29
126
|
var s = store.snap();
|
|
@@ -121,6 +218,12 @@ export function initHeader() {
|
|
|
121
218
|
|
|
122
219
|
// --- Session info popover ---
|
|
123
220
|
if (headerInfoBtn) {
|
|
221
|
+
store.subscribe(function (state, prev) {
|
|
222
|
+
if (state.activeSessionId !== prev.activeSessionId || state.currentSlug !== prev.currentSlug || state.activeProjectMateId !== prev.activeProjectMateId || state.splitPanes !== prev.splitPanes) {
|
|
223
|
+
closeSessionInfoPopover();
|
|
224
|
+
refreshHeaderWorkerHistory();
|
|
225
|
+
}
|
|
226
|
+
});
|
|
124
227
|
headerInfoBtn.addEventListener("click", function (e) {
|
|
125
228
|
e.stopPropagation();
|
|
126
229
|
if (sessionInfoPopover) { closeSessionInfoPopover(); return; }
|
|
@@ -193,6 +296,7 @@ export function initHeader() {
|
|
|
193
296
|
}
|
|
194
297
|
});
|
|
195
298
|
}
|
|
299
|
+
refreshHeaderWorkerHistory();
|
|
196
300
|
}
|
|
197
301
|
|
|
198
302
|
export function closeSessionInfoPopover() {
|
|
@@ -269,11 +373,13 @@ export function prependOlderHistory(items, meta) {
|
|
|
269
373
|
var anchorEl = getPrependAnchor();
|
|
270
374
|
var anchorOffset = anchorEl ? anchorEl.getBoundingClientRect().top : 0;
|
|
271
375
|
|
|
376
|
+
beginProjectDebatePrepend();
|
|
272
377
|
// Process each item through the rendering pipeline
|
|
273
378
|
for (var i = 0; i < items.length; i++) {
|
|
274
379
|
processMessage(items[i]);
|
|
275
380
|
}
|
|
276
381
|
|
|
382
|
+
endProjectDebatePrepend();
|
|
277
383
|
// Finalize any open assistant block from the batch
|
|
278
384
|
finalizeAssistantBlock();
|
|
279
385
|
|
|
@@ -2,11 +2,11 @@ import { handleIssueReference } from './clay-issue-links.js';
|
|
|
2
2
|
// Narrow pre-router for Home and Capsule protocol responses kept out of the legacy router.
|
|
3
3
|
|
|
4
4
|
import { processMessage as processAppMessage } from './app-messages.js';
|
|
5
|
-
import { handleHomeMateModelsState, handleHomeMateModelResult } from './home-mate-settings.js';
|
|
5
|
+
import { handleMateInstructionsResult, handleHomeMateModelsState, handleHomeMateModelResult } from './home-mate-settings.js';
|
|
6
6
|
import { handleHomeMateSessionIdentity, handleHomeDebateTranscript, handleHomeWorkspaceAssignment } from './home-mate-chat.js';
|
|
7
7
|
import { handleToolLlmConfigState } from './tool-llm-status.js';
|
|
8
8
|
import { handleToolSourceState, handleToolMateAccessState } from './home-tools.js';
|
|
9
|
-
import {
|
|
9
|
+
import { handleDebatesWorkbenchState } from './debates-workbench.js';
|
|
10
10
|
import { renderProjectWorkspaceAssignment, showProjectWorkspaceAssignmentError } from './project-workspace-assignment.js';
|
|
11
11
|
import { isHomeWorkspaceAssignmentMessage } from './workspace-assignment-routing.js';
|
|
12
12
|
import { handleSearchClayMessage } from './search-clay-chat.js';
|
|
@@ -15,6 +15,8 @@ import { handleDefaultAiMessage } from './default-ai.js';
|
|
|
15
15
|
import { handleCursorSharingMessage } from './cursor-sharing-preference.js';
|
|
16
16
|
import { handlePendingMessageQueueMessage } from './pending-message-queue.js';
|
|
17
17
|
import { receiveHistoryReplay } from './history-replay-batch.js';
|
|
18
|
+
import { handleProjectMateCreationMessage } from './project-mate-creation-workspace.js';
|
|
19
|
+
import { handleProjectDebatePlanningMessage } from './project-debate-planning-workspace.js';
|
|
18
20
|
|
|
19
21
|
export function handleHomeProtocolMessage(msg) {
|
|
20
22
|
if (handleIssueReference(msg)) return true;
|
|
@@ -32,9 +34,10 @@ export function handleHomeProtocolMessage(msg) {
|
|
|
32
34
|
return true;
|
|
33
35
|
}
|
|
34
36
|
if (msg.type === "home_debates_state") {
|
|
35
|
-
|
|
37
|
+
handleDebatesWorkbenchState(msg);
|
|
36
38
|
return true;
|
|
37
39
|
}
|
|
40
|
+
if (msg.type === "mate_instructions_result") { handleMateInstructionsResult(msg); return true; }
|
|
38
41
|
if (msg.type === "home_mate_models_state") {
|
|
39
42
|
handleHomeMateModelsState(msg);
|
|
40
43
|
return true;
|
|
@@ -87,6 +90,12 @@ export function processMessage(msg) {
|
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
function dispatchMessage(msg) {
|
|
93
|
+
if (typeof handleProjectDebatePlanningMessage === "function" && handleProjectDebatePlanningMessage(msg)) return;
|
|
94
|
+
if (msg.type === "home_debate_event" && msg.eventType) {
|
|
95
|
+
processAppMessage(Object.assign({}, msg, { type: msg.eventType, mateId: msg.speakerMateId || null }));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (handleProjectMateCreationMessage(msg)) return;
|
|
90
99
|
if (handlePendingMessageQueueMessage(msg)) return;
|
|
91
100
|
if (handleDefaultAiMessage(msg)) return;
|
|
92
101
|
if (handleCursorSharingMessage(msg)) return;
|