clay-server 5.2.0-beta.3 → 5.2.0-beta.5
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/lib/account-auth-socket.js +1 -0
- package/lib/builtin-mates.js +19 -16
- package/lib/bundled-skills/clay-agent-browser/SKILL.md +6 -2
- package/lib/canonical-clay-record-authority.js +15 -0
- package/lib/canonical-clay-scheduling-authority.js +19 -0
- package/lib/claude-hook-installer.js +28 -0
- package/lib/clay-mate-chat-receipts.js +26 -0
- package/lib/clay-mate-chat.js +87 -0
- package/lib/clay-mate-knowledge-input.js +26 -0
- package/lib/clay-mate-knowledge.js +95 -0
- package/lib/clay-mate-lifecycle.js +95 -0
- package/lib/clay-product-control-input.js +33 -0
- package/lib/clay-product-control-tools.js +51 -0
- package/lib/clay-product-control.js +237 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +83 -0
- package/lib/clay-scheduling-input.js +21 -0
- package/lib/clay-scheduling-receipts.js +26 -0
- package/lib/clay-scheduling.js +119 -0
- package/lib/clay-screen-controls.js +96 -0
- package/lib/clay-workspace-controls.js +83 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -0
- package/lib/daemon-project-access.js +11 -0
- package/lib/daemon-project-lifecycle-callbacks.js +15 -0
- package/lib/daemon-project-lifecycle.js +262 -0
- package/lib/daemon-projects.js +1 -1
- package/lib/daemon.js +73 -221
- package/lib/issues-service.js +29 -15
- package/lib/knowledge-db-import.js +5 -4
- package/lib/knowledge-db-service.js +9 -6
- package/lib/knowledge-document-index.js +2 -1
- package/lib/knowledge-file-store.js +7 -1
- package/lib/knowledge-product-operations.js +46 -0
- package/lib/mate-avatar-catalog.js +12 -0
- package/lib/mate-avatar-migration.js +41 -0
- package/lib/mate-creation-mcp-server.js +2 -0
- package/lib/mate-knowledge-canonical-access.js +10 -0
- package/lib/mate-knowledge-service.js +7 -4
- package/lib/mate-lifecycle-service.js +94 -0
- package/lib/mate-message-delivery.js +43 -0
- package/lib/mate-ready-creation.js +9 -1
- package/lib/mate-schedule-input.js +29 -0
- package/lib/mate-schedule-lifecycle.js +151 -0
- package/lib/mate-scheduling.js +103 -0
- package/lib/mates.js +18 -6
- package/lib/mcp-agent-tools.js +117 -0
- package/lib/mcp-connection-store.js +119 -15
- package/lib/mcp-import-credentials.js +31 -0
- package/lib/mcp-local-transport.js +13 -0
- package/lib/mcp-oauth.js +8 -6
- package/lib/mcp-query-bridge.js +30 -0
- package/lib/mcp-remote-connections.js +74 -20
- package/lib/mcp-source-adapters.js +91 -0
- package/lib/mcp-source-context.js +42 -0
- package/lib/mcp-source-discovery.js +169 -0
- package/lib/mcp-source-plugins.js +68 -0
- package/lib/mcp-source-restrictions.js +47 -0
- package/lib/mcp-tool-policy.js +34 -0
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-users.js +20 -5
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +8 -4
- package/lib/project-debate.js +1 -0
- package/lib/project-delegated-follow-up.js +2 -1
- package/lib/project-directory-claim.js +65 -0
- package/lib/project-file-operations.js +61 -0
- package/lib/project-filesystem.js +13 -87
- package/lib/project-full-access.js +23 -2
- package/lib/project-knowledge.js +32 -18
- package/lib/project-lifecycle-operations.js +98 -0
- package/lib/project-lifecycle-process-witness.js +32 -0
- package/lib/project-lifecycle-runtime.js +50 -0
- package/lib/project-linux-access.js +22 -0
- package/lib/project-logs-canonical-clay.js +27 -0
- package/lib/project-logs-clay-query.js +16 -0
- package/lib/project-logs-schema.js +4 -2
- package/lib/project-logs-service.js +8 -7
- package/lib/project-logs.js +1 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-mate-chat-control.js +55 -0
- package/lib/project-mate-creation-proposal.js +18 -3
- package/lib/project-mate-interaction.js +8 -0
- package/lib/project-mcp.js +54 -16
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +74 -16
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pending-message-queue.js +1 -0
- package/lib/project-product-control.js +87 -0
- package/lib/project-product-session-queue.js +46 -0
- package/lib/project-push-access.js +28 -0
- package/lib/project-scheduled-message-queue.js +30 -0
- package/lib/project-scheduled-messages.js +63 -64
- package/lib/project-scheduled-task-control.js +83 -0
- package/lib/project-scheduled-tasks.js +13 -2
- package/lib/project-scheduling-access.js +10 -0
- package/lib/project-session-actions.js +65 -0
- package/lib/project-session-delete.js +8 -1
- package/lib/project-session-document.js +8 -3
- package/lib/project-session-github.js +63 -19
- package/lib/project-session-history-actions.js +165 -0
- package/lib/project-session-linear.js +14 -6
- package/lib/project-session-notes.js +7 -3
- package/lib/project-session-runtime-actions.js +63 -0
- package/lib/project-session-vendor.js +54 -0
- package/lib/project-sessions.js +68 -241
- package/lib/project-shared-browser.js +56 -12
- package/lib/project-user-message.js +30 -1
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +9 -2
- package/lib/project.js +144 -37
- package/lib/public/app.js +5 -0
- package/lib/public/appearance-bootstrap.js +14 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/clay-workspace.css +29 -0
- package/lib/public/css/home-debate-planning.css +2 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/mate-avatar-gallery.css +12 -0
- package/lib/public/css/mate-conversation.css +10 -5
- package/lib/public/css/overlays.css +4 -2
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +46 -1
- package/lib/public/css/shared-browser.css +35 -1
- package/lib/public/css/sticky-notes.css +61 -1
- package/lib/public/index.html +11 -5
- package/lib/public/mate-avatars/B01.png +0 -0
- package/lib/public/mate-avatars/B02.png +0 -0
- package/lib/public/mate-avatars/B03.png +0 -0
- package/lib/public/mate-avatars/B04.png +0 -0
- package/lib/public/mate-avatars/B05.png +0 -0
- package/lib/public/mate-avatars/B06.png +0 -0
- package/lib/public/mate-avatars/B07.png +0 -0
- package/lib/public/mate-avatars/B08.png +0 -0
- package/lib/public/mate-avatars/B09.png +0 -0
- package/lib/public/mate-avatars/B10.png +0 -0
- package/lib/public/mate-avatars/B11.png +0 -0
- package/lib/public/mate-avatars/B12.png +0 -0
- package/lib/public/mate-avatars/B13.png +0 -0
- package/lib/public/mate-avatars/B14.png +0 -0
- package/lib/public/mate-avatars/B15.png +0 -0
- package/lib/public/mate-avatars/B16.png +0 -0
- package/lib/public/mate-avatars/B17.png +0 -0
- package/lib/public/mate-avatars/B18.png +0 -0
- package/lib/public/mate-avatars/B19.png +0 -0
- package/lib/public/mate-avatars/B20.png +0 -0
- package/lib/public/mate-avatars/B21.png +0 -0
- package/lib/public/mate-avatars/B22.png +0 -0
- package/lib/public/mate-avatars/B23.png +0 -0
- package/lib/public/mate-avatars/B24.png +0 -0
- package/lib/public/mate-avatars/B25.png +0 -0
- package/lib/public/mate-avatars/B26.png +0 -0
- package/lib/public/mate-avatars/B27.png +0 -0
- package/lib/public/mate-avatars/B28.png +0 -0
- package/lib/public/mate-avatars/B29.png +0 -0
- package/lib/public/mate-avatars/B30.png +0 -0
- package/lib/public/mate-avatars/B31.png +0 -0
- package/lib/public/mate-avatars/B32.png +0 -0
- package/lib/public/mate-avatars/B33.png +0 -0
- package/lib/public/mate-avatars/B34.png +0 -0
- package/lib/public/mate-avatars/B35.png +0 -0
- package/lib/public/mate-avatars/B36.png +0 -0
- package/lib/public/mate-avatars/B37.png +0 -0
- package/lib/public/mate-avatars/B38.png +0 -0
- package/lib/public/mate-avatars/B39.png +0 -0
- package/lib/public/mate-avatars/B40.png +0 -0
- package/lib/public/mate-avatars/B41.png +0 -0
- package/lib/public/mate-avatars/B42.png +0 -0
- package/lib/public/mate-avatars/B43.png +0 -0
- package/lib/public/mate-avatars/B44.png +0 -0
- package/lib/public/mate-avatars/B45.png +0 -0
- package/lib/public/mate-avatars/B46.png +0 -0
- package/lib/public/mate-avatars/B47.png +0 -0
- package/lib/public/mate-avatars/B48.png +0 -0
- package/lib/public/mate-avatars/C01.png +0 -0
- package/lib/public/mate-avatars/C02.png +0 -0
- package/lib/public/mate-avatars/C03.png +0 -0
- package/lib/public/mate-avatars/C04.png +0 -0
- package/lib/public/mate-avatars/C05.png +0 -0
- package/lib/public/mate-avatars/C06.png +0 -0
- package/lib/public/mate-avatars/C07.png +0 -0
- package/lib/public/mate-avatars/C08.png +0 -0
- package/lib/public/mate-avatars/C09.png +0 -0
- package/lib/public/mate-avatars/C10.png +0 -0
- package/lib/public/mate-avatars/C11.png +0 -0
- package/lib/public/mate-avatars/C12.png +0 -0
- package/lib/public/mate-avatars/C13.png +0 -0
- package/lib/public/mate-avatars/C14.png +0 -0
- package/lib/public/mate-avatars/C15.png +0 -0
- package/lib/public/mate-avatars/C16.png +0 -0
- package/lib/public/mate-avatars/C17.png +0 -0
- package/lib/public/mate-avatars/C18.png +0 -0
- package/lib/public/mate-avatars/C19.png +0 -0
- package/lib/public/mate-avatars/C20.png +0 -0
- package/lib/public/mate-avatars/C21.png +0 -0
- package/lib/public/mate-avatars/C22.png +0 -0
- package/lib/public/mate-avatars/C23.png +0 -0
- package/lib/public/mate-avatars/C24.png +0 -0
- package/lib/public/mate-avatars/C25.png +0 -0
- package/lib/public/mate-avatars/C26.png +0 -0
- package/lib/public/mate-avatars/C27.png +0 -0
- package/lib/public/mate-avatars/C28.png +0 -0
- package/lib/public/mate-avatars/C29.png +0 -0
- package/lib/public/mate-avatars/C30.png +0 -0
- package/lib/public/mate-avatars/C31.png +0 -0
- package/lib/public/mate-avatars/C32.png +0 -0
- package/lib/public/mate-avatars/C33.png +0 -0
- package/lib/public/mate-avatars/C34.png +0 -0
- package/lib/public/mate-avatars/C35.png +0 -0
- package/lib/public/mate-avatars/C36.png +0 -0
- package/lib/public/mate-avatars/C37.png +0 -0
- package/lib/public/mate-avatars/C38.png +0 -0
- package/lib/public/mate-avatars/C39.png +0 -0
- package/lib/public/mate-avatars/C40.png +0 -0
- package/lib/public/mate-avatars/C41.png +0 -0
- package/lib/public/mate-avatars/C42.png +0 -0
- package/lib/public/mate-avatars/C43.png +0 -0
- package/lib/public/mate-avatars/C44.png +0 -0
- package/lib/public/mate-avatars/C45.png +0 -0
- package/lib/public/mate-avatars/C46.png +0 -0
- package/lib/public/mate-avatars/C47.png +0 -0
- package/lib/public/mate-avatars/C48.png +0 -0
- package/lib/public/mate-avatars/catalog.json +482 -0
- package/lib/public/mate-avatars/lead-clay.png +0 -0
- package/lib/public/modules/admin-settings-projects.js +6 -2
- package/lib/public/modules/app-connection.js +8 -1
- package/lib/public/modules/app-message-router.js +4 -0
- package/lib/public/modules/app-messages.js +31 -5
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/app-rendering.js +1 -1
- package/lib/public/modules/avatar.js +15 -41
- package/lib/public/modules/chat-render-runtime.js +10 -1
- package/lib/public/modules/clay-browser-links.js +47 -0
- package/lib/public/modules/clay-log-links.js +1 -1
- package/lib/public/modules/clay-owner-navigation.js +27 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +338 -0
- package/lib/public/modules/command-palette.js +2 -2
- package/lib/public/modules/debate.js +1 -0
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/history-replay-batch.js +5 -1
- package/lib/public/modules/home-debate-live.js +2 -0
- package/lib/public/modules/home-debate-planning.js +7 -7
- package/lib/public/modules/home-mate-avatar-editor.js +127 -208
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/home-mate-settings.js +19 -12
- package/lib/public/modules/markdown.js +4 -0
- package/lib/public/modules/mate-avatar-catalog.js +97 -0
- package/lib/public/modules/mate-management.js +40 -7
- package/lib/public/modules/mcp-connection-view.js +31 -13
- package/lib/public/modules/mcp-discovery-view.js +31 -0
- package/lib/public/modules/mcp-ui.js +23 -4
- package/lib/public/modules/mention.js +3 -0
- package/lib/public/modules/pane-browser-bridge.js +20 -0
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/profile.js +1 -238
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/project-mate-navigation.js +99 -14
- package/lib/public/modules/search-clay-chat.js +16 -2
- package/lib/public/modules/session-folder-layout.js +1 -1
- package/lib/public/modules/session-folder-view-menu.js +9 -0
- package/lib/public/modules/session-github.js +85 -14
- package/lib/public/modules/session-work-primary.js +51 -0
- package/lib/public/modules/shared-browser-settings.js +112 -0
- package/lib/public/modules/shared-browser-tabs.js +13 -3
- package/lib/public/modules/shared-browser.js +27 -6
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/split-view.js +2 -0
- package/lib/public/modules/sticky-note-markdown.js +72 -6
- package/lib/public/modules/sticky-notes-actions.js +30 -0
- package/lib/public/modules/sticky-notes-browser.js +9 -2
- package/lib/public/modules/sticky-notes-card.js +23 -7
- package/lib/public/modules/sticky-notes-checklist.js +71 -0
- package/lib/public/modules/sticky-notes-editor.js +108 -44
- package/lib/public/modules/sticky-notes-shared.js +50 -2
- package/lib/public/modules/sticky-notes-state.js +66 -0
- package/lib/public/modules/sticky-notes.js +34 -51
- package/lib/public/modules/theme.js +8 -1
- package/lib/public/modules/thinking-lifecycle.js +33 -3
- package/lib/public/modules/thinking-view.js +23 -1
- package/lib/public/modules/tools.js +36 -7
- package/lib/public/modules/user-settings-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +11 -2
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +12 -2
- package/lib/public/modules/user-settings.js +3 -2
- package/lib/public/style.css +3 -0
- package/lib/public/sw.js +3 -1
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +228 -23
- package/lib/sdk-message-processor.js +2 -0
- package/lib/sdk-response-recovery.js +155 -0
- package/lib/server-admin.js +63 -16
- package/lib/server-appearance-settings.js +13 -1
- package/lib/server-dm.js +2 -1
- package/lib/server-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +18 -4
- package/lib/server-home-chat.js +12 -16
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +14 -0
- package/lib/server-mates.js +25 -62
- package/lib/server-owner-ui.js +77 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server-settings.js +4 -1
- package/lib/server.js +144 -41
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-github.js +9 -2
- package/lib/session-visibility.js +5 -2
- package/lib/session-work-primary.js +50 -0
- package/lib/sessions.js +13 -0
- package/lib/shared-browser-cookie-sync.js +32 -0
- package/lib/shared-browser-cookies.js +79 -0
- package/lib/shared-browser-runtime.js +25 -9
- package/lib/shared-browser-storage-sync.js +43 -0
- package/lib/shared-browser-storage.js +101 -0
- package/lib/shared-browser-tools.js +2 -1
- package/lib/shared-browser-worker.js +46 -10
- package/lib/terminal-manager.js +52 -0
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +4 -0
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +8 -2
- package/lib/yoke/acp-agent-profiles.js +2 -2
- package/lib/yoke/adapters/claude.js +47 -8
- package/lib/yoke/adapters/codex.js +52 -111
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/session-tool-transport.js +3 -0
- package/package.json +5 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Reconcile canonical broadcasts with optimistic checklist actions and text drafts.
|
|
2
|
+
import { store } from './store.js';
|
|
3
|
+
import { getNoteUiState, setNoteUiState, send } from './sticky-notes-shared.js';
|
|
4
|
+
|
|
5
|
+
function project(ui, pending, error) {
|
|
6
|
+
var canonical = ui.canonical || {};
|
|
7
|
+
var text = ui.draft ? ui.text : canonical.text || "";
|
|
8
|
+
var mode = canonical.checklistMode === true;
|
|
9
|
+
var state = Object.assign({}, canonical.checklistState || {});
|
|
10
|
+
pending.forEach(function (request) {
|
|
11
|
+
var changes = request.changes;
|
|
12
|
+
if (changes.text !== undefined) text = changes.text;
|
|
13
|
+
if (changes.checklistMode !== undefined) mode = changes.checklistMode;
|
|
14
|
+
if (changes.checklistKey) state[decodeURIComponent(changes.checklistKey)] = changes.checklistChecked;
|
|
15
|
+
});
|
|
16
|
+
return setNoteUiState(canonical.id, {
|
|
17
|
+
text: text,
|
|
18
|
+
checklistMode: mode, checklistState: state, pending: pending, error: error || '',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function reconcileNote(data) {
|
|
23
|
+
var ui = getNoteUiState(data.id, data);
|
|
24
|
+
var draft = ui.draft && ui.text !== (data.text || '');
|
|
25
|
+
ui = setNoteUiState(data.id, { canonical: data, canonicalRevision: (ui.canonicalRevision || 0) + 1, draft: draft });
|
|
26
|
+
project(ui, ui.pending || [], ui.error);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function mutateChecklist(id, changes) {
|
|
30
|
+
var ui = getNoteUiState(id);
|
|
31
|
+
var requestId = 'note-update-' + Date.now() + '-' + Math.random().toString(36).slice(2);
|
|
32
|
+
var pending = (ui.pending || []).concat([{ requestId: requestId, changes: changes, revision: ui.canonicalRevision, draftText: ui.text }]);
|
|
33
|
+
project(ui, pending, '');
|
|
34
|
+
if (!send(Object.assign({}, changes, { type: changes.humanClose ? 'note_close' : 'note_update', id: id, requestId: requestId }))) {
|
|
35
|
+
project(getNoteUiState(id), pending.slice(0, -1), 'Connection unavailable');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function reconcileNoteResult(msg) {
|
|
40
|
+
var ui = getNoteUiState(msg.noteId);
|
|
41
|
+
var request = (ui.pending || []).find(function (item) { return item.requestId === msg.requestId; });
|
|
42
|
+
if (!request) return;
|
|
43
|
+
// The server broadcasts before acknowledgement. Use the returned note when
|
|
44
|
+
// that broadcast was absent, but never replace a newer remote canonical note.
|
|
45
|
+
if (msg.ok && msg.note && ui.canonicalRevision === request.revision) {
|
|
46
|
+
reconcileNote(msg.note);
|
|
47
|
+
ui = getNoteUiState(msg.noteId);
|
|
48
|
+
}
|
|
49
|
+
if (msg.ok && request.changes.checklistConvert && ui.text === request.draftText) {
|
|
50
|
+
ui = setNoteUiState(msg.noteId, { draft: false, text: ui.canonical.text || '' });
|
|
51
|
+
}
|
|
52
|
+
if (msg.ok && (request.changes.checklistEdit || request.changes.checklistConvert || request.changes.humanClose)) {
|
|
53
|
+
ui = setNoteUiState(msg.noteId, { checklistInputs: null });
|
|
54
|
+
}
|
|
55
|
+
var remaining = ui.pending.filter(function (item) { return item.requestId !== msg.requestId; });
|
|
56
|
+
project(ui, remaining, msg.ok ? '' : msg.error || 'Could not save checklist change');
|
|
57
|
+
return ui.canonical;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
store.subscribe(function (next, previous) {
|
|
61
|
+
if (next.connected || next.connected === previous.connected) return;
|
|
62
|
+
var all = next.stickyNoteUiState || {};
|
|
63
|
+
Object.keys(all).forEach(function (id) {
|
|
64
|
+
if (all[id].pending && all[id].pending.length) project(all[id], [], 'Connection unavailable');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
// The sticky-note canvas: the board of floating cards over the conversation.
|
|
2
|
-
//
|
|
3
2
|
// This module owns the notes map, visibility, the badges, and the WebSocket
|
|
4
3
|
// handlers. Card markup and interactions live in sticky-notes-card.js, text
|
|
5
|
-
// editing in sticky-notes-editor.js, and
|
|
4
|
+
// editing in sticky-notes-editor.js, and leaf helpers in
|
|
6
5
|
// sticky-notes-shared.js. The browse/index pane is sticky-notes-browser.js.
|
|
7
6
|
|
|
8
7
|
import { refreshIcons, iconHtml } from './icons.js';
|
|
9
|
-
import {
|
|
10
|
-
import { enhanceClayLogLinks } from './clay-log-links.js';
|
|
11
|
-
import { isClosedNote, send, clampPos, clearNoteTimers, syncTitle } from './sticky-notes-shared.js';
|
|
8
|
+
import { isClosedNote, send, clampPos, clearNoteTimers, deleteNoteUiState } from './sticky-notes-shared.js';
|
|
12
9
|
import { renderNote, closeColorPicker } from './sticky-notes-card.js';
|
|
13
10
|
import { closeFormatToolbar, isFormatToolbarOpen } from './sticky-notes-editor.js';
|
|
14
11
|
import { store } from './store.js';
|
|
12
|
+
import { reconcileNote, reconcileNoteResult } from './sticky-notes-state.js';
|
|
15
13
|
|
|
16
14
|
var notes = new Map(); // id -> { data, el }
|
|
17
15
|
var notesVisible = false;
|
|
18
16
|
var notesResizeObserver = null;
|
|
19
17
|
|
|
20
|
-
// The canvas shows open notes only. Closed notes
|
|
21
|
-
// the browser's Closed tab until they are reopened.
|
|
18
|
+
// The canvas shows open notes only. Closed notes live in the browser's Closed tab.
|
|
22
19
|
function openCount() {
|
|
23
20
|
var count = 0;
|
|
24
21
|
notes.forEach(function (entry) {
|
|
@@ -259,9 +256,7 @@ export function handleNotesList(msg) {
|
|
|
259
256
|
var container = document.getElementById("sticky-notes-container");
|
|
260
257
|
if (!container) return;
|
|
261
258
|
|
|
262
|
-
//
|
|
263
|
-
// list unchanged; tearing every note down and recreating it made all the
|
|
264
|
-
// floating cards vanish and reappear, and destroyed any open editor.
|
|
259
|
+
// Reconcile keyed cards in place so reconnects retain the active editor.
|
|
265
260
|
var list = msg.notes || [];
|
|
266
261
|
var seen = {};
|
|
267
262
|
var created = false;
|
|
@@ -283,28 +278,27 @@ export function handleNotesList(msg) {
|
|
|
283
278
|
created = true;
|
|
284
279
|
}
|
|
285
280
|
|
|
286
|
-
// Remove
|
|
281
|
+
// Remove subscriptions and delayed writes along with stale cards.
|
|
287
282
|
var staleIds = [];
|
|
288
283
|
notes.forEach(function (value, id) {
|
|
289
284
|
if (!seen[id]) staleIds.push(id);
|
|
290
285
|
});
|
|
291
286
|
for (i = 0; i < staleIds.length; i++) {
|
|
292
287
|
var stale = notes.get(staleIds[i]);
|
|
288
|
+
if (stale && stale.el && stale.el._stickyNoteDispose) stale.el._stickyNoteDispose();
|
|
293
289
|
if (stale && stale.el && stale.el.parentNode) stale.el.parentNode.removeChild(stale.el);
|
|
290
|
+
clearNoteTimers(staleIds[i]);
|
|
291
|
+
deleteNoteUiState(staleIds[i]);
|
|
294
292
|
notes.delete(staleIds[i]);
|
|
295
293
|
}
|
|
296
294
|
|
|
297
|
-
//
|
|
298
|
-
// pass introduces no new Lucide markup and must not trigger a document scan.
|
|
295
|
+
// An all-patch list adds no icon markup and needs no document-wide scan.
|
|
299
296
|
if (created) refreshIcons();
|
|
300
297
|
|
|
301
298
|
updateBadge();
|
|
302
299
|
updateSidebarBadge();
|
|
303
300
|
refreshBrowser();
|
|
304
301
|
|
|
305
|
-
// Auto-show only when something is actually asking for attention. A board of
|
|
306
|
-
// nothing but closed notes must not pop the canvas open. Temporary hiding is
|
|
307
|
-
// explicit view state and must survive reconnects and list updates.
|
|
308
302
|
if (openCount() > 0 && !notesVisible) {
|
|
309
303
|
notesVisible = true;
|
|
310
304
|
applyCanvasVisibility();
|
|
@@ -337,18 +331,13 @@ export function handleNoteCreated(msg) {
|
|
|
337
331
|
syncFlightControls();
|
|
338
332
|
}
|
|
339
333
|
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
//
|
|
343
|
-
// applied. The rendered markdown is only replaced when the text actually
|
|
344
|
-
// changed and the note is not being edited, so a geometry-only or z-only
|
|
345
|
-
// update never destroys the user's caret, selection, or in-progress draft.
|
|
346
|
-
// Returns true when icon markup was replaced, so the caller can decide whether
|
|
347
|
-
// a Lucide pass is needed at all.
|
|
334
|
+
// Canonical content reconciles through the store; geometry patches independently
|
|
335
|
+
// so movement and stacking updates preserve the editor and its draft.
|
|
336
|
+
// Return whether the minimize control introduced fresh icon markup.
|
|
348
337
|
function patchNote(entry, next) {
|
|
349
338
|
if (!entry || !next) return false;
|
|
350
|
-
var previous = entry.data || {};
|
|
351
339
|
entry.data = next;
|
|
340
|
+
reconcileNote(next);
|
|
352
341
|
var el = entry.el;
|
|
353
342
|
|
|
354
343
|
el.style.left = next.x + "px";
|
|
@@ -358,26 +347,6 @@ function patchNote(entry, next) {
|
|
|
358
347
|
el.style.zIndex = 100 + (next.zIndex || 0);
|
|
359
348
|
el.dataset.color = next.color || "purple";
|
|
360
349
|
|
|
361
|
-
var textarea = el.querySelector(".sticky-note-text");
|
|
362
|
-
var rendered = el.querySelector(".sticky-note-rendered");
|
|
363
|
-
var nextText = next.text || "";
|
|
364
|
-
var editing = rendered === document.activeElement || textarea === document.activeElement;
|
|
365
|
-
// A draft the user typed but has not committed must survive a redraw.
|
|
366
|
-
var hasDraft = !!(textarea && textarea.value !== (previous.text || ""));
|
|
367
|
-
var textChanged = nextText !== (previous.text || "");
|
|
368
|
-
if (rendered && !editing && !hasDraft && textChanged) {
|
|
369
|
-
if (textarea) textarea.value = nextText;
|
|
370
|
-
if (nextText.trim()) {
|
|
371
|
-
rendered.innerHTML = renderMiniMarkdown(nextText);
|
|
372
|
-
enhanceClayLogLinks(rendered);
|
|
373
|
-
rendered.classList.remove("is-empty");
|
|
374
|
-
} else {
|
|
375
|
-
rendered.innerHTML = "";
|
|
376
|
-
rendered.classList.add("is-empty");
|
|
377
|
-
}
|
|
378
|
-
syncTitle(el, nextText);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
350
|
if (typeof next.opacity === "number") {
|
|
382
351
|
el.style.setProperty("--note-opacity", next.opacity);
|
|
383
352
|
var slider = el.querySelector(".sticky-note-opacity-slider");
|
|
@@ -388,8 +357,6 @@ function patchNote(entry, next) {
|
|
|
388
357
|
else el.classList.remove("hidden");
|
|
389
358
|
syncFlightState(el, true);
|
|
390
359
|
|
|
391
|
-
// The minimize button swaps its icon, which is the only path here that can
|
|
392
|
-
// introduce fresh Lucide markup.
|
|
393
360
|
var iconsReplaced = false;
|
|
394
361
|
var wasMinimized = el.classList.contains("minimized");
|
|
395
362
|
var minBtn = el.querySelector(".sticky-note-min-btn");
|
|
@@ -419,13 +386,18 @@ export function handleNoteUpdated(msg) {
|
|
|
419
386
|
if (patchNote(entry, msg.note)) refreshIcons();
|
|
420
387
|
reclampAllNotes();
|
|
421
388
|
|
|
422
|
-
// A close or reopen arrives as an ordinary update, so the canvas count and
|
|
423
|
-
// the browser both follow from the same message.
|
|
424
389
|
updateBadge();
|
|
425
390
|
updateSidebarBadge();
|
|
426
391
|
refreshBrowser();
|
|
427
392
|
}
|
|
428
393
|
|
|
394
|
+
export function handleNoteUpdateResult(msg) {
|
|
395
|
+
var entry = notes.get(msg.noteId);
|
|
396
|
+
if (!entry || !msg.requestId) return;
|
|
397
|
+
var canonical = reconcileNoteResult(msg);
|
|
398
|
+
if (canonical) { entry.data = canonical; refreshBrowser(); }
|
|
399
|
+
}
|
|
400
|
+
|
|
429
401
|
export function handleNoteWritten(msg) {
|
|
430
402
|
var entry = notes.get(msg.id);
|
|
431
403
|
if (!entry) return;
|
|
@@ -437,11 +409,11 @@ export function handleNoteWritten(msg) {
|
|
|
437
409
|
}, 2100);
|
|
438
410
|
}
|
|
439
411
|
|
|
440
|
-
// Defensive only. The server no longer deletes notes and never sends this, but
|
|
441
|
-
// an older daemon on the other end of the socket still must not corrupt state.
|
|
442
412
|
export function handleNoteDeleted(msg) {
|
|
443
413
|
var entry = notes.get(msg.id);
|
|
414
|
+
if (entry && entry.el._stickyNoteDispose) entry.el._stickyNoteDispose();
|
|
444
415
|
if (entry) entry.el.remove();
|
|
416
|
+
deleteNoteUiState(msg.id);
|
|
445
417
|
clearNoteTimers(msg.id);
|
|
446
418
|
notes.delete(msg.id);
|
|
447
419
|
updateBadge();
|
|
@@ -467,3 +439,14 @@ function updateSidebarBadge() {
|
|
|
467
439
|
export function isNotesVisible() {
|
|
468
440
|
return notesVisible;
|
|
469
441
|
}
|
|
442
|
+
|
|
443
|
+
// Project navigation must cancel writes and detach subscriptions before reuse.
|
|
444
|
+
export function resetStickyNotes() {
|
|
445
|
+
handleNotesList({ notes: [] });
|
|
446
|
+
closeFormatToolbar();
|
|
447
|
+
closeColorPicker();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
store.subscribe(function (next, previous) {
|
|
451
|
+
if (next.currentSlug !== previous.currentSlug) resetStickyNotes();
|
|
452
|
+
});
|
|
@@ -614,7 +614,14 @@ function rebuildPicker() {
|
|
|
614
614
|
|
|
615
615
|
// --- Init ---
|
|
616
616
|
export function initTheme() {
|
|
617
|
-
|
|
617
|
+
var seed = window.__clayAppearanceSeed;
|
|
618
|
+
if (seed && seed.configured) store.set({ appearancePreference: seed });
|
|
619
|
+
var initialMode = seed && seed.configured && (seed.mode === 'light' || seed.mode === 'dark')
|
|
620
|
+
? seed.mode
|
|
621
|
+
: getSystemMode();
|
|
622
|
+
currentThemeId = seed && seed.configured && seed[initialMode + 'Theme']
|
|
623
|
+
? seed[initialMode + 'Theme']
|
|
624
|
+
: (initialMode === 'light' ? DEFAULT_LIGHT_THEME_ID : DEFAULT_DARK_THEME_ID);
|
|
618
625
|
document.body.classList.toggle('wide-view', isWideView());
|
|
619
626
|
|
|
620
627
|
// Load all themes from server, then apply properly
|
|
@@ -27,6 +27,32 @@ function maybeScrollToBottom() {
|
|
|
27
27
|
if (!store.get('replayingHistory')) scrollToBottom();
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function cancelThinkingRender() {
|
|
31
|
+
var frame = store.get('thinkingRenderFrame');
|
|
32
|
+
if (frame == null) return;
|
|
33
|
+
cancelAnimationFrame(frame);
|
|
34
|
+
store.set({ thinkingRenderFrame: null });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function flushThinkingRender() {
|
|
38
|
+
cancelThinkingRender();
|
|
39
|
+
var state = getThinkingState();
|
|
40
|
+
if (!state) return;
|
|
41
|
+
updateThinkingView(state.el, state.segmentText || state.latestText, state.detailsText);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function scheduleThinkingRender() {
|
|
45
|
+
if (store.get('replayingHistory') || store.get('thinkingRenderFrame') != null) return;
|
|
46
|
+
store.set({ thinkingRenderFrame: requestAnimationFrame(function () {
|
|
47
|
+
store.set({ thinkingRenderFrame: null });
|
|
48
|
+
var state = getThinkingState();
|
|
49
|
+
if (!state || !state.active) return;
|
|
50
|
+
keepActiveThinkingAtTail();
|
|
51
|
+
updateThinkingView(state.el, state.segmentText || state.latestText, state.detailsText);
|
|
52
|
+
maybeScrollToBottom();
|
|
53
|
+
}) });
|
|
54
|
+
}
|
|
55
|
+
|
|
30
56
|
function createThinkingElement() {
|
|
31
57
|
var el = document.createElement("div");
|
|
32
58
|
el.className = "thinking-item";
|
|
@@ -111,14 +137,13 @@ export function appendThinkingText(text) {
|
|
|
111
137
|
detailsText: thinkingState.detailsText + separator + text,
|
|
112
138
|
latestText: segmentText.trim() ? segmentText : thinkingState.latestText,
|
|
113
139
|
});
|
|
114
|
-
|
|
115
|
-
updateThinkingView(thinkingState.el, thinkingState.segmentText || thinkingState.latestText, thinkingState.detailsText);
|
|
116
|
-
maybeScrollToBottom();
|
|
140
|
+
scheduleThinkingRender();
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
export function stopThinkingSegment(duration) {
|
|
120
144
|
var thinkingState = getThinkingState();
|
|
121
145
|
if (!thinkingState || !thinkingState.active) return;
|
|
146
|
+
cancelThinkingRender();
|
|
122
147
|
var seconds = typeof duration === "number" ? duration : (Date.now() - thinkingState.startTime) / 1000;
|
|
123
148
|
thinkingState = updateThinkingState(thinkingState, {
|
|
124
149
|
totalDuration: thinkingState.totalDuration + seconds,
|
|
@@ -145,20 +170,25 @@ export function resetThinkingTurn() {
|
|
|
145
170
|
}
|
|
146
171
|
|
|
147
172
|
export function clearThinkingState() {
|
|
173
|
+
cancelThinkingRender();
|
|
148
174
|
setThinkingState(null);
|
|
149
175
|
}
|
|
150
176
|
|
|
151
177
|
export function saveThinkingState() {
|
|
178
|
+
flushThinkingRender();
|
|
152
179
|
return getThinkingState();
|
|
153
180
|
}
|
|
154
181
|
|
|
155
182
|
export function restoreThinkingState(saved) {
|
|
183
|
+
cancelThinkingRender();
|
|
156
184
|
setThinkingState(saved || null);
|
|
185
|
+
if (saved && saved.active) scheduleThinkingRender();
|
|
157
186
|
}
|
|
158
187
|
|
|
159
188
|
export function resumeThinkingAfterReplay(processing) {
|
|
160
189
|
var thinkingState = getThinkingState();
|
|
161
190
|
if (!thinkingState || !thinkingState.active || !processing) return;
|
|
191
|
+
flushThinkingRender();
|
|
162
192
|
keepActiveThinkingAtTail();
|
|
163
193
|
setThinkingViewLive(thinkingState.el, !isMateThinking());
|
|
164
194
|
showMateActivity(thinkingState.el, true, !!thinkingState.detailsText.trim());
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import { thinkingSummary } from './thinking-summary.js';
|
|
2
2
|
import { renderMarkdown } from './markdown.js';
|
|
3
|
+
import { store } from './store.js';
|
|
4
|
+
|
|
5
|
+
// Retain complete source for each historical entry; parse only on disclosure.
|
|
6
|
+
function thinkingDetailsCache() {
|
|
7
|
+
var cache = store.get('thinkingDetailsCache');
|
|
8
|
+
if (!cache) {
|
|
9
|
+
cache = new WeakMap();
|
|
10
|
+
store.set({ thinkingDetailsCache: cache });
|
|
11
|
+
}
|
|
12
|
+
return cache;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function renderThinkingDetails(el) {
|
|
16
|
+
var details = thinkingDetailsCache().get(el);
|
|
17
|
+
if (!details || details.rendered === details.text) return;
|
|
18
|
+
el.querySelector(".thinking-content").innerHTML = details.text.trim() ? renderMarkdown(details.text) : "";
|
|
19
|
+
details.rendered = details.text;
|
|
20
|
+
}
|
|
3
21
|
|
|
4
22
|
export function prepareThinkingView(el) {
|
|
23
|
+
thinkingDetailsCache().set(el, { text: "", rendered: "" });
|
|
5
24
|
el.hidden = false;
|
|
6
25
|
el.classList.remove("empty", "done", "expanded", "thinking-live");
|
|
7
26
|
var header = el.querySelector(".thinking-header");
|
|
@@ -21,6 +40,7 @@ export function bindThinkingView(el) {
|
|
|
21
40
|
var header = el.querySelector(".thinking-header");
|
|
22
41
|
function toggle() {
|
|
23
42
|
if (header.getAttribute("aria-disabled") === "true") return;
|
|
43
|
+
if (!el.classList.contains("expanded")) renderThinkingDetails(el);
|
|
24
44
|
el.classList.toggle("expanded");
|
|
25
45
|
header.setAttribute("aria-expanded", el.classList.contains("expanded") ? "true" : "false");
|
|
26
46
|
}
|
|
@@ -37,7 +57,9 @@ export function updateThinkingView(el, summaryText, detailsText) {
|
|
|
37
57
|
var label = el.querySelector(".thinking-label");
|
|
38
58
|
label.textContent = summary;
|
|
39
59
|
label.title = summary;
|
|
40
|
-
|
|
60
|
+
var details = thinkingDetailsCache().get(el);
|
|
61
|
+
if (details) details.text = detailsText;
|
|
62
|
+
if (el.classList.contains("expanded")) renderThinkingDetails(el);
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
export function setThinkingViewLive(el, live) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { clayToolGroupSummary } from './clay-tool-presentation.js';
|
|
2
|
+
import { applyClayToolItem, applyClayToolResult, finishClayToolItem, findEndedClayTool, clayToolResultGroup, bindToolGroupDisclosure, syncToolGroupDisclosure, syncClayToolGroup } from './clay-tool-activity.js';
|
|
1
3
|
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
2
4
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
3
5
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks } from './markdown.js';
|
|
@@ -76,6 +78,8 @@ function findToolGroup(groupId) {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
function toolGroupSummary(group) {
|
|
81
|
+
var claySummary = clayToolGroupSummary(group, tools);
|
|
82
|
+
if (claySummary) return claySummary;
|
|
79
83
|
var names = group.toolNames;
|
|
80
84
|
var count = names.length;
|
|
81
85
|
var allDone = group.doneCount >= count;
|
|
@@ -167,6 +171,8 @@ function updateToolGroupHeader(group) {
|
|
|
167
171
|
header.style.display = "none";
|
|
168
172
|
group.el.classList.remove("collapsed");
|
|
169
173
|
}
|
|
174
|
+
syncToolGroupDisclosure(group.el);
|
|
175
|
+
syncClayToolGroup(group);
|
|
170
176
|
}
|
|
171
177
|
|
|
172
178
|
function isPlanFile(filePath) {
|
|
@@ -244,6 +250,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
244
250
|
|
|
245
251
|
var container = document.createElement("div");
|
|
246
252
|
container.className = "ask-user-container";
|
|
253
|
+
if (input.source === "mcp-import") container.classList.add("mcp-import-consent");
|
|
247
254
|
container.dataset.toolId = toolId;
|
|
248
255
|
var requestKey = getAskUserRequestKey(toolId);
|
|
249
256
|
container.dataset.askUserRequestKey = requestKey;
|
|
@@ -364,7 +371,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
364
371
|
}
|
|
365
372
|
});
|
|
366
373
|
otherDiv.appendChild(otherInput);
|
|
367
|
-
qDiv.appendChild(otherDiv);
|
|
374
|
+
if (q.allowOther !== false || !(q.options || []).length) qDiv.appendChild(otherDiv);
|
|
368
375
|
container.appendChild(qDiv);
|
|
369
376
|
});
|
|
370
377
|
|
|
@@ -1627,9 +1634,9 @@ export function createToolItem(id, name) {
|
|
|
1627
1634
|
}
|
|
1628
1635
|
|
|
1629
1636
|
applyProjectAssistantIdentity(groupEl, identity);
|
|
1630
|
-
groupEl
|
|
1631
|
-
groupEl.
|
|
1632
|
-
if (
|
|
1637
|
+
bindToolGroupDisclosure(groupEl, function () {
|
|
1638
|
+
var group = findToolGroup(groupEl.dataset.groupId);
|
|
1639
|
+
if (group) group.userToggled = true;
|
|
1633
1640
|
});
|
|
1634
1641
|
|
|
1635
1642
|
ctx.addToMessages(groupEl);
|
|
@@ -1639,6 +1646,8 @@ export function createToolItem(id, name) {
|
|
|
1639
1646
|
el: groupEl,
|
|
1640
1647
|
id: "g" + toolGroupCounter,
|
|
1641
1648
|
toolNames: [],
|
|
1649
|
+
toolIds: [],
|
|
1650
|
+
toolRecords: {},
|
|
1642
1651
|
toolCount: 0,
|
|
1643
1652
|
doneCount: 0,
|
|
1644
1653
|
errorCount: 0,
|
|
@@ -1665,17 +1674,21 @@ export function createToolItem(id, name) {
|
|
|
1665
1674
|
|
|
1666
1675
|
el.querySelector(".tool-name").textContent = name;
|
|
1667
1676
|
|
|
1677
|
+
tools[id] = { el: el, name: name, input: null, done: false, groupId: currentToolGroup.id };
|
|
1678
|
+
applyClayToolItem(tools[id]);
|
|
1679
|
+
|
|
1668
1680
|
// Append to group instead of messages directly
|
|
1669
1681
|
currentToolGroup.el.querySelector(".tool-group-items").appendChild(el);
|
|
1670
1682
|
currentToolGroup.toolNames.push(name);
|
|
1683
|
+
currentToolGroup.toolIds.push(id);
|
|
1684
|
+
currentToolGroup.toolRecords[id] = tools[id];
|
|
1671
1685
|
currentToolGroup.toolCount++;
|
|
1672
1686
|
updateToolGroupHeader(currentToolGroup);
|
|
1673
1687
|
|
|
1674
1688
|
refreshIcons();
|
|
1675
1689
|
maybeScrollToBottom();
|
|
1676
1690
|
|
|
1677
|
-
tools[id]
|
|
1678
|
-
ctx.setActivity("Running " + name + "...");
|
|
1691
|
+
ctx.setActivity(tools[id].clayActivity ? tools[id].clayActivity.label : "Running " + name + "...");
|
|
1679
1692
|
}
|
|
1680
1693
|
|
|
1681
1694
|
export function updateToolExecuting(id, name, input) {
|
|
@@ -1683,6 +1696,12 @@ export function updateToolExecuting(id, name, input) {
|
|
|
1683
1696
|
if (!tool) return;
|
|
1684
1697
|
|
|
1685
1698
|
tool.input = input;
|
|
1699
|
+
if (applyClayToolItem(tool)) {
|
|
1700
|
+
ctx.setActivity(tool.clayActivity.label);
|
|
1701
|
+
updateToolGroupHeader(findToolGroup(tool.groupId));
|
|
1702
|
+
maybeScrollToBottom();
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1686
1705
|
var descEl = tool.el.querySelector(".tool-desc");
|
|
1687
1706
|
descEl.textContent = toolSummary(name, input);
|
|
1688
1707
|
|
|
@@ -1892,9 +1911,17 @@ function isImagePath(filePath) {
|
|
|
1892
1911
|
}
|
|
1893
1912
|
|
|
1894
1913
|
export function updateToolResult(id, content, isError, images) {
|
|
1895
|
-
var tool = tools[id];
|
|
1914
|
+
var tool = tools[id] || findEndedClayTool(ctx.messagesEl, id);
|
|
1896
1915
|
if (!tool) return;
|
|
1897
1916
|
|
|
1917
|
+
if (applyClayToolResult(tool, content, isError)) {
|
|
1918
|
+
markToolDone(id, tool.clayActivity.phase === "error" || tool.clayActivity.phase === "cancelled");
|
|
1919
|
+
applyClayToolItem(tool);
|
|
1920
|
+
updateToolGroupHeader(clayToolResultGroup(tool, findToolGroup(tool.groupId)));
|
|
1921
|
+
maybeScrollToBottom();
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1898
1925
|
// Re-render the sublabel from the now-complete input (streaming can have
|
|
1899
1926
|
// built it from a partial one), but in its terminal form: a result has
|
|
1900
1927
|
// arrived, so this call is no longer running.
|
|
@@ -2025,6 +2052,7 @@ export function markToolDone(id, isError) {
|
|
|
2025
2052
|
icon.innerHTML = '<span class="check">' + iconHtml("check") + '</span>';
|
|
2026
2053
|
}
|
|
2027
2054
|
refreshIcons();
|
|
2055
|
+
finishClayToolItem(tool, findToolGroup(tool.groupId));
|
|
2028
2056
|
|
|
2029
2057
|
// Update group state
|
|
2030
2058
|
if (tool.groupId) {
|
|
@@ -2243,6 +2271,7 @@ export function removeToolFromGroup(toolId) {
|
|
|
2243
2271
|
var group = findToolGroup(tool.groupId);
|
|
2244
2272
|
if (!group) return;
|
|
2245
2273
|
group.toolCount--;
|
|
2274
|
+
if (group.toolIds) group.toolIds = group.toolIds.filter(function (id) { return id !== toolId; });
|
|
2246
2275
|
// Remove tool name from the names array (remove first occurrence)
|
|
2247
2276
|
var idx = group.toolNames.indexOf(tool.name);
|
|
2248
2277
|
if (idx !== -1) group.toolNames.splice(idx, 1);
|
|
@@ -31,7 +31,11 @@ function addTerminalTypography(section) {
|
|
|
31
31
|
var option = document.createElement('option'); option.value = font.family; option.textContent = font.label; family.appendChild(option);
|
|
32
32
|
});
|
|
33
33
|
function sync() {
|
|
34
|
-
if (store.get('userTerminalDirty'))
|
|
34
|
+
if (store.get('userTerminalDirty')) {
|
|
35
|
+
var dirty = family.value !== getTerminalFontFamily() || size.value !== String(getTerminalFontSize());
|
|
36
|
+
store.set({userTerminalDirty:dirty});
|
|
37
|
+
if (dirty) return;
|
|
38
|
+
}
|
|
35
39
|
var value = getTerminalFontFamily();
|
|
36
40
|
if (!Array.from(family.options).some(function (option) { return option.value === value; })) {
|
|
37
41
|
var option = document.createElement('option'); option.value = value; option.textContent = 'Custom font'; family.appendChild(option);
|
|
@@ -41,7 +45,10 @@ function addTerminalTypography(section) {
|
|
|
41
45
|
family.dispatchEvent(new Event('settings-sync'));
|
|
42
46
|
}
|
|
43
47
|
async function save() {
|
|
44
|
-
var
|
|
48
|
+
var dirty = family.value !== getTerminalFontFamily() || size.value !== String(getTerminalFontSize());
|
|
49
|
+
store.set({userTerminalDirty:dirty});
|
|
50
|
+
if (!dirty) {retry.hidden = true;status.textContent = '';status.dataset.state = '';return;}
|
|
51
|
+
var value = Number(size.value);
|
|
45
52
|
if (!Number.isInteger(value) || value < 9 || value > 32) { status.textContent = 'Choose a whole size from 9 to 32.'; status.dataset.state = 'error'; return; }
|
|
46
53
|
family.disabled = true; size.disabled = true; retry.hidden = true; status.textContent = 'Saving…'; status.dataset.state = '';
|
|
47
54
|
try {
|
|
@@ -50,6 +57,6 @@ function addTerminalTypography(section) {
|
|
|
50
57
|
finally { family.disabled = false; size.disabled = false; family.dispatchEvent(new Event('settings-sync')); }
|
|
51
58
|
}
|
|
52
59
|
family.onchange = save; size.onchange = save; retry.onclick = save;
|
|
53
|
-
size.oninput = function () { store.set({ userTerminalDirty:
|
|
60
|
+
size.oninput = function () { store.set({ userTerminalDirty: family.value !== getTerminalFontFamily() || size.value !== String(getTerminalFontSize()) }); };
|
|
54
61
|
onTerminalFontChange(sync); sync(); enhanceSettingsSelects(content);
|
|
55
62
|
}
|
|
@@ -19,6 +19,6 @@ function wrapEditor(content, title, summary) {
|
|
|
19
19
|
}
|
|
20
20
|
export function initPersonalEditors() {
|
|
21
21
|
var allow=document.getElementById('us-claude-allow-list');var permission=wrapEditor(allow.closest('.settings-card'),'Personal allow rules',function(){var count=(store.get('userAllowSaved') || []).length;return count+' personal rules. Managed defaults apply separately.';});
|
|
22
|
-
permission.done.textContent='Cancel';permission.done.onclick=function(){function cancel(){allow.value=(store.get('userAllowSaved') || []).join('\n');store.set({userAllowDirty:false});permission.content.hidden=true;permission.state.hidden=false;permission.edit.hidden=false;permission.edit.focus();}if(store.get('userAllowDirty'))showConfirmDialog('Discard unsaved command rules?', 'Discard',cancel);else cancel();};
|
|
22
|
+
permission.done.textContent='Cancel';permission.done.onclick=function(){function cancel(){allow.value=(store.get('userAllowSaved') || []).join('\n');store.set({userAllowDirty:false,userAllowNeedsRetry:false});permission.content.hidden=true;permission.state.hidden=false;permission.edit.hidden=false;permission.edit.focus();}if(store.get('userAllowDirty'))showConfirmDialog('Discard unsaved command rules?', 'Discard',cancel);else cancel();};
|
|
23
23
|
store.subscribe(function(state,previous){if(state.userAllowSaved!==previous.userAllowSaved){permission.state.textContent=(state.userAllowSaved || []).length+' personal rules. Managed defaults apply separately.';if(previous.userAllowDirty && !state.userAllowDirty){permission.content.hidden=true;permission.state.hidden=false;permission.edit.hidden=false;permission.edit.focus();}}});
|
|
24
24
|
}
|
|
@@ -69,12 +69,21 @@ export function loadUserSettingsExtras(page) {
|
|
|
69
69
|
if (page === 'us-ai') { mountDefaultAi(document.getElementById('us-default-ai')); requestDefaultAi(); var ws=getWs();if(ws && ws.readyState===1)ws.send(JSON.stringify({type:'get_claude_allow_list'})); }
|
|
70
70
|
}
|
|
71
71
|
export function finishUserSettingsExtras() {closeSpeechPicker();unmountDefaultAi(document.getElementById('us-default-ai'));}
|
|
72
|
-
export function guardUserSettingsLeave(done) {
|
|
72
|
+
export function guardUserSettingsLeave(done, destination) {
|
|
73
|
+
var active = document.querySelector('#user-settings .us-section.active');
|
|
74
|
+
var page = active && active.dataset.section;
|
|
75
|
+
if (destination && resolveUserSettingsPage(destination) === page) {done();return;}
|
|
76
|
+
function leaving(id) {return !destination || page === id;}
|
|
73
77
|
var pin = document.getElementById('us-pin-form');
|
|
74
78
|
var pinDirty = pin && !pin.classList.contains('hidden') && Array.from(pin.querySelectorAll('input')).some(function (input) {return !!input.value;});
|
|
75
79
|
var key = document.getElementById('us-linear-key');
|
|
76
80
|
if(store.get('speechPopup'))return;
|
|
77
|
-
var dirty =
|
|
81
|
+
var dirty = leaving('us-integrations') && (store.get('personalEmailDirty') || store.get('personalLinearDirty') || key && key.value) ||
|
|
82
|
+
leaving('us-chat') && store.get('userVoiceDirty') ||
|
|
83
|
+
leaving('us-notifications') && store.get('notificationDraft') ||
|
|
84
|
+
leaving('us-appearance') && (store.get('appearanceDraft') || store.get('userTerminalDirty')) ||
|
|
85
|
+
leaving('us-account') && (store.get('userProfileDirty') || pinDirty) ||
|
|
86
|
+
leaving('us-ai') && (store.get('defaultAiDraftDirty') || store.get('userAllowDirty'));
|
|
78
87
|
if (!dirty) {done();return;}
|
|
79
88
|
showConfirmDialog('Your unsaved changes will remain in this tab. Leave this editor and keep the draft?', 'Keep draft and leave', done);
|
|
80
89
|
}
|
|
@@ -27,7 +27,10 @@ export function initPersonalPreferences() {
|
|
|
27
27
|
catch(error){preferenceStatus('us-layout-switcher',error.message+' Try again.',true);}
|
|
28
28
|
finally{controls.forEach(function(el){el.disabled=false;});}
|
|
29
29
|
};});
|
|
30
|
-
var textarea=document.getElementById('us-claude-allow-list');textarea.oninput=function(){
|
|
30
|
+
var textarea=document.getElementById('us-claude-allow-list');textarea.oninput=function(){
|
|
31
|
+
var patterns=textarea.value.split('\n').map(function(line){return line.trim();}).filter(Boolean);
|
|
32
|
+
store.set({userAllowDirty:!!store.get('userAllowNeedsRetry') || JSON.stringify(patterns)!==JSON.stringify(store.get('userAllowSaved') || [])});
|
|
33
|
+
};
|
|
31
34
|
document.getElementById('us-claude-allow-save').onclick=function(){
|
|
32
35
|
var ws=getWs();if(!ws || ws.readyState!==1){preferenceStatus('us-claude-allow-list','Disconnected. Your draft is retained.',true);return;}
|
|
33
36
|
this.disabled=true;preferenceStatus('us-claude-allow-list','Saving…');ws.send(JSON.stringify({type:'set_claude_user_allow_list',patterns:textarea.value.split('\n').map(function(line){return line.trim();}).filter(Boolean)}));
|
|
@@ -37,11 +40,12 @@ export function initPersonalPreferences() {
|
|
|
37
40
|
export function handlePersonalSettingsMessage(msg) {
|
|
38
41
|
if(msg.type==='claude_allow_list') {
|
|
39
42
|
store.set({userAllowSaved:msg.user || []});
|
|
43
|
+
if(store.get('userAllowDirty'))document.getElementById('us-claude-allow-list').oninput();
|
|
40
44
|
if(store.get('userAllowDirty'))return;
|
|
41
45
|
}
|
|
42
46
|
if(msg.type==='set_claude_user_allow_list_result') {
|
|
43
47
|
document.getElementById('us-claude-allow-save').disabled=false;
|
|
44
|
-
if(msg.ok)store.set({userAllowDirty:msg.effective===false,userAllowSaved:msg.patterns || []});
|
|
48
|
+
if(msg.ok)store.set({userAllowDirty:msg.effective===false,userAllowNeedsRetry:msg.effective===false,userAllowSaved:msg.patterns || []});
|
|
45
49
|
var message=msg.ok ? (msg.effective===false ? 'Saved to your account, but not installed in Claude. Check filesystem access, then Save to retry.' : 'Saved. Applies on the next Claude invocation.') : msg.error || 'Save failed. Your draft is retained.';
|
|
46
50
|
preferenceStatus('us-claude-allow-list',message,!msg.ok || msg.effective===false);
|
|
47
51
|
}
|
|
@@ -13,10 +13,20 @@ export function initPersonalProfile() {
|
|
|
13
13
|
name.after(form); var input = form.querySelector('input');
|
|
14
14
|
function close() { form.hidden = true; name.hidden = false; edit.hidden = false; edit.focus(); }
|
|
15
15
|
edit.onclick = function () {
|
|
16
|
-
if (!store.get('userProfileDirty'))
|
|
16
|
+
if (!store.get('userProfileDirty')) {
|
|
17
|
+
input.value = name.textContent || getProfile().name;
|
|
18
|
+
store.set({userProfileSavedName:input.value.trim()});
|
|
19
|
+
}
|
|
17
20
|
form.hidden = false; name.hidden = true; edit.hidden = true; input.focus(); input.select();
|
|
18
21
|
};
|
|
19
|
-
input.oninput = function () { store.set({ userProfileDirty:
|
|
22
|
+
input.oninput = function () { store.set({ userProfileDirty: input.value.trim() !== store.get('userProfileSavedName') }); };
|
|
23
|
+
store.subscribe(function (state, previous) {
|
|
24
|
+
if (state.userSettingsProfile === previous.userSettingsProfile || !state.userSettingsProfile) return;
|
|
25
|
+
var data = state.userSettingsProfile;
|
|
26
|
+
var saved = data.name || data.displayName || data.username || 'Clay User';
|
|
27
|
+
if (!state.userProfileDirty) input.value = saved;
|
|
28
|
+
store.set({userProfileSavedName:saved.trim(), userProfileDirty:input.value.trim() !== saved.trim()});
|
|
29
|
+
});
|
|
20
30
|
form.onsubmit = async function (event) {
|
|
21
31
|
event.preventDefault(); var save = form.querySelector('[type=submit]'); var status = form.querySelector('[role=status]');
|
|
22
32
|
if (!input.value.trim()) { status.textContent = 'Enter a display name.'; return; }
|
|
@@ -75,7 +75,7 @@ export function initUserSettings() {
|
|
|
75
75
|
for (var i = 0; i < navItems.length; i++) {
|
|
76
76
|
navItems[i].addEventListener('click', function () {
|
|
77
77
|
var section = this.dataset.section;
|
|
78
|
-
guardUserSettingsLeave(function () { switchSection(section); });
|
|
78
|
+
guardUserSettingsLeave(function () { switchSection(section); }, section);
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -83,7 +83,8 @@ export function initUserSettings() {
|
|
|
83
83
|
var navDropdown = document.getElementById('user-settings-nav-dropdown');
|
|
84
84
|
if (navDropdown) {
|
|
85
85
|
navDropdown.addEventListener('change', function () {
|
|
86
|
-
var value = this.value; guardUserSettingsLeave(function () {switchSection(value);});
|
|
86
|
+
var value = this.value; guardUserSettingsLeave(function () {switchSection(value);}, value);
|
|
87
|
+
this.value = settingsEl.querySelector('.us-section.active').dataset.section;
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
|