tabminal 3.0.14 → 3.0.15
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/package.json +1 -1
- package/public/app.js +457 -16
- package/public/styles.css +73 -0
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -105,6 +105,10 @@ const HEARTBEAT_INTERVAL_MS = 1000;
|
|
|
105
105
|
const RECONNECT_RETRY_MS = 5000;
|
|
106
106
|
const FILE_TREE_REFRESH_INTERVAL_MS = 3000;
|
|
107
107
|
const FILE_VERSION_CHECK_INTERVAL_MS = 3000;
|
|
108
|
+
const AGENT_TRANSCRIPT_INITIAL_VISIBLE_BLOCKS = 100;
|
|
109
|
+
const AGENT_TRANSCRIPT_WINDOW_STEP = 50;
|
|
110
|
+
const AGENT_TRANSCRIPT_FOLLOW_LATEST_TOLERANCE = 5;
|
|
111
|
+
const WORKSPACE_TAB_TITLE_MAX_LENGTH = 20;
|
|
108
112
|
const MAIN_SERVER_ID = 'main';
|
|
109
113
|
const RUNTIME_BOOT_ID_STORAGE_KEY = 'tabminal_runtime_boot_id';
|
|
110
114
|
const WORKSPACE_DEVICE_ID_STORAGE_KEY = 'tabminal_workspace_device_id';
|
|
@@ -417,6 +421,20 @@ function resolveMarkdownLocalTarget(baseFilePath, href) {
|
|
|
417
421
|
}
|
|
418
422
|
}
|
|
419
423
|
|
|
424
|
+
function buildMarkdownContextBasePath(filePath = '', baseDirectory = '') {
|
|
425
|
+
const nextFilePath = String(filePath || '').trim();
|
|
426
|
+
if (nextFilePath) {
|
|
427
|
+
return nextFilePath;
|
|
428
|
+
}
|
|
429
|
+
const nextBaseDirectory = String(baseDirectory || '')
|
|
430
|
+
.trim()
|
|
431
|
+
.replace(/\/+$/, '');
|
|
432
|
+
if (!nextBaseDirectory) {
|
|
433
|
+
return '';
|
|
434
|
+
}
|
|
435
|
+
return `${nextBaseDirectory}/__tabminal__.md`;
|
|
436
|
+
}
|
|
437
|
+
|
|
420
438
|
function slugifyMarkdownHeading(text) {
|
|
421
439
|
return String(text || '')
|
|
422
440
|
.trim()
|
|
@@ -1535,6 +1553,24 @@ class EditorManager {
|
|
|
1535
1553
|
this.agentTranscript = document.createElement('div');
|
|
1536
1554
|
this.agentTranscript.className = 'agent-panel-transcript';
|
|
1537
1555
|
this.agentTranscript.addEventListener('click', (event) => {
|
|
1556
|
+
const markdownLink = event.target.closest(
|
|
1557
|
+
'a[data-markdown-local-path]'
|
|
1558
|
+
);
|
|
1559
|
+
if (markdownLink) {
|
|
1560
|
+
const filePath = String(
|
|
1561
|
+
markdownLink.dataset.markdownLocalPath || ''
|
|
1562
|
+
).trim();
|
|
1563
|
+
if (!filePath) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
event.preventDefault();
|
|
1567
|
+
event.stopPropagation();
|
|
1568
|
+
void this.openLocalMarkdownLink(
|
|
1569
|
+
filePath,
|
|
1570
|
+
String(markdownLink.dataset.markdownLocalHash || '')
|
|
1571
|
+
);
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1538
1574
|
const anchor = event.target.closest('a');
|
|
1539
1575
|
if (!anchor) return;
|
|
1540
1576
|
const href = anchor.getAttribute('href') || '';
|
|
@@ -1545,6 +1581,20 @@ class EditorManager {
|
|
|
1545
1581
|
void this.openFile(href);
|
|
1546
1582
|
});
|
|
1547
1583
|
this.agentTranscript.addEventListener('scroll', () => {
|
|
1584
|
+
const activeAgentTab = getActiveAgentTab();
|
|
1585
|
+
if (
|
|
1586
|
+
activeAgentTab
|
|
1587
|
+
&& this.agentTranscript.scrollTop <= 24
|
|
1588
|
+
) {
|
|
1589
|
+
activeAgentTab.scrollToBottomOnNextRender = false;
|
|
1590
|
+
void this.loadOlderAgentTimeline(activeAgentTab);
|
|
1591
|
+
} else if (
|
|
1592
|
+
activeAgentTab
|
|
1593
|
+
&& this.isAgentTranscriptNearBottom(24)
|
|
1594
|
+
) {
|
|
1595
|
+
activeAgentTab.scrollToBottomOnNextRender = false;
|
|
1596
|
+
void this.loadNewerAgentTimeline(activeAgentTab);
|
|
1597
|
+
}
|
|
1548
1598
|
this.updateAgentScrollBottomButton();
|
|
1549
1599
|
this.rememberAgentTranscriptLayout();
|
|
1550
1600
|
});
|
|
@@ -4197,6 +4247,64 @@ class EditorManager {
|
|
|
4197
4247
|
}
|
|
4198
4248
|
}
|
|
4199
4249
|
|
|
4250
|
+
getAgentMarkdownBaseDirectory(agentTab, message) {
|
|
4251
|
+
const messageCwd = String(message?.cwd || '').trim();
|
|
4252
|
+
if (messageCwd) {
|
|
4253
|
+
return messageCwd;
|
|
4254
|
+
}
|
|
4255
|
+
const tabCwd = String(agentTab?.cwd || '').trim();
|
|
4256
|
+
if (tabCwd) {
|
|
4257
|
+
return tabCwd;
|
|
4258
|
+
}
|
|
4259
|
+
const session = this.currentSession;
|
|
4260
|
+
return String(session?.cwd || session?.initialCwd || '').trim();
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4263
|
+
async enhanceAgentMarkdownBody(agentTab, message, body) {
|
|
4264
|
+
if (!(body instanceof HTMLElement) || !message?.text) {
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
const session = this.currentSession;
|
|
4268
|
+
if (!session) {
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
const renderToken = `${Date.now()}:${Math.random()}`;
|
|
4273
|
+
body.dataset.markdownRenderToken = renderToken;
|
|
4274
|
+
|
|
4275
|
+
try {
|
|
4276
|
+
const { renderer } = await loadMarkdownPreviewBundle();
|
|
4277
|
+
if (
|
|
4278
|
+
!body.isConnected
|
|
4279
|
+
|| body.dataset.markdownRenderToken !== renderToken
|
|
4280
|
+
) {
|
|
4281
|
+
return;
|
|
4282
|
+
}
|
|
4283
|
+
const rendered = renderer.render(String(message.text || ''));
|
|
4284
|
+
const sanitized = DOMPurify.sanitize(rendered, {
|
|
4285
|
+
USE_PROFILES: {
|
|
4286
|
+
html: true,
|
|
4287
|
+
mathMl: true,
|
|
4288
|
+
svg: true
|
|
4289
|
+
}
|
|
4290
|
+
});
|
|
4291
|
+
const template = document.createElement('template');
|
|
4292
|
+
template.innerHTML = sanitized;
|
|
4293
|
+
const basePath = buildMarkdownContextBasePath(
|
|
4294
|
+
'',
|
|
4295
|
+
this.getAgentMarkdownBaseDirectory(agentTab, message)
|
|
4296
|
+
);
|
|
4297
|
+
this.decorateMarkdownPreviewContent(
|
|
4298
|
+
template.content,
|
|
4299
|
+
basePath,
|
|
4300
|
+
session
|
|
4301
|
+
);
|
|
4302
|
+
body.replaceChildren(template.content);
|
|
4303
|
+
} catch {
|
|
4304
|
+
// Keep the lightweight fallback rendering.
|
|
4305
|
+
}
|
|
4306
|
+
}
|
|
4307
|
+
|
|
4200
4308
|
scrollMarkdownPreviewHash(hash) {
|
|
4201
4309
|
const nextHash = String(hash || '').trim();
|
|
4202
4310
|
if (!nextHash || !this.markdownPreviewScroll) {
|
|
@@ -5171,7 +5279,10 @@ class EditorManager {
|
|
|
5171
5279
|
);
|
|
5172
5280
|
|
|
5173
5281
|
const label = document.createElement('span');
|
|
5174
|
-
|
|
5282
|
+
tab.title = String(getAgentDisplayLabel(agentTab) || '').trim();
|
|
5283
|
+
label.textContent = formatWorkspaceTabTitle(
|
|
5284
|
+
getAgentDisplayLabel(agentTab)
|
|
5285
|
+
);
|
|
5175
5286
|
|
|
5176
5287
|
const closeBtn = document.createElement('span');
|
|
5177
5288
|
closeBtn.className = 'close-btn';
|
|
@@ -5475,7 +5586,9 @@ class EditorManager {
|
|
|
5475
5586
|
this.hideMarkdownPreview();
|
|
5476
5587
|
this.emptyState.style.display = 'none';
|
|
5477
5588
|
this.agentContainer.style.display = 'flex';
|
|
5478
|
-
this.renderAgentPanel(agentTab
|
|
5589
|
+
this.renderAgentPanel(agentTab, {
|
|
5590
|
+
reason: isRestore ? 'activate-restore' : 'activate'
|
|
5591
|
+
});
|
|
5479
5592
|
}
|
|
5480
5593
|
|
|
5481
5594
|
async closeAgentTab(agentTabKey) {
|
|
@@ -5485,7 +5598,7 @@ class EditorManager {
|
|
|
5485
5598
|
removeAgentTab(agentTabKey);
|
|
5486
5599
|
}
|
|
5487
5600
|
|
|
5488
|
-
renderAgentPanel(agentTab) {
|
|
5601
|
+
renderAgentPanel(agentTab, options = {}) {
|
|
5489
5602
|
this.disposeAgentEmbeddedEditors();
|
|
5490
5603
|
const previousLayout = this.captureAgentTranscriptLayout();
|
|
5491
5604
|
const previousScrollTop = previousLayout?.scrollTop || 0;
|
|
@@ -5552,12 +5665,29 @@ class EditorManager {
|
|
|
5552
5665
|
|
|
5553
5666
|
this.agentTranscript.innerHTML = '';
|
|
5554
5667
|
const timeline = getAgentTimelineItems(agentTab);
|
|
5668
|
+
const shouldPinToBottom = wasNearBottom || (
|
|
5669
|
+
agentTab.scrollToBottomOnNextRender
|
|
5670
|
+
&& isAgentTranscriptWindowNearLatest(
|
|
5671
|
+
agentTab,
|
|
5672
|
+
timeline.length
|
|
5673
|
+
)
|
|
5674
|
+
);
|
|
5675
|
+
const transcriptWindow = getAgentTranscriptWindow(
|
|
5676
|
+
agentTab,
|
|
5677
|
+
timeline.length,
|
|
5678
|
+
{ pinToBottom: shouldPinToBottom }
|
|
5679
|
+
);
|
|
5680
|
+
const visibleTimeline = timeline.slice(
|
|
5681
|
+
transcriptWindow.start,
|
|
5682
|
+
transcriptWindow.end
|
|
5683
|
+
);
|
|
5555
5684
|
if (timeline.length === 0) {
|
|
5556
5685
|
this.agentTranscript.appendChild(
|
|
5557
5686
|
this.buildAgentEmptyState(agentTab)
|
|
5558
5687
|
);
|
|
5559
5688
|
} else {
|
|
5560
|
-
for (const [index, entry] of
|
|
5689
|
+
for (const [index, entry] of visibleTimeline.entries()) {
|
|
5690
|
+
const timelineIndex = transcriptWindow.start + index;
|
|
5561
5691
|
let node = null;
|
|
5562
5692
|
if (entry.type === 'message') {
|
|
5563
5693
|
node = this.buildAgentMessageNode(agentTab, entry.value);
|
|
@@ -5575,8 +5705,12 @@ class EditorManager {
|
|
|
5575
5705
|
);
|
|
5576
5706
|
}
|
|
5577
5707
|
if (node) {
|
|
5708
|
+
node.dataset.timelineKey = getAgentTimelineItemKey(
|
|
5709
|
+
entry,
|
|
5710
|
+
timelineIndex
|
|
5711
|
+
);
|
|
5578
5712
|
if (
|
|
5579
|
-
|
|
5713
|
+
timelineIndex > 0
|
|
5580
5714
|
&& entry.type === 'message'
|
|
5581
5715
|
&& String(entry.value?.role || '').toLowerCase()
|
|
5582
5716
|
=== 'user'
|
|
@@ -5587,13 +5721,19 @@ class EditorManager {
|
|
|
5587
5721
|
}
|
|
5588
5722
|
}
|
|
5589
5723
|
}
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5724
|
+
if (options.preserveTranscriptAnchor) {
|
|
5725
|
+
const restored = this.restoreAgentTranscriptAnchor(
|
|
5726
|
+
options.preserveTranscriptAnchor
|
|
5727
|
+
);
|
|
5728
|
+
if (!restored) {
|
|
5729
|
+
this.agentTranscript.scrollTop = previousScrollTop;
|
|
5730
|
+
}
|
|
5731
|
+
} else if (shouldPinToBottom) {
|
|
5593
5732
|
this.agentTranscript.scrollTop = this.agentTranscript.scrollHeight;
|
|
5594
5733
|
agentTab.scrollToBottomOnNextRender = false;
|
|
5595
5734
|
} else {
|
|
5596
5735
|
this.agentTranscript.scrollTop = previousScrollTop;
|
|
5736
|
+
agentTab.scrollToBottomOnNextRender = false;
|
|
5597
5737
|
}
|
|
5598
5738
|
this.updateAgentScrollBottomButton();
|
|
5599
5739
|
this.rememberAgentTranscriptLayout();
|
|
@@ -5611,6 +5751,95 @@ class EditorManager {
|
|
|
5611
5751
|
this.scheduleAgentTranscriptViewportUpdate(shouldPinToBottom);
|
|
5612
5752
|
}
|
|
5613
5753
|
|
|
5754
|
+
async loadOlderAgentTimeline(agentTab) {
|
|
5755
|
+
if (!agentTab || agentTab.historyWindowLoading) {
|
|
5756
|
+
return;
|
|
5757
|
+
}
|
|
5758
|
+
const timeline = getAgentTimelineItems(agentTab);
|
|
5759
|
+
const transcriptWindow = getAgentTranscriptWindow(
|
|
5760
|
+
agentTab,
|
|
5761
|
+
timeline.length
|
|
5762
|
+
);
|
|
5763
|
+
if (transcriptWindow.start <= 0) {
|
|
5764
|
+
return;
|
|
5765
|
+
}
|
|
5766
|
+
agentTab.scrollToBottomOnNextRender = false;
|
|
5767
|
+
const currentWindowSize = transcriptWindow.end
|
|
5768
|
+
- transcriptWindow.start;
|
|
5769
|
+
const step = Math.min(
|
|
5770
|
+
AGENT_TRANSCRIPT_WINDOW_STEP,
|
|
5771
|
+
transcriptWindow.start
|
|
5772
|
+
);
|
|
5773
|
+
const nextStart = Math.max(0, transcriptWindow.start - step);
|
|
5774
|
+
const anchor = this.captureAgentTranscriptAnchor(
|
|
5775
|
+
getAgentTimelineItemKey(
|
|
5776
|
+
timeline[transcriptWindow.start],
|
|
5777
|
+
transcriptWindow.start
|
|
5778
|
+
)
|
|
5779
|
+
);
|
|
5780
|
+
agentTab.historyWindowLoading = true;
|
|
5781
|
+
agentTab.historyWindowStart = nextStart;
|
|
5782
|
+
agentTab.historyWindowEnd = Math.min(
|
|
5783
|
+
timeline.length,
|
|
5784
|
+
nextStart + currentWindowSize
|
|
5785
|
+
);
|
|
5786
|
+
try {
|
|
5787
|
+
this.renderAgentPanel(agentTab, {
|
|
5788
|
+
reason: 'history-older',
|
|
5789
|
+
preserveTranscriptAnchor: anchor
|
|
5790
|
+
});
|
|
5791
|
+
} finally {
|
|
5792
|
+
agentTab.historyWindowLoading = false;
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
|
|
5796
|
+
async loadNewerAgentTimeline(agentTab) {
|
|
5797
|
+
if (!agentTab || agentTab.historyWindowLoading) {
|
|
5798
|
+
return;
|
|
5799
|
+
}
|
|
5800
|
+
const timeline = getAgentTimelineItems(agentTab);
|
|
5801
|
+
const transcriptWindow = getAgentTranscriptWindow(
|
|
5802
|
+
agentTab,
|
|
5803
|
+
timeline.length
|
|
5804
|
+
);
|
|
5805
|
+
if (transcriptWindow.end >= timeline.length) {
|
|
5806
|
+
return;
|
|
5807
|
+
}
|
|
5808
|
+
agentTab.scrollToBottomOnNextRender = false;
|
|
5809
|
+
const currentWindowSize = transcriptWindow.end
|
|
5810
|
+
- transcriptWindow.start;
|
|
5811
|
+
const step = Math.min(
|
|
5812
|
+
AGENT_TRANSCRIPT_WINDOW_STEP,
|
|
5813
|
+
timeline.length - transcriptWindow.end
|
|
5814
|
+
);
|
|
5815
|
+
const nextEnd = Math.min(
|
|
5816
|
+
timeline.length,
|
|
5817
|
+
transcriptWindow.end + step
|
|
5818
|
+
);
|
|
5819
|
+
const nextStart = Math.max(0, nextEnd - currentWindowSize);
|
|
5820
|
+
const anchorIndex = Math.max(
|
|
5821
|
+
transcriptWindow.start,
|
|
5822
|
+
transcriptWindow.end - 1
|
|
5823
|
+
);
|
|
5824
|
+
const anchor = this.captureAgentTranscriptAnchor(
|
|
5825
|
+
getAgentTimelineItemKey(
|
|
5826
|
+
timeline[anchorIndex],
|
|
5827
|
+
anchorIndex
|
|
5828
|
+
)
|
|
5829
|
+
);
|
|
5830
|
+
agentTab.historyWindowLoading = true;
|
|
5831
|
+
agentTab.historyWindowStart = nextStart;
|
|
5832
|
+
agentTab.historyWindowEnd = nextEnd;
|
|
5833
|
+
try {
|
|
5834
|
+
this.renderAgentPanel(agentTab, {
|
|
5835
|
+
reason: 'history-newer',
|
|
5836
|
+
preserveTranscriptAnchor: anchor
|
|
5837
|
+
});
|
|
5838
|
+
} finally {
|
|
5839
|
+
agentTab.historyWindowLoading = false;
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
5842
|
+
|
|
5614
5843
|
refreshAgentTimelineTimestamps() {
|
|
5615
5844
|
if (!this.agentContainer || this.agentContainer.style.display === 'none') {
|
|
5616
5845
|
return;
|
|
@@ -5914,6 +6143,7 @@ class EditorManager {
|
|
|
5914
6143
|
) {
|
|
5915
6144
|
body.classList.add('markdown');
|
|
5916
6145
|
body.innerHTML = renderAgentMessageMarkdown(message.text || '');
|
|
6146
|
+
void this.enhanceAgentMarkdownBody(agentTab, message, body);
|
|
5917
6147
|
} else {
|
|
5918
6148
|
body.classList.add('plain');
|
|
5919
6149
|
body.textContent = message.text || '';
|
|
@@ -5999,9 +6229,27 @@ class EditorManager {
|
|
|
5999
6229
|
toolStatusClass
|
|
6000
6230
|
);
|
|
6001
6231
|
details.appendChild(summary);
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
)
|
|
6232
|
+
const bodyHost = document.createElement('div');
|
|
6233
|
+
bodyHost.className = 'agent-tool-call-section-content';
|
|
6234
|
+
const mountBody = () => {
|
|
6235
|
+
if (bodyHost.dataset.mounted === 'true') {
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
bodyHost.dataset.mounted = 'true';
|
|
6239
|
+
bodyHost.appendChild(
|
|
6240
|
+
this.buildAgentSectionBody(details, section)
|
|
6241
|
+
);
|
|
6242
|
+
};
|
|
6243
|
+
details.appendChild(bodyHost);
|
|
6244
|
+
if (details.open) {
|
|
6245
|
+
queueMicrotask(mountBody);
|
|
6246
|
+
} else {
|
|
6247
|
+
details.addEventListener('toggle', () => {
|
|
6248
|
+
if (details.open) {
|
|
6249
|
+
mountBody();
|
|
6250
|
+
}
|
|
6251
|
+
}, { once: true });
|
|
6252
|
+
}
|
|
6005
6253
|
sectionContainer.appendChild(details);
|
|
6006
6254
|
}
|
|
6007
6255
|
node.appendChild(sectionContainer);
|
|
@@ -6093,9 +6341,27 @@ class EditorManager {
|
|
|
6093
6341
|
permission.status || 'pending'
|
|
6094
6342
|
);
|
|
6095
6343
|
details.appendChild(summary);
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
)
|
|
6344
|
+
const bodyHost = document.createElement('div');
|
|
6345
|
+
bodyHost.className = 'agent-tool-call-section-content';
|
|
6346
|
+
const mountBody = () => {
|
|
6347
|
+
if (bodyHost.dataset.mounted === 'true') {
|
|
6348
|
+
return;
|
|
6349
|
+
}
|
|
6350
|
+
bodyHost.dataset.mounted = 'true';
|
|
6351
|
+
bodyHost.appendChild(
|
|
6352
|
+
this.buildAgentSectionBody(details, section)
|
|
6353
|
+
);
|
|
6354
|
+
};
|
|
6355
|
+
details.appendChild(bodyHost);
|
|
6356
|
+
if (details.open) {
|
|
6357
|
+
queueMicrotask(mountBody);
|
|
6358
|
+
} else {
|
|
6359
|
+
details.addEventListener('toggle', () => {
|
|
6360
|
+
if (details.open) {
|
|
6361
|
+
mountBody();
|
|
6362
|
+
}
|
|
6363
|
+
}, { once: true });
|
|
6364
|
+
}
|
|
6099
6365
|
sectionContainer.appendChild(details);
|
|
6100
6366
|
}
|
|
6101
6367
|
card.appendChild(sectionContainer);
|
|
@@ -6790,6 +7056,51 @@ class EditorManager {
|
|
|
6790
7056
|
};
|
|
6791
7057
|
}
|
|
6792
7058
|
|
|
7059
|
+
findAgentTranscriptNodeByKey(timelineKey = '') {
|
|
7060
|
+
if (!this.agentTranscript || !timelineKey) {
|
|
7061
|
+
return null;
|
|
7062
|
+
}
|
|
7063
|
+
for (const node of this.agentTranscript.children) {
|
|
7064
|
+
if (node?.dataset?.timelineKey === timelineKey) {
|
|
7065
|
+
return node;
|
|
7066
|
+
}
|
|
7067
|
+
}
|
|
7068
|
+
return null;
|
|
7069
|
+
}
|
|
7070
|
+
|
|
7071
|
+
captureAgentTranscriptAnchor(timelineKey = '') {
|
|
7072
|
+
const node = this.findAgentTranscriptNodeByKey(timelineKey);
|
|
7073
|
+
if (!node || !this.agentTranscript) {
|
|
7074
|
+
return null;
|
|
7075
|
+
}
|
|
7076
|
+
return {
|
|
7077
|
+
timelineKey,
|
|
7078
|
+
scrollTop: this.agentTranscript.scrollTop,
|
|
7079
|
+
offsetTop: node.offsetTop
|
|
7080
|
+
};
|
|
7081
|
+
}
|
|
7082
|
+
|
|
7083
|
+
restoreAgentTranscriptAnchor(anchor = null) {
|
|
7084
|
+
if (!anchor || !this.agentTranscript) {
|
|
7085
|
+
return false;
|
|
7086
|
+
}
|
|
7087
|
+
const node = this.findAgentTranscriptNodeByKey(
|
|
7088
|
+
anchor.timelineKey || ''
|
|
7089
|
+
);
|
|
7090
|
+
if (!node) {
|
|
7091
|
+
return false;
|
|
7092
|
+
}
|
|
7093
|
+
const previousOffsetTop = Number.isFinite(anchor.offsetTop)
|
|
7094
|
+
? anchor.offsetTop
|
|
7095
|
+
: 0;
|
|
7096
|
+
const previousScrollTop = Number.isFinite(anchor.scrollTop)
|
|
7097
|
+
? anchor.scrollTop
|
|
7098
|
+
: 0;
|
|
7099
|
+
this.agentTranscript.scrollTop = previousScrollTop
|
|
7100
|
+
+ (node.offsetTop - previousOffsetTop);
|
|
7101
|
+
return true;
|
|
7102
|
+
}
|
|
7103
|
+
|
|
6793
7104
|
rememberAgentTranscriptLayout() {
|
|
6794
7105
|
this.agentTranscriptLayout = this.captureAgentTranscriptLayout();
|
|
6795
7106
|
}
|
|
@@ -6810,6 +7121,32 @@ class EditorManager {
|
|
|
6810
7121
|
}
|
|
6811
7122
|
|
|
6812
7123
|
scrollAgentTranscriptToBottom() {
|
|
7124
|
+
const activeTab = getActiveAgentTab();
|
|
7125
|
+
if (activeTab) {
|
|
7126
|
+
const total = getAgentTimelineItems(activeTab).length;
|
|
7127
|
+
const transcriptWindow = getAgentTranscriptWindow(
|
|
7128
|
+
activeTab,
|
|
7129
|
+
total,
|
|
7130
|
+
{ pinToBottom: false }
|
|
7131
|
+
);
|
|
7132
|
+
const latestWindow = getAgentTranscriptWindow(
|
|
7133
|
+
null,
|
|
7134
|
+
total,
|
|
7135
|
+
{ pinToBottom: true }
|
|
7136
|
+
);
|
|
7137
|
+
const alreadyLatest = transcriptWindow.start === latestWindow.start
|
|
7138
|
+
&& transcriptWindow.end === latestWindow.end;
|
|
7139
|
+
if (!alreadyLatest) {
|
|
7140
|
+
activeTab.historyWindowStart = latestWindow.start;
|
|
7141
|
+
activeTab.historyWindowEnd = latestWindow.end;
|
|
7142
|
+
activeTab.scrollToBottomOnNextRender = true;
|
|
7143
|
+
this.renderAgentPanel(activeTab, {
|
|
7144
|
+
reason: 'scroll-latest'
|
|
7145
|
+
});
|
|
7146
|
+
return;
|
|
7147
|
+
}
|
|
7148
|
+
activeTab.scrollToBottomOnNextRender = false;
|
|
7149
|
+
}
|
|
6813
7150
|
if (!this.agentTranscript) return;
|
|
6814
7151
|
this.agentTranscript.scrollTop = this.agentTranscript.scrollHeight;
|
|
6815
7152
|
this.updateAgentScrollBottomButton();
|
|
@@ -8315,10 +8652,11 @@ class Session {
|
|
|
8315
8652
|
|
|
8316
8653
|
const titleEl = tab.querySelector('.title');
|
|
8317
8654
|
const titleTextEl = tab.querySelector('.tab-title-text');
|
|
8655
|
+
const displayTitle = formatWorkspaceTabTitle(this.title);
|
|
8318
8656
|
if (titleTextEl) {
|
|
8319
|
-
titleTextEl.textContent =
|
|
8657
|
+
titleTextEl.textContent = displayTitle;
|
|
8320
8658
|
} else if (titleEl) {
|
|
8321
|
-
titleEl.textContent =
|
|
8659
|
+
titleEl.textContent = displayTitle;
|
|
8322
8660
|
}
|
|
8323
8661
|
|
|
8324
8662
|
const titleIconEl = tab.querySelector('.tab-status-icon');
|
|
@@ -8747,6 +9085,9 @@ class AgentTab {
|
|
|
8747
9085
|
this.scrollToBottomOnNextRender = true;
|
|
8748
9086
|
this.busySyncTimer = null;
|
|
8749
9087
|
this.planHistory = [];
|
|
9088
|
+
this.historyWindowStart = -1;
|
|
9089
|
+
this.historyWindowEnd = -1;
|
|
9090
|
+
this.historyWindowLoading = false;
|
|
8750
9091
|
this.resumeSessions = [];
|
|
8751
9092
|
this.resumeSessionsLoadedAt = 0;
|
|
8752
9093
|
this.resumeSessionsPromise = null;
|
|
@@ -10880,6 +11221,106 @@ function getAgentTimelineItems(agentTab) {
|
|
|
10880
11221
|
return items;
|
|
10881
11222
|
}
|
|
10882
11223
|
|
|
11224
|
+
function getAgentTimelineItemKey(entry, absoluteIndex = 0) {
|
|
11225
|
+
if (!entry) {
|
|
11226
|
+
return `unknown:${absoluteIndex}`;
|
|
11227
|
+
}
|
|
11228
|
+
const order = Number.isFinite(entry.order) ? entry.order : -1;
|
|
11229
|
+
return `${entry.type}:${order}:${absoluteIndex}`;
|
|
11230
|
+
}
|
|
11231
|
+
|
|
11232
|
+
function formatWorkspaceTabTitle(
|
|
11233
|
+
value,
|
|
11234
|
+
maxLength = WORKSPACE_TAB_TITLE_MAX_LENGTH
|
|
11235
|
+
) {
|
|
11236
|
+
const text = String(value || '');
|
|
11237
|
+
const characters = Array.from(text);
|
|
11238
|
+
if (characters.length <= maxLength) {
|
|
11239
|
+
return text;
|
|
11240
|
+
}
|
|
11241
|
+
if (maxLength <= 3) {
|
|
11242
|
+
return '.'.repeat(Math.max(0, maxLength));
|
|
11243
|
+
}
|
|
11244
|
+
return `${characters.slice(0, maxLength - 3).join('')}...`;
|
|
11245
|
+
}
|
|
11246
|
+
|
|
11247
|
+
function getAgentTranscriptWindow(
|
|
11248
|
+
agentTab,
|
|
11249
|
+
totalCount = 0,
|
|
11250
|
+
options = {}
|
|
11251
|
+
) {
|
|
11252
|
+
const total = Number.isFinite(totalCount)
|
|
11253
|
+
? Math.max(0, totalCount)
|
|
11254
|
+
: 0;
|
|
11255
|
+
const windowSize = Math.min(total, AGENT_TRANSCRIPT_INITIAL_VISIBLE_BLOCKS);
|
|
11256
|
+
const latestStart = Math.max(0, total - windowSize);
|
|
11257
|
+
const latestWindow = {
|
|
11258
|
+
start: latestStart,
|
|
11259
|
+
end: total
|
|
11260
|
+
};
|
|
11261
|
+
if (!agentTab) {
|
|
11262
|
+
return latestWindow;
|
|
11263
|
+
}
|
|
11264
|
+
if (windowSize === 0) {
|
|
11265
|
+
agentTab.historyWindowStart = 0;
|
|
11266
|
+
agentTab.historyWindowEnd = 0;
|
|
11267
|
+
return { start: 0, end: 0 };
|
|
11268
|
+
}
|
|
11269
|
+
if (options.pinToBottom) {
|
|
11270
|
+
agentTab.historyWindowStart = latestWindow.start;
|
|
11271
|
+
agentTab.historyWindowEnd = latestWindow.end;
|
|
11272
|
+
return latestWindow;
|
|
11273
|
+
}
|
|
11274
|
+
let start = Number.isFinite(agentTab.historyWindowStart)
|
|
11275
|
+
? Math.max(0, Math.floor(agentTab.historyWindowStart))
|
|
11276
|
+
: latestWindow.start;
|
|
11277
|
+
let end = Number.isFinite(agentTab.historyWindowEnd)
|
|
11278
|
+
? Math.max(start, Math.floor(agentTab.historyWindowEnd))
|
|
11279
|
+
: latestWindow.end;
|
|
11280
|
+
if (end > total) {
|
|
11281
|
+
end = total;
|
|
11282
|
+
}
|
|
11283
|
+
if (end - start !== windowSize) {
|
|
11284
|
+
if (total <= windowSize) {
|
|
11285
|
+
start = 0;
|
|
11286
|
+
end = total;
|
|
11287
|
+
} else if (end >= total) {
|
|
11288
|
+
end = total;
|
|
11289
|
+
start = latestWindow.start;
|
|
11290
|
+
} else if (start <= 0) {
|
|
11291
|
+
start = 0;
|
|
11292
|
+
end = windowSize;
|
|
11293
|
+
} else {
|
|
11294
|
+
end = Math.min(total, start + windowSize);
|
|
11295
|
+
start = Math.max(0, end - windowSize);
|
|
11296
|
+
}
|
|
11297
|
+
}
|
|
11298
|
+
agentTab.historyWindowStart = start;
|
|
11299
|
+
agentTab.historyWindowEnd = end;
|
|
11300
|
+
return { start, end };
|
|
11301
|
+
}
|
|
11302
|
+
|
|
11303
|
+
function isAgentTranscriptWindowNearLatest(agentTab, totalCount = 0) {
|
|
11304
|
+
const total = Number.isFinite(totalCount)
|
|
11305
|
+
? Math.max(0, totalCount)
|
|
11306
|
+
: 0;
|
|
11307
|
+
if (!agentTab) {
|
|
11308
|
+
return true;
|
|
11309
|
+
}
|
|
11310
|
+
if (
|
|
11311
|
+
!Number.isFinite(agentTab.historyWindowStart)
|
|
11312
|
+
|| !Number.isFinite(agentTab.historyWindowEnd)
|
|
11313
|
+
|| agentTab.historyWindowStart < 0
|
|
11314
|
+
|| agentTab.historyWindowEnd < 0
|
|
11315
|
+
) {
|
|
11316
|
+
return true;
|
|
11317
|
+
}
|
|
11318
|
+
return agentTab.historyWindowEnd >= Math.max(
|
|
11319
|
+
0,
|
|
11320
|
+
total - AGENT_TRANSCRIPT_FOLLOW_LATEST_TOLERANCE
|
|
11321
|
+
);
|
|
11322
|
+
}
|
|
11323
|
+
|
|
10883
11324
|
function normalizePlanStatusClass(status = '') {
|
|
10884
11325
|
const value = String(status || '').toLowerCase();
|
|
10885
11326
|
if (value === 'completed') return 'completed';
|
package/public/styles.css
CHANGED
|
@@ -2480,6 +2480,7 @@ kbd {
|
|
|
2480
2480
|
justify-content: space-between;
|
|
2481
2481
|
gap: 10px;
|
|
2482
2482
|
flex-wrap: wrap;
|
|
2483
|
+
min-width: 0;
|
|
2483
2484
|
}
|
|
2484
2485
|
|
|
2485
2486
|
.agent-tool-call-title,
|
|
@@ -2487,12 +2488,18 @@ kbd {
|
|
|
2487
2488
|
color: var(--text-highlight);
|
|
2488
2489
|
font-weight: 600;
|
|
2489
2490
|
font-size: 12px;
|
|
2491
|
+
min-width: 0;
|
|
2492
|
+
flex: 1 1 auto;
|
|
2493
|
+
overflow-wrap: anywhere;
|
|
2494
|
+
word-break: break-word;
|
|
2490
2495
|
}
|
|
2491
2496
|
|
|
2492
2497
|
.agent-tool-call-meta {
|
|
2493
2498
|
color: var(--text-muted);
|
|
2494
2499
|
font-size: 10px;
|
|
2495
2500
|
margin-top: 4px;
|
|
2501
|
+
overflow-wrap: anywhere;
|
|
2502
|
+
word-break: break-word;
|
|
2496
2503
|
}
|
|
2497
2504
|
|
|
2498
2505
|
.agent-path-links {
|
|
@@ -2916,10 +2923,28 @@ kbd {
|
|
|
2916
2923
|
margin: 0 0 8px;
|
|
2917
2924
|
}
|
|
2918
2925
|
|
|
2926
|
+
.agent-message-body.markdown h1,
|
|
2927
|
+
.agent-message-body.markdown h2,
|
|
2928
|
+
.agent-message-body.markdown h3,
|
|
2929
|
+
.agent-message-body.markdown h4,
|
|
2930
|
+
.agent-message-body.markdown h5,
|
|
2931
|
+
.agent-message-body.markdown h6 {
|
|
2932
|
+
margin: 0 0 10px;
|
|
2933
|
+
color: var(--text-highlight);
|
|
2934
|
+
line-height: 1.35;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2919
2937
|
.agent-message-body.markdown ul {
|
|
2920
2938
|
padding-left: 18px;
|
|
2921
2939
|
}
|
|
2922
2940
|
|
|
2941
|
+
.agent-message-body.markdown blockquote {
|
|
2942
|
+
margin: 0 0 10px;
|
|
2943
|
+
padding: 2px 0 2px 12px;
|
|
2944
|
+
border-left: 3px solid rgba(38, 139, 210, 0.34);
|
|
2945
|
+
color: var(--text-muted);
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2923
2948
|
.agent-message-body.markdown code {
|
|
2924
2949
|
font: inherit;
|
|
2925
2950
|
font-size: 11px;
|
|
@@ -2927,6 +2952,8 @@ kbd {
|
|
|
2927
2952
|
border: 1px solid rgba(131, 148, 150, 0.18);
|
|
2928
2953
|
border-radius: 6px;
|
|
2929
2954
|
padding: 1px 4px;
|
|
2955
|
+
overflow-wrap: anywhere;
|
|
2956
|
+
word-break: break-word;
|
|
2930
2957
|
}
|
|
2931
2958
|
|
|
2932
2959
|
.agent-message-body.markdown pre {
|
|
@@ -2949,6 +2976,52 @@ kbd {
|
|
|
2949
2976
|
color: var(--accent-primary);
|
|
2950
2977
|
text-decoration: underline;
|
|
2951
2978
|
text-underline-offset: 2px;
|
|
2979
|
+
overflow-wrap: anywhere;
|
|
2980
|
+
word-break: break-word;
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
.agent-message-body.markdown img {
|
|
2984
|
+
display: block;
|
|
2985
|
+
max-width: 100%;
|
|
2986
|
+
height: auto;
|
|
2987
|
+
margin: 0 0 10px;
|
|
2988
|
+
border-radius: 8px;
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
.agent-message-body.markdown table {
|
|
2992
|
+
display: block;
|
|
2993
|
+
width: max-content;
|
|
2994
|
+
max-width: 100%;
|
|
2995
|
+
overflow-x: auto;
|
|
2996
|
+
border-collapse: collapse;
|
|
2997
|
+
margin: 0 0 10px;
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
.agent-message-body.markdown th,
|
|
3001
|
+
.agent-message-body.markdown td {
|
|
3002
|
+
border: 1px solid rgba(131, 148, 150, 0.2);
|
|
3003
|
+
padding: 6px 8px;
|
|
3004
|
+
text-align: left;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
.agent-message-body.markdown hr {
|
|
3008
|
+
border: 0;
|
|
3009
|
+
border-top: 1px solid rgba(131, 148, 150, 0.18);
|
|
3010
|
+
margin: 10px 0;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
.agent-message-body.markdown .task-list-item {
|
|
3014
|
+
list-style: none;
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
.agent-message-body.markdown .task-list-item input {
|
|
3018
|
+
margin-right: 8px;
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
.agent-message-body.markdown .katex-display {
|
|
3022
|
+
overflow-x: auto;
|
|
3023
|
+
overflow-y: hidden;
|
|
3024
|
+
margin: 0 0 10px;
|
|
2952
3025
|
}
|
|
2953
3026
|
|
|
2954
3027
|
.agent-message-attachments {
|