clay-server 2.36.0 → 2.36.1-beta.1
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/public/app.js
CHANGED
|
@@ -66,7 +66,7 @@ import { initAppNotifications, handleNotificationsState as _notifHandleState, ha
|
|
|
66
66
|
import { createStore, store } from './modules/store.js';
|
|
67
67
|
import { initPanels, updateConfigChip as _panUpdateConfigChip, getModelEffortLevels as _panGetModelEffortLevels, accumulateUsage as _panAccumulateUsage, updateUsagePanel as _panUpdateUsagePanel, resetUsage as _panResetUsage, toggleUsagePanel as _panToggleUsagePanel, formatTokens as _panFormatTokens, updateStatusPanel as _panUpdateStatusPanel, requestProcessStats as _panRequestProcessStats, toggleStatusPanel as _panToggleStatusPanel, accumulateContext as _panAccumulateContext, updateContextPanel as _panUpdateContextPanel, resetContext as _panResetContext, resetContextData as _panResetContextData, minimizeContext as _panMinimizeContext, expandContext as _panExpandContext, toggleContextPanel as _panToggleContextPanel, getContextView as _panGetContextView, renderCtxPopover as _panRenderCtxPopover, hideCtxPopover as _panHideCtxPopover, formatBytes as _panFormatBytes, formatUptime as _panFormatUptime, getModelSupportsEffort as _panGetModelSupportsEffort, getSessionUsage, setSessionUsage, getContextData, setContextData, setContextView as _panSetContextView, applyContextView as _panApplyContextView } from './modules/app-panels.js';
|
|
68
68
|
import { initProjects, updateProjectList as _projUpdateProjectList, renderProjectList as _projRenderProjectList, renderTopbarPresence as _projRenderTopbarPresence, switchProject as _projSwitchProject, resetClientState as _projResetClientState, confirmRemoveProject as _projConfirmRemoveProject, handleRemoveProjectCheckResult as _projHandleRemoveProjectCheckResult, handleRemoveProjectResult as _projHandleRemoveProjectResult, openAddProjectModal as _projOpenAddProjectModal, closeAddProjectModal as _projCloseAddProjectModal, handleBrowseDirResult as _projHandleBrowseDirResult, handleAddProjectResult as _projHandleAddProjectResult, handleCloneProgress as _projHandleCloneProgress, showUpdateAvailable as _projShowUpdateAvailable, getCachedProjects, setCachedProjects, getCachedProjectCount, getCachedRemovedProjects, setCachedRemovedProjects } from './modules/app-projects.js';
|
|
69
|
-
import { initRendering, addToMessages as _renAddToMessages, scrollToBottom as _renScrollToBottom, forceScrollToBottom as _renForceScrollToBottom, addUserMessage as _renAddUserMessage, getMsgTime as _renGetMsgTime, shouldGroupMessage as _renShouldGroupMessage, ensureAssistantBlock as _renEnsureAssistantBlock, addCopyHandler as _renAddCopyHandler, appendDelta as _renAppendDelta, flushStreamBuffer as _renFlushStreamBuffer, finalizeAssistantBlock as _renFinalizeAssistantBlock, addSystemMessage as _renAddSystemMessage, addConflictMessage as _renAddConflictMessage, addContextOverflowMessage as _renAddContextOverflowMessage, showClaudePreThinking as _renShowClaudePreThinking, showMatePreThinking as _renShowMatePreThinking, removeMatePreThinking as _renRemoveMatePreThinking, showSuggestionChips as _renShowSuggestionChips, hideSuggestionChips as _renHideSuggestionChips, getGhostSuggestion as _renGetGhostSuggestion, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp } from './modules/app-rendering.js';
|
|
69
|
+
import { initRendering, addToMessages as _renAddToMessages, scrollToBottom as _renScrollToBottom, forceScrollToBottom as _renForceScrollToBottom, addUserMessage as _renAddUserMessage, getMsgTime as _renGetMsgTime, shouldGroupMessage as _renShouldGroupMessage, ensureAssistantBlock as _renEnsureAssistantBlock, addCopyHandler as _renAddCopyHandler, appendDelta as _renAppendDelta, flushStreamBuffer as _renFlushStreamBuffer, finalizeAssistantBlock as _renFinalizeAssistantBlock, addSystemMessage as _renAddSystemMessage, addConflictMessage as _renAddConflictMessage, addContextOverflowMessage as _renAddContextOverflowMessage, showClaudePreThinking as _renShowClaudePreThinking, showMatePreThinking as _renShowMatePreThinking, removeMatePreThinking as _renRemoveMatePreThinking, showSuggestionChips as _renShowSuggestionChips, hideSuggestionChips as _renHideSuggestionChips, getGhostSuggestion as _renGetGhostSuggestion, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp, getStickyBottom, armStickyBottom, disarmStickyBottom } from './modules/app-rendering.js';
|
|
70
70
|
import { initDm, openDm as _dmOpenDm, enterDmMode as _dmEnterDmMode, exitDmMode as _dmExitDmMode, handleMateCreatedInApp as _dmHandleMateCreatedInApp, renderAvailableBuiltins as _dmRenderAvailableBuiltins, buildMateInterviewPrompt as _dmBuildMateInterviewPrompt, updateMateIconStatus as _dmUpdateMateIconStatus, connectMateProject as _dmConnectMateProject, disconnectMateProject as _dmDisconnectMateProject, appendDmMessage as _dmAppendDmMessage, showDmTypingIndicator as _dmShowDmTypingIndicator, handleDmSend as _dmHandleDmSend } from './modules/app-dm.js';
|
|
71
71
|
import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
|
|
72
72
|
import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState, exportDebateAsPdf, renderMcpDebateProposal } from './modules/debate.js';
|
|
@@ -518,6 +518,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
518
518
|
var newMsgBtnActivity = "\u2193 New activity";
|
|
519
519
|
|
|
520
520
|
messagesEl.addEventListener("scroll", function () {
|
|
521
|
+
// While sticky-bottom is armed (e.g. just after history_done or a "New
|
|
522
|
+
// activity" click), suppress "user scrolled up" detection. Growth-induced
|
|
523
|
+
// scroll events from deferred layout are not the user — the ResizeObserver
|
|
524
|
+
// is busy re-pinning to bottom. Real user input (wheel/touch/PageUp)
|
|
525
|
+
// disarms the flag separately, so this gate doesn't block genuine intent.
|
|
526
|
+
if (getStickyBottom()) return;
|
|
521
527
|
var distFromBottom = messagesEl.scrollHeight - messagesEl.scrollTop - messagesEl.clientHeight;
|
|
522
528
|
var scrolledUp = distFromBottom > 150;
|
|
523
529
|
setIsUserScrolledUp(scrolledUp);
|
|
@@ -38,7 +38,7 @@ import { handleMcpServersState } from './mcp-ui.js';
|
|
|
38
38
|
import { handleLoopRegistryUpdated, handleScheduleRunStarted, handleScheduleRunFinished, handleLoopScheduled, isSchedulerOpen, enterCraftingMode, exitCraftingMode, handleLoopRegistryFiles } from './scheduler.js';
|
|
39
39
|
|
|
40
40
|
// --- App module imports ---
|
|
41
|
-
import { scrollToBottom, addToMessages, addUserMessage, addSystemMessage, removeMatePreThinking, appendDelta, finalizeAssistantBlock, addConflictMessage, addContextOverflowMessage, showSuggestionChips } from './app-rendering.js';
|
|
41
|
+
import { scrollToBottom, addToMessages, addUserMessage, addSystemMessage, removeMatePreThinking, appendDelta, finalizeAssistantBlock, addConflictMessage, addContextOverflowMessage, showSuggestionChips, armStickyBottom } from './app-rendering.js';
|
|
42
42
|
import { setActivity, startUrgentBlink, stopUrgentBlink, blinkSessionDot, updateCrossProjectBlink } from './app-favicon.js';
|
|
43
43
|
import { setStatus } from './app-connection.js';
|
|
44
44
|
import { getModelEffortLevels, accumulateUsage, updateUsagePanel, accumulateContext, updateContextPanel, renderCtxPopover, updateStatusPanel } from './app-panels.js';
|
|
@@ -190,10 +190,29 @@ export function processMessage(msg) {
|
|
|
190
190
|
var dbBanner = document.getElementById("debate-floor-banner");
|
|
191
191
|
if (dbBanner) dbBanner.remove();
|
|
192
192
|
}
|
|
193
|
-
|
|
194
|
-
//
|
|
193
|
+
// Resume landing position: arm sticky-bottom for ~1.5s so deferred
|
|
194
|
+
// layout (tool widgets via tools.js, markdown/syntax highlighting,
|
|
195
|
+
// image loads, IntersectionObserver-driven todo sticky reflows)
|
|
196
|
+
// can't strand the user mid-conversation. The ResizeObserver
|
|
197
|
+
// re-pins on every height change while armed. Disarms early on
|
|
198
|
+
// any real user scroll input.
|
|
199
|
+
// Skip arming when we have a pending in-conversation navigate
|
|
200
|
+
// target (file-edit deeplink) — the navigate block below scrolls
|
|
201
|
+
// that element into view, and sticky-bottom would fight it.
|
|
195
202
|
var nav = getPendingNavigate();
|
|
196
|
-
|
|
203
|
+
var hasNavTarget = nav && (nav.toolId || nav.assistantUuid);
|
|
204
|
+
if (hasNavTarget) {
|
|
205
|
+
// Navigate block below will scrollIntoView on the target — don't
|
|
206
|
+
// arm sticky-bottom or it would fight that scroll.
|
|
207
|
+
scrollToBottom();
|
|
208
|
+
} else {
|
|
209
|
+
// Quiet window: ResizeObserver extends this for as long as
|
|
210
|
+
// layout keeps shifting (long sessions, late-rendering tool
|
|
211
|
+
// widgets, image loads), bounded by an internal hard ceiling.
|
|
212
|
+
armStickyBottom(750);
|
|
213
|
+
}
|
|
214
|
+
// Scroll to tool element if navigating from file edit history
|
|
215
|
+
if (hasNavTarget) {
|
|
197
216
|
requestAnimationFrame(function() {
|
|
198
217
|
// Prefer scrolling to the exact tool element
|
|
199
218
|
var target = nav.toolId ? messagesEl.querySelector('[data-tool-id="' + nav.toolId + '"]') : null;
|
|
@@ -36,6 +36,109 @@ var streamDrainTimer = null;
|
|
|
36
36
|
var isUserScrolledUp = false;
|
|
37
37
|
var scrollThreshold = 150;
|
|
38
38
|
|
|
39
|
+
// --- Sticky-bottom mode ---
|
|
40
|
+
// While armed, a ResizeObserver re-pins #messages to scrollHeight on every
|
|
41
|
+
// height change so deferred content (tools, syntax highlighting, images,
|
|
42
|
+
// IntersectionObserver-driven reflows) doesn't strand the user mid-page.
|
|
43
|
+
// The scroll listener in app.js consults getStickyBottom() and ignores
|
|
44
|
+
// growth-induced scroll events while armed.
|
|
45
|
+
//
|
|
46
|
+
// Disarm rules:
|
|
47
|
+
// - Real user input (wheel / touchmove / PageUp / Home / ArrowUp): immediate.
|
|
48
|
+
// - Quiet detector: armStickyBottom(durationMs) treats durationMs as the
|
|
49
|
+
// QUIET WINDOW, not a hard timer. Each ResizeObserver callback resets
|
|
50
|
+
// a debounce timer; sticky-bottom only disarms after no resize for
|
|
51
|
+
// durationMs. Long-settling sessions (large todo widgets, slow code
|
|
52
|
+
// highlighting) keep extending the window naturally.
|
|
53
|
+
// - Hard ceiling: a separate cap prevents pathological lock-in.
|
|
54
|
+
var stickyBottom = false;
|
|
55
|
+
var stickyBottomQuietTimer = null;
|
|
56
|
+
var stickyBottomCeilingTimer = null;
|
|
57
|
+
var stickyBottomQuietMs = 750;
|
|
58
|
+
var stickyBottomCeilingMs = 8000;
|
|
59
|
+
var stickyBottomResizeObs = null;
|
|
60
|
+
var stickyBottomInputBound = false;
|
|
61
|
+
|
|
62
|
+
export function getStickyBottom() { return stickyBottom; }
|
|
63
|
+
|
|
64
|
+
function pinToBottomNow() {
|
|
65
|
+
var messagesEl = getMessagesEl();
|
|
66
|
+
if (!messagesEl) return;
|
|
67
|
+
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function ensureStickyInfrastructure() {
|
|
71
|
+
var messagesEl = getMessagesEl();
|
|
72
|
+
if (!messagesEl) return;
|
|
73
|
+
if (!stickyBottomResizeObs && typeof ResizeObserver !== "undefined") {
|
|
74
|
+
stickyBottomResizeObs = new ResizeObserver(function () {
|
|
75
|
+
if (!stickyBottom) return;
|
|
76
|
+
// Re-pin on every layout change while armed.
|
|
77
|
+
pinToBottomNow();
|
|
78
|
+
// Reset the quiet timer — settling has not finished yet.
|
|
79
|
+
if (stickyBottomQuietTimer) clearTimeout(stickyBottomQuietTimer);
|
|
80
|
+
stickyBottomQuietTimer = setTimeout(disarmStickyBottom, stickyBottomQuietMs);
|
|
81
|
+
});
|
|
82
|
+
stickyBottomResizeObs.observe(messagesEl);
|
|
83
|
+
// Also observe direct children so child-size changes (image loads, code
|
|
84
|
+
// block highlighting, expanding tool groups) trigger a re-pin even when
|
|
85
|
+
// they don't change the scroller's own size.
|
|
86
|
+
var kids = messagesEl.children;
|
|
87
|
+
for (var i = 0; i < kids.length; i++) stickyBottomResizeObs.observe(kids[i]);
|
|
88
|
+
}
|
|
89
|
+
if (!stickyBottomInputBound) {
|
|
90
|
+
stickyBottomInputBound = true;
|
|
91
|
+
var disarmOnUserScroll = function () { disarmStickyBottom(); };
|
|
92
|
+
messagesEl.addEventListener("wheel", disarmOnUserScroll, { passive: true });
|
|
93
|
+
messagesEl.addEventListener("touchmove", disarmOnUserScroll, { passive: true });
|
|
94
|
+
document.addEventListener("keydown", function (e) {
|
|
95
|
+
if (!stickyBottom) return;
|
|
96
|
+
if (e.key === "PageUp" || e.key === "Home" || e.key === "ArrowUp") {
|
|
97
|
+
disarmStickyBottom();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function armStickyBottom(durationMs) {
|
|
104
|
+
if (prependAnchor) return; // never fight pagination
|
|
105
|
+
ensureStickyInfrastructure();
|
|
106
|
+
stickyBottom = true;
|
|
107
|
+
isUserScrolledUp = false;
|
|
108
|
+
var newMsgBtn = document.getElementById("new-msg-btn");
|
|
109
|
+
if (newMsgBtn) {
|
|
110
|
+
newMsgBtn.classList.add("hidden");
|
|
111
|
+
newMsgBtn.textContent = NEW_MSG_BTN_DEFAULT;
|
|
112
|
+
}
|
|
113
|
+
pinToBottomNow();
|
|
114
|
+
// After children may have been replaced since last arm, re-observe.
|
|
115
|
+
if (stickyBottomResizeObs) {
|
|
116
|
+
var messagesEl = getMessagesEl();
|
|
117
|
+
if (messagesEl) {
|
|
118
|
+
var kids = messagesEl.children;
|
|
119
|
+
for (var i = 0; i < kids.length; i++) {
|
|
120
|
+
try { stickyBottomResizeObs.observe(kids[i]); } catch (e) {}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Quiet window: callers pass intended quiet duration; ResizeObserver
|
|
125
|
+
// resets this each time layout changes, so the actual armed duration
|
|
126
|
+
// stretches to "no resize for durationMs".
|
|
127
|
+
stickyBottomQuietMs = durationMs || 750;
|
|
128
|
+
if (stickyBottomQuietTimer) clearTimeout(stickyBottomQuietTimer);
|
|
129
|
+
stickyBottomQuietTimer = setTimeout(disarmStickyBottom, stickyBottomQuietMs);
|
|
130
|
+
// Hard ceiling so we never lock the scroller indefinitely if some
|
|
131
|
+
// animation/observer keeps firing forever.
|
|
132
|
+
if (stickyBottomCeilingTimer) clearTimeout(stickyBottomCeilingTimer);
|
|
133
|
+
stickyBottomCeilingTimer = setTimeout(disarmStickyBottom, stickyBottomCeilingMs);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function disarmStickyBottom() {
|
|
137
|
+
stickyBottom = false;
|
|
138
|
+
if (stickyBottomQuietTimer) { clearTimeout(stickyBottomQuietTimer); stickyBottomQuietTimer = null; }
|
|
139
|
+
if (stickyBottomCeilingTimer) { clearTimeout(stickyBottomCeilingTimer); stickyBottomCeilingTimer = null; }
|
|
140
|
+
}
|
|
141
|
+
|
|
39
142
|
export function initRendering() {
|
|
40
143
|
// Update input placeholder when vendor changes
|
|
41
144
|
store.subscribe(function (state, prev) {
|
|
@@ -86,14 +189,11 @@ export function scrollToBottom() {
|
|
|
86
189
|
|
|
87
190
|
export function forceScrollToBottom() {
|
|
88
191
|
if (prependAnchor) return;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
requestAnimationFrame(function () {
|
|
95
|
-
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
96
|
-
});
|
|
192
|
+
// Arm sticky-bottom mode so deferred layout (tool widgets, code highlighting,
|
|
193
|
+
// image loads) can't strand the user partway down — single-rAF pin captures
|
|
194
|
+
// a stale scrollHeight, then growth below pushes the bottom further away.
|
|
195
|
+
// The quiet detector extends the window automatically while layout shifts.
|
|
196
|
+
armStickyBottom(750);
|
|
97
197
|
}
|
|
98
198
|
|
|
99
199
|
export function getMsgTime() {
|
|
@@ -10,6 +10,16 @@ import { VENDOR_NAMES } from './app-rendering.js';
|
|
|
10
10
|
|
|
11
11
|
var ctx;
|
|
12
12
|
|
|
13
|
+
// During history replay, individual tool renders (todos, file edits, command
|
|
14
|
+
// outputs) must not auto-scroll. The history_done handler arms sticky-bottom
|
|
15
|
+
// which pins the viewport to the true bottom after the whole replay settles.
|
|
16
|
+
// Per-tool scroll calls during replay fight that and re-anchor the user to
|
|
17
|
+
// whichever tool widget grew last (commonly the todo widget).
|
|
18
|
+
function maybeScrollToBottom() {
|
|
19
|
+
if (store.get('replayingHistory')) return;
|
|
20
|
+
if (ctx && ctx.scrollToBottom) ctx.scrollToBottom();
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
// --- Plan mode state ---
|
|
14
24
|
var inPlanMode = false;
|
|
15
25
|
var planContent = null;
|
|
@@ -365,7 +375,7 @@ export function renderAskUserQuestion(toolId, input) {
|
|
|
365
375
|
ctx.addToMessages(container);
|
|
366
376
|
disableMainInput();
|
|
367
377
|
ctx.setActivity(null);
|
|
368
|
-
|
|
378
|
+
maybeScrollToBottom();
|
|
369
379
|
}
|
|
370
380
|
|
|
371
381
|
export function disableMainInput() {
|
|
@@ -602,7 +612,7 @@ function renderFormalPermission(requestId, toolName, toolInput, decisionReason)
|
|
|
602
612
|
pendingPermissions[requestId] = container;
|
|
603
613
|
refreshIcons();
|
|
604
614
|
ctx.setActivity(null);
|
|
605
|
-
|
|
615
|
+
maybeScrollToBottom();
|
|
606
616
|
}
|
|
607
617
|
|
|
608
618
|
function renderPlanPermission(requestId) {
|
|
@@ -709,7 +719,7 @@ function renderPlanPermission(requestId) {
|
|
|
709
719
|
pendingPermissions[requestId] = container;
|
|
710
720
|
refreshIcons();
|
|
711
721
|
ctx.setActivity(null);
|
|
712
|
-
|
|
722
|
+
maybeScrollToBottom();
|
|
713
723
|
// Focus the feedback input after render
|
|
714
724
|
setTimeout(function () { feedbackInput.focus(); }, 50);
|
|
715
725
|
}
|
|
@@ -888,7 +898,7 @@ function renderConversationalPermission(requestId, toolName, toolInput, mateId,
|
|
|
888
898
|
pendingPermissions[requestId] = container;
|
|
889
899
|
refreshIcons();
|
|
890
900
|
ctx.setActivity(null);
|
|
891
|
-
|
|
901
|
+
maybeScrollToBottom();
|
|
892
902
|
}
|
|
893
903
|
|
|
894
904
|
function sendPermissionResponse(container, requestId, decision) {
|
|
@@ -1115,7 +1125,7 @@ export function renderElicitationRequest(msg) {
|
|
|
1115
1125
|
pendingElicitations[msg.requestId] = container;
|
|
1116
1126
|
refreshIcons();
|
|
1117
1127
|
ctx.setActivity(null);
|
|
1118
|
-
|
|
1128
|
+
maybeScrollToBottom();
|
|
1119
1129
|
}
|
|
1120
1130
|
|
|
1121
1131
|
function sendElicitationResponse(container, requestId, action, content) {
|
|
@@ -1194,7 +1204,7 @@ export function renderPlanBanner(type) {
|
|
|
1194
1204
|
|
|
1195
1205
|
ctx.addToMessages(el);
|
|
1196
1206
|
refreshIcons();
|
|
1197
|
-
|
|
1207
|
+
maybeScrollToBottom();
|
|
1198
1208
|
return el;
|
|
1199
1209
|
}
|
|
1200
1210
|
|
|
@@ -1255,7 +1265,7 @@ export function renderPlanCard(content) {
|
|
|
1255
1265
|
}
|
|
1256
1266
|
|
|
1257
1267
|
refreshIcons();
|
|
1258
|
-
if (isNew)
|
|
1268
|
+
if (isNew) maybeScrollToBottom();
|
|
1259
1269
|
return el;
|
|
1260
1270
|
}
|
|
1261
1271
|
|
|
@@ -1388,7 +1398,7 @@ function renderTodoWidget() {
|
|
|
1388
1398
|
}
|
|
1389
1399
|
updateTodoSticky();
|
|
1390
1400
|
refreshIcons();
|
|
1391
|
-
|
|
1401
|
+
maybeScrollToBottom();
|
|
1392
1402
|
}
|
|
1393
1403
|
|
|
1394
1404
|
function setupTodoObserver() {
|
|
@@ -1517,7 +1527,7 @@ export function startThinking() {
|
|
|
1517
1527
|
}
|
|
1518
1528
|
currentThinking = { el: el, fullText: "", startTime: Date.now() };
|
|
1519
1529
|
refreshIcons();
|
|
1520
|
-
|
|
1530
|
+
maybeScrollToBottom();
|
|
1521
1531
|
if (!el.classList.contains("mate-thinking")) {
|
|
1522
1532
|
ctx.setActivity("thinking");
|
|
1523
1533
|
}
|
|
@@ -1561,7 +1571,7 @@ export function startThinking() {
|
|
|
1561
1571
|
|
|
1562
1572
|
ctx.addToMessages(el);
|
|
1563
1573
|
refreshIcons();
|
|
1564
|
-
|
|
1574
|
+
maybeScrollToBottom();
|
|
1565
1575
|
thinkingGroup = { el: el, count: 0, totalDuration: 0 };
|
|
1566
1576
|
currentThinking = { el: el, fullText: "", startTime: Date.now() };
|
|
1567
1577
|
if (!ctx.isMateDm()) {
|
|
@@ -1573,7 +1583,7 @@ export function appendThinking(text) {
|
|
|
1573
1583
|
if (!currentThinking) return;
|
|
1574
1584
|
currentThinking.fullText += text;
|
|
1575
1585
|
currentThinking.el.querySelector(".thinking-content").textContent = currentThinking.fullText;
|
|
1576
|
-
|
|
1586
|
+
maybeScrollToBottom();
|
|
1577
1587
|
}
|
|
1578
1588
|
|
|
1579
1589
|
export function stopThinking(duration) {
|
|
@@ -1699,7 +1709,7 @@ export function createToolItem(id, name) {
|
|
|
1699
1709
|
updateToolGroupHeader(currentToolGroup);
|
|
1700
1710
|
|
|
1701
1711
|
refreshIcons();
|
|
1702
|
-
|
|
1712
|
+
maybeScrollToBottom();
|
|
1703
1713
|
|
|
1704
1714
|
tools[id] = { el: el, name: name, input: null, done: false, groupId: currentToolGroup.id };
|
|
1705
1715
|
ctx.setActivity("Running " + name + "...");
|
|
@@ -1737,7 +1747,7 @@ export function updateToolExecuting(id, name, input) {
|
|
|
1737
1747
|
var subtitleText = tool.el.querySelector(".tool-subtitle-text");
|
|
1738
1748
|
if (subtitleText) subtitleText.textContent = toolActivityText(name, input);
|
|
1739
1749
|
|
|
1740
|
-
|
|
1750
|
+
maybeScrollToBottom();
|
|
1741
1751
|
}
|
|
1742
1752
|
|
|
1743
1753
|
// Shared chrome (filename header + unified/split toggle) for diff renderings.
|
|
@@ -2029,7 +2039,7 @@ export function updateToolResult(id, content, isError, images) {
|
|
|
2029
2039
|
});
|
|
2030
2040
|
|
|
2031
2041
|
markToolDone(id, isError);
|
|
2032
|
-
|
|
2042
|
+
maybeScrollToBottom();
|
|
2033
2043
|
}
|
|
2034
2044
|
|
|
2035
2045
|
export function markToolDone(id, isError) {
|
|
@@ -2087,7 +2097,7 @@ export function updateSubagentActivity(parentToolId, text) {
|
|
|
2087
2097
|
}
|
|
2088
2098
|
|
|
2089
2099
|
ctx.setActivity(text);
|
|
2090
|
-
|
|
2100
|
+
maybeScrollToBottom();
|
|
2091
2101
|
}
|
|
2092
2102
|
|
|
2093
2103
|
export function addSubagentToolEntry(parentToolId, toolName, toolId, text) {
|
|
@@ -2121,7 +2131,7 @@ export function addSubagentToolEntry(parentToolId, toolName, toolId, text) {
|
|
|
2121
2131
|
log.scrollTop = log.scrollHeight;
|
|
2122
2132
|
|
|
2123
2133
|
ctx.setActivity(text);
|
|
2124
|
-
|
|
2134
|
+
maybeScrollToBottom();
|
|
2125
2135
|
}
|
|
2126
2136
|
|
|
2127
2137
|
function fmtTokens(n) {
|
|
@@ -2254,7 +2264,7 @@ export function addTurnMeta(cost, duration) {
|
|
|
2254
2264
|
if (parts.length) {
|
|
2255
2265
|
div.textContent = parts.join(" \u00b7 ");
|
|
2256
2266
|
ctx.addToMessages(div);
|
|
2257
|
-
|
|
2267
|
+
maybeScrollToBottom();
|
|
2258
2268
|
}
|
|
2259
2269
|
}
|
|
2260
2270
|
|
package/package.json
CHANGED