clay-server 5.2.0-beta.4 → 5.2.0-beta.6
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 +17 -14
- package/lib/canonical-clay-record-authority.js +15 -0
- package/lib/canonical-clay-scheduling-authority.js +19 -0
- package/lib/claude-hook-installer.js +1 -239
- package/lib/claude-jsonl-watcher.js +1 -204
- 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-skill-install.js +1 -33
- 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/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- 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 +78 -276
- package/lib/default-ai-runtime.js +4 -8
- package/lib/email-mcp-server.js +1 -1
- package/lib/issues-service.js +29 -15
- package/lib/kiro-defaults.js +1 -22
- 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-product-operations.js +46 -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 +4 -3
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +1 -1
- package/lib/mcp-source-adapters.js +1 -91
- package/lib/mcp-source-context.js +1 -42
- package/lib/mcp-source-discovery.js +1 -169
- package/lib/mcp-source-plugins.js +1 -68
- package/lib/mcp-source-restrictions.js +1 -47
- package/lib/mcp-tool-policy.js +1 -26
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +24 -70
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +4 -2
- package/lib/project-connection.js +8 -7
- 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-http.js +4 -4
- 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-mcp.js +2 -2
- 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-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +4 -1
- 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-github.js +47 -12
- package/lib/project-session-history-actions.js +167 -0
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +64 -0
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +55 -0
- package/lib/project-sessions.js +82 -267
- package/lib/project-user-message.js +31 -1
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +9 -2
- package/lib/project.js +95 -3
- package/lib/public/app.js +1 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/messages.css +6 -2
- 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 +3 -0
- package/lib/public/css/sticky-notes.css +61 -1
- package/lib/public/index.html +1 -1
- package/lib/public/modules/admin-settings-projects.js +6 -2
- package/lib/public/modules/app-connection.js +8 -1
- package/lib/public/modules/app-favicon.js +11 -2
- package/lib/public/modules/app-header.js +4 -2
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +1 -1
- package/lib/public/modules/app-messages.js +54 -8
- package/lib/public/modules/app-notifications.js +1 -2
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/chat-render-runtime.js +3 -0
- 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 +1 -1
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/home-debate-planning.js +5 -5
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/mcp-connection-view.js +1 -1
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/session-create-form.js +10 -10
- 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 +65 -8
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- 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/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/tui-grab.js +1 -2
- 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/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +2 -0
- package/lib/safe-bash-commands.js +3 -45
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +334 -403
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +52 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-admin.js +63 -16
- package/lib/server-dm.js +1 -1
- package/lib/server-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +7 -3
- package/lib/server-home-chat.js +4 -16
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +3 -3
- package/lib/server-mates.js +25 -67
- 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.js +100 -30
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-fork-history.js +21 -0
- package/lib/session-github.js +9 -2
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +5 -2
- package/lib/sessions.js +27 -89
- package/lib/terminal-manager.js +52 -0
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +4 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +8 -2
- package/lib/yoke/acp-agent-profiles.js +5 -3
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +54 -50
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +53 -111
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +267 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +34 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +3 -2
|
@@ -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
|
+
});
|
|
@@ -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,10 +171,13 @@ 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) {
|
|
173
|
-
|
|
179
|
+
var info = (store.get('vendorInfo') || {})[store.get('currentVendor')] || {};
|
|
180
|
+
return !!filePath && (info.planPathSegments || []).some(function (segment) { return filePath.indexOf(segment) !== -1; });
|
|
174
181
|
}
|
|
175
182
|
|
|
176
183
|
export function toolSummary(name, input) {
|
|
@@ -1628,9 +1635,9 @@ export function createToolItem(id, name) {
|
|
|
1628
1635
|
}
|
|
1629
1636
|
|
|
1630
1637
|
applyProjectAssistantIdentity(groupEl, identity);
|
|
1631
|
-
groupEl
|
|
1632
|
-
groupEl.
|
|
1633
|
-
if (
|
|
1638
|
+
bindToolGroupDisclosure(groupEl, function () {
|
|
1639
|
+
var group = findToolGroup(groupEl.dataset.groupId);
|
|
1640
|
+
if (group) group.userToggled = true;
|
|
1634
1641
|
});
|
|
1635
1642
|
|
|
1636
1643
|
ctx.addToMessages(groupEl);
|
|
@@ -1640,6 +1647,8 @@ export function createToolItem(id, name) {
|
|
|
1640
1647
|
el: groupEl,
|
|
1641
1648
|
id: "g" + toolGroupCounter,
|
|
1642
1649
|
toolNames: [],
|
|
1650
|
+
toolIds: [],
|
|
1651
|
+
toolRecords: {},
|
|
1643
1652
|
toolCount: 0,
|
|
1644
1653
|
doneCount: 0,
|
|
1645
1654
|
errorCount: 0,
|
|
@@ -1666,17 +1675,21 @@ export function createToolItem(id, name) {
|
|
|
1666
1675
|
|
|
1667
1676
|
el.querySelector(".tool-name").textContent = name;
|
|
1668
1677
|
|
|
1678
|
+
tools[id] = { el: el, name: name, input: null, done: false, groupId: currentToolGroup.id };
|
|
1679
|
+
applyClayToolItem(tools[id]);
|
|
1680
|
+
|
|
1669
1681
|
// Append to group instead of messages directly
|
|
1670
1682
|
currentToolGroup.el.querySelector(".tool-group-items").appendChild(el);
|
|
1671
1683
|
currentToolGroup.toolNames.push(name);
|
|
1684
|
+
currentToolGroup.toolIds.push(id);
|
|
1685
|
+
currentToolGroup.toolRecords[id] = tools[id];
|
|
1672
1686
|
currentToolGroup.toolCount++;
|
|
1673
1687
|
updateToolGroupHeader(currentToolGroup);
|
|
1674
1688
|
|
|
1675
1689
|
refreshIcons();
|
|
1676
1690
|
maybeScrollToBottom();
|
|
1677
1691
|
|
|
1678
|
-
tools[id]
|
|
1679
|
-
ctx.setActivity("Running " + name + "...");
|
|
1692
|
+
ctx.setActivity(tools[id].clayActivity ? tools[id].clayActivity.label : "Running " + name + "...");
|
|
1680
1693
|
}
|
|
1681
1694
|
|
|
1682
1695
|
export function updateToolExecuting(id, name, input) {
|
|
@@ -1684,6 +1697,12 @@ export function updateToolExecuting(id, name, input) {
|
|
|
1684
1697
|
if (!tool) return;
|
|
1685
1698
|
|
|
1686
1699
|
tool.input = input;
|
|
1700
|
+
if (applyClayToolItem(tool)) {
|
|
1701
|
+
ctx.setActivity(tool.clayActivity.label);
|
|
1702
|
+
updateToolGroupHeader(findToolGroup(tool.groupId));
|
|
1703
|
+
maybeScrollToBottom();
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1687
1706
|
var descEl = tool.el.querySelector(".tool-desc");
|
|
1688
1707
|
descEl.textContent = toolSummary(name, input);
|
|
1689
1708
|
|
|
@@ -1893,9 +1912,17 @@ function isImagePath(filePath) {
|
|
|
1893
1912
|
}
|
|
1894
1913
|
|
|
1895
1914
|
export function updateToolResult(id, content, isError, images) {
|
|
1896
|
-
var tool = tools[id];
|
|
1915
|
+
var tool = tools[id] || findEndedClayTool(ctx.messagesEl, id);
|
|
1897
1916
|
if (!tool) return;
|
|
1898
1917
|
|
|
1918
|
+
if (applyClayToolResult(tool, content, isError)) {
|
|
1919
|
+
markToolDone(id, tool.clayActivity.phase === "error" || tool.clayActivity.phase === "cancelled");
|
|
1920
|
+
applyClayToolItem(tool);
|
|
1921
|
+
updateToolGroupHeader(clayToolResultGroup(tool, findToolGroup(tool.groupId)));
|
|
1922
|
+
maybeScrollToBottom();
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1899
1926
|
// Re-render the sublabel from the now-complete input (streaming can have
|
|
1900
1927
|
// built it from a partial one), but in its terminal form: a result has
|
|
1901
1928
|
// arrived, so this call is no longer running.
|
|
@@ -2026,6 +2053,7 @@ export function markToolDone(id, isError) {
|
|
|
2026
2053
|
icon.innerHTML = '<span class="check">' + iconHtml("check") + '</span>';
|
|
2027
2054
|
}
|
|
2028
2055
|
refreshIcons();
|
|
2056
|
+
finishClayToolItem(tool, findToolGroup(tool.groupId));
|
|
2029
2057
|
|
|
2030
2058
|
// Update group state
|
|
2031
2059
|
if (tool.groupId) {
|
|
@@ -2244,6 +2272,7 @@ export function removeToolFromGroup(toolId) {
|
|
|
2244
2272
|
var group = findToolGroup(tool.groupId);
|
|
2245
2273
|
if (!group) return;
|
|
2246
2274
|
group.toolCount--;
|
|
2275
|
+
if (group.toolIds) group.toolIds = group.toolIds.filter(function (id) { return id !== toolId; });
|
|
2247
2276
|
// Remove tool name from the names array (remove first occurrence)
|
|
2248
2277
|
var idx = group.toolNames.indexOf(tool.name);
|
|
2249
2278
|
if (idx !== -1) group.toolNames.splice(idx, 1);
|
|
@@ -635,10 +635,9 @@ export function attachTuiGrab(xterm, containerEl, localId, opts) {
|
|
|
635
635
|
if (opts && opts.vendor) {
|
|
636
636
|
var vendors = store.get('vendorInfo') || {};
|
|
637
637
|
var info = vendors[opts.vendor];
|
|
638
|
-
var legacyTuiVendors = ["claude"];
|
|
639
638
|
var supportsTui = info
|
|
640
639
|
? Array.isArray(info.sessionModes) && info.sessionModes.indexOf("tui") !== -1
|
|
641
|
-
:
|
|
640
|
+
: false;
|
|
642
641
|
if (!supportsTui) return;
|
|
643
642
|
}
|
|
644
643
|
|
|
@@ -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
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { escapeHtml } from './utils.js';
|
|
1
2
|
import { store } from './store.js';
|
|
2
3
|
import { getWs } from './ws-ref.js';
|
|
3
4
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
@@ -33,7 +34,8 @@ export function openLoginBrowser(msg) {
|
|
|
33
34
|
}
|
|
34
35
|
closeLoginBrowser();
|
|
35
36
|
var isMcp = msg.kind === 'mcp';
|
|
36
|
-
var
|
|
37
|
+
var provider = (store.get('vendorInfo') || {})[msg.vendor] || {};
|
|
38
|
+
var title = 'Sign in to ' + (isMcp ? msg.label || 'MCP server' : provider.displayName || msg.vendor || 'Provider');
|
|
37
39
|
store.set({ vendorLoginBrowser: {
|
|
38
40
|
browserId: msg.browserId, vendor: msg.vendor, kind: msg.kind, connectionId: msg.connectionId, slug: msg.slug || store.get('currentSlug'),
|
|
39
41
|
previousFocus: document.activeElement, decoding: false, pointerY: null, pointerId: null, mouseDown: false, moveTimer: null, pendingMove: null, resizeObserver: null, requestedSize: null, phase: "loading",
|
|
@@ -43,7 +45,7 @@ export function openLoginBrowser(msg) {
|
|
|
43
45
|
dialog.className = "login-browser";
|
|
44
46
|
dialog.setAttribute("aria-labelledby", "login-browser-title");
|
|
45
47
|
dialog.innerHTML = '<header class="login-browser-header">' +
|
|
46
|
-
'<img class="login-browser-vendor" src="
|
|
48
|
+
'<img class="login-browser-vendor" src="' + escapeHtml(provider.avatar || '') + '" alt="">' +
|
|
47
49
|
'<div class="login-browser-heading"><h2 id="login-browser-title"></h2>' +
|
|
48
50
|
'<span class="login-browser-origin">Opening sign-in page…</span></div>' +
|
|
49
51
|
'<div class="login-browser-actions">' +
|
|
@@ -56,7 +58,7 @@ export function openLoginBrowser(msg) {
|
|
|
56
58
|
'<div class="login-browser-loading"><span class="login-browser-spinner" aria-hidden="true"></span><strong>Opening your sign-in page</strong><span>This may take a moment.</span></div>' +
|
|
57
59
|
'<textarea class="login-browser-keyboard" aria-label="Type into the remote sign-in page" autocomplete="off" autocapitalize="off" spellcheck="false"></textarea></div>' +
|
|
58
60
|
'<footer class="login-browser-footer"><div class="login-browser-info"><div class="login-browser-status"><span class="login-browser-status-dot" aria-hidden="true"></span><p role="status">Preparing sign-in…</p></div>' +
|
|
59
|
-
'<p class="login-browser-privacy">Browser cookies are discarded when this session ends. You stay signed in to ' + (msg.vendor
|
|
61
|
+
'<p class="login-browser-privacy">Browser cookies are discarded when this session ends. You stay signed in to ' + escapeHtml(provider.displayName || msg.vendor || 'the provider') + ' after this browser closes.</p></div>' +
|
|
60
62
|
'<button type="button" data-action="terminal" class="login-browser-terminal">' + iconHtml("terminal") + '<span>Use terminal sign-in</span>' + iconHtml("arrow-up-right") + '</button></footer>';
|
|
61
63
|
dialog.querySelector("h2").textContent = title;
|
|
62
64
|
document.body.appendChild(dialog);
|
|
@@ -31,7 +31,7 @@ function vendorDisplayName(vendor) {
|
|
|
31
31
|
var vendors = store.get('vendorInfo') || {};
|
|
32
32
|
var info = vendors[vendor];
|
|
33
33
|
if (info && info.displayName) return info.displayName;
|
|
34
|
-
return vendor
|
|
34
|
+
return vendor || "Provider";
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function currentProjectSlug() {
|
|
@@ -170,7 +170,7 @@ export function requestVendorLogin(vendor, opts) {
|
|
|
170
170
|
vendor: target,
|
|
171
171
|
auto: !!options.auto,
|
|
172
172
|
sessionId: options.sessionId || store.get('activeSessionId') || null,
|
|
173
|
-
mode: options.mode || ((
|
|
173
|
+
mode: options.mode || ((((store.get("vendorInfo") || {})[target] || {}).browserLoginSupported === true) ? "browser" : "terminal"),
|
|
174
174
|
}));
|
|
175
175
|
showLoginStartedBanner(target);
|
|
176
176
|
return true;
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
export var VENDOR_ORDER = ["claude", "codex", "grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode", "kiro"];
|
|
1
|
+
export var VENDOR_ORDER = ["claude", "codex", "muse", "grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode", "kiro"];
|
|
2
|
+
|
|
3
|
+
// Availability comes from the caller's server catalog. Unknown providers keep
|
|
4
|
+
// their catalog order within each availability group.
|
|
5
|
+
export function sortVendorEntries(entries) {
|
|
6
|
+
return entries.map(function (entry, index) { return { entry: entry, index: index }; }).sort(function (a, b) {
|
|
7
|
+
var installed = Number(!!b.entry.installed) - Number(!!a.entry.installed);
|
|
8
|
+
if (installed) return installed;
|
|
9
|
+
var aRank = VENDOR_ORDER.indexOf(a.entry.id);
|
|
10
|
+
var bRank = VENDOR_ORDER.indexOf(b.entry.id);
|
|
11
|
+
if (aRank === -1) aRank = VENDOR_ORDER.length;
|
|
12
|
+
if (bRank === -1) bRank = VENDOR_ORDER.length;
|
|
13
|
+
return aRank - bRank || a.index - b.index;
|
|
14
|
+
}).map(function (item) { return item.entry; });
|
|
15
|
+
}
|
|
2
16
|
export var EXPERIMENTAL_VENDORS = ["grok", "kimi", "copilot", "qwen", "junie", "antigravity", "opencode"];
|
|
3
17
|
|
|
4
18
|
export function isExperimentalVendor(vendor) {
|