clay-server 4.0.0-beta.8 → 4.0.0
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/capsule-display-floor.js +51 -0
- package/lib/capsule-frame-server.js +255 -0
- package/lib/capsule-mate-turn.js +105 -0
- package/lib/capsule-pig-logic.js +300 -0
- package/lib/capsule-server-runtimes.js +39 -0
- package/lib/capsules/pig/display.js +198 -0
- package/lib/capsules/pig/manifest.json +9 -0
- package/lib/capsules/pig/ui.json +84 -0
- package/lib/config.js +25 -1
- package/lib/daemon-projects.js +13 -8
- package/lib/daemon.js +127 -14
- package/lib/git-cli.js +95 -1
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +240 -0
- package/lib/mate-knowledge-mcp-server.js +151 -0
- package/lib/mate-knowledge-migration.js +283 -0
- package/lib/mate-knowledge-service.js +488 -0
- package/lib/mate-knowledge-sync.js +482 -0
- package/lib/migrate-single-user.js +2 -0
- package/lib/notes-lifecycle.js +149 -0
- package/lib/notes.js +60 -3
- package/lib/os-users.js +3 -1
- package/lib/project-capsule-catalog.js +9 -1
- package/lib/project-capsule-turn.js +96 -0
- package/lib/project-connection.js +15 -1
- package/lib/project-file-history.js +223 -0
- package/lib/project-file-watch.js +77 -49
- package/lib/project-filesystem.js +31 -220
- package/lib/project-http.js +15 -1
- package/lib/project-knowledge.js +22 -0
- package/lib/project-log-context.js +172 -0
- package/lib/project-log-feedback-delivery.js +118 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-context-state.js +42 -0
- package/lib/project-logs-mcp-server.js +328 -0
- package/lib/project-logs-query.js +185 -0
- package/lib/project-logs-root.js +75 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +463 -0
- package/lib/project-logs-snapshot.js +205 -0
- package/lib/project-logs-store.js +495 -0
- package/lib/project-logs-versioning.js +132 -0
- package/lib/project-logs.js +400 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +22 -0
- package/lib/project-message-delivery.js +70 -0
- package/lib/project-pair-lifecycle.js +460 -0
- package/lib/project-request-access.js +66 -0
- package/lib/project-session-handoff.js +1 -1
- package/lib/project-session-notes.js +64 -13
- package/lib/project-session-pair.js +159 -146
- package/lib/project-session-spawn.js +1 -1
- package/lib/project-sessions.js +58 -13
- package/lib/project-user-message.js +53 -4
- package/lib/project-worker-permission.js +430 -0
- package/lib/project-worker-proposal.js +208 -62
- package/lib/project.js +185 -6
- package/lib/public/app.js +63 -35
- package/lib/public/css/admin.css +2 -2
- package/lib/public/css/capsule-ui.css +38 -0
- package/lib/public/css/command-palette.css +19 -9
- package/lib/public/css/git-placard.css +154 -0
- package/lib/public/css/home-hub.css +4 -0
- package/lib/public/css/home-session-actions.css +66 -0
- package/lib/public/css/home-sidebar.css +66 -0
- package/lib/public/css/input.css +84 -3
- package/lib/public/css/messages.css +40 -1
- package/lib/public/css/mobile-nav.css +80 -0
- package/lib/public/css/notifications-center.css +67 -0
- package/lib/public/css/pane.css +97 -10
- package/lib/public/css/project-logs.css +198 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/session-actions.css +16 -101
- package/lib/public/css/sidebar.css +103 -0
- package/lib/public/css/sticky-notes.css +237 -229
- package/lib/public/css/worker-proposal.css +36 -3
- package/lib/public/index.html +43 -11
- package/lib/public/modules/admin.js +8 -8
- package/lib/public/modules/app-connection.js +124 -6
- package/lib/public/modules/app-home-hub.js +12 -8
- package/lib/public/modules/app-message-cards.js +2 -1
- package/lib/public/modules/app-messages.js +92 -11
- package/lib/public/modules/app-misc.js +2 -14
- package/lib/public/modules/app-notifications.js +11 -7
- package/lib/public/modules/app-panels.js +3 -2
- package/lib/public/modules/app-projects.js +56 -18
- package/lib/public/modules/app-rendering.js +1 -0
- package/lib/public/modules/capsule-preference.js +44 -0
- package/lib/public/modules/chat-bubble-renderer.js +1 -1
- package/lib/public/modules/clay-log-links.js +70 -0
- package/lib/public/modules/command-palette.js +52 -15
- package/lib/public/modules/context-sources.js +0 -3
- package/lib/public/modules/git-agent-sessions.js +85 -0
- package/lib/public/modules/git-panel.js +111 -84
- package/lib/public/modules/git-placard.js +161 -0
- package/lib/public/modules/home-chat-empty-state.js +39 -0
- package/lib/public/modules/home-chat-identity.js +9 -0
- package/lib/public/modules/home-conversations-sheet.js +102 -48
- package/lib/public/modules/home-mate-chat.js +15 -35
- package/lib/public/modules/home-session-actions.js +6 -0
- package/lib/public/modules/home-sidebar-chat-list.js +101 -41
- package/lib/public/modules/home-sidebar.js +7 -0
- package/lib/public/modules/home-surface-boot.js +7 -3
- package/lib/public/modules/home-tool-frame.js +182 -0
- package/lib/public/modules/home-tools.js +138 -1
- package/lib/public/modules/input.js +38 -7
- package/lib/public/modules/markdown.js +2 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/message-delivery.js +97 -0
- package/lib/public/modules/paste-modal.js +84 -0
- package/lib/public/modules/project-activation.js +45 -0
- package/lib/public/modules/project-logs-render.js +405 -0
- package/lib/public/modules/project-logs.js +461 -0
- package/lib/public/modules/project-removal-target.js +26 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/session-actions.js +29 -105
- package/lib/public/modules/session-hierarchy.js +54 -0
- package/lib/public/modules/sidebar-mobile.js +40 -15
- package/lib/public/modules/sidebar-session-hierarchy.js +214 -0
- package/lib/public/modules/sidebar-sessions.js +77 -11
- package/lib/public/modules/sidebar.js +17 -5
- package/lib/public/modules/split-group-helpers.js +8 -0
- package/lib/public/modules/split-pair-ui.js +15 -4
- package/lib/public/modules/split-view.js +5 -2
- package/lib/public/modules/split-worker-runtime.js +24 -0
- package/lib/public/modules/sticky-note-markdown.js +5 -0
- package/lib/public/modules/sticky-notes-browser.js +326 -0
- package/lib/public/modules/sticky-notes-card.js +360 -0
- package/lib/public/modules/sticky-notes-editor.js +291 -0
- package/lib/public/modules/sticky-notes-shared.js +90 -0
- package/lib/public/modules/sticky-notes.js +170 -946
- package/lib/public/modules/thinking-lifecycle.js +175 -0
- package/lib/public/modules/thinking-summary.js +28 -0
- package/lib/public/modules/thinking-view.js +75 -0
- package/lib/public/modules/tool-palette-order.js +143 -0
- package/lib/public/modules/tool-palette-overlays.js +159 -0
- package/lib/public/modules/tool-palette.js +21 -188
- package/lib/public/modules/tools.js +31 -123
- package/lib/public/modules/update-snooze.js +169 -0
- package/lib/public/modules/user-settings.js +4 -0
- package/lib/public/modules/worker-pane-lock.js +176 -0
- package/lib/public/modules/worker-proposal-state.js +16 -0
- package/lib/public/modules/worker-proposal.js +49 -20
- package/lib/public/style.css +3 -1
- package/lib/sdk-bridge.js +135 -46
- package/lib/sdk-message-processor.js +36 -19
- package/lib/server-experimental-settings.js +49 -0
- package/lib/server-global-ws.js +11 -0
- package/lib/server-home-chat-events.js +31 -1
- package/lib/server-home-chat.js +27 -4
- package/lib/server-home-clay-entry.js +1 -1
- package/lib/server-home-clay-session-links.js +34 -5
- package/lib/server-settings.js +5 -0
- package/lib/server-tools.js +127 -9
- package/lib/server.js +137 -22
- package/lib/session-driver-eligibility.js +38 -0
- package/lib/session-driver-orchestration.js +31 -0
- package/lib/session-hygiene.js +3 -0
- package/lib/session-notes-mcp-server.js +25 -5
- package/lib/session-pair-factory.js +247 -0
- package/lib/session-pair-mcp-server.js +46 -8
- package/lib/session-pair-prompts.js +79 -0
- package/lib/session-pair-turn-control.js +153 -0
- package/lib/session-provenance.js +119 -0
- package/lib/session-spawn-mcp-server.js +1 -1
- package/lib/session-split-groups.js +4 -1
- package/lib/session-title-policy.js +60 -0
- package/lib/session-visibility.js +41 -0
- package/lib/sessions.js +57 -10
- package/lib/tools-registry.js +89 -10
- package/lib/update-snooze.js +437 -0
- package/lib/users-experimental-preferences.js +30 -0
- package/lib/users-permissions.js +6 -6
- package/lib/users.js +22 -16
- package/lib/workspace-query-access.js +102 -0
- package/lib/workspace-query-service.js +24 -17
- package/lib/worktree.js +25 -38
- package/lib/ws-schema.js +38 -7
- package/lib/yoke/adapters/claude-worker.js +16 -6
- package/lib/yoke/adapters/claude.js +12 -0
- package/lib/yoke/adapters/codex.js +24 -14
- package/lib/yoke/vendor-registry.js +1 -1
- package/package.json +2 -2
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// All dependencies are direct imports; no context injection needed.
|
|
4
4
|
|
|
5
5
|
import { store } from './store.js';
|
|
6
|
+
import { acknowledgeMessage, replayPendingMessages } from './message-delivery.js';
|
|
6
7
|
import { getWs } from './ws-ref.js';
|
|
7
8
|
|
|
8
9
|
// --- Leaf module imports ---
|
|
@@ -15,7 +16,7 @@ import { updateDmBadge, setMentionActive, renderUserStrip } from './sidebar-mate
|
|
|
15
16
|
import { renderSidebarPresence } from './sidebar-presence.js';
|
|
16
17
|
import { refreshMobileChatSheet } from './sidebar-mobile.js';
|
|
17
18
|
import { renderMateSessionList, handleMateSearchResults, updateMateSidebarProfile } from './mate-sidebar.js';
|
|
18
|
-
import { openHomeChat, handleHomeMateHistory, handleHomeMateDelta, handleHomeMateDone, handleHomeMateError, handleHomeMateSessionsState } from './home-mate-chat.js';
|
|
19
|
+
import { openHomeChat, handleHomeMateHistory, handleHomeMateDelta, handleHomeMateSegment, handleHomeMateDone, handleHomeMateError, handleHomeMateSessionsState } from './home-mate-chat.js';
|
|
19
20
|
import { handleHomeSurfaceState } from './home-surface.js';
|
|
20
21
|
import { handleHomeMateMemoryState, handleHomeMateKnowledgeState } from './home-mate-settings.js';
|
|
21
22
|
import { renderKnowledgeList, handleKnowledgeContent } from './mate-knowledge.js';
|
|
@@ -28,6 +29,7 @@ import { handleSessionActionMessage } from './session-actions.js';
|
|
|
28
29
|
import { renderWorkerProposal, updateWorkerProposal } from './worker-proposal.js';
|
|
29
30
|
import { handleInputSync, autoResize, builtinCommands, setScheduleBtnDisabled, sendShellResultToAgent } from './input.js';
|
|
30
31
|
import { startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, closeToolGroup, removeToolFromGroup, resetToolState, getTools, getPlanContent, setPlanContent, renderPlanBanner, renderPlanCard, getTodoTools, handleTodoWrite, handleTaskCreate, handleTaskUpdate, applyDeadSessionTodoCompaction, isPlanFilePath, enableMainInput, addTurnMeta, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, initSubagentStop, updateSubagentProgress, updateSubagentTaskStatus, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionCancelled, markPermissionResolved, renderElicitationRequest, markElicitationResolved, renderUserDialogRequest, markUserDialogResolved, updateThinkingTokens } from './tools.js';
|
|
32
|
+
import { finishThinkingTurn, resumeThinkingAfterReplay } from './thinking-lifecycle.js';
|
|
31
33
|
import { showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './notifications.js';
|
|
32
34
|
import { handleFsList, handleFsRead, handleFileChanged, handleDirChanged, handleFileHistory, handleGitDiff, handleFileAt, refreshIfOpen, getPendingNavigate, handleFsSearch, presentMarkdownEdit } from './filebrowser.js';
|
|
33
35
|
import { beginMarkdownTurn, finishMarkdownTurn, markdownPathFromToolInput } from './markdown-live-edit.js';
|
|
@@ -41,6 +43,7 @@ import { tuiModalHandleTermOutput, tuiModalHandleTermResized, tuiModalHandleTerm
|
|
|
41
43
|
import { updateTerminalList, handleContextSourcesState, updateEmailAccountList, updateEmailUnreadCounts, handleEmailTestResult, handleEmailAddResult, handleEmailRemoveResult } from './context-sources.js';
|
|
42
44
|
import { refreshEmailSettings } from './user-settings.js';
|
|
43
45
|
import { handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, handleNoteWritten } from './sticky-notes.js';
|
|
46
|
+
import { handleProjectLogsState, handleProjectLogEntry, handleProjectLogCommented, handleProjectLogCommentReviewed, handleProjectLogDeleted, handleProjectLogUpdated, handleProjectLogsError } from './project-logs.js';
|
|
44
47
|
import { handleSkillInstalled, handleSkillUninstalled } from './skills.js';
|
|
45
48
|
import { showRewindModal, onRewindComplete, setRewindMode, onRewindError, clearPendingRewindUuid, addRewindButton } from './rewind.js';
|
|
46
49
|
import { checkAdminAccess } from './admin.js';
|
|
@@ -61,11 +64,12 @@ import { resolvePaneSession, resolveSwitchedVendor } from './pane-session.js';
|
|
|
61
64
|
import { selectDefaultVendorForBlankSession } from './vendor-selection.js';
|
|
62
65
|
import { getModelInfoUpdate, modelEntryValue, modelEntryMatches, handleModelSelectionResult, requestVendorModels } from './model-picker.js';
|
|
63
66
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel } from './app-panels.js';
|
|
64
|
-
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress } from './app-projects.js';
|
|
67
|
+
import { updateProjectList, resetClientState, showUpdateAvailable, handleRemoveProjectCheckResult, handleRemoveProjectResult, handleBrowseDirResult, handleAddProjectResult, handleCloneProgress, finishProjectSessionActivation } from './app-projects.js';
|
|
65
68
|
import { updateHistorySentinel, prependOlderHistory } from './app-header.js';
|
|
66
69
|
import { hideHomeHub, showHomeHub } from './app-home-hub.js';
|
|
67
|
-
import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest } from './home-tools.js';
|
|
70
|
+
import { handleToolsState, handleToolInstalled, handleToolRemoved, handleToolStorageResult, handleToolLlmResult, handleToolsError, handleToolControlRequest, handleToolServerState, handleToolServerEvent, handleCapsuleGameSession } from './home-tools.js';
|
|
68
71
|
import { handleHomeDockState } from './home-dock.js';
|
|
72
|
+
import { handleToolFrameUrlState } from './home-tool-frame.js';
|
|
69
73
|
import { enterDmMode, exitDmMode, handleMateCreatedInApp, updateMateIconStatus, appendDmMessage, showDmTypingIndicator, buildMateInterviewPrompt } from './app-dm.js';
|
|
70
74
|
import { handleRateLimitEvent, updateRateLimitUsage, addScheduledMessageBubble, removeScheduledMessageBubble, handleFastModeState } from './app-rate-limit.js';
|
|
71
75
|
import { handleRemoteCursorMove, handleRemoteCursorLeave, handleRemoteSelection, clearRemoteCursors } from './app-cursors.js';
|
|
@@ -73,6 +77,7 @@ import { showLoopBanner, updateLoopBanner, updateLoopInputVisibility, showRalphA
|
|
|
73
77
|
import { showDebateSticky, showDebateConcludeConfirm, showDebateUserFloor, exitDebateFloorMode, exitDebateConcludeMode, exitDebateEndedMode, updateDebateRound, renderDebateUserFloorDone } from './app-debate-ui.js';
|
|
74
78
|
import { handleSkillInstallWs } from './app-skills-install.js';
|
|
75
79
|
import { handleNotificationsState, handleNotificationCreated, handleNotificationDismissed, handleNotificationDismissedAll, showUpdateBanner } from './app-notifications.js';
|
|
80
|
+
import { handleUpdateSnoozed } from './update-snooze.js';
|
|
76
81
|
import { autoStartLoginIfNeeded, handleVendorLoginReady, handleVendorLoginState, handleVendorLoginError, handleAuthRefreshed } from './vendor-login.js';
|
|
77
82
|
import { handleDebatePreparing, handleDebateBriefReady, renderDebateBriefReady, handleDebateStarted, renderDebateStarted, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, renderDebateCommentInjected, handleDebateResumed, handleDebateEnded, renderDebateEnded, handleDebateError, isDebateActive, renderMcpDebateProposal, renderDebateUserResume } from './debate.js';
|
|
78
83
|
import { handleMentionStart, handleMentionActivity, handleMentionStream, handleMentionDone, handleMentionError, renderMentionUser, renderMentionResponse, renderUserMention } from './mention.js';
|
|
@@ -160,6 +165,20 @@ export function processMessage(msg) {
|
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
switch (msg.type) {
|
|
168
|
+
case "message_ack":
|
|
169
|
+
var acknowledgedEl = msg.clientMessageId
|
|
170
|
+
? messagesEl.querySelector('[data-client-message-id="' + msg.clientMessageId + '"]')
|
|
171
|
+
: null;
|
|
172
|
+
acknowledgeMessage(msg.clientMessageId);
|
|
173
|
+
if (!acknowledgedEl && msg.message) {
|
|
174
|
+
addUserMessage(msg.message.text, msg.message.images || null, msg.message.pastes || null, msg.message.from, msg.message.fromName);
|
|
175
|
+
var acknowledgedUsers = messagesEl.querySelectorAll(".msg-user");
|
|
176
|
+
if (acknowledgedUsers.length > 0) {
|
|
177
|
+
acknowledgedUsers[acknowledgedUsers.length - 1].dataset.clientMessageId = msg.clientMessageId;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
|
|
163
182
|
case "history_meta":
|
|
164
183
|
store.set({ historyFrom: msg.from, historyTotal: msg.total, replayingHistory: true });
|
|
165
184
|
updateHistorySentinel();
|
|
@@ -171,6 +190,7 @@ export function processMessage(msg) {
|
|
|
171
190
|
|
|
172
191
|
case "history_done":
|
|
173
192
|
store.set({ replayingHistory: false });
|
|
193
|
+
resumeThinkingAfterReplay(store.get('sessionIsProcessing'));
|
|
174
194
|
// Batched syntax highlight + mermaid pass for the entire replayed
|
|
175
195
|
// transcript. Per-message highlights are skipped during replay
|
|
176
196
|
// (see markdown.js) to avoid cascading reflows that the sticky-
|
|
@@ -293,7 +313,7 @@ export function processMessage(msg) {
|
|
|
293
313
|
detachTuiView();
|
|
294
314
|
store.set({ projectName: msg.project || msg.cwd, vendorInfo: msg.vendors || {} });
|
|
295
315
|
if (msg.cwd) store.set({ cwd: msg.cwd });
|
|
296
|
-
if (msg.slug) store.set({ currentSlug: msg.slug });
|
|
316
|
+
if (msg.slug) store.set({ currentSlug: msg.slug, activeProjectSlug: msg.slug });
|
|
297
317
|
try { var _is = store.snap(); localStorage.setItem("clay-project-name-" + (_is.currentSlug || "default"), _is.projectName); } catch (e) {}
|
|
298
318
|
// In mate DM, keep title as mate name and re-apply mate color
|
|
299
319
|
if (store.get('dmMode') && store.get('dmTargetUser') && store.get('dmTargetUser').isMate) {
|
|
@@ -330,7 +350,9 @@ export function processMessage(msg) {
|
|
|
330
350
|
break;
|
|
331
351
|
|
|
332
352
|
case "update_available":
|
|
333
|
-
//
|
|
353
|
+
// The server already refuses to send this frame to anyone who is not
|
|
354
|
+
// admin-grade, so this check is defence in depth for the UI, not the
|
|
355
|
+
// access control.
|
|
334
356
|
if (store.get('isMultiUserMode')) {
|
|
335
357
|
checkAdminAccess().then(function (isAdmin) {
|
|
336
358
|
if (!isAdmin) return;
|
|
@@ -343,6 +365,10 @@ export function processMessage(msg) {
|
|
|
343
365
|
}
|
|
344
366
|
break;
|
|
345
367
|
|
|
368
|
+
case "update_snoozed":
|
|
369
|
+
handleUpdateSnoozed(msg);
|
|
370
|
+
break;
|
|
371
|
+
|
|
346
372
|
case "up_to_date":
|
|
347
373
|
var utdBtn = document.getElementById("settings-update-check");
|
|
348
374
|
if (utdBtn) {
|
|
@@ -619,6 +645,26 @@ export function processMessage(msg) {
|
|
|
619
645
|
handleToolControlRequest(msg);
|
|
620
646
|
break;
|
|
621
647
|
|
|
648
|
+
case "tool_server_state":
|
|
649
|
+
handleToolServerState(msg);
|
|
650
|
+
break;
|
|
651
|
+
|
|
652
|
+
case "tool_server_event":
|
|
653
|
+
handleToolServerEvent(msg);
|
|
654
|
+
break;
|
|
655
|
+
|
|
656
|
+
case "tool_frame_url_state":
|
|
657
|
+
handleToolFrameUrlState(msg);
|
|
658
|
+
break;
|
|
659
|
+
|
|
660
|
+
case "capsule_game_session":
|
|
661
|
+
handleCapsuleGameSession(msg);
|
|
662
|
+
break;
|
|
663
|
+
|
|
664
|
+
case "home_mate_segment":
|
|
665
|
+
handleHomeMateSegment(msg);
|
|
666
|
+
break;
|
|
667
|
+
|
|
622
668
|
case "input_sync":
|
|
623
669
|
if (!store.get('dmMode')) handleInputSync(msg.text);
|
|
624
670
|
break;
|
|
@@ -718,7 +764,6 @@ export function processMessage(msg) {
|
|
|
718
764
|
break;
|
|
719
765
|
|
|
720
766
|
case "session_switched":
|
|
721
|
-
hideHomeHub();
|
|
722
767
|
closeWhatsNewArticle();
|
|
723
768
|
// Save draft from outgoing session
|
|
724
769
|
var _prevSid = store.get('activeSessionId');
|
|
@@ -737,6 +782,7 @@ export function processMessage(msg) {
|
|
|
737
782
|
? msg.runtimeTerminalId
|
|
738
783
|
: (typeof msg.terminalId === "number" ? msg.terminalId : null);
|
|
739
784
|
store.set({ activeSessionId: msg.id, cliSessionId: msg.cliSessionId || null, currentModel: msg.model || "", currentEffort: msg.effort || store.get('currentEffort'), vendorCapabilities: msg.capabilities || {}, sessionIsProcessing: !!msg.isProcessing, activeSessionMode: _effectiveMode, activeTerminalId: _effectiveTerminalId, sessionHasHistory: !!msg.hasHistory, sessionVendorBound: !!msg.vendor || !!msg.hasHistory, sessionFullAccess: msg.permissionMode === "bypassPermissions", currentMode: msg.permissionMode || store.get('currentMode') });
|
|
785
|
+
replayPendingMessages(msg.id);
|
|
740
786
|
// TUI sessions swap the chat UI for an embedded xterm running
|
|
741
787
|
// `claude` inside a real PTY. Mount or tear down before the rest of
|
|
742
788
|
// the chat-side bookkeeping runs so we don't waste work on hidden DOM.
|
|
@@ -815,6 +861,7 @@ export function processMessage(msg) {
|
|
|
815
861
|
// Reload survival: a restored active session that is a split-group
|
|
816
862
|
// member reopens its group (no-op when a split is already open).
|
|
817
863
|
maybeRestoreSplitGroup();
|
|
864
|
+
if (finishProjectSessionActivation()) hideHomeHub();
|
|
818
865
|
break;
|
|
819
866
|
|
|
820
867
|
case "session_full_access_changed":
|
|
@@ -858,6 +905,10 @@ export function processMessage(msg) {
|
|
|
858
905
|
} else {
|
|
859
906
|
addUserMessage(msg.text, msg.images || null, msg.pastes || null, msg.from, msg.fromName, msg.delegated ? msg : null);
|
|
860
907
|
}
|
|
908
|
+
if (msg.clientMessageId) {
|
|
909
|
+
var replayedUsers = messagesEl.querySelectorAll(".msg-user");
|
|
910
|
+
if (replayedUsers.length > 0) replayedUsers[replayedUsers.length - 1].dataset.clientMessageId = msg.clientMessageId;
|
|
911
|
+
}
|
|
861
912
|
// Split Worker pane: a delegated instruction starts (or replays into) a
|
|
862
913
|
// driven turn; surface the composer notice. Cleared on "done".
|
|
863
914
|
if (msg.delegated) showWorkerDelegationNotice(msg.delegatedByTitle || null);
|
|
@@ -979,7 +1030,6 @@ export function processMessage(msg) {
|
|
|
979
1030
|
if (typeof msg.text !== "string") break;
|
|
980
1031
|
removeMatePreThinking();
|
|
981
1032
|
stopThinking();
|
|
982
|
-
resetThinkingGroup();
|
|
983
1033
|
setActivity(null);
|
|
984
1034
|
appendDelta(msg.text);
|
|
985
1035
|
break;
|
|
@@ -1179,7 +1229,7 @@ export function processMessage(msg) {
|
|
|
1179
1229
|
// were missed by the client).
|
|
1180
1230
|
removeMatePreThinking();
|
|
1181
1231
|
setActivity(null);
|
|
1182
|
-
|
|
1232
|
+
finishThinkingTurn();
|
|
1183
1233
|
markAllToolsDone();
|
|
1184
1234
|
closeToolGroup();
|
|
1185
1235
|
clearAllImageGenerationProgress();
|
|
@@ -1199,7 +1249,7 @@ export function processMessage(msg) {
|
|
|
1199
1249
|
case "done":
|
|
1200
1250
|
removeMatePreThinking();
|
|
1201
1251
|
setActivity(null);
|
|
1202
|
-
|
|
1252
|
+
finishThinkingTurn();
|
|
1203
1253
|
hideWorkerDelegationNotice();
|
|
1204
1254
|
markAllToolsDone();
|
|
1205
1255
|
closeToolGroup();
|
|
@@ -1222,6 +1272,7 @@ export function processMessage(msg) {
|
|
|
1222
1272
|
case "error":
|
|
1223
1273
|
removeMatePreThinking();
|
|
1224
1274
|
setActivity(null);
|
|
1275
|
+
finishThinkingTurn();
|
|
1225
1276
|
addSystemMessage(msg.text, true);
|
|
1226
1277
|
break;
|
|
1227
1278
|
|
|
@@ -1273,13 +1324,14 @@ export function processMessage(msg) {
|
|
|
1273
1324
|
case "process_conflict":
|
|
1274
1325
|
removeMatePreThinking();
|
|
1275
1326
|
setActivity(null);
|
|
1327
|
+
finishThinkingTurn();
|
|
1276
1328
|
addConflictMessage(msg);
|
|
1277
1329
|
break;
|
|
1278
1330
|
|
|
1279
1331
|
case "session_writer_conflict":
|
|
1280
1332
|
removeMatePreThinking();
|
|
1281
1333
|
setActivity(null);
|
|
1282
|
-
|
|
1334
|
+
finishThinkingTurn();
|
|
1283
1335
|
markAllToolsDone();
|
|
1284
1336
|
closeToolGroup();
|
|
1285
1337
|
addSystemMessage(msg.text || "This session is already open in another process.", true);
|
|
@@ -1288,13 +1340,14 @@ export function processMessage(msg) {
|
|
|
1288
1340
|
case "context_overflow":
|
|
1289
1341
|
removeMatePreThinking();
|
|
1290
1342
|
setActivity(null);
|
|
1343
|
+
finishThinkingTurn();
|
|
1291
1344
|
addContextOverflowMessage(msg);
|
|
1292
1345
|
break;
|
|
1293
1346
|
|
|
1294
1347
|
case "auth_required":
|
|
1295
1348
|
removeMatePreThinking();
|
|
1296
1349
|
setActivity(null);
|
|
1297
|
-
|
|
1350
|
+
finishThinkingTurn();
|
|
1298
1351
|
markAllToolsDone();
|
|
1299
1352
|
closeToolGroup();
|
|
1300
1353
|
appendDelta((msg.text || "Authentication required.") + "\n");
|
|
@@ -1567,6 +1620,34 @@ export function processMessage(msg) {
|
|
|
1567
1620
|
handleNoteDeleted(msg);
|
|
1568
1621
|
break;
|
|
1569
1622
|
|
|
1623
|
+
case "project_logs_state":
|
|
1624
|
+
handleProjectLogsState(msg);
|
|
1625
|
+
break;
|
|
1626
|
+
|
|
1627
|
+
case "project_log_entry":
|
|
1628
|
+
handleProjectLogEntry(msg);
|
|
1629
|
+
break;
|
|
1630
|
+
|
|
1631
|
+
case "project_log_commented":
|
|
1632
|
+
handleProjectLogCommented(msg);
|
|
1633
|
+
break;
|
|
1634
|
+
|
|
1635
|
+
case "project_log_comment_reviewed":
|
|
1636
|
+
handleProjectLogCommentReviewed(msg);
|
|
1637
|
+
break;
|
|
1638
|
+
|
|
1639
|
+
case "project_log_deleted":
|
|
1640
|
+
handleProjectLogDeleted(msg);
|
|
1641
|
+
break;
|
|
1642
|
+
|
|
1643
|
+
case "project_log_updated":
|
|
1644
|
+
handleProjectLogUpdated(msg);
|
|
1645
|
+
break;
|
|
1646
|
+
|
|
1647
|
+
case "project_logs_error":
|
|
1648
|
+
handleProjectLogsError(msg);
|
|
1649
|
+
break;
|
|
1650
|
+
|
|
1570
1651
|
case "process_stats":
|
|
1571
1652
|
updateStatusPanel(msg);
|
|
1572
1653
|
updateSettingsStats(msg);
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// Extracted from app.js (PR-34)
|
|
3
3
|
|
|
4
4
|
import { refreshIcons, iconHtml } from './icons.js';
|
|
5
|
-
import { escapeHtml, copyToClipboard } from './utils.js';
|
|
6
5
|
import { getWs } from './ws-ref.js';
|
|
7
6
|
import { updateBrowserTabList } from './context-sources.js';
|
|
8
7
|
import { setExtensionConnected } from './mcp-ui.js';
|
|
8
|
+
import { initPasteModal } from './paste-modal.js';
|
|
9
9
|
|
|
10
10
|
// --- Module-owned state ---
|
|
11
11
|
var confirmCallback = null;
|
|
@@ -44,6 +44,7 @@ export function flushPendingExtMessages() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export function initMisc() {
|
|
47
|
+
initPasteModal();
|
|
47
48
|
// --- Confirm modal listeners ---
|
|
48
49
|
var confirmModal = document.getElementById("confirm-modal");
|
|
49
50
|
var confirmOk = document.getElementById("confirm-ok");
|
|
@@ -258,19 +259,6 @@ export function closeImageModal() {
|
|
|
258
259
|
if (modal) modal.classList.add("hidden");
|
|
259
260
|
}
|
|
260
261
|
|
|
261
|
-
export function showPasteModal(text) {
|
|
262
|
-
var modal = document.getElementById("paste-modal");
|
|
263
|
-
var body = document.getElementById("paste-modal-body");
|
|
264
|
-
if (!modal || !body) return;
|
|
265
|
-
body.textContent = text;
|
|
266
|
-
modal.classList.remove("hidden");
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export function closePasteModal() {
|
|
270
|
-
var modal = document.getElementById("paste-modal");
|
|
271
|
-
if (modal) modal.classList.add("hidden");
|
|
272
|
-
}
|
|
273
|
-
|
|
274
262
|
export function showConfirm(text, onConfirm, okLabel, destructive) {
|
|
275
263
|
var confirmText = document.getElementById("confirm-text");
|
|
276
264
|
var confirmOk = document.getElementById("confirm-ok");
|
|
@@ -14,6 +14,7 @@ import { openTuiModal } from './tui-attention.js';
|
|
|
14
14
|
import { requestVendorLogin } from './vendor-login.js';
|
|
15
15
|
import { startUrgentBlink, stopUrgentBlink } from './app-favicon.js';
|
|
16
16
|
import { playDoneSound, isNotifSoundEnabled } from './notifications.js';
|
|
17
|
+
import { attachSnoozeControl, setSnoozeBannerRemover } from './update-snooze.js';
|
|
17
18
|
var notifications = [];
|
|
18
19
|
var unreadCount = 0;
|
|
19
20
|
var bannerContainer = null;
|
|
@@ -56,6 +57,10 @@ export function initAppNotifications() {
|
|
|
56
57
|
bellBtn = document.getElementById("notif-center-btn");
|
|
57
58
|
badgeEl = document.getElementById("notif-center-badge");
|
|
58
59
|
|
|
60
|
+
// Banner teardown lives here (exit animation, clear-all sync), so the
|
|
61
|
+
// snooze module borrows it rather than importing this module back.
|
|
62
|
+
setSnoozeBannerRemover(removeBanner);
|
|
63
|
+
|
|
59
64
|
// Split panes are secondary clients inside the parent shell. They keep
|
|
60
65
|
// notification state in sync, but the parent owns the single visible
|
|
61
66
|
// banner surface for the whole split view.
|
|
@@ -708,13 +713,11 @@ export function showUpdateBanner(msg) {
|
|
|
708
713
|
banner.setAttribute("data-notif-id", "_update");
|
|
709
714
|
banner.setAttribute("data-update-version", msg.version);
|
|
710
715
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
'</div>';
|
|
717
|
-
}
|
|
716
|
+
// Headless installs update from the shell, so they get no install button —
|
|
717
|
+
// but they still get the action row, because Snooze applies either way.
|
|
718
|
+
var actionsHtml = '<div class="notif-banner-actions">' +
|
|
719
|
+
(isHeadless ? '' : '<button class="notif-banner-update-now">Update now</button>') +
|
|
720
|
+
'</div>';
|
|
718
721
|
|
|
719
722
|
banner.innerHTML =
|
|
720
723
|
'<div class="notif-banner-icon"><img src="/clay-studio-symbol.png" width="32" height="32" alt="Clay Studio"></div>' +
|
|
@@ -729,6 +732,7 @@ export function showUpdateBanner(msg) {
|
|
|
729
732
|
'<button class="notif-banner-close">' + iconHtml("x") + '</button>';
|
|
730
733
|
|
|
731
734
|
bannerContainer.appendChild(banner);
|
|
735
|
+
attachSnoozeControl(banner.querySelector(".notif-banner-actions"));
|
|
732
736
|
refreshIcons();
|
|
733
737
|
|
|
734
738
|
requestAnimationFrame(function () {
|
|
@@ -91,7 +91,7 @@ var MODE_FULL_AUTO = { value: "bypassPermissions", label: "Full auto" };
|
|
|
91
91
|
var EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
92
92
|
var EFFORT_LEVELS_BY_VENDOR = {
|
|
93
93
|
claude: ["low", "medium", "high", "xhigh", "max"],
|
|
94
|
-
codex: ["
|
|
94
|
+
codex: ["low", "medium", "high", "xhigh", "max"],
|
|
95
95
|
antigravity: [],
|
|
96
96
|
opencode: [],
|
|
97
97
|
kiro: ["low", "medium", "high", "xhigh", "max"],
|
|
@@ -115,7 +115,8 @@ var CODEX_WEBSEARCH_OPTIONS = [
|
|
|
115
115
|
var KNOWN_CONTEXT_WINDOWS = {
|
|
116
116
|
"opus-4-6": 1000000,
|
|
117
117
|
"claude-sonnet-4": 1000000,
|
|
118
|
-
"gpt-
|
|
118
|
+
"gpt-6-astra": 1050000,
|
|
119
|
+
"gpt-5.6": 1050000,
|
|
119
120
|
"gpt-5.5": 1048576,
|
|
120
121
|
"gpt-5.4": 1048576,
|
|
121
122
|
"gpt-5.3": 1048576,
|
|
@@ -19,7 +19,7 @@ import { exitDmMode } from './app-dm.js';
|
|
|
19
19
|
import { isHomeHubVisible, hideHomeHub, showHomeHub } from './app-home-hub.js';
|
|
20
20
|
import { closeArticle as closeWhatsNewArticle } from './whats-new-article.js';
|
|
21
21
|
import { resetFileBrowser } from './filebrowser.js';
|
|
22
|
-
import {
|
|
22
|
+
import { closeNotesBrowser } from './sticky-notes-browser.js';
|
|
23
23
|
import { hideMemory } from './mate-memory.js';
|
|
24
24
|
import { isSchedulerOpen, closeScheduler, resetScheduler } from './scheduler.js';
|
|
25
25
|
import { connect, cancelReconnect, setStatus } from './app-connection.js';
|
|
@@ -34,6 +34,10 @@ import { resetRateLimitState } from './app-rate-limit.js';
|
|
|
34
34
|
import { closeSessionInfoPopover } from './app-header.js';
|
|
35
35
|
import { resetDebateState } from './debate.js';
|
|
36
36
|
import { removeDebateBottomBar } from './app-debate-ui.js';
|
|
37
|
+
import { closeProjectSettings } from './project-settings.js';
|
|
38
|
+
import { chooseProjectAfterRemoval } from './project-removal-target.js';
|
|
39
|
+
import { isProjectActivated, isProjectActivationPending, isProjectContextConnected, projectWsPath } from './project-activation.js';
|
|
40
|
+
import { rememberHomePrimarySurface } from './home-surface.js';
|
|
37
41
|
|
|
38
42
|
// --- Module-owned state ---
|
|
39
43
|
var cachedProjects = [];
|
|
@@ -415,43 +419,76 @@ export function switchProject(slug) {
|
|
|
415
419
|
if (!slug) return;
|
|
416
420
|
document.cookie = "clay_last_project=" + encodeURIComponent(slug) + "; Path=/; SameSite=Strict; Max-Age=31536000";
|
|
417
421
|
var st = store.snap();
|
|
422
|
+
var ws = getWs();
|
|
423
|
+
var targetWsPath = projectWsPath(slug);
|
|
424
|
+
var homeVisible = isHomeHubVisible();
|
|
425
|
+
var alreadyInProject = isProjectActivated(st, slug, ws);
|
|
418
426
|
var wasDm = st.dmMode;
|
|
419
427
|
var wasMate = st.dmMode && st.dmTargetUser && st.dmTargetUser.isMate;
|
|
420
428
|
if (st.dmMode) exitDmMode(wasMate);
|
|
421
429
|
closeWhatsNewArticle();
|
|
422
|
-
if (
|
|
430
|
+
if (homeVisible && alreadyInProject) {
|
|
431
|
+
rememberHomePrimarySurface("project", slug);
|
|
423
432
|
hideHomeHub();
|
|
424
|
-
if (
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
history.pushState(null, "", "/p/" + slug + "/");
|
|
429
|
-
}
|
|
430
|
-
return;
|
|
433
|
+
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
434
|
+
history.replaceState(null, "", "/p/" + slug + "/");
|
|
435
|
+
} else {
|
|
436
|
+
history.pushState(null, "", "/p/" + slug + "/");
|
|
431
437
|
}
|
|
438
|
+
return;
|
|
432
439
|
}
|
|
433
|
-
if (
|
|
434
|
-
var ws = getWs();
|
|
440
|
+
if (alreadyInProject) {
|
|
435
441
|
if (wasDm && ws && ws.readyState === 1) {
|
|
436
442
|
ws.send(JSON.stringify({ type: "switch_session", id: store.get('activeSessionId') }));
|
|
437
443
|
}
|
|
438
444
|
return;
|
|
439
445
|
}
|
|
446
|
+
if (homeVisible) store.set({ pendingHomeProjectSlug: slug });
|
|
447
|
+
if (isProjectActivationPending(store.snap(), slug, ws)) return;
|
|
440
448
|
resetFileBrowser();
|
|
441
|
-
|
|
449
|
+
closeNotesBrowser();
|
|
442
450
|
hideMemory();
|
|
443
451
|
if (isSchedulerOpen()) closeScheduler();
|
|
444
452
|
resetScheduler(slug);
|
|
445
453
|
store.set({ currentSlug: slug });
|
|
446
454
|
store.set({ basePath: "/p/" + slug + "/" });
|
|
447
|
-
store.set({ wsPath:
|
|
455
|
+
store.set({ wsPath: targetWsPath });
|
|
456
|
+
if (!homeVisible) {
|
|
457
|
+
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
458
|
+
history.replaceState(null, "", "/p/" + slug + "/");
|
|
459
|
+
} else {
|
|
460
|
+
history.pushState(null, "", "/p/" + slug + "/");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
resetClientState();
|
|
464
|
+
connect();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export function completePendingProjectActivation() {
|
|
468
|
+
var slug = store.get('pendingHomeProjectSlug');
|
|
469
|
+
if (!slug || !isProjectActivated(store.snap(), slug, getWs())) return false;
|
|
470
|
+
store.set({ pendingHomeProjectSlug: null });
|
|
471
|
+
rememberHomePrimarySurface("project", slug);
|
|
448
472
|
if (document.documentElement.classList.contains("pwa-standalone")) {
|
|
449
473
|
history.replaceState(null, "", "/p/" + slug + "/");
|
|
450
474
|
} else {
|
|
451
475
|
history.pushState(null, "", "/p/" + slug + "/");
|
|
452
476
|
}
|
|
453
|
-
|
|
454
|
-
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export function confirmCurrentProjectSessionActivation() {
|
|
481
|
+
var slug = store.get('activeProjectSlug');
|
|
482
|
+
if (!slug || !isProjectContextConnected(store.snap(), slug, getWs())) return false;
|
|
483
|
+
store.set({ sessionActivatedProjectSlug: slug });
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export function finishProjectSessionActivation() {
|
|
488
|
+
var confirmed = confirmCurrentProjectSessionActivation();
|
|
489
|
+
if (!confirmed) return false;
|
|
490
|
+
if (!store.get('pendingHomeProjectSlug')) return true;
|
|
491
|
+
return completePendingProjectActivation();
|
|
455
492
|
}
|
|
456
493
|
|
|
457
494
|
export function showUpdateAvailable(msg) {
|
|
@@ -572,9 +609,10 @@ export function handleRemoveProjectResult(msg) {
|
|
|
572
609
|
var currentSlug = store.get('currentSlug');
|
|
573
610
|
if (msg.slug === currentSlug) {
|
|
574
611
|
var isWorktree = msg.slug.indexOf("--") !== -1;
|
|
575
|
-
var
|
|
612
|
+
var targetSlug = chooseProjectAfterRemoval(cachedProjects, msg.slug);
|
|
576
613
|
|
|
577
614
|
showToast(isWorktree ? "Worktree removed" : "Project removed", "success");
|
|
615
|
+
closeProjectSettings();
|
|
578
616
|
|
|
579
617
|
// Suppress disconnect overlay and reconnect by detaching the WS
|
|
580
618
|
var ws = getWs();
|
|
@@ -602,8 +640,8 @@ export function handleRemoveProjectResult(msg) {
|
|
|
602
640
|
renderProjectList();
|
|
603
641
|
resetClientState();
|
|
604
642
|
|
|
605
|
-
if (
|
|
606
|
-
switchProject(
|
|
643
|
+
if (targetSlug) {
|
|
644
|
+
switchProject(targetSlug);
|
|
607
645
|
} else {
|
|
608
646
|
showHomeHub();
|
|
609
647
|
}
|
|
@@ -111,6 +111,7 @@ export function finalizeAssistantBlock() {
|
|
|
111
111
|
|
|
112
112
|
export function showClaudePreThinking() {
|
|
113
113
|
if (getChatLayout() !== "channel") return;
|
|
114
|
+
removeMatePreThinking();
|
|
114
115
|
var vendor = store.get('currentVendor') || "claude";
|
|
115
116
|
var vendorAvatar = VENDOR_AVATARS[vendor] || VENDOR_AVATARS.claude;
|
|
116
117
|
var vendorName = VENDOR_NAMES[vendor] || VENDOR_NAMES.claude;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { requestTools } from './home-tools.js';
|
|
3
|
+
import { closeHomeDock } from './home-dock.js';
|
|
4
|
+
import { showToast } from './utils.js';
|
|
5
|
+
|
|
6
|
+
function applyCapsulesEnabled(enabled, refreshTools) {
|
|
7
|
+
var want = enabled === true;
|
|
8
|
+
store.set({ capsulesEnabled: want, capsulesPreferenceLoaded: true });
|
|
9
|
+
if (document.body) document.body.classList.toggle('capsules-disabled', !want);
|
|
10
|
+
if (!want && store.get('dockOpen') === true) closeHomeDock();
|
|
11
|
+
if (refreshTools !== false) requestTools();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function initCapsulePreference() {
|
|
15
|
+
var toggle = document.getElementById('us-capsules-enabled');
|
|
16
|
+
if (!toggle) return;
|
|
17
|
+
toggle.addEventListener('change', function () {
|
|
18
|
+
var previous = store.get('capsulesEnabled') === true;
|
|
19
|
+
var want = this.checked === true;
|
|
20
|
+
applyCapsulesEnabled(want, false);
|
|
21
|
+
fetch('/api/user/capsules-enabled', {
|
|
22
|
+
method: 'PUT',
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
body: JSON.stringify({ enabled: want }),
|
|
25
|
+
}).then(function (response) {
|
|
26
|
+
if (!response.ok) throw new Error('Could not save the Capsules preference.');
|
|
27
|
+
return response.json();
|
|
28
|
+
}).then(function (data) {
|
|
29
|
+
applyCapsulesEnabled(data.capsulesEnabled === true, true);
|
|
30
|
+
showToast(data.capsulesEnabled ? 'Experimental Capsules enabled' : 'Experimental Capsules disabled');
|
|
31
|
+
}).catch(function () {
|
|
32
|
+
toggle.checked = previous;
|
|
33
|
+
applyCapsulesEnabled(previous, true);
|
|
34
|
+
showToast('Could not save the Capsules preference.', 'error');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function syncCapsulePreference(enabled) {
|
|
40
|
+
var want = enabled === true;
|
|
41
|
+
var toggle = document.getElementById('us-capsules-enabled');
|
|
42
|
+
if (toggle) toggle.checked = want;
|
|
43
|
+
applyCapsulesEnabled(want, true);
|
|
44
|
+
}
|
|
@@ -105,7 +105,7 @@ export function addAssistantCopyHandler(row, rawText) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
row.addEventListener("click", function (event) {
|
|
108
|
-
if (event.target.closest("a, pre, code")) return;
|
|
108
|
+
if (event.target.closest("a, button, pre, code")) return;
|
|
109
109
|
var selection = window.getSelection();
|
|
110
110
|
if (selection && selection.toString().length > 0) return;
|
|
111
111
|
if (!primed) {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export function parseClayLogReferences(text) {
|
|
2
|
+
var pattern = /\[clayos\/(log:[A-Za-z0-9_-]{24})(?:\s+[\u2014-]\s+([^\]\n]{1,80}))?\]|(^|[^A-Za-z0-9_/:])(log:[A-Za-z0-9_-]{24})(?![A-Za-z0-9_-])/g;
|
|
3
|
+
var results = [];
|
|
4
|
+
var match;
|
|
5
|
+
while ((match = pattern.exec(text || ""))) {
|
|
6
|
+
results.push({
|
|
7
|
+
start: match.index,
|
|
8
|
+
end: pattern.lastIndex,
|
|
9
|
+
prefix: match[3] || "",
|
|
10
|
+
ref: match[1] || match[4],
|
|
11
|
+
label: match[2] ? match[2].trim() : "",
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return results;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isExactClayLogReference(text) {
|
|
18
|
+
return /^log:[A-Za-z0-9_-]{24}$/.test((text || "").trim());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createLogLink(ref, labelText) {
|
|
22
|
+
var button = document.createElement("button");
|
|
23
|
+
button.type = "button";
|
|
24
|
+
button.className = "clayos-log-link";
|
|
25
|
+
button.contentEditable = "false";
|
|
26
|
+
button.dataset.logRef = ref;
|
|
27
|
+
button.setAttribute("aria-label", "Open Project Log" + (labelText ? " " + labelText : ""));
|
|
28
|
+
var label = document.createElement("span");
|
|
29
|
+
label.textContent = "Log";
|
|
30
|
+
button.appendChild(label);
|
|
31
|
+
if (labelText) {
|
|
32
|
+
var meta = document.createElement("small");
|
|
33
|
+
meta.textContent = labelText;
|
|
34
|
+
button.appendChild(meta);
|
|
35
|
+
}
|
|
36
|
+
return button;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function enhanceClayLogLinks(root) {
|
|
40
|
+
var codeNodes = root.querySelectorAll("code");
|
|
41
|
+
for (var codeIndex = 0; codeIndex < codeNodes.length; codeIndex++) {
|
|
42
|
+
var code = codeNodes[codeIndex];
|
|
43
|
+
var codeText = (code.textContent || "").trim();
|
|
44
|
+
if (code.closest("pre") || !isExactClayLogReference(codeText)) continue;
|
|
45
|
+
code.parentNode.replaceChild(createLogLink(codeText, ""), code);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
49
|
+
var nodes = [];
|
|
50
|
+
var node;
|
|
51
|
+
while ((node = walker.nextNode())) {
|
|
52
|
+
if (!node.parentElement || node.parentElement.closest("code, pre, a, button")) continue;
|
|
53
|
+
if (parseClayLogReferences(node.nodeValue).length) nodes.push(node);
|
|
54
|
+
}
|
|
55
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
56
|
+
var text = nodes[i].nodeValue || "";
|
|
57
|
+
var matches = parseClayLogReferences(text);
|
|
58
|
+
var fragment = document.createDocumentFragment();
|
|
59
|
+
var offset = 0;
|
|
60
|
+
for (var j = 0; j < matches.length; j++) {
|
|
61
|
+
var match = matches[j];
|
|
62
|
+
fragment.appendChild(document.createTextNode(text.slice(offset, match.start)));
|
|
63
|
+
if (match.prefix) fragment.appendChild(document.createTextNode(match.prefix));
|
|
64
|
+
fragment.appendChild(createLogLink(match.ref, match.label));
|
|
65
|
+
offset = match.end;
|
|
66
|
+
}
|
|
67
|
+
fragment.appendChild(document.createTextNode(text.slice(offset)));
|
|
68
|
+
nodes[i].parentNode.replaceChild(fragment, nodes[i]);
|
|
69
|
+
}
|
|
70
|
+
}
|