clay-server 3.8.1 → 4.0.0-beta.10
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/ask-user-mcp-server.js +5 -119
- package/lib/background-task-timing.js +105 -0
- package/lib/builtin-mates.js +6 -6
- package/lib/claude-hook-installer.js +15 -0
- package/lib/clay-history-mcp-server.js +62 -297
- package/lib/daemon.js +23 -1
- package/lib/debate-model-selection.js +119 -0
- package/lib/home-debate-tool-policy.js +164 -0
- package/lib/home-response-notifications.js +26 -0
- package/lib/knowledge-import.js +436 -0
- package/lib/knowledge-record-store.js +188 -0
- package/lib/knowledge-search.js +224 -0
- package/lib/mate-creation-mcp-server.js +55 -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/mate-ready-creation.js +95 -0
- package/lib/mates.js +2 -0
- package/lib/notes.js +2 -1
- package/lib/project-ask-user.js +64 -0
- package/lib/project-capsule-catalog.js +101 -0
- package/lib/project-connection.js +17 -0
- package/lib/project-debate-proposal.js +133 -17
- package/lib/project-debate.js +214 -110
- package/lib/project-delegated-follow-up.js +84 -0
- package/lib/project-delegated-session.js +53 -0
- package/lib/project-filesystem.js +7 -9
- package/lib/project-knowledge.js +23 -0
- package/lib/project-logs-comments.js +137 -0
- package/lib/project-logs-mcp-server.js +290 -0
- package/lib/project-logs-query.js +167 -0
- package/lib/project-logs-root.js +67 -0
- package/lib/project-logs-schema.js +259 -0
- package/lib/project-logs-service.js +357 -0
- package/lib/project-logs-snapshot.js +202 -0
- package/lib/project-logs-store.js +498 -0
- package/lib/project-logs-versioning.js +128 -0
- package/lib/project-logs.js +347 -0
- package/lib/project-mate-creation-proposal.js +120 -0
- package/lib/project-mate-interaction.js +14 -0
- package/lib/project-mate-knowledge.js +110 -0
- package/lib/project-memory.js +36 -7
- package/lib/project-models.js +157 -32
- package/lib/project-session-notes.js +2 -2
- package/lib/project-session-pair.js +8 -8
- package/lib/project-sessions.js +66 -51
- package/lib/project-vendor-login.js +414 -0
- package/lib/project-worker-proposal.js +25 -25
- package/lib/project-workspace-query.js +144 -0
- package/lib/project.js +433 -102
- package/lib/public/app.js +109 -48
- package/lib/public/css/avatar-imprints.css +0 -1
- package/lib/public/css/base.css +4 -0
- package/lib/public/css/capsule-ui.css +389 -0
- package/lib/public/css/command-palette.css +306 -6
- package/lib/public/css/home-capsule-library.css +243 -0
- package/lib/public/css/home-capsule-source.css +192 -0
- package/lib/public/css/home-debate-live.css +146 -0
- package/lib/public/css/home-debate-planning.css +125 -0
- package/lib/public/css/home-debates-archive.css +281 -0
- package/lib/public/css/home-hub.css +896 -405
- package/lib/public/css/home-mate-creation.css +34 -0
- package/lib/public/css/home-mate-model-picker.css +131 -0
- package/lib/public/css/home-mate-settings.css +344 -0
- package/lib/public/css/home-session-actions.css +265 -0
- package/lib/public/css/home-sidebar.css +667 -0
- package/lib/public/css/icon-strip.css +1 -2
- package/lib/public/css/input.css +79 -25
- package/lib/public/css/mates.css +7 -34
- package/lib/public/css/pane.css +1 -1
- package/lib/public/css/playbook.css +0 -80
- package/lib/public/css/project-logs.css +234 -0
- package/lib/public/css/scheduler.css +1 -1
- package/lib/public/css/sticky-notes.css +53 -117
- package/lib/public/css/tui-attention.css +0 -44
- package/lib/public/css/workspace-assignment.css +45 -0
- package/lib/public/fonts/source-serif-4/LICENSE.md +93 -0
- package/lib/public/fonts/source-serif-4/SourceSerif4Caption-Semibold.ttf.woff2 +0 -0
- package/lib/public/index.html +96 -74
- package/lib/public/modules/app-connection.js +100 -5
- package/lib/public/modules/app-dm.js +43 -160
- package/lib/public/modules/app-home-hub.js +328 -585
- package/lib/public/modules/app-message-cards.js +242 -0
- package/lib/public/modules/app-message-router.js +84 -0
- package/lib/public/modules/app-messages.js +124 -38
- package/lib/public/modules/app-notifications.js +8 -119
- package/lib/public/modules/app-panels.js +43 -2
- package/lib/public/modules/app-projects.js +9 -1
- package/lib/public/modules/app-rendering.js +21 -602
- package/lib/public/modules/avatar-imprint.js +11 -8
- package/lib/public/modules/background-tasks-ui.js +139 -16
- package/lib/public/modules/chat-bubble-renderer.js +152 -0
- package/lib/public/modules/chat-render-runtime.js +198 -0
- package/lib/public/modules/command-palette.js +225 -436
- package/lib/public/modules/dm-render.js +82 -0
- package/lib/public/modules/home-capsule-creation-intent.js +31 -0
- package/lib/public/modules/home-capsule-library.js +146 -0
- package/lib/public/modules/home-capsule-source.js +383 -0
- package/lib/public/modules/home-chat-identity.js +35 -0
- package/lib/public/modules/home-chat-scroll.js +77 -0
- package/lib/public/modules/home-chat-stream-state.js +34 -0
- package/lib/public/modules/home-composer-focus.js +25 -0
- package/lib/public/modules/home-conversations-sheet.js +179 -0
- package/lib/public/modules/home-debate-activity.js +48 -0
- package/lib/public/modules/home-debate-controls.js +295 -0
- package/lib/public/modules/home-debate-launch.js +41 -0
- package/lib/public/modules/home-debate-live.js +284 -0
- package/lib/public/modules/home-debate-models.js +73 -0
- package/lib/public/modules/home-debate-planning.js +335 -0
- package/lib/public/modules/home-debates-archive.js +279 -0
- package/lib/public/modules/home-dock-resize.js +74 -0
- package/lib/public/modules/home-dock.js +446 -0
- package/lib/public/modules/home-mate-chat.js +496 -0
- package/lib/public/modules/home-mate-creation.js +109 -0
- package/lib/public/modules/home-mate-model-picker.js +281 -0
- package/lib/public/modules/home-mate-selection.js +38 -0
- package/lib/public/modules/home-mate-settings-menu.js +131 -0
- package/lib/public/modules/home-mate-settings.js +383 -0
- package/lib/public/modules/home-session-actions.js +373 -0
- package/lib/public/modules/home-session-model-confirmation.js +13 -0
- package/lib/public/modules/home-shell.js +9 -0
- package/lib/public/modules/home-sidebar-chat-list.js +63 -0
- package/lib/public/modules/home-sidebar.js +165 -0
- package/lib/public/modules/home-sub-surface.js +19 -0
- package/lib/public/modules/home-surface-boot.js +68 -0
- package/lib/public/modules/home-surface.js +141 -0
- package/lib/public/modules/home-tools.js +271 -0
- package/lib/public/modules/markdown.js +50 -2
- package/lib/public/modules/mate-management.js +86 -0
- package/lib/public/modules/mate-sidebar.js +0 -8
- package/lib/public/modules/mate-wizard.js +0 -7
- package/lib/public/modules/mention.js +17 -19
- package/lib/public/modules/pane-bridge.js +9 -0
- package/lib/public/modules/profile.js +4 -5
- package/lib/public/modules/project-logs-ambient.js +238 -0
- package/lib/public/modules/project-logs-render.js +359 -0
- package/lib/public/modules/project-logs.js +328 -0
- package/lib/public/modules/project-settings.js +34 -28
- package/lib/public/modules/project-switcher.js +11 -5
- package/lib/public/modules/project-workspace-assignment.js +23 -0
- package/lib/public/modules/scheduler.js +17 -3
- package/lib/public/modules/search-clay-chat.js +402 -0
- package/lib/public/modules/server-settings.js +14 -12
- package/lib/public/modules/session-actions.js +1 -1
- package/lib/public/modules/sidebar-mates.js +56 -552
- package/lib/public/modules/sidebar-mobile.js +12 -73
- package/lib/public/modules/sidebar-presence.js +37 -0
- package/lib/public/modules/sidebar-sessions.js +25 -1
- package/lib/public/modules/split-pair-ui.js +13 -13
- package/lib/public/modules/split-view.js +7 -0
- package/lib/public/modules/sticky-notes.js +106 -53
- package/lib/public/modules/tool-input-composition.js +48 -0
- package/lib/public/modules/tool-llm-status.js +167 -0
- package/lib/public/modules/tool-palette.js +76 -4
- package/lib/public/modules/tool-renderer-advanced.js +285 -0
- package/lib/public/modules/tool-renderer-chart.js +158 -0
- package/lib/public/modules/tool-renderer-semantics.js +35 -0
- package/lib/public/modules/tool-renderer.js +464 -0
- package/lib/public/modules/tool-runtime.js +309 -0
- package/lib/public/modules/tool-ui-evaluator.js +97 -0
- package/lib/public/modules/tool-ui-tree.js +21 -0
- package/lib/public/modules/tui-attention.js +10 -0
- package/lib/public/modules/user-settings.js +16 -23
- package/lib/public/modules/vendor-login.js +287 -0
- package/lib/public/modules/worker-proposal.js +2 -2
- package/lib/public/modules/workspace-assignment-card.js +149 -0
- package/lib/public/modules/workspace-assignment-routing.js +4 -0
- package/lib/public/style.css +14 -2
- package/lib/runtime-env.js +65 -0
- package/lib/sdk-bridge.js +120 -32
- package/lib/sdk-message-processor.js +34 -13
- package/lib/server-home-capsule-creation.js +36 -0
- package/lib/server-home-chat-events.js +287 -0
- package/lib/server-home-chat.js +518 -0
- package/lib/server-home-clay-entry.js +65 -0
- package/lib/server-home-clay-session-links.js +26 -0
- package/lib/server-home-debate-planning.js +214 -0
- package/lib/server-home-debates.js +137 -0
- package/lib/server-home-mate-creation.js +261 -0
- package/lib/server-home-models.js +241 -0
- package/lib/server-home-preferences.js +61 -0
- package/lib/server-mates.js +37 -0
- package/lib/server-tools.js +377 -0
- package/lib/server.js +166 -59
- package/lib/session-pair-mcp-server.js +6 -6
- package/lib/sessions.js +22 -4
- package/lib/tool-capsule-source.js +142 -0
- package/lib/tool-control-mcp-server.js +126 -0
- package/lib/tool-llm.js +48 -0
- package/lib/tool-storage.js +77 -0
- package/lib/tool-ui-spec-advanced.js +82 -0
- package/lib/tool-ui-spec.js +261 -0
- package/lib/tools-registry.js +286 -0
- package/lib/users-home-dock-preferences.js +77 -0
- package/lib/users-home-surface-preferences.js +99 -0
- package/lib/users-preferences.js +4 -7
- package/lib/users.js +12 -0
- package/lib/whats-new-content.js +3 -3
- package/lib/workspace-assignment-service.js +420 -0
- package/lib/workspace-query-mcp-server.js +154 -0
- package/lib/workspace-query-service.js +492 -0
- package/lib/ws-schema.js +107 -12
- package/lib/yoke/adapters/acp.js +2 -1
- package/lib/yoke/adapters/antigravity.js +2 -1
- package/lib/yoke/adapters/claude-worker.js +11 -4
- package/lib/yoke/adapters/claude.js +141 -46
- package/lib/yoke/adapters/codex.js +79 -11
- package/lib/yoke/adapters/kiro.js +2 -1
- package/lib/yoke/claude-user-input.js +38 -0
- package/lib/yoke/codex-app-server.js +20 -2
- package/lib/yoke/codex-background-tasks.js +8 -2
- package/lib/yoke/codex-user-input.js +64 -0
- package/lib/yoke/complete-once.js +164 -0
- package/lib/yoke/index.js +5 -1
- package/lib/yoke/interface.js +19 -0
- package/lib/yoke/mcp-bridge-server.js +2 -6
- package/lib/yoke/user-input.js +254 -0
- package/package.json +4 -3
- package/lib/public/css/home-chat.css +0 -380
- package/lib/public/modules/home-chat.js +0 -438
- package/lib/server-clay-home.js +0 -245
|
@@ -7,7 +7,6 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
7
7
|
import { parseEmojis } from './markdown.js';
|
|
8
8
|
import { getCurrentTheme, getChatLayout, setChatLayout } from './theme.js';
|
|
9
9
|
import { openCommandPalette } from './command-palette.js';
|
|
10
|
-
import { getMateSessions } from './mate-sidebar.js';
|
|
11
10
|
import { openProjectSettings } from './project-settings.js';
|
|
12
11
|
import {
|
|
13
12
|
getCachedSessions,
|
|
@@ -33,8 +32,8 @@ import { store } from './store.js';
|
|
|
33
32
|
import { getWs } from './ws-ref.js';
|
|
34
33
|
import { dismissOverlayPanels, closeSidebar } from './sidebar.js';
|
|
35
34
|
import { switchProject, getCachedProjects } from './app-projects.js';
|
|
36
|
-
import { openDm } from './app-dm.js';
|
|
37
35
|
import { showHomeHub } from './app-home-hub.js';
|
|
36
|
+
import { openHomeChat } from './home-mate-chat.js';
|
|
38
37
|
import { openTerminal } from './terminal.js';
|
|
39
38
|
import { requestKnowledgeList } from './mate-knowledge.js';
|
|
40
39
|
import { loadRootDirectory } from './filebrowser.js';
|
|
@@ -319,9 +318,9 @@ function renderSheetSessions(listEl) {
|
|
|
319
318
|
if (type === "project") {
|
|
320
319
|
renderMobileSessionsInto(sessionListEl);
|
|
321
320
|
} else if (type === "mate") {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
321
|
+
closeMobileSheet();
|
|
322
|
+
showHomeHub();
|
|
323
|
+
openHomeChat(mateId);
|
|
325
324
|
}
|
|
326
325
|
|
|
327
326
|
refreshIcons();
|
|
@@ -370,12 +369,8 @@ function renderSheetSessions(listEl) {
|
|
|
370
369
|
// Track that chat sheet is open
|
|
371
370
|
mobileChatSheetOpen = true;
|
|
372
371
|
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
renderSessionsForContext("mate", null, getCurrentDmUserId());
|
|
376
|
-
} else {
|
|
377
|
-
renderSessionsForContext("project", getCachedCurrentSlug(), null);
|
|
378
|
-
}
|
|
372
|
+
// Mate chips navigate away immediately, so the sheet always renders project sessions.
|
|
373
|
+
renderSessionsForContext("project", getCachedCurrentSlug(), null);
|
|
379
374
|
}
|
|
380
375
|
|
|
381
376
|
// Helper: create a mobile session item element
|
|
@@ -659,54 +654,6 @@ function createMobileLoopGroup(loopId, children, groupKey) {
|
|
|
659
654
|
return wrapper;
|
|
660
655
|
}
|
|
661
656
|
|
|
662
|
-
function renderMateMobileActions(container) {
|
|
663
|
-
var newSessionBtn = document.createElement("button");
|
|
664
|
-
newSessionBtn.className = "mobile-session-new";
|
|
665
|
-
newSessionBtn.innerHTML = '<i data-lucide="plus" style="width:16px;height:16px"></i> New session';
|
|
666
|
-
newSessionBtn.addEventListener("click", function () {
|
|
667
|
-
if (getWs() && store.get('connected')) {
|
|
668
|
-
getWs().send(JSON.stringify({ type: "new_session" }));
|
|
669
|
-
}
|
|
670
|
-
closeMobileSheet();
|
|
671
|
-
});
|
|
672
|
-
container.appendChild(newSessionBtn);
|
|
673
|
-
|
|
674
|
-
var debateBtn = document.createElement("button");
|
|
675
|
-
debateBtn.className = "mobile-session-new";
|
|
676
|
-
debateBtn.innerHTML = '<i data-lucide="mic" style="width:16px;height:16px"></i> New debate';
|
|
677
|
-
debateBtn.addEventListener("click", function () {
|
|
678
|
-
closeMobileSheet();
|
|
679
|
-
var targetBtn = document.getElementById("mate-debate-btn");
|
|
680
|
-
if (targetBtn) setTimeout(function () { targetBtn.click(); }, 250);
|
|
681
|
-
});
|
|
682
|
-
container.appendChild(debateBtn);
|
|
683
|
-
|
|
684
|
-
// Render mate session list
|
|
685
|
-
var mateSessions = getMateSessions();
|
|
686
|
-
if (mateSessions.length > 0) {
|
|
687
|
-
var sorted = mateSessions.slice().sort(function (a, b) {
|
|
688
|
-
return (b.lastActivity || 0) - (a.lastActivity || 0);
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
var currentGroup = "";
|
|
692
|
-
for (var i = 0; i < sorted.length; i++) {
|
|
693
|
-
var s = sorted[i];
|
|
694
|
-
var group = getDateGroup(s.lastActivity || 0);
|
|
695
|
-
if (group !== currentGroup) {
|
|
696
|
-
currentGroup = group;
|
|
697
|
-
var header = document.createElement("div");
|
|
698
|
-
header.className = "mobile-sheet-group";
|
|
699
|
-
header.textContent = group;
|
|
700
|
-
container.appendChild(header);
|
|
701
|
-
}
|
|
702
|
-
var mateItem = createMobileSessionItem(s);
|
|
703
|
-
container.appendChild(mateItem);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
refreshIcons();
|
|
708
|
-
}
|
|
709
|
-
|
|
710
657
|
// Helper: render sorted sessions into a container with date groups (with loop session grouping)
|
|
711
658
|
function renderMobileSessionsInto(container) {
|
|
712
659
|
// Mirrors the desktop sidebar's split button: one "New session" action on
|
|
@@ -902,11 +849,7 @@ export function refreshMobileChatSheet() {
|
|
|
902
849
|
|
|
903
850
|
// Re-render sessions for current context
|
|
904
851
|
sessionListEl.innerHTML = "";
|
|
905
|
-
|
|
906
|
-
renderMateMobileActions(sessionListEl);
|
|
907
|
-
} else {
|
|
908
|
-
renderMobileSessionsInto(sessionListEl);
|
|
909
|
-
}
|
|
852
|
+
renderMobileSessionsInto(sessionListEl);
|
|
910
853
|
|
|
911
854
|
refreshIcons();
|
|
912
855
|
}
|
|
@@ -944,8 +887,7 @@ function renderSheetMateProfile(listEl) {
|
|
|
944
887
|
var actions = [
|
|
945
888
|
{ icon: "book-open", label: "Knowledge", btnId: "mate-knowledge-btn", countId: "mate-knowledge-count" },
|
|
946
889
|
{ icon: "sticky-note", label: "Sticky Notes", btnId: "sticky-notes-sidebar-btn", countId: "sticky-notes-sidebar-count" },
|
|
947
|
-
{ icon: "puzzle", label: "Skills", btnId: "mate-skills-btn" }
|
|
948
|
-
{ icon: "calendar", label: "Scheduled Tasks", btnId: "mate-scheduler-btn" }
|
|
890
|
+
{ icon: "puzzle", label: "Skills", btnId: "mate-skills-btn" }
|
|
949
891
|
];
|
|
950
892
|
|
|
951
893
|
for (var i = 0; i < actions.length; i++) {
|
|
@@ -1062,12 +1004,11 @@ function renderSheetTools(listEl) {
|
|
|
1062
1004
|
{ icon: "brain", label: "Memory", action: "mate-memory" },
|
|
1063
1005
|
{ icon: "book-open", label: "Knowledge", action: "mate-knowledge" },
|
|
1064
1006
|
{ icon: "sticky-note", label: "Sticky Notes", action: "mate-sticky" },
|
|
1065
|
-
{ icon: "puzzle", label: "Skills", action: "mate-skills" }
|
|
1066
|
-
{ icon: "calendar-clock", label: "Scheduled Tasks", action: "mate-scheduler" }
|
|
1007
|
+
{ icon: "puzzle", label: "Skills", action: "mate-skills" }
|
|
1067
1008
|
] : [
|
|
1068
1009
|
{ icon: "folder-tree", label: "Files", action: "files" },
|
|
1069
1010
|
{ icon: "square-terminal", label: "Terminal", action: "terminal" },
|
|
1070
|
-
{ icon: "
|
|
1011
|
+
{ icon: "notebook-tabs", label: "Logs", action: "project-logs" }
|
|
1071
1012
|
];
|
|
1072
1013
|
|
|
1073
1014
|
for (var i = 0; i < items.length; i++) {
|
|
@@ -1082,8 +1023,8 @@ function renderSheetTools(listEl) {
|
|
|
1082
1023
|
setTimeout(function () { openMobileSheet("files"); }, 250);
|
|
1083
1024
|
} else if (item.action === "terminal") {
|
|
1084
1025
|
openTerminal();
|
|
1085
|
-
} else if (item.action === "
|
|
1086
|
-
targetId = "
|
|
1026
|
+
} else if (item.action === "project-logs") {
|
|
1027
|
+
targetId = "project-logs-btn";
|
|
1087
1028
|
} else if (item.action === "mate-knowledge") {
|
|
1088
1029
|
setTimeout(function () { openMobileSheet("mate-knowledge"); }, 250);
|
|
1089
1030
|
return;
|
|
@@ -1093,8 +1034,6 @@ function renderSheetTools(listEl) {
|
|
|
1093
1034
|
targetId = "mate-skills-btn";
|
|
1094
1035
|
} else if (item.action === "mate-memory") {
|
|
1095
1036
|
targetId = "mate-memory-btn";
|
|
1096
|
-
} else if (item.action === "mate-scheduler") {
|
|
1097
|
-
targetId = "mate-scheduler-btn";
|
|
1098
1037
|
} else if (item.action === "mate-debate") {
|
|
1099
1038
|
targetId = "mate-debate-btn";
|
|
1100
1039
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Compact online-user presence renderer for the project sidebar.
|
|
2
|
+
|
|
3
|
+
import { userAvatarUrl } from './avatar.js';
|
|
4
|
+
|
|
5
|
+
var lastSidebarPresenceIds = [];
|
|
6
|
+
|
|
7
|
+
export function renderSidebarPresence(onlineUsers) {
|
|
8
|
+
var container = document.getElementById("sidebar-presence");
|
|
9
|
+
if (!container) return;
|
|
10
|
+
if (!onlineUsers || onlineUsers.length < 2) {
|
|
11
|
+
if (lastSidebarPresenceIds.length > 0) {
|
|
12
|
+
lastSidebarPresenceIds = [];
|
|
13
|
+
container.innerHTML = "";
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
var newIds = onlineUsers.map(function (user) { return user.id; }).sort();
|
|
18
|
+
if (newIds.length === lastSidebarPresenceIds.length && newIds.every(function (id, index) { return id === lastSidebarPresenceIds[index]; })) return;
|
|
19
|
+
lastSidebarPresenceIds = newIds;
|
|
20
|
+
container.innerHTML = "";
|
|
21
|
+
var maxShow = 4;
|
|
22
|
+
for (var i = 0; i < Math.min(onlineUsers.length, maxShow); i++) {
|
|
23
|
+
var user = onlineUsers[i];
|
|
24
|
+
var image = document.createElement("img");
|
|
25
|
+
image.className = "sidebar-presence-avatar";
|
|
26
|
+
image.src = userAvatarUrl(user, 24);
|
|
27
|
+
image.alt = user.displayName;
|
|
28
|
+
image.dataset.tip = user.displayName + " (@" + user.username + ")";
|
|
29
|
+
container.appendChild(image);
|
|
30
|
+
}
|
|
31
|
+
if (onlineUsers.length > maxShow) {
|
|
32
|
+
var more = document.createElement("span");
|
|
33
|
+
more.className = "sidebar-presence-more";
|
|
34
|
+
more.textContent = "+" + (onlineUsers.length - maxShow);
|
|
35
|
+
container.appendChild(more);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1376,8 +1376,29 @@ function renderSplitGroupItem(group, members) {
|
|
|
1376
1376
|
|
|
1377
1377
|
// --- Main session list ---
|
|
1378
1378
|
|
|
1379
|
+
// Fingerprint of the last completed render: the whole session payload plus the
|
|
1380
|
+
// two store values this render also reads. Nothing is cherry-picked, so the
|
|
1381
|
+
// guard can only skip a frame that is byte-identical to what is already on
|
|
1382
|
+
// screen. A re-render triggered by other state (sessions === null) always
|
|
1383
|
+
// runs and resets the fingerprint afterwards.
|
|
1384
|
+
var lastRenderFingerprint = null;
|
|
1385
|
+
|
|
1386
|
+
function sessionRenderFingerprint(sessions) {
|
|
1387
|
+
try {
|
|
1388
|
+
return JSON.stringify([sessions, store.get('splitGroups') || [], store.get('splitPanes') || null]);
|
|
1389
|
+
} catch (e) {
|
|
1390
|
+
return null;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1379
1394
|
export function renderSessionList(sessions) {
|
|
1380
|
-
if (sessions)
|
|
1395
|
+
if (sessions) {
|
|
1396
|
+
// A reconnect and a streaming turn both re-send this list unchanged;
|
|
1397
|
+
// rebuilding the sidebar for an identical frame is what made it flicker.
|
|
1398
|
+
var incoming = sessionRenderFingerprint(sessions);
|
|
1399
|
+
if (incoming !== null && incoming === lastRenderFingerprint) return;
|
|
1400
|
+
cachedSessions = sessions;
|
|
1401
|
+
}
|
|
1381
1402
|
|
|
1382
1403
|
// If mobile chat sheet is open, refresh it
|
|
1383
1404
|
if (refreshMobileChatSheet) refreshMobileChatSheet();
|
|
@@ -1516,6 +1537,9 @@ export function renderSessionList(sessions) {
|
|
|
1516
1537
|
refreshIcons();
|
|
1517
1538
|
if (updatePageTitle) updatePageTitle();
|
|
1518
1539
|
syncHeaderSearchUi();
|
|
1540
|
+
// Recorded from the sessions actually rendered, so a null-argument re-render
|
|
1541
|
+
// driven by other state refreshes the fingerprint rather than stranding it.
|
|
1542
|
+
lastRenderFingerprint = sessionRenderFingerprint(cachedSessions);
|
|
1519
1543
|
}
|
|
1520
1544
|
|
|
1521
1545
|
// --- Search results ---
|
|
@@ -5,8 +5,8 @@ import { buildAgentVendorSelect, fillAgentModels, buildAgentEffortSelect, fillAg
|
|
|
5
5
|
import { showToast } from './utils.js';
|
|
6
6
|
|
|
7
7
|
var pairDialog = null;
|
|
8
|
-
// Set when the dialog was opened via "Add Worker" on an existing session:
|
|
9
|
-
// that session becomes the Driver and the dialog only configures the Worker.
|
|
8
|
+
// Set when the dialog was opened via "Add Split Worker" on an existing session:
|
|
9
|
+
// that session becomes the Driver and the dialog only configures the Split Worker.
|
|
10
10
|
var pendingDriver = null;
|
|
11
11
|
|
|
12
12
|
function closePairDialog() {
|
|
@@ -35,7 +35,7 @@ function roleColumn(role, description, vendorSelect, modelSelect, effortSelect,
|
|
|
35
35
|
col.className = "pair-modal-role";
|
|
36
36
|
var heading = document.createElement("div");
|
|
37
37
|
heading.className = "pair-modal-role-heading";
|
|
38
|
-
heading.innerHTML = '<span class="pair-role-dot pair-role-' + role.toLowerCase() + '"></span><div><strong>' + role + '</strong><span>' + description + '</span></div>';
|
|
38
|
+
heading.innerHTML = '<span class="pair-role-dot pair-role-' + role.toLowerCase().replace(/ /g, "-") + '"></span><div><strong>' + role + '</strong><span>' + description + '</span></div>';
|
|
39
39
|
col.appendChild(heading);
|
|
40
40
|
var vendorField = fieldLabel("Vendor", vendorSelect);
|
|
41
41
|
col.appendChild(vendorField.fragment);
|
|
@@ -82,13 +82,13 @@ export function showPairDialog(options) {
|
|
|
82
82
|
|
|
83
83
|
var title = document.createElement("div");
|
|
84
84
|
title.className = "wt-modal-title";
|
|
85
|
-
title.textContent = driverInfo ? "Add Worker" : "Pair session";
|
|
85
|
+
title.textContent = driverInfo ? "Add Split Worker" : "Pair session";
|
|
86
86
|
modal.appendChild(title);
|
|
87
87
|
var desc = document.createElement("div");
|
|
88
88
|
desc.className = "pair-modal-desc";
|
|
89
89
|
desc.textContent = driverInfo
|
|
90
|
-
? "This session becomes the Driver; a new Worker opens beside it."
|
|
91
|
-
: "One Driver plans and directs a visible Worker session.";
|
|
90
|
+
? "This session becomes the Driver; a new Split Worker opens beside it."
|
|
91
|
+
: "One Driver plans and directs a visible Split Worker session.";
|
|
92
92
|
modal.appendChild(desc);
|
|
93
93
|
|
|
94
94
|
var driverVendor = buildAgentVendorSelect(installed, installed.indexOf("claude") !== -1 ? "claude" : installed[0]);
|
|
@@ -137,7 +137,7 @@ export function showPairDialog(options) {
|
|
|
137
137
|
} else {
|
|
138
138
|
roles.appendChild(roleColumn("Driver", "Plans, delegates, and integrates", driverVendor, driverModel, driverEffort, options));
|
|
139
139
|
}
|
|
140
|
-
roles.appendChild(roleColumn("Worker", "Executes delegated tasks", workerVendor, workerModel, workerEffort, options));
|
|
140
|
+
roles.appendChild(roleColumn("Split Worker", "Executes delegated tasks", workerVendor, workerModel, workerEffort, options));
|
|
141
141
|
modal.appendChild(roles);
|
|
142
142
|
|
|
143
143
|
var actions = document.createElement("div");
|
|
@@ -149,7 +149,7 @@ export function showPairDialog(options) {
|
|
|
149
149
|
var createBtn = document.createElement("button");
|
|
150
150
|
createBtn.type = "button";
|
|
151
151
|
createBtn.className = "wt-modal-btn primary";
|
|
152
|
-
createBtn.textContent = driverInfo ? "Add Worker" : "Create pair";
|
|
152
|
+
createBtn.textContent = driverInfo ? "Add Split Worker" : "Create pair";
|
|
153
153
|
actions.appendChild(cancelBtn);
|
|
154
154
|
actions.appendChild(createBtn);
|
|
155
155
|
modal.appendChild(actions);
|
|
@@ -218,7 +218,7 @@ export function handleSplitDelegation(msg) {
|
|
|
218
218
|
if (msg.active) states[msg.groupId] = msg;
|
|
219
219
|
else delete states[msg.groupId];
|
|
220
220
|
store.set({ splitDelegations: states });
|
|
221
|
-
// Inside the
|
|
221
|
+
// Inside the Split Worker's own pane, mirror the delegation into the composer
|
|
222
222
|
// notice (the delegated user_message shows it too; this covers the end).
|
|
223
223
|
if (store.get('paneMode') && msg.to === store.get('activeSessionId')) {
|
|
224
224
|
if (msg.active) showWorkerDelegationNotice(null);
|
|
@@ -252,7 +252,7 @@ export function syncPairChrome(host, split) {
|
|
|
252
252
|
setBtn.type = "button";
|
|
253
253
|
setBtn.className = "split-pair-set-driver";
|
|
254
254
|
setBtn.textContent = "Set Driver";
|
|
255
|
-
setBtn.title = "Make this session the Driver; the other pane becomes its Worker";
|
|
255
|
+
setBtn.title = "Make this session the Driver; the other pane becomes its Split Worker";
|
|
256
256
|
setBtn.addEventListener("click", function () { sendSetPair(group.id, paneSessionId); });
|
|
257
257
|
var titleEl = header.querySelector(".split-pane-title");
|
|
258
258
|
var accessEl = header.querySelector(".split-pane-full-access");
|
|
@@ -264,11 +264,11 @@ export function syncPairChrome(host, split) {
|
|
|
264
264
|
for (var pi = 0; pi < split.panes.length && pi < headers.length; pi++) {
|
|
265
265
|
(function (sessionId, header) {
|
|
266
266
|
var isDriver = sessionId === group.pair.driverId;
|
|
267
|
-
var role = isDriver ? "Driver" : "Worker";
|
|
267
|
+
var role = isDriver ? "Driver" : "Split Worker";
|
|
268
268
|
var badge = document.createElement("span");
|
|
269
|
-
badge.className = "split-pair-role split-pair-role-" + role.toLowerCase();
|
|
269
|
+
badge.className = "split-pair-role split-pair-role-" + role.toLowerCase().replace(/ /g, "-");
|
|
270
270
|
badge.textContent = role;
|
|
271
|
-
badge.title = isDriver ? "Driver controls this Worker" : "Worker controlled by the Driver";
|
|
271
|
+
badge.title = isDriver ? "Driver controls this Split Worker" : "Split Worker controlled by the Driver";
|
|
272
272
|
var title = header.querySelector(".split-pane-title");
|
|
273
273
|
var access = header.querySelector(".split-pane-full-access");
|
|
274
274
|
header.insertBefore(badge, access ? access.nextSibling : (title ? title.nextSibling : null));
|
|
@@ -11,6 +11,7 @@ import { groupedSessionIds, findSplitGroup } from './split-group-helpers.js';
|
|
|
11
11
|
import { showConfirm } from './app-misc.js';
|
|
12
12
|
import { syncPairChrome } from './split-pair-ui.js';
|
|
13
13
|
import { presentMarkdownEdit } from './filebrowser.js';
|
|
14
|
+
import { autoStartLoginIfNeeded } from './vendor-login.js';
|
|
14
15
|
|
|
15
16
|
var host = null;
|
|
16
17
|
var nativeApp = null;
|
|
@@ -276,6 +277,12 @@ function handlePaneMessage(event) {
|
|
|
276
277
|
if (present) presentMarkdownEdit(present);
|
|
277
278
|
return;
|
|
278
279
|
}
|
|
280
|
+
// Both panes can report auth_required for their own sessions. The shell runs
|
|
281
|
+
// one login flow for the project; repeat events are no-ops there.
|
|
282
|
+
if (msg.type === "clay-pane-auth-required") {
|
|
283
|
+
if (msg.message) autoStartLoginIfNeeded(msg.message);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
279
286
|
if (msg.type !== "clay-pane-context") return;
|
|
280
287
|
var frames = host.querySelectorAll(".split-pane-frame");
|
|
281
288
|
for (var i = 0; i < frames.length; i++) {
|
|
@@ -11,7 +11,7 @@ var textTimers = {};
|
|
|
11
11
|
var colorPickerEl = null;
|
|
12
12
|
var formatToolbarEl = null;
|
|
13
13
|
|
|
14
|
-
var NOTE_COLORS = ["
|
|
14
|
+
var NOTE_COLORS = ["purple", "green", "yellow", "blue", "pink", "orange"];
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
function getContainerBounds() {
|
|
@@ -98,7 +98,8 @@ export function createNote() {
|
|
|
98
98
|
type: "note_create",
|
|
99
99
|
x: 60 + offset,
|
|
100
100
|
y: 60 + offset,
|
|
101
|
-
color: "
|
|
101
|
+
color: "purple",
|
|
102
|
+
opacity: 0.64,
|
|
102
103
|
});
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -154,7 +155,7 @@ function renderNote(data) {
|
|
|
154
155
|
el.style.width = data.w + "px";
|
|
155
156
|
el.style.height = data.h + "px";
|
|
156
157
|
el.style.zIndex = 100 + (data.zIndex || 0);
|
|
157
|
-
el.dataset.color = data.color || "
|
|
158
|
+
el.dataset.color = data.color || "purple";
|
|
158
159
|
|
|
159
160
|
if (data.minimized) el.classList.add("minimized");
|
|
160
161
|
if (data.hidden) el.classList.add("hidden");
|
|
@@ -217,7 +218,7 @@ function renderNote(data) {
|
|
|
217
218
|
opacitySlider.type = "range";
|
|
218
219
|
opacitySlider.min = "20";
|
|
219
220
|
opacitySlider.max = "100";
|
|
220
|
-
opacitySlider.value = String(Math.round((data.opacity
|
|
221
|
+
opacitySlider.value = String(Math.round((typeof data.opacity === "number" ? data.opacity : 0.64) * 100));
|
|
221
222
|
opacitySlider.className = "sticky-note-opacity-slider";
|
|
222
223
|
opacitySlider.title = "Opacity";
|
|
223
224
|
opacityWrap.appendChild(opacitySlider);
|
|
@@ -754,17 +755,44 @@ export function handleNotesList(msg) {
|
|
|
754
755
|
var container = document.getElementById("sticky-notes-container");
|
|
755
756
|
if (!container) return;
|
|
756
757
|
|
|
757
|
-
//
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
758
|
+
// Keyed reconciliation, never a clear-and-rebuild. A reconnect re-sends this
|
|
759
|
+
// list unchanged; tearing every note down and recreating it made all the
|
|
760
|
+
// floating cards vanish and reappear, and destroyed any open editor.
|
|
761
761
|
var list = msg.notes || [];
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
762
|
+
var seen = {};
|
|
763
|
+
var created = false;
|
|
764
|
+
var i;
|
|
765
|
+
|
|
766
|
+
for (i = 0; i < list.length; i++) {
|
|
767
|
+
var data = list[i];
|
|
768
|
+
if (!data || !data.id) continue;
|
|
769
|
+
seen[data.id] = true;
|
|
770
|
+
var entry = notes.get(data.id);
|
|
771
|
+
if (entry && entry.el && entry.el.parentNode === container) {
|
|
772
|
+
patchNote(entry, data);
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
var el = renderNote(data);
|
|
776
|
+
notes.set(data.id, { data: data, el: el });
|
|
765
777
|
container.appendChild(el);
|
|
778
|
+
created = true;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// Remove notes the server no longer lists.
|
|
782
|
+
var staleIds = [];
|
|
783
|
+
notes.forEach(function (value, id) {
|
|
784
|
+
if (!seen[id]) staleIds.push(id);
|
|
785
|
+
});
|
|
786
|
+
for (i = 0; i < staleIds.length; i++) {
|
|
787
|
+
var stale = notes.get(staleIds[i]);
|
|
788
|
+
if (stale && stale.el && stale.el.parentNode) stale.el.parentNode.removeChild(stale.el);
|
|
789
|
+
notes.delete(staleIds[i]);
|
|
766
790
|
}
|
|
767
791
|
|
|
792
|
+
// renderNote already refreshes icons for the nodes it builds; an all-patch
|
|
793
|
+
// pass introduces no new Lucide markup and must not trigger a document scan.
|
|
794
|
+
if (created) refreshIcons();
|
|
795
|
+
|
|
768
796
|
updateBadge();
|
|
769
797
|
updateSidebarBadge();
|
|
770
798
|
|
|
@@ -800,59 +828,84 @@ export function handleNoteCreated(msg) {
|
|
|
800
828
|
}
|
|
801
829
|
}
|
|
802
830
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
entry
|
|
813
|
-
|
|
814
|
-
entry.
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
831
|
+
// Patch one existing note element in place from a server payload.
|
|
832
|
+
//
|
|
833
|
+
// Geometry, z-order, colour, and opacity are plain style writes and are always
|
|
834
|
+
// applied. The rendered markdown is only replaced when the text actually
|
|
835
|
+
// changed and the note is not being edited, so a geometry-only or z-only
|
|
836
|
+
// update never destroys the user's caret, selection, or in-progress draft.
|
|
837
|
+
// Returns true when icon markup was replaced, so the caller can decide whether
|
|
838
|
+
// a Lucide pass is needed at all.
|
|
839
|
+
function patchNote(entry, next) {
|
|
840
|
+
if (!entry || !next) return false;
|
|
841
|
+
var previous = entry.data || {};
|
|
842
|
+
entry.data = next;
|
|
843
|
+
var el = entry.el;
|
|
844
|
+
|
|
845
|
+
el.style.left = next.x + "px";
|
|
846
|
+
el.style.top = next.y + "px";
|
|
847
|
+
el.style.width = next.w + "px";
|
|
848
|
+
el.style.height = next.h + "px";
|
|
849
|
+
el.style.zIndex = 100 + (next.zIndex || 0);
|
|
850
|
+
el.dataset.color = next.color || "purple";
|
|
851
|
+
|
|
852
|
+
var textarea = el.querySelector(".sticky-note-text");
|
|
853
|
+
var rendered = el.querySelector(".sticky-note-rendered");
|
|
854
|
+
var nextText = next.text || "";
|
|
855
|
+
var editing = rendered === document.activeElement || textarea === document.activeElement;
|
|
856
|
+
// A draft the user typed but has not committed must survive a redraw.
|
|
857
|
+
var hasDraft = !!(textarea && textarea.value !== (previous.text || ""));
|
|
858
|
+
var textChanged = nextText !== (previous.text || "");
|
|
859
|
+
if (rendered && !editing && !hasDraft && textChanged) {
|
|
860
|
+
if (textarea) textarea.value = nextText;
|
|
861
|
+
if (nextText.trim()) {
|
|
862
|
+
rendered.innerHTML = renderMiniMarkdown(nextText);
|
|
825
863
|
rendered.classList.remove("is-empty");
|
|
826
864
|
} else {
|
|
827
865
|
rendered.innerHTML = "";
|
|
828
866
|
rendered.classList.add("is-empty");
|
|
829
867
|
}
|
|
830
|
-
syncTitle(
|
|
868
|
+
syncTitle(el, nextText);
|
|
831
869
|
}
|
|
832
870
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if (slider) slider.value = String(Math.round(msg.note.opacity * 100));
|
|
871
|
+
if (typeof next.opacity === "number") {
|
|
872
|
+
el.style.setProperty("--note-opacity", next.opacity);
|
|
873
|
+
var slider = el.querySelector(".sticky-note-opacity-slider");
|
|
874
|
+
if (slider) slider.value = String(Math.round(next.opacity * 100));
|
|
838
875
|
}
|
|
839
876
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
877
|
+
if (next.hidden) el.classList.add("hidden");
|
|
878
|
+
else el.classList.remove("hidden");
|
|
879
|
+
|
|
880
|
+
// The minimize button swaps its icon, which is the only path here that can
|
|
881
|
+
// introduce fresh Lucide markup.
|
|
882
|
+
var iconsReplaced = false;
|
|
883
|
+
var wasMinimized = el.classList.contains("minimized");
|
|
884
|
+
var minBtn = el.querySelector(".sticky-note-min-btn");
|
|
885
|
+
if (next.minimized) {
|
|
886
|
+
el.classList.add("minimized");
|
|
887
|
+
if (minBtn && !wasMinimized) {
|
|
888
|
+
minBtn.innerHTML = iconHtml("maximize-2");
|
|
889
|
+
minBtn.title = "Expand";
|
|
890
|
+
iconsReplaced = true;
|
|
891
|
+
}
|
|
843
892
|
} else {
|
|
844
|
-
|
|
893
|
+
el.classList.remove("minimized");
|
|
894
|
+
if (minBtn && wasMinimized) {
|
|
895
|
+
minBtn.innerHTML = iconHtml("minus");
|
|
896
|
+
minBtn.title = "Minimize";
|
|
897
|
+
iconsReplaced = true;
|
|
898
|
+
}
|
|
845
899
|
}
|
|
900
|
+
return iconsReplaced;
|
|
901
|
+
}
|
|
846
902
|
|
|
847
|
-
|
|
848
|
-
if (msg.note
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
if (minBtn) { minBtn.innerHTML = iconHtml("minus"); minBtn.title = "Minimize"; }
|
|
854
|
-
}
|
|
855
|
-
refreshIcons();
|
|
903
|
+
export function handleNoteUpdated(msg) {
|
|
904
|
+
if (!msg.note) return;
|
|
905
|
+
var entry = notes.get(msg.note.id);
|
|
906
|
+
if (!entry) return;
|
|
907
|
+
|
|
908
|
+
if (patchNote(entry, msg.note)) refreshIcons();
|
|
856
909
|
|
|
857
910
|
// Re-render archive if open (text or color may have changed)
|
|
858
911
|
if (archiveOpen) renderArchiveCards();
|
|
@@ -926,7 +979,7 @@ function renderArchiveCards() {
|
|
|
926
979
|
(function (noteData) {
|
|
927
980
|
var card = document.createElement("div");
|
|
928
981
|
card.className = "notes-archive-card" + (noteData.data.hidden ? " archived" : "");
|
|
929
|
-
card.dataset.color = noteData.data.color || "
|
|
982
|
+
card.dataset.color = noteData.data.color || "purple";
|
|
930
983
|
|
|
931
984
|
// Header with title + delete
|
|
932
985
|
var header = document.createElement("div");
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Composition-safe action binding for declarative Capsule text controls.
|
|
2
|
+
|
|
3
|
+
var inputStates = new WeakMap();
|
|
4
|
+
|
|
5
|
+
export function isToolTextInputComposing(input) {
|
|
6
|
+
var state = inputStates.get(input);
|
|
7
|
+
return !!state && state.composing;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function bindToolTextInput(input, commit, options) {
|
|
11
|
+
options = options || {};
|
|
12
|
+
var state = { composing: false, trailingValue: null };
|
|
13
|
+
inputStates.set(input, state);
|
|
14
|
+
|
|
15
|
+
function isAlive() {
|
|
16
|
+
return typeof options.isAlive !== "function" || options.isAlive(input);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
input.addEventListener("compositionstart", function () {
|
|
20
|
+
state.composing = true;
|
|
21
|
+
state.trailingValue = null;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
input.addEventListener("beforeinput", function (event) {
|
|
25
|
+
if (state.trailingValue === null && event && (event.isComposing || event.inputType === "insertCompositionText")) {
|
|
26
|
+
state.composing = true;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
input.addEventListener("compositionend", function () {
|
|
31
|
+
state.composing = false;
|
|
32
|
+
state.trailingValue = input.value;
|
|
33
|
+
if (!isAlive()) return;
|
|
34
|
+
commit(input.value);
|
|
35
|
+
if (typeof options.onCompositionEnd === "function") options.onCompositionEnd(input);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
input.addEventListener("input", function (event) {
|
|
39
|
+
if (state.composing || (event && event.isComposing)) return;
|
|
40
|
+
if (state.trailingValue !== null && input.value === state.trailingValue) {
|
|
41
|
+
state.trailingValue = null;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
state.trailingValue = null;
|
|
45
|
+
if (!isAlive()) return;
|
|
46
|
+
commit(input.value);
|
|
47
|
+
});
|
|
48
|
+
}
|