@xcanwin/manyoyo 6.1.1 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/web/frontend/app.css +315 -187
- package/lib/web/frontend/app.html +32 -38
- package/lib/web/frontend/app.js +346 -223
- package/lib/web/frontend/chat-behavior.js +49 -0
- package/lib/web/server.js +1 -0
- package/package.json +1 -1
package/lib/web/frontend/app.js
CHANGED
|
@@ -47,7 +47,8 @@
|
|
|
47
47
|
loadingMessages: false,
|
|
48
48
|
loadingSessionDetail: false,
|
|
49
49
|
mobileSidebarOpen: false,
|
|
50
|
-
|
|
50
|
+
workspaceSwitcherOpen: false,
|
|
51
|
+
composerOptionsOpen: false,
|
|
51
52
|
configModalOpen: false,
|
|
52
53
|
createModalOpen: false,
|
|
53
54
|
agentTemplateModalOpen: false,
|
|
@@ -122,20 +123,18 @@
|
|
|
122
123
|
const sessionList = document.getElementById('sessionList');
|
|
123
124
|
const sessionCount = document.getElementById('sessionCount');
|
|
124
125
|
const mobileSessionToggle = document.getElementById('mobileSessionToggle');
|
|
125
|
-
const mobileActionsToggle = document.getElementById('mobileActionsToggle');
|
|
126
|
-
const headerActions = document.getElementById('headerActions');
|
|
127
126
|
const viewActivityBtn = document.getElementById('viewActivityBtn');
|
|
127
|
+
const workspaceSwitcherToggle = document.getElementById('workspaceSwitcherToggle');
|
|
128
|
+
const workspaceSwitcherPanel = document.getElementById('workspaceSwitcherPanel');
|
|
128
129
|
const viewTerminalBtn = document.getElementById('viewTerminalBtn');
|
|
129
130
|
const viewFilesBtn = document.getElementById('viewFilesBtn');
|
|
130
131
|
const viewDetailBtn = document.getElementById('viewDetailBtn');
|
|
131
132
|
const viewConfigBtn = document.getElementById('viewConfigBtn');
|
|
132
133
|
const viewCheckBtn = document.getElementById('viewCheckBtn');
|
|
133
|
-
const addAgentBtn = document.getElementById('addAgentBtn');
|
|
134
134
|
const mobileSidebarClose = document.getElementById('mobileSidebarClose');
|
|
135
135
|
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
|
136
136
|
const openConfigBtn = document.getElementById('openConfigBtn');
|
|
137
137
|
const openCreateBtn = document.getElementById('openCreateBtn');
|
|
138
|
-
const openCreateMenuBtn = document.getElementById('openCreateMenuBtn');
|
|
139
138
|
const configModal = document.getElementById('configModal');
|
|
140
139
|
const configModalTitle = document.getElementById('configModalTitle');
|
|
141
140
|
const configPath = document.getElementById('configPath');
|
|
@@ -178,12 +177,12 @@
|
|
|
178
177
|
const directoryPickerError = document.getElementById('directoryPickerError');
|
|
179
178
|
const directoryPickerCancelBtn = document.getElementById('directoryPickerCancelBtn');
|
|
180
179
|
const directoryPickerSelectBtn = document.getElementById('directoryPickerSelectBtn');
|
|
181
|
-
const activeTitle = document.getElementById('activeTitle');
|
|
182
|
-
const activeMeta = document.getElementById('activeMeta');
|
|
183
180
|
const activityCommandBtn = document.getElementById('activityCommandBtn');
|
|
184
181
|
const activityAgentBtn = document.getElementById('activityAgentBtn');
|
|
185
182
|
const agentTemplateBtn = document.getElementById('agentTemplateBtn');
|
|
186
183
|
const activityModelChip = document.getElementById('activityModelChip');
|
|
184
|
+
const composerOptionsToggle = document.getElementById('composerOptionsToggle');
|
|
185
|
+
const composerOptionsPanel = document.getElementById('composerOptionsPanel');
|
|
187
186
|
const messagesNode = document.getElementById('messages');
|
|
188
187
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
189
188
|
const filesPanel = document.getElementById('filesPanel');
|
|
@@ -196,10 +195,7 @@
|
|
|
196
195
|
const terminalScreen = document.getElementById('terminalScreen');
|
|
197
196
|
const composer = document.getElementById('composer');
|
|
198
197
|
const commandInput = document.getElementById('commandInput');
|
|
199
|
-
const composerHint = document.getElementById('composerHint');
|
|
200
|
-
const sendState = document.getElementById('sendState');
|
|
201
198
|
const sendBtn = document.getElementById('sendBtn');
|
|
202
|
-
const stopBtn = document.getElementById('stopBtn');
|
|
203
199
|
const agentTemplateModal = document.getElementById('agentTemplateModal');
|
|
204
200
|
const agentTemplatePrimary = document.getElementById('agentTemplatePrimary');
|
|
205
201
|
const containerCliSelect = document.getElementById('containerCliSelect');
|
|
@@ -215,9 +211,6 @@
|
|
|
215
211
|
const externalLinkUrl = document.getElementById('externalLinkUrl');
|
|
216
212
|
const externalLinkCancelBtn = document.getElementById('externalLinkCancelBtn');
|
|
217
213
|
const externalLinkOpenBtn = document.getElementById('externalLinkOpenBtn');
|
|
218
|
-
const refreshBtn = document.getElementById('refreshBtn');
|
|
219
|
-
const removeBtn = document.getElementById('removeBtn');
|
|
220
|
-
const removeAllBtn = document.getElementById('removeAllBtn');
|
|
221
214
|
const MOBILE_LAYOUT_MEDIA = window.matchMedia('(max-width: 980px)');
|
|
222
215
|
const MOBILE_COMPACT_MEDIA = window.matchMedia('(max-width: 640px)');
|
|
223
216
|
const TERMINAL_FIT_DEBOUNCE_MS = 60;
|
|
@@ -318,6 +311,40 @@
|
|
|
318
311
|
bubble.appendChild(pre);
|
|
319
312
|
}
|
|
320
313
|
|
|
314
|
+
function copyTextToClipboard(text) {
|
|
315
|
+
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
|
316
|
+
return navigator.clipboard.writeText(text);
|
|
317
|
+
}
|
|
318
|
+
return Promise.reject(new Error('clipboard unavailable'));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function appendMessageCopyActions(container, items) {
|
|
322
|
+
const actions = document.createElement('div');
|
|
323
|
+
actions.className = 'msg-actions';
|
|
324
|
+
items.forEach(function (item) {
|
|
325
|
+
const btn = document.createElement('button');
|
|
326
|
+
btn.type = 'button';
|
|
327
|
+
btn.className = 'msg-copy-btn';
|
|
328
|
+
btn.textContent = item.label;
|
|
329
|
+
btn.addEventListener('click', function () {
|
|
330
|
+
const text = String(item.getText() || '');
|
|
331
|
+
if (!text) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
copyTextToClipboard(text).then(function () {
|
|
335
|
+
btn.textContent = '已复制';
|
|
336
|
+
btn.classList.add('is-copied');
|
|
337
|
+
window.setTimeout(function () {
|
|
338
|
+
btn.textContent = item.label;
|
|
339
|
+
btn.classList.remove('is-copied');
|
|
340
|
+
}, 1200);
|
|
341
|
+
}).catch(function () {});
|
|
342
|
+
});
|
|
343
|
+
actions.appendChild(btn);
|
|
344
|
+
});
|
|
345
|
+
container.appendChild(actions);
|
|
346
|
+
}
|
|
347
|
+
|
|
321
348
|
function stringifyPrettyJson(value) {
|
|
322
349
|
if (value === undefined || value === null) {
|
|
323
350
|
return '';
|
|
@@ -545,6 +572,8 @@
|
|
|
545
572
|
return card;
|
|
546
573
|
}
|
|
547
574
|
|
|
575
|
+
const traceFlowExpandedState = new Map();
|
|
576
|
+
|
|
548
577
|
function appendStructuredTraceContent(bubble, message) {
|
|
549
578
|
bubble.classList.add('trace-bubble');
|
|
550
579
|
const container = document.createElement('div');
|
|
@@ -555,10 +584,33 @@
|
|
|
555
584
|
buildStructuredTraceResidualLines(message).forEach(function (line) {
|
|
556
585
|
flow.appendChild(createResidualTraceCard(line));
|
|
557
586
|
});
|
|
558
|
-
|
|
587
|
+
const traceEvents = Array.isArray(message && message.traceEvents) ? message.traceEvents : [];
|
|
588
|
+
traceEvents.forEach(function (traceEvent) {
|
|
559
589
|
flow.appendChild(createTraceEventCard(traceEvent));
|
|
560
590
|
});
|
|
561
|
-
|
|
591
|
+
|
|
592
|
+
const messageId = message && message.id ? message.id : '';
|
|
593
|
+
const pending = Boolean(state.agentRun.active && state.agentRun.traceMessageId === messageId);
|
|
594
|
+
const summaryInfo = window.ManyoyoChatBehavior.summarizeTraceFlow(traceEvents, { pending });
|
|
595
|
+
const hasError = traceEvents.some(function (event) {
|
|
596
|
+
return event && event.kind === 'error';
|
|
597
|
+
});
|
|
598
|
+
const defaultOpen = hasError;
|
|
599
|
+
const toggle = document.createElement('details');
|
|
600
|
+
toggle.className = 'trace-flow-toggle';
|
|
601
|
+
toggle.open = traceFlowExpandedState.has(messageId) ? traceFlowExpandedState.get(messageId) : defaultOpen;
|
|
602
|
+
toggle.addEventListener('toggle', function () {
|
|
603
|
+
if (messageId) {
|
|
604
|
+
traceFlowExpandedState.set(messageId, toggle.open);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
const summary = document.createElement('summary');
|
|
609
|
+
summary.className = 'trace-flow-toggle-summary';
|
|
610
|
+
summary.textContent = summaryInfo.label;
|
|
611
|
+
toggle.appendChild(summary);
|
|
612
|
+
toggle.appendChild(flow);
|
|
613
|
+
container.appendChild(toggle);
|
|
562
614
|
|
|
563
615
|
bubble.appendChild(container);
|
|
564
616
|
}
|
|
@@ -570,7 +622,7 @@
|
|
|
570
622
|
return 'AGENT 实时回复';
|
|
571
623
|
}
|
|
572
624
|
if (message && message.streamTrace) {
|
|
573
|
-
return 'AGENT
|
|
625
|
+
return 'AGENT 回复';
|
|
574
626
|
}
|
|
575
627
|
if (message && message.mode === 'agent') {
|
|
576
628
|
return 'AGENT 回复';
|
|
@@ -1573,17 +1625,6 @@
|
|
|
1573
1625
|
return '自动';
|
|
1574
1626
|
}
|
|
1575
1627
|
|
|
1576
|
-
function buildActiveMeta(session) {
|
|
1577
|
-
if (!session) {
|
|
1578
|
-
return '会话不可用';
|
|
1579
|
-
}
|
|
1580
|
-
const status = sessionStatusInfo(session.status);
|
|
1581
|
-
const messageCount = safeMessageCount(session.messageCount);
|
|
1582
|
-
const updatedAt = formatDateTime(session.updatedAt) || '暂无更新';
|
|
1583
|
-
const containerName = session.containerName || '未绑定容器';
|
|
1584
|
-
return `${containerName} · ${status.label} · ${messageCount} 条对话 · ${updatedAt}`;
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
1628
|
function buildMessageMetaLines(message) {
|
|
1588
1629
|
const lines = [];
|
|
1589
1630
|
const timeText = formatDateTime(message && message.timestamp);
|
|
@@ -1918,16 +1959,34 @@
|
|
|
1918
1959
|
setMobileSessionPanel(false);
|
|
1919
1960
|
}
|
|
1920
1961
|
|
|
1921
|
-
function
|
|
1922
|
-
state.
|
|
1923
|
-
document.body.classList.toggle('
|
|
1924
|
-
if (
|
|
1925
|
-
|
|
1962
|
+
function setWorkspaceSwitcherMenu(open) {
|
|
1963
|
+
state.workspaceSwitcherOpen = Boolean(open);
|
|
1964
|
+
document.body.classList.toggle('workspace-switcher-open', state.workspaceSwitcherOpen);
|
|
1965
|
+
if (workspaceSwitcherToggle) {
|
|
1966
|
+
workspaceSwitcherToggle.setAttribute('aria-expanded', state.workspaceSwitcherOpen ? 'true' : 'false');
|
|
1967
|
+
}
|
|
1968
|
+
if (workspaceSwitcherPanel) {
|
|
1969
|
+
workspaceSwitcherPanel.hidden = !state.workspaceSwitcherOpen;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function closeWorkspaceSwitcherMenu() {
|
|
1974
|
+
setWorkspaceSwitcherMenu(false);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
function setComposerOptionsMenu(open) {
|
|
1978
|
+
state.composerOptionsOpen = Boolean(open);
|
|
1979
|
+
document.body.classList.toggle('composer-options-open', state.composerOptionsOpen);
|
|
1980
|
+
if (composerOptionsToggle) {
|
|
1981
|
+
composerOptionsToggle.setAttribute('aria-expanded', state.composerOptionsOpen ? 'true' : 'false');
|
|
1982
|
+
}
|
|
1983
|
+
if (composerOptionsPanel) {
|
|
1984
|
+
composerOptionsPanel.hidden = !state.composerOptionsOpen;
|
|
1926
1985
|
}
|
|
1927
1986
|
}
|
|
1928
1987
|
|
|
1929
|
-
function
|
|
1930
|
-
|
|
1988
|
+
function closeComposerOptionsMenu() {
|
|
1989
|
+
setComposerOptionsMenu(false);
|
|
1931
1990
|
}
|
|
1932
1991
|
|
|
1933
1992
|
const VIEW_LABELS = {
|
|
@@ -2199,15 +2258,15 @@
|
|
|
2199
2258
|
|
|
2200
2259
|
function syncUi() {
|
|
2201
2260
|
if (!state.active) {
|
|
2202
|
-
|
|
2203
|
-
activeMeta.textContent = '请选择左侧会话';
|
|
2261
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle('');
|
|
2204
2262
|
if (isComposerMode()) {
|
|
2205
2263
|
commandInput.value = '';
|
|
2206
2264
|
}
|
|
2207
2265
|
} else {
|
|
2208
2266
|
const activeSession = getActiveSession();
|
|
2209
|
-
|
|
2210
|
-
|
|
2267
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle(
|
|
2268
|
+
activeSession && activeSession.agentName ? activeSession.agentName : state.active
|
|
2269
|
+
);
|
|
2211
2270
|
}
|
|
2212
2271
|
|
|
2213
2272
|
const activityTab = state.activeTab === 'activity';
|
|
@@ -2253,6 +2312,7 @@
|
|
|
2253
2312
|
if (viewDetailBtn) viewDetailBtn.classList.toggle('is-active', detailTab);
|
|
2254
2313
|
if (viewConfigBtn) viewConfigBtn.classList.toggle('is-active', configTab);
|
|
2255
2314
|
if (viewCheckBtn) viewCheckBtn.classList.toggle('is-active', checkTab);
|
|
2315
|
+
if (workspaceSwitcherToggle) workspaceSwitcherToggle.classList.toggle('is-active', !activityTab);
|
|
2256
2316
|
if (messagesNode) {
|
|
2257
2317
|
messagesNode.hidden = !activityTab;
|
|
2258
2318
|
}
|
|
@@ -2285,16 +2345,15 @@
|
|
|
2285
2345
|
|
|
2286
2346
|
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
2287
2347
|
const busy = state.loadingSessions || state.loadingMessages || state.sending || state.creatingAgent;
|
|
2288
|
-
|
|
2289
|
-
if (
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
|
|
2348
|
+
const showStop = agentMode && activeAgentRunning;
|
|
2349
|
+
if (showStop) {
|
|
2350
|
+
sendBtn.disabled = !activityTab || !state.active || state.agentRun.stopping;
|
|
2351
|
+
sendBtn.textContent = state.agentRun.stopping ? '停止中…' : '停止';
|
|
2352
|
+
sendBtn.classList.add('danger-outline');
|
|
2353
|
+
} else {
|
|
2354
|
+
sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && !agentEnabled);
|
|
2355
|
+
sendBtn.textContent = '发送';
|
|
2356
|
+
sendBtn.classList.remove('danger-outline');
|
|
2298
2357
|
}
|
|
2299
2358
|
if (agentTemplateBtn) {
|
|
2300
2359
|
agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
|
|
@@ -2305,17 +2364,9 @@
|
|
|
2305
2364
|
? '输入提示词,例如:请帮我分析当前项目结构并给出重构建议'
|
|
2306
2365
|
: '输入容器命令,例如: ls -la';
|
|
2307
2366
|
}
|
|
2308
|
-
if (composerHint) {
|
|
2309
|
-
composerHint.textContent = agentMode
|
|
2310
|
-
? 'Enter 发送提示词 · Shift/Alt + Enter 换行 · 执行中可停止'
|
|
2311
|
-
: 'Enter 发送 · Shift/Alt + Enter 换行';
|
|
2312
|
-
}
|
|
2313
2367
|
if (openCreateBtn) {
|
|
2314
2368
|
openCreateBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2315
2369
|
}
|
|
2316
|
-
if (openCreateMenuBtn) {
|
|
2317
|
-
openCreateMenuBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2318
|
-
}
|
|
2319
2370
|
if (openConfigBtn) {
|
|
2320
2371
|
openConfigBtn.disabled = state.configLoading || state.configSaving;
|
|
2321
2372
|
}
|
|
@@ -2342,24 +2393,6 @@
|
|
|
2342
2393
|
if (createCancelBtn) {
|
|
2343
2394
|
createCancelBtn.disabled = state.createSubmitting;
|
|
2344
2395
|
}
|
|
2345
|
-
if (sendState) {
|
|
2346
|
-
if (!state.active) {
|
|
2347
|
-
sendState.textContent = '未选择会话';
|
|
2348
|
-
sendState.classList.remove('is-active');
|
|
2349
|
-
} else if (state.creatingAgent) {
|
|
2350
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2351
|
-
sendState.classList.add('is-active');
|
|
2352
|
-
} else if (activeAgentRunning && agentMode) {
|
|
2353
|
-
sendState.textContent = state.agentRun.stopping ? '正在停止 Agent…' : 'Agent 执行中';
|
|
2354
|
-
sendState.classList.add('is-active');
|
|
2355
|
-
} else if (busy) {
|
|
2356
|
-
sendState.textContent = '处理中';
|
|
2357
|
-
sendState.classList.add('is-active');
|
|
2358
|
-
} else {
|
|
2359
|
-
sendState.textContent = agentMode ? 'Agent 就绪' : '命令就绪';
|
|
2360
|
-
sendState.classList.remove('is-active');
|
|
2361
|
-
}
|
|
2362
|
-
}
|
|
2363
2396
|
if (configModal) {
|
|
2364
2397
|
configModal.hidden = !state.configModalOpen;
|
|
2365
2398
|
}
|
|
@@ -2400,25 +2433,10 @@
|
|
|
2400
2433
|
'modal-open',
|
|
2401
2434
|
state.configModalOpen || state.createModalOpen || state.directoryPicker.open || state.agentTemplateModalOpen || state.externalLinkModalOpen
|
|
2402
2435
|
);
|
|
2403
|
-
if (!state.active) {
|
|
2404
|
-
sendState.textContent = '未选择会话';
|
|
2405
|
-
} else if (state.creatingAgent) {
|
|
2406
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2407
|
-
} else if (agentMode && !agentEnabled) {
|
|
2408
|
-
sendState.textContent = '当前会话未配置 AGENT 模板';
|
|
2409
|
-
} else if (state.sending) {
|
|
2410
|
-
sendState.textContent = '发送中...';
|
|
2411
|
-
} else if (state.loadingSessions || state.loadingMessages) {
|
|
2412
|
-
sendState.textContent = '加载中...';
|
|
2413
|
-
} else {
|
|
2414
|
-
sendState.textContent = '就绪';
|
|
2415
|
-
}
|
|
2416
|
-
sendState.classList.toggle('is-active', state.sending || state.creatingAgent);
|
|
2417
2436
|
if (composer) {
|
|
2418
2437
|
composer.hidden = !activityTab;
|
|
2419
2438
|
}
|
|
2420
2439
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
2421
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
2422
2440
|
renderSessionDetailPanels();
|
|
2423
2441
|
}
|
|
2424
2442
|
|
|
@@ -3041,6 +3059,122 @@
|
|
|
3041
3059
|
return findLatestCreatedSessionName(remaining, removedRef.containerName);
|
|
3042
3060
|
}
|
|
3043
3061
|
|
|
3062
|
+
let openTreeNodeMenu = null;
|
|
3063
|
+
|
|
3064
|
+
function closeOpenTreeNodeMenu() {
|
|
3065
|
+
if (openTreeNodeMenu) {
|
|
3066
|
+
const menu = openTreeNodeMenu;
|
|
3067
|
+
openTreeNodeMenu = null;
|
|
3068
|
+
menu.close();
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
function createTreeNodeMenu(items) {
|
|
3073
|
+
const wrap = document.createElement('div');
|
|
3074
|
+
wrap.className = 'tree-node-menu';
|
|
3075
|
+
|
|
3076
|
+
const trigger = document.createElement('button');
|
|
3077
|
+
trigger.type = 'button';
|
|
3078
|
+
trigger.className = 'secondary tree-node-menu-trigger';
|
|
3079
|
+
trigger.setAttribute('aria-haspopup', 'true');
|
|
3080
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3081
|
+
trigger.setAttribute('aria-label', '更多操作');
|
|
3082
|
+
trigger.innerHTML = '<svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><circle cx="3" cy="8" r="1.4"></circle><circle cx="8" cy="8" r="1.4"></circle><circle cx="13" cy="8" r="1.4"></circle></svg>';
|
|
3083
|
+
|
|
3084
|
+
const panel = document.createElement('div');
|
|
3085
|
+
panel.className = 'tree-node-menu-panel';
|
|
3086
|
+
panel.hidden = true;
|
|
3087
|
+
|
|
3088
|
+
function close() {
|
|
3089
|
+
panel.hidden = true;
|
|
3090
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3091
|
+
wrap.classList.remove('is-open');
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
trigger.addEventListener('click', function (event) {
|
|
3095
|
+
event.stopPropagation();
|
|
3096
|
+
if (panel.hidden) {
|
|
3097
|
+
closeOpenTreeNodeMenu();
|
|
3098
|
+
panel.hidden = false;
|
|
3099
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
3100
|
+
wrap.classList.add('is-open');
|
|
3101
|
+
openTreeNodeMenu = { wrap, close };
|
|
3102
|
+
} else {
|
|
3103
|
+
close();
|
|
3104
|
+
openTreeNodeMenu = null;
|
|
3105
|
+
}
|
|
3106
|
+
});
|
|
3107
|
+
|
|
3108
|
+
(Array.isArray(items) ? items : []).forEach(function (item) {
|
|
3109
|
+
const itemBtn = document.createElement('button');
|
|
3110
|
+
itemBtn.type = 'button';
|
|
3111
|
+
itemBtn.className = 'tree-node-menu-panel-item' + (item.danger ? ' is-danger' : '');
|
|
3112
|
+
itemBtn.textContent = item.label;
|
|
3113
|
+
itemBtn.addEventListener('click', function (event) {
|
|
3114
|
+
event.stopPropagation();
|
|
3115
|
+
close();
|
|
3116
|
+
openTreeNodeMenu = null;
|
|
3117
|
+
if (typeof item.onClick === 'function') {
|
|
3118
|
+
item.onClick();
|
|
3119
|
+
}
|
|
3120
|
+
});
|
|
3121
|
+
panel.appendChild(itemBtn);
|
|
3122
|
+
});
|
|
3123
|
+
|
|
3124
|
+
wrap.appendChild(trigger);
|
|
3125
|
+
wrap.appendChild(panel);
|
|
3126
|
+
return wrap;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
async function removeContainerByName(containerName) {
|
|
3130
|
+
const target = String(containerName || '').trim();
|
|
3131
|
+
if (!target) return;
|
|
3132
|
+
const yes = confirm('确认删除容器 ' + target + ' ?');
|
|
3133
|
+
if (!yes) return;
|
|
3134
|
+
try {
|
|
3135
|
+
const wasActiveContainer = parseSessionKey(state.active).containerName === target;
|
|
3136
|
+
if (parseSessionKey(state.terminal.sessionName).containerName === target
|
|
3137
|
+
&& (state.terminal.connected || state.terminal.connecting)) {
|
|
3138
|
+
disconnectTerminal('容器删除,终端已断开', true);
|
|
3139
|
+
}
|
|
3140
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove', {
|
|
3141
|
+
method: 'POST'
|
|
3142
|
+
});
|
|
3143
|
+
await refreshSessions({
|
|
3144
|
+
preferredName: wasActiveContainer ? target : (state.active || ''),
|
|
3145
|
+
withLoading: true,
|
|
3146
|
+
reloadMessages: wasActiveContainer
|
|
3147
|
+
});
|
|
3148
|
+
} catch (e) {
|
|
3149
|
+
alert(e.message);
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
async function removeAgentSessionByName(sessionName, agentLabel) {
|
|
3154
|
+
const target = String(sessionName || '').trim();
|
|
3155
|
+
if (!target) return;
|
|
3156
|
+
const yes = confirm('确认删除 AGENT ' + (agentLabel || target) + ' ?');
|
|
3157
|
+
if (!yes) return;
|
|
3158
|
+
const isActive = target === state.active;
|
|
3159
|
+
try {
|
|
3160
|
+
const containerName = parseSessionKey(target).containerName;
|
|
3161
|
+
const fallbackSessionName = isActive
|
|
3162
|
+
? findPreferredSessionNameAfterRemoval(state.sessions, target)
|
|
3163
|
+
: '';
|
|
3164
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove-with-history', {
|
|
3165
|
+
method: 'POST'
|
|
3166
|
+
});
|
|
3167
|
+
await refreshSessions({
|
|
3168
|
+
preferredName: isActive ? (fallbackSessionName || '') : (state.active || ''),
|
|
3169
|
+
preferredContainerName: containerName,
|
|
3170
|
+
withLoading: true,
|
|
3171
|
+
reloadMessages: isActive
|
|
3172
|
+
});
|
|
3173
|
+
} catch (e) {
|
|
3174
|
+
alert(e.message);
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3044
3178
|
function createDisclosureButton(expanded, label) {
|
|
3045
3179
|
const button = document.createElement('button');
|
|
3046
3180
|
button.type = 'button';
|
|
@@ -3179,18 +3313,21 @@
|
|
|
3179
3313
|
const status = sessionStatusInfo(containerGroup && containerGroup.status);
|
|
3180
3314
|
const historyClassName = status.tone === 'history' ? 'tree-node-tone-history' : '';
|
|
3181
3315
|
const containerName = String(containerGroup && containerGroup.containerName ? containerGroup.containerName : '').trim() || '未命名容器';
|
|
3182
|
-
const
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3316
|
+
const containerMenu = createTreeNodeMenu([
|
|
3317
|
+
{
|
|
3318
|
+
label: '新建 AGENT',
|
|
3319
|
+
onClick: function () {
|
|
3320
|
+
createAgentSession(containerName);
|
|
3321
|
+
}
|
|
3322
|
+
},
|
|
3323
|
+
{
|
|
3324
|
+
label: '删除容器',
|
|
3325
|
+
danger: true,
|
|
3326
|
+
onClick: function () {
|
|
3327
|
+
removeContainerByName(containerName);
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
]);
|
|
3194
3331
|
|
|
3195
3332
|
return {
|
|
3196
3333
|
kind: 'container',
|
|
@@ -3201,18 +3338,28 @@
|
|
|
3201
3338
|
disclosureLabel: containerName,
|
|
3202
3339
|
expanded: isContainerExpanded(containerGroup),
|
|
3203
3340
|
hasActive: containerContainsActiveSession(containerGroup),
|
|
3204
|
-
overlayNode:
|
|
3341
|
+
overlayNode: containerMenu,
|
|
3205
3342
|
onToggle: function (expanded) {
|
|
3206
3343
|
setSidebarContainerExpanded(containerGroup.containerName, expanded);
|
|
3207
3344
|
},
|
|
3208
3345
|
children: (Array.isArray(containerGroup.sessions) ? containerGroup.sessions : []).map(function (session) {
|
|
3346
|
+
const agentTitle = session.agentName || session.name;
|
|
3209
3347
|
return {
|
|
3210
3348
|
kind: 'agent',
|
|
3211
|
-
title:
|
|
3349
|
+
title: agentTitle,
|
|
3212
3350
|
meta: formatDateTime(session.updatedAt) || '暂无更新',
|
|
3213
3351
|
className: historyClassName,
|
|
3214
3352
|
active: state.active === session.name,
|
|
3215
|
-
sessionName: session.name
|
|
3353
|
+
sessionName: session.name,
|
|
3354
|
+
overlayNode: createTreeNodeMenu([
|
|
3355
|
+
{
|
|
3356
|
+
label: '删除 AGENT',
|
|
3357
|
+
danger: true,
|
|
3358
|
+
onClick: function () {
|
|
3359
|
+
removeAgentSessionByName(session.name, agentTitle);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
])
|
|
3216
3363
|
};
|
|
3217
3364
|
})
|
|
3218
3365
|
};
|
|
@@ -3376,9 +3523,13 @@
|
|
|
3376
3523
|
}
|
|
3377
3524
|
|
|
3378
3525
|
function isMessagesNearBottom(thresholdPx) {
|
|
3379
|
-
const threshold = Number.isFinite(thresholdPx) ? thresholdPx : 40;
|
|
3380
3526
|
if (!messagesNode) return true;
|
|
3381
|
-
return
|
|
3527
|
+
return window.ManyoyoChatBehavior.isNearBottom(
|
|
3528
|
+
messagesNode.scrollTop,
|
|
3529
|
+
messagesNode.scrollHeight,
|
|
3530
|
+
messagesNode.clientHeight,
|
|
3531
|
+
thresholdPx
|
|
3532
|
+
);
|
|
3382
3533
|
}
|
|
3383
3534
|
|
|
3384
3535
|
function scrollMessagesToBottomImmediate() {
|
|
@@ -3396,18 +3547,21 @@
|
|
|
3396
3547
|
}
|
|
3397
3548
|
|
|
3398
3549
|
function getMessageRenderKey(msg, index) {
|
|
3550
|
+
const pairedTrace = msg && msg.pairedTrace ? msg.pairedTrace : null;
|
|
3551
|
+
const tracePart = pairedTrace ? `|paired:${String(pairedTrace.content || '')}` : '';
|
|
3399
3552
|
if (msg && msg.id && msg.streamingReply) {
|
|
3400
3553
|
const content = msg.content ? String(msg.content) : '';
|
|
3401
3554
|
const timestamp = msg.timestamp ? String(msg.timestamp) : '';
|
|
3402
|
-
return `id:${msg.id}|streaming|${timestamp}|${content}`;
|
|
3555
|
+
return `id:${msg.id}|streaming|${timestamp}|${content}${tracePart}`;
|
|
3403
3556
|
}
|
|
3404
3557
|
if (msg && msg.id && msg.streamTrace) {
|
|
3405
3558
|
const content = msg.content ? String(msg.content) : '';
|
|
3406
3559
|
const timestamp = msg.timestamp ? String(msg.timestamp) : '';
|
|
3407
|
-
|
|
3560
|
+
const running = (state.agentRun.active && state.agentRun.traceMessageId === msg.id) ? '1' : '0';
|
|
3561
|
+
return `id:${msg.id}|trace|${timestamp}|${content}|${running}`;
|
|
3408
3562
|
}
|
|
3409
3563
|
if (msg && msg.id) {
|
|
3410
|
-
return `id:${msg.id}`;
|
|
3564
|
+
return `id:${msg.id}${tracePart}`;
|
|
3411
3565
|
}
|
|
3412
3566
|
const role = msg && msg.role ? String(msg.role) : '';
|
|
3413
3567
|
const mode = msg && msg.mode ? String(msg.mode) : '';
|
|
@@ -3415,7 +3569,7 @@
|
|
|
3415
3569
|
const exitCode = msg && typeof msg.exitCode === 'number' ? String(msg.exitCode) : '';
|
|
3416
3570
|
const pending = msg && msg.pending ? '1' : '0';
|
|
3417
3571
|
const content = msg && msg.content ? String(msg.content) : '';
|
|
3418
|
-
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}`;
|
|
3572
|
+
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}${tracePart}`;
|
|
3419
3573
|
}
|
|
3420
3574
|
|
|
3421
3575
|
function resolveMessageOrigin(msg) {
|
|
@@ -3452,13 +3606,12 @@
|
|
|
3452
3606
|
const bubble = document.createElement('div');
|
|
3453
3607
|
bubble.className = 'bubble';
|
|
3454
3608
|
|
|
3609
|
+
if (msg && msg.pairedTrace) {
|
|
3610
|
+
appendStructuredTraceContent(bubble, msg.pairedTrace);
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3455
3613
|
const isStreamingReply = Boolean(msg && msg.streamingReply);
|
|
3456
|
-
const shouldRenderStructuredTrace = Boolean(
|
|
3457
|
-
msg
|
|
3458
|
-
&& msg.streamTrace
|
|
3459
|
-
&& Array.isArray(msg.traceEvents)
|
|
3460
|
-
&& msg.traceEvents.length
|
|
3461
|
-
);
|
|
3614
|
+
const shouldRenderStructuredTrace = Boolean(msg && msg.streamTrace);
|
|
3462
3615
|
const shouldRenderMarkdown = Boolean(!msg.streamTrace && !msg.streamingReply && markdownRenderer && markdownRenderer.shouldRenderMessage(msg));
|
|
3463
3616
|
if (isStreamingReply) {
|
|
3464
3617
|
bubble.classList.add('streaming-reply');
|
|
@@ -3498,11 +3651,20 @@
|
|
|
3498
3651
|
if (renderedMarkdown) {
|
|
3499
3652
|
markdownNode.innerHTML = renderedMarkdown;
|
|
3500
3653
|
bubble.appendChild(markdownNode);
|
|
3654
|
+
appendMessageCopyActions(bubble, [
|
|
3655
|
+
{ label: '复制文本', getText: function () { return markdownNode.innerText || markdownNode.textContent || ''; } },
|
|
3656
|
+
{ label: '复制 Markdown', getText: function () { return msg.content; } }
|
|
3657
|
+
]);
|
|
3501
3658
|
} else {
|
|
3502
3659
|
appendPlainMessageContent(bubble, msg.content);
|
|
3503
3660
|
}
|
|
3504
3661
|
} else {
|
|
3505
3662
|
appendPlainMessageContent(bubble, msg.content);
|
|
3663
|
+
if (msg.role === 'user') {
|
|
3664
|
+
appendMessageCopyActions(bubble, [
|
|
3665
|
+
{ label: '复制', getText: function () { return msg.content; } }
|
|
3666
|
+
]);
|
|
3667
|
+
}
|
|
3506
3668
|
}
|
|
3507
3669
|
|
|
3508
3670
|
row.appendChild(meta);
|
|
@@ -3510,7 +3672,8 @@
|
|
|
3510
3672
|
return row;
|
|
3511
3673
|
}
|
|
3512
3674
|
|
|
3513
|
-
function renderMessages(
|
|
3675
|
+
function renderMessages(rawMessages, options) {
|
|
3676
|
+
const messages = window.ManyoyoChatBehavior.mergeTraceIntoReply(rawMessages);
|
|
3514
3677
|
const renderOptions = options && typeof options === 'object' ? options : {};
|
|
3515
3678
|
const stickToBottom = renderOptions.stickToBottom === true || isMessagesNearBottom(40);
|
|
3516
3679
|
|
|
@@ -3932,7 +4095,7 @@
|
|
|
3932
4095
|
traceLines.push(line);
|
|
3933
4096
|
updateAgentTraceMessageLocal(sessionName, traceMessageId, traceLines.join('\n'), traceEvent);
|
|
3934
4097
|
if (state.active === sessionName) {
|
|
3935
|
-
renderMessages(state.messages
|
|
4098
|
+
renderMessages(state.messages);
|
|
3936
4099
|
}
|
|
3937
4100
|
}
|
|
3938
4101
|
|
|
@@ -3971,7 +4134,7 @@
|
|
|
3971
4134
|
}
|
|
3972
4135
|
updateStreamingReplyLocal(sessionName, streamingReplyId, content);
|
|
3973
4136
|
if (state.active === sessionName) {
|
|
3974
|
-
renderMessages(state.messages
|
|
4137
|
+
renderMessages(state.messages);
|
|
3975
4138
|
}
|
|
3976
4139
|
return;
|
|
3977
4140
|
}
|
|
@@ -4007,6 +4170,9 @@
|
|
|
4007
4170
|
}
|
|
4008
4171
|
}
|
|
4009
4172
|
finalizeAgentRunState();
|
|
4173
|
+
if (state.active === sessionName) {
|
|
4174
|
+
renderMessages(state.messages);
|
|
4175
|
+
}
|
|
4010
4176
|
syncUi();
|
|
4011
4177
|
}
|
|
4012
4178
|
|
|
@@ -4019,7 +4185,7 @@
|
|
|
4019
4185
|
|
|
4020
4186
|
appendAssistantMessageLocal(sessionName, finalResult, 'agent');
|
|
4021
4187
|
if (state.active === sessionName) {
|
|
4022
|
-
renderMessages(state.messages
|
|
4188
|
+
renderMessages(state.messages);
|
|
4023
4189
|
}
|
|
4024
4190
|
bumpSessionMetaAfterSend(sessionName);
|
|
4025
4191
|
refreshSessionsSilent({ preferredName: sessionName }).catch(function () {
|
|
@@ -4039,15 +4205,9 @@
|
|
|
4039
4205
|
});
|
|
4040
4206
|
}
|
|
4041
4207
|
|
|
4042
|
-
if (openCreateMenuBtn) {
|
|
4043
|
-
openCreateMenuBtn.addEventListener('click', function () {
|
|
4044
|
-
closeMobileActionsMenu();
|
|
4045
|
-
openCreateModal();
|
|
4046
|
-
});
|
|
4047
|
-
}
|
|
4048
|
-
|
|
4049
4208
|
if (agentTemplateBtn) {
|
|
4050
4209
|
agentTemplateBtn.addEventListener('click', function () {
|
|
4210
|
+
closeComposerOptionsMenu();
|
|
4051
4211
|
openAgentTemplateModal().catch(function (e) {
|
|
4052
4212
|
alert(e && e.message ? e.message : '加载 Agent 模板失败');
|
|
4053
4213
|
});
|
|
@@ -4239,10 +4399,29 @@
|
|
|
4239
4399
|
composer.addEventListener('submit', async function (event) {
|
|
4240
4400
|
event.preventDefault();
|
|
4241
4401
|
if (!state.active) return;
|
|
4242
|
-
if (state.sending) return;
|
|
4243
|
-
if (state.loadingSessions || state.loadingMessages) return;
|
|
4244
4402
|
if (state.activeTab !== 'activity') return;
|
|
4403
|
+
|
|
4245
4404
|
const mode = state.mode === 'agent' ? 'agent' : 'command';
|
|
4405
|
+
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
4406
|
+
if (mode === 'agent' && activeAgentRunning) {
|
|
4407
|
+
if (state.agentRun.stopping) return;
|
|
4408
|
+
state.agentRun.stopping = true;
|
|
4409
|
+
syncUi();
|
|
4410
|
+
try {
|
|
4411
|
+
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4412
|
+
method: 'POST',
|
|
4413
|
+
body: JSON.stringify({})
|
|
4414
|
+
});
|
|
4415
|
+
} catch (e) {
|
|
4416
|
+
alert(e.message);
|
|
4417
|
+
state.agentRun.stopping = false;
|
|
4418
|
+
syncUi();
|
|
4419
|
+
}
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
if (state.sending) return;
|
|
4424
|
+
if (state.loadingSessions || state.loadingMessages) return;
|
|
4246
4425
|
if (mode === 'agent' && !isActiveAgentEnabled()) {
|
|
4247
4426
|
syncUi();
|
|
4248
4427
|
return;
|
|
@@ -4285,7 +4464,7 @@
|
|
|
4285
4464
|
}
|
|
4286
4465
|
appendAssistantMessageLocal(submitSession, runResult, mode);
|
|
4287
4466
|
if (state.active === submitSession) {
|
|
4288
|
-
renderMessages(state.messages
|
|
4467
|
+
renderMessages(state.messages);
|
|
4289
4468
|
}
|
|
4290
4469
|
bumpSessionMetaAfterSend(submitSession);
|
|
4291
4470
|
refreshSessionsSilent({ preferredName: submitSession }).catch(function () {
|
|
@@ -4303,37 +4482,16 @@
|
|
|
4303
4482
|
state.messages = state.messages.filter(function (message) {
|
|
4304
4483
|
return !(message && message.id === pendingMessage.id);
|
|
4305
4484
|
});
|
|
4306
|
-
renderMessages(state.messages
|
|
4485
|
+
renderMessages(state.messages);
|
|
4307
4486
|
}
|
|
4308
4487
|
alert(e.message);
|
|
4309
4488
|
}
|
|
4310
4489
|
} finally {
|
|
4311
4490
|
state.sending = false;
|
|
4312
4491
|
syncUi();
|
|
4313
|
-
commandInput.focus();
|
|
4314
4492
|
}
|
|
4315
4493
|
});
|
|
4316
4494
|
|
|
4317
|
-
if (stopBtn) {
|
|
4318
|
-
stopBtn.addEventListener('click', async function () {
|
|
4319
|
-
if (!state.active || !isAgentRunActiveForSession(state.active) || state.agentRun.stopping) {
|
|
4320
|
-
return;
|
|
4321
|
-
}
|
|
4322
|
-
state.agentRun.stopping = true;
|
|
4323
|
-
syncUi();
|
|
4324
|
-
try {
|
|
4325
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4326
|
-
method: 'POST',
|
|
4327
|
-
body: JSON.stringify({})
|
|
4328
|
-
});
|
|
4329
|
-
} catch (e) {
|
|
4330
|
-
alert(e.message);
|
|
4331
|
-
state.agentRun.stopping = false;
|
|
4332
|
-
syncUi();
|
|
4333
|
-
}
|
|
4334
|
-
});
|
|
4335
|
-
}
|
|
4336
|
-
|
|
4337
4495
|
commandInput.addEventListener('keydown', function (event) {
|
|
4338
4496
|
if (event.key !== 'Enter' || event.isComposing) {
|
|
4339
4497
|
return;
|
|
@@ -4356,6 +4514,7 @@
|
|
|
4356
4514
|
activityCommandBtn.addEventListener('click', function () {
|
|
4357
4515
|
state.mode = 'command';
|
|
4358
4516
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4517
|
+
closeComposerOptionsMenu();
|
|
4359
4518
|
syncUi();
|
|
4360
4519
|
commandInput.focus();
|
|
4361
4520
|
});
|
|
@@ -4365,13 +4524,21 @@
|
|
|
4365
4524
|
activityAgentBtn.addEventListener('click', function () {
|
|
4366
4525
|
state.mode = 'agent';
|
|
4367
4526
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4527
|
+
closeComposerOptionsMenu();
|
|
4368
4528
|
syncUi();
|
|
4369
4529
|
commandInput.focus();
|
|
4370
4530
|
});
|
|
4371
4531
|
}
|
|
4372
4532
|
|
|
4533
|
+
if (composerOptionsToggle) {
|
|
4534
|
+
composerOptionsToggle.addEventListener('click', function () {
|
|
4535
|
+
setComposerOptionsMenu(!state.composerOptionsOpen);
|
|
4536
|
+
});
|
|
4537
|
+
}
|
|
4538
|
+
|
|
4373
4539
|
if (viewActivityBtn) {
|
|
4374
4540
|
viewActivityBtn.addEventListener('click', function () {
|
|
4541
|
+
closeWorkspaceSwitcherMenu();
|
|
4375
4542
|
setActiveTab('activity');
|
|
4376
4543
|
commandInput.focus();
|
|
4377
4544
|
});
|
|
@@ -4379,39 +4546,39 @@
|
|
|
4379
4546
|
|
|
4380
4547
|
if (viewTerminalBtn) {
|
|
4381
4548
|
viewTerminalBtn.addEventListener('click', function () {
|
|
4549
|
+
closeWorkspaceSwitcherMenu();
|
|
4382
4550
|
setActiveTab('terminal');
|
|
4383
4551
|
});
|
|
4384
4552
|
}
|
|
4385
4553
|
|
|
4386
4554
|
if (viewFilesBtn) {
|
|
4387
4555
|
viewFilesBtn.addEventListener('click', function () {
|
|
4556
|
+
closeWorkspaceSwitcherMenu();
|
|
4388
4557
|
setActiveTab('files');
|
|
4389
4558
|
});
|
|
4390
4559
|
}
|
|
4391
4560
|
|
|
4392
4561
|
if (viewDetailBtn) {
|
|
4393
4562
|
viewDetailBtn.addEventListener('click', function () {
|
|
4563
|
+
closeWorkspaceSwitcherMenu();
|
|
4394
4564
|
setActiveTab('detail');
|
|
4395
4565
|
});
|
|
4396
4566
|
}
|
|
4397
4567
|
|
|
4398
4568
|
if (viewConfigBtn) {
|
|
4399
4569
|
viewConfigBtn.addEventListener('click', function () {
|
|
4570
|
+
closeWorkspaceSwitcherMenu();
|
|
4400
4571
|
setActiveTab('config');
|
|
4401
4572
|
});
|
|
4402
4573
|
}
|
|
4403
4574
|
|
|
4404
4575
|
if (viewCheckBtn) {
|
|
4405
4576
|
viewCheckBtn.addEventListener('click', function () {
|
|
4577
|
+
closeWorkspaceSwitcherMenu();
|
|
4406
4578
|
setActiveTab('check');
|
|
4407
4579
|
});
|
|
4408
4580
|
}
|
|
4409
4581
|
|
|
4410
|
-
refreshBtn.addEventListener('click', function () {
|
|
4411
|
-
closeMobileActionsMenu();
|
|
4412
|
-
loadSessions(state.active).catch(function (e) { alert(e.message); });
|
|
4413
|
-
});
|
|
4414
|
-
|
|
4415
4582
|
const TERM_KEY_SEQUENCES = {
|
|
4416
4583
|
esc: '\x1b',
|
|
4417
4584
|
tab: '\x09',
|
|
@@ -4453,9 +4620,9 @@
|
|
|
4453
4620
|
});
|
|
4454
4621
|
}
|
|
4455
4622
|
|
|
4456
|
-
if (
|
|
4457
|
-
|
|
4458
|
-
|
|
4623
|
+
if (workspaceSwitcherToggle) {
|
|
4624
|
+
workspaceSwitcherToggle.addEventListener('click', function () {
|
|
4625
|
+
setWorkspaceSwitcherMenu(!state.workspaceSwitcherOpen);
|
|
4459
4626
|
});
|
|
4460
4627
|
}
|
|
4461
4628
|
|
|
@@ -4471,18 +4638,6 @@
|
|
|
4471
4638
|
});
|
|
4472
4639
|
}
|
|
4473
4640
|
|
|
4474
|
-
if (addAgentBtn) {
|
|
4475
|
-
addAgentBtn.addEventListener('click', function () {
|
|
4476
|
-
const activeSession = getActiveSession();
|
|
4477
|
-
const targetContainer = activeSession ? getSessionContainerName(activeSession) : '';
|
|
4478
|
-
if (!targetContainer) {
|
|
4479
|
-
return;
|
|
4480
|
-
}
|
|
4481
|
-
closeMobileActionsMenu();
|
|
4482
|
-
createAgentSession(targetContainer);
|
|
4483
|
-
});
|
|
4484
|
-
}
|
|
4485
|
-
|
|
4486
4641
|
if (configModal) {
|
|
4487
4642
|
configModal.addEventListener('click', function (event) {
|
|
4488
4643
|
if (event.target === configModal && !state.configSaving) {
|
|
@@ -4550,14 +4705,19 @@
|
|
|
4550
4705
|
if (event.key === 'Escape' && state.mobileSidebarOpen) {
|
|
4551
4706
|
closeMobileSessionPanel();
|
|
4552
4707
|
}
|
|
4553
|
-
if (event.key === 'Escape' && state.
|
|
4554
|
-
|
|
4708
|
+
if (event.key === 'Escape' && state.workspaceSwitcherOpen) {
|
|
4709
|
+
closeWorkspaceSwitcherMenu();
|
|
4710
|
+
}
|
|
4711
|
+
if (event.key === 'Escape' && state.composerOptionsOpen) {
|
|
4712
|
+
closeComposerOptionsMenu();
|
|
4713
|
+
}
|
|
4714
|
+
if (event.key === 'Escape' && openTreeNodeMenu) {
|
|
4715
|
+
closeOpenTreeNodeMenu();
|
|
4555
4716
|
}
|
|
4556
4717
|
});
|
|
4557
4718
|
|
|
4558
4719
|
function onLayoutMediaChange() {
|
|
4559
4720
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
4560
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
4561
4721
|
if (state.activeTab === 'terminal' && state.terminal.terminalReady) {
|
|
4562
4722
|
scheduleTerminalFit(false);
|
|
4563
4723
|
}
|
|
@@ -4601,59 +4761,22 @@
|
|
|
4601
4761
|
|
|
4602
4762
|
document.addEventListener('click', function (event) {
|
|
4603
4763
|
const target = event.target;
|
|
4604
|
-
if (state.
|
|
4605
|
-
if (
|
|
4606
|
-
if (
|
|
4607
|
-
|
|
4764
|
+
if (state.workspaceSwitcherOpen) {
|
|
4765
|
+
if (workspaceSwitcherToggle && workspaceSwitcherToggle.contains(target)) return;
|
|
4766
|
+
if (workspaceSwitcherPanel && workspaceSwitcherPanel.contains(target)) return;
|
|
4767
|
+
closeWorkspaceSwitcherMenu();
|
|
4608
4768
|
}
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
closeMobileActionsMenu();
|
|
4614
|
-
const activeSession = getActiveSession();
|
|
4615
|
-
const targetContainer = activeSession && activeSession.containerName ? activeSession.containerName : state.active;
|
|
4616
|
-
const yes = confirm('确认删除容器 ' + targetContainer + ' ?');
|
|
4617
|
-
if (!yes) return;
|
|
4618
|
-
try {
|
|
4619
|
-
const current = state.active;
|
|
4620
|
-
if (state.terminal.sessionName === current && (state.terminal.connected || state.terminal.connecting)) {
|
|
4621
|
-
disconnectTerminal('容器删除,终端已断开', true);
|
|
4622
|
-
}
|
|
4623
|
-
await api('/api/sessions/' + encodeURIComponent(current) + '/remove', {
|
|
4624
|
-
method: 'POST'
|
|
4625
|
-
});
|
|
4626
|
-
await loadSessions(current);
|
|
4627
|
-
} catch (e) {
|
|
4628
|
-
alert(e.message);
|
|
4769
|
+
if (state.composerOptionsOpen) {
|
|
4770
|
+
if (composerOptionsToggle && composerOptionsToggle.contains(target)) return;
|
|
4771
|
+
if (composerOptionsPanel && composerOptionsPanel.contains(target)) return;
|
|
4772
|
+
closeComposerOptionsMenu();
|
|
4629
4773
|
}
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
removeAllBtn.addEventListener('click', async function () {
|
|
4633
|
-
if (!state.active) return;
|
|
4634
|
-
closeMobileActionsMenu();
|
|
4635
|
-
const activeSession = getActiveSession();
|
|
4636
|
-
const targetAgent = activeSession && activeSession.agentName ? activeSession.agentName : state.active;
|
|
4637
|
-
const yes = confirm('确认删除 AGENT ' + targetAgent + ' ?');
|
|
4638
|
-
if (!yes) return;
|
|
4639
|
-
try {
|
|
4640
|
-
const current = state.active;
|
|
4641
|
-
const targetContainerName = activeSession && activeSession.containerName ? activeSession.containerName : '';
|
|
4642
|
-
const fallbackSessionName = findPreferredSessionNameAfterRemoval(state.sessions, current);
|
|
4643
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/remove-with-history', {
|
|
4644
|
-
method: 'POST'
|
|
4645
|
-
});
|
|
4646
|
-
await refreshSessions({
|
|
4647
|
-
preferredName: fallbackSessionName || '',
|
|
4648
|
-
preferredContainerName: targetContainerName,
|
|
4649
|
-
withLoading: true,
|
|
4650
|
-
reloadMessages: true
|
|
4651
|
-
});
|
|
4652
|
-
} catch (e) {
|
|
4653
|
-
alert(e.message);
|
|
4774
|
+
if (openTreeNodeMenu && !openTreeNodeMenu.wrap.contains(target)) {
|
|
4775
|
+
closeOpenTreeNodeMenu();
|
|
4654
4776
|
}
|
|
4655
4777
|
});
|
|
4656
4778
|
|
|
4779
|
+
|
|
4657
4780
|
if (externalLinkCancelBtn) {
|
|
4658
4781
|
externalLinkCancelBtn.addEventListener('click', function () {
|
|
4659
4782
|
closeExternalLinkModalView();
|