@xcanwin/manyoyo 6.1.3 → 6.2.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/web/frontend/app.css +196 -389
- package/lib/web/frontend/app.html +19 -39
- package/lib/web/frontend/app.js +239 -274
- package/lib/web/frontend/chat-behavior.js +23 -4
- package/package.json +1 -1
package/lib/web/frontend/app.js
CHANGED
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
loadingMessages: false,
|
|
48
48
|
loadingSessionDetail: false,
|
|
49
49
|
mobileSidebarOpen: false,
|
|
50
|
-
mobileActionsOpen: false,
|
|
51
50
|
workspaceSwitcherOpen: false,
|
|
51
|
+
composerOptionsOpen: false,
|
|
52
52
|
configModalOpen: false,
|
|
53
53
|
createModalOpen: false,
|
|
54
54
|
agentTemplateModalOpen: false,
|
|
@@ -123,8 +123,6 @@
|
|
|
123
123
|
const sessionList = document.getElementById('sessionList');
|
|
124
124
|
const sessionCount = document.getElementById('sessionCount');
|
|
125
125
|
const mobileSessionToggle = document.getElementById('mobileSessionToggle');
|
|
126
|
-
const mobileActionsToggle = document.getElementById('mobileActionsToggle');
|
|
127
|
-
const headerActions = document.getElementById('headerActions');
|
|
128
126
|
const viewActivityBtn = document.getElementById('viewActivityBtn');
|
|
129
127
|
const workspaceSwitcherToggle = document.getElementById('workspaceSwitcherToggle');
|
|
130
128
|
const workspaceSwitcherPanel = document.getElementById('workspaceSwitcherPanel');
|
|
@@ -133,12 +131,10 @@
|
|
|
133
131
|
const viewDetailBtn = document.getElementById('viewDetailBtn');
|
|
134
132
|
const viewConfigBtn = document.getElementById('viewConfigBtn');
|
|
135
133
|
const viewCheckBtn = document.getElementById('viewCheckBtn');
|
|
136
|
-
const addAgentBtn = document.getElementById('addAgentBtn');
|
|
137
134
|
const mobileSidebarClose = document.getElementById('mobileSidebarClose');
|
|
138
135
|
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
|
139
136
|
const openConfigBtn = document.getElementById('openConfigBtn');
|
|
140
137
|
const openCreateBtn = document.getElementById('openCreateBtn');
|
|
141
|
-
const openCreateMenuBtn = document.getElementById('openCreateMenuBtn');
|
|
142
138
|
const configModal = document.getElementById('configModal');
|
|
143
139
|
const configModalTitle = document.getElementById('configModalTitle');
|
|
144
140
|
const configPath = document.getElementById('configPath');
|
|
@@ -181,12 +177,12 @@
|
|
|
181
177
|
const directoryPickerError = document.getElementById('directoryPickerError');
|
|
182
178
|
const directoryPickerCancelBtn = document.getElementById('directoryPickerCancelBtn');
|
|
183
179
|
const directoryPickerSelectBtn = document.getElementById('directoryPickerSelectBtn');
|
|
184
|
-
const activeTitle = document.getElementById('activeTitle');
|
|
185
|
-
const activeMeta = document.getElementById('activeMeta');
|
|
186
180
|
const activityCommandBtn = document.getElementById('activityCommandBtn');
|
|
187
181
|
const activityAgentBtn = document.getElementById('activityAgentBtn');
|
|
188
182
|
const agentTemplateBtn = document.getElementById('agentTemplateBtn');
|
|
189
183
|
const activityModelChip = document.getElementById('activityModelChip');
|
|
184
|
+
const composerOptionsToggle = document.getElementById('composerOptionsToggle');
|
|
185
|
+
const composerOptionsPanel = document.getElementById('composerOptionsPanel');
|
|
190
186
|
const messagesNode = document.getElementById('messages');
|
|
191
187
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
192
188
|
const filesPanel = document.getElementById('filesPanel');
|
|
@@ -199,10 +195,7 @@
|
|
|
199
195
|
const terminalScreen = document.getElementById('terminalScreen');
|
|
200
196
|
const composer = document.getElementById('composer');
|
|
201
197
|
const commandInput = document.getElementById('commandInput');
|
|
202
|
-
const composerHint = document.getElementById('composerHint');
|
|
203
|
-
const sendState = document.getElementById('sendState');
|
|
204
198
|
const sendBtn = document.getElementById('sendBtn');
|
|
205
|
-
const stopBtn = document.getElementById('stopBtn');
|
|
206
199
|
const agentTemplateModal = document.getElementById('agentTemplateModal');
|
|
207
200
|
const agentTemplatePrimary = document.getElementById('agentTemplatePrimary');
|
|
208
201
|
const containerCliSelect = document.getElementById('containerCliSelect');
|
|
@@ -218,9 +211,6 @@
|
|
|
218
211
|
const externalLinkUrl = document.getElementById('externalLinkUrl');
|
|
219
212
|
const externalLinkCancelBtn = document.getElementById('externalLinkCancelBtn');
|
|
220
213
|
const externalLinkOpenBtn = document.getElementById('externalLinkOpenBtn');
|
|
221
|
-
const refreshBtn = document.getElementById('refreshBtn');
|
|
222
|
-
const removeBtn = document.getElementById('removeBtn');
|
|
223
|
-
const removeAllBtn = document.getElementById('removeAllBtn');
|
|
224
214
|
const MOBILE_LAYOUT_MEDIA = window.matchMedia('(max-width: 980px)');
|
|
225
215
|
const MOBILE_COMPACT_MEDIA = window.matchMedia('(max-width: 640px)');
|
|
226
216
|
const TERMINAL_FIT_DEBOUNCE_MS = 60;
|
|
@@ -328,7 +318,7 @@
|
|
|
328
318
|
return Promise.reject(new Error('clipboard unavailable'));
|
|
329
319
|
}
|
|
330
320
|
|
|
331
|
-
function appendMessageCopyActions(
|
|
321
|
+
function appendMessageCopyActions(container, items) {
|
|
332
322
|
const actions = document.createElement('div');
|
|
333
323
|
actions.className = 'msg-actions';
|
|
334
324
|
items.forEach(function (item) {
|
|
@@ -352,7 +342,7 @@
|
|
|
352
342
|
});
|
|
353
343
|
actions.appendChild(btn);
|
|
354
344
|
});
|
|
355
|
-
|
|
345
|
+
container.appendChild(actions);
|
|
356
346
|
}
|
|
357
347
|
|
|
358
348
|
function stringifyPrettyJson(value) {
|
|
@@ -605,7 +595,7 @@
|
|
|
605
595
|
const hasError = traceEvents.some(function (event) {
|
|
606
596
|
return event && event.kind === 'error';
|
|
607
597
|
});
|
|
608
|
-
const defaultOpen = hasError
|
|
598
|
+
const defaultOpen = hasError;
|
|
609
599
|
const toggle = document.createElement('details');
|
|
610
600
|
toggle.className = 'trace-flow-toggle';
|
|
611
601
|
toggle.open = traceFlowExpandedState.has(messageId) ? traceFlowExpandedState.get(messageId) : defaultOpen;
|
|
@@ -632,7 +622,7 @@
|
|
|
632
622
|
return 'AGENT 实时回复';
|
|
633
623
|
}
|
|
634
624
|
if (message && message.streamTrace) {
|
|
635
|
-
return 'AGENT
|
|
625
|
+
return 'AGENT 回复';
|
|
636
626
|
}
|
|
637
627
|
if (message && message.mode === 'agent') {
|
|
638
628
|
return 'AGENT 回复';
|
|
@@ -961,17 +951,6 @@
|
|
|
961
951
|
return base.replace(/\/+$/, '') + '/' + child.replace(/^\/+/, '');
|
|
962
952
|
}
|
|
963
953
|
|
|
964
|
-
function envMapToText(envMap) {
|
|
965
|
-
if (!envMap || typeof envMap !== 'object') {
|
|
966
|
-
return '';
|
|
967
|
-
}
|
|
968
|
-
return Object.entries(envMap)
|
|
969
|
-
.map(function (entry) {
|
|
970
|
-
return entry[0] + '=' + String(entry[1] == null ? '' : entry[1]);
|
|
971
|
-
})
|
|
972
|
-
.join('\n');
|
|
973
|
-
}
|
|
974
|
-
|
|
975
954
|
function textToLineArray(text) {
|
|
976
955
|
return String(text || '')
|
|
977
956
|
.split('\n')
|
|
@@ -1635,17 +1614,6 @@
|
|
|
1635
1614
|
return '自动';
|
|
1636
1615
|
}
|
|
1637
1616
|
|
|
1638
|
-
function buildActiveMeta(session) {
|
|
1639
|
-
if (!session) {
|
|
1640
|
-
return '会话不可用';
|
|
1641
|
-
}
|
|
1642
|
-
const status = sessionStatusInfo(session.status);
|
|
1643
|
-
const messageCount = safeMessageCount(session.messageCount);
|
|
1644
|
-
const updatedAt = formatDateTime(session.updatedAt) || '暂无更新';
|
|
1645
|
-
const containerName = session.containerName || '未绑定容器';
|
|
1646
|
-
return `${containerName} · ${status.label} · ${messageCount} 条对话 · ${updatedAt}`;
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
1617
|
function buildMessageMetaLines(message) {
|
|
1650
1618
|
const lines = [];
|
|
1651
1619
|
const timeText = formatDateTime(message && message.timestamp);
|
|
@@ -1980,18 +1948,6 @@
|
|
|
1980
1948
|
setMobileSessionPanel(false);
|
|
1981
1949
|
}
|
|
1982
1950
|
|
|
1983
|
-
function setMobileActionsMenu(open) {
|
|
1984
|
-
state.mobileActionsOpen = Boolean(open);
|
|
1985
|
-
document.body.classList.toggle('mobile-actions-open', state.mobileActionsOpen);
|
|
1986
|
-
if (mobileActionsToggle) {
|
|
1987
|
-
mobileActionsToggle.setAttribute('aria-expanded', state.mobileActionsOpen ? 'true' : 'false');
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
function closeMobileActionsMenu() {
|
|
1992
|
-
setMobileActionsMenu(false);
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
1951
|
function setWorkspaceSwitcherMenu(open) {
|
|
1996
1952
|
state.workspaceSwitcherOpen = Boolean(open);
|
|
1997
1953
|
document.body.classList.toggle('workspace-switcher-open', state.workspaceSwitcherOpen);
|
|
@@ -2007,6 +1963,21 @@
|
|
|
2007
1963
|
setWorkspaceSwitcherMenu(false);
|
|
2008
1964
|
}
|
|
2009
1965
|
|
|
1966
|
+
function setComposerOptionsMenu(open) {
|
|
1967
|
+
state.composerOptionsOpen = Boolean(open);
|
|
1968
|
+
document.body.classList.toggle('composer-options-open', state.composerOptionsOpen);
|
|
1969
|
+
if (composerOptionsToggle) {
|
|
1970
|
+
composerOptionsToggle.setAttribute('aria-expanded', state.composerOptionsOpen ? 'true' : 'false');
|
|
1971
|
+
}
|
|
1972
|
+
if (composerOptionsPanel) {
|
|
1973
|
+
composerOptionsPanel.hidden = !state.composerOptionsOpen;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
function closeComposerOptionsMenu() {
|
|
1978
|
+
setComposerOptionsMenu(false);
|
|
1979
|
+
}
|
|
1980
|
+
|
|
2010
1981
|
const VIEW_LABELS = {
|
|
2011
1982
|
activity: '活动',
|
|
2012
1983
|
terminal: '终端',
|
|
@@ -2274,31 +2245,17 @@
|
|
|
2274
2245
|
}
|
|
2275
2246
|
}
|
|
2276
2247
|
|
|
2277
|
-
function syncComposerExpanded() {
|
|
2278
|
-
if (!composer || !commandInput) {
|
|
2279
|
-
return;
|
|
2280
|
-
}
|
|
2281
|
-
// 判定条件必须是"焦点是否还在 composer 内部"而不是"是否等于 commandInput":
|
|
2282
|
-
// 点击 Agent/命令 切换或 CLI/模型 按钮时,commandInput 会先 blur,
|
|
2283
|
-
// 若立刻按 commandInput 是否聚焦来收起,会在 mousedown 与 click 之间把工具栏收起,
|
|
2284
|
-
// 导致按钮的点击事件因布局变化而落空(点了没反应)。
|
|
2285
|
-
const focused = composer.contains(document.activeElement);
|
|
2286
|
-
const hasDraft = Boolean(commandInput.value && commandInput.value.trim());
|
|
2287
|
-
const expanded = window.ManyoyoChatBehavior.shouldExpandComposer({ focused, hasDraft });
|
|
2288
|
-
composer.classList.toggle('is-expanded', expanded);
|
|
2289
|
-
}
|
|
2290
|
-
|
|
2291
2248
|
function syncUi() {
|
|
2292
2249
|
if (!state.active) {
|
|
2293
|
-
|
|
2294
|
-
activeMeta.textContent = '请选择左侧会话';
|
|
2250
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle('');
|
|
2295
2251
|
if (isComposerMode()) {
|
|
2296
2252
|
commandInput.value = '';
|
|
2297
2253
|
}
|
|
2298
2254
|
} else {
|
|
2299
2255
|
const activeSession = getActiveSession();
|
|
2300
|
-
|
|
2301
|
-
|
|
2256
|
+
document.title = window.ManyoyoChatBehavior.buildDocumentTitle(
|
|
2257
|
+
activeSession && activeSession.agentName ? activeSession.agentName : state.active
|
|
2258
|
+
);
|
|
2302
2259
|
}
|
|
2303
2260
|
|
|
2304
2261
|
const activityTab = state.activeTab === 'activity';
|
|
@@ -2377,16 +2334,15 @@
|
|
|
2377
2334
|
|
|
2378
2335
|
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
2379
2336
|
const busy = state.loadingSessions || state.loadingMessages || state.sending || state.creatingAgent;
|
|
2380
|
-
|
|
2381
|
-
if (
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
|
|
2337
|
+
const showStop = agentMode && activeAgentRunning;
|
|
2338
|
+
if (showStop) {
|
|
2339
|
+
sendBtn.disabled = !activityTab || !state.active || state.agentRun.stopping;
|
|
2340
|
+
sendBtn.textContent = state.agentRun.stopping ? '停止中…' : '停止';
|
|
2341
|
+
sendBtn.classList.add('danger-outline');
|
|
2342
|
+
} else {
|
|
2343
|
+
sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && !agentEnabled);
|
|
2344
|
+
sendBtn.textContent = '发送';
|
|
2345
|
+
sendBtn.classList.remove('danger-outline');
|
|
2390
2346
|
}
|
|
2391
2347
|
if (agentTemplateBtn) {
|
|
2392
2348
|
agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
|
|
@@ -2397,18 +2353,9 @@
|
|
|
2397
2353
|
? '输入提示词,例如:请帮我分析当前项目结构并给出重构建议'
|
|
2398
2354
|
: '输入容器命令,例如: ls -la';
|
|
2399
2355
|
}
|
|
2400
|
-
if (composerHint) {
|
|
2401
|
-
composerHint.textContent = agentMode
|
|
2402
|
-
? 'Enter 发送提示词 · Shift/Alt + Enter 换行 · 执行中可停止'
|
|
2403
|
-
: 'Enter 发送 · Shift/Alt + Enter 换行';
|
|
2404
|
-
}
|
|
2405
|
-
syncComposerExpanded();
|
|
2406
2356
|
if (openCreateBtn) {
|
|
2407
2357
|
openCreateBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2408
2358
|
}
|
|
2409
|
-
if (openCreateMenuBtn) {
|
|
2410
|
-
openCreateMenuBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2411
|
-
}
|
|
2412
2359
|
if (openConfigBtn) {
|
|
2413
2360
|
openConfigBtn.disabled = state.configLoading || state.configSaving;
|
|
2414
2361
|
}
|
|
@@ -2435,24 +2382,6 @@
|
|
|
2435
2382
|
if (createCancelBtn) {
|
|
2436
2383
|
createCancelBtn.disabled = state.createSubmitting;
|
|
2437
2384
|
}
|
|
2438
|
-
if (sendState) {
|
|
2439
|
-
if (!state.active) {
|
|
2440
|
-
sendState.textContent = '未选择会话';
|
|
2441
|
-
sendState.classList.remove('is-active');
|
|
2442
|
-
} else if (state.creatingAgent) {
|
|
2443
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2444
|
-
sendState.classList.add('is-active');
|
|
2445
|
-
} else if (activeAgentRunning && agentMode) {
|
|
2446
|
-
sendState.textContent = state.agentRun.stopping ? '正在停止 Agent…' : 'Agent 执行中';
|
|
2447
|
-
sendState.classList.add('is-active');
|
|
2448
|
-
} else if (busy) {
|
|
2449
|
-
sendState.textContent = '处理中';
|
|
2450
|
-
sendState.classList.add('is-active');
|
|
2451
|
-
} else {
|
|
2452
|
-
sendState.textContent = agentMode ? 'Agent 就绪' : '命令就绪';
|
|
2453
|
-
sendState.classList.remove('is-active');
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
2385
|
if (configModal) {
|
|
2457
2386
|
configModal.hidden = !state.configModalOpen;
|
|
2458
2387
|
}
|
|
@@ -2493,25 +2422,10 @@
|
|
|
2493
2422
|
'modal-open',
|
|
2494
2423
|
state.configModalOpen || state.createModalOpen || state.directoryPicker.open || state.agentTemplateModalOpen || state.externalLinkModalOpen
|
|
2495
2424
|
);
|
|
2496
|
-
if (!state.active) {
|
|
2497
|
-
sendState.textContent = '未选择会话';
|
|
2498
|
-
} else if (state.creatingAgent) {
|
|
2499
|
-
sendState.textContent = '正在新建 AGENT…';
|
|
2500
|
-
} else if (agentMode && !agentEnabled) {
|
|
2501
|
-
sendState.textContent = '当前会话未配置 AGENT 模板';
|
|
2502
|
-
} else if (state.sending) {
|
|
2503
|
-
sendState.textContent = '发送中...';
|
|
2504
|
-
} else if (state.loadingSessions || state.loadingMessages) {
|
|
2505
|
-
sendState.textContent = '加载中...';
|
|
2506
|
-
} else {
|
|
2507
|
-
sendState.textContent = '就绪';
|
|
2508
|
-
}
|
|
2509
|
-
sendState.classList.toggle('is-active', state.sending || state.creatingAgent);
|
|
2510
2425
|
if (composer) {
|
|
2511
2426
|
composer.hidden = !activityTab;
|
|
2512
2427
|
}
|
|
2513
2428
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
2514
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
2515
2429
|
renderSessionDetailPanels();
|
|
2516
2430
|
}
|
|
2517
2431
|
|
|
@@ -3028,10 +2942,6 @@
|
|
|
3028
2942
|
});
|
|
3029
2943
|
}
|
|
3030
2944
|
|
|
3031
|
-
function createTreeMetaText(parts) {
|
|
3032
|
-
return (parts || []).filter(Boolean).join(' · ');
|
|
3033
|
-
}
|
|
3034
|
-
|
|
3035
2945
|
function getSessionCreatedTime(session) {
|
|
3036
2946
|
if (session && session.createdAt) {
|
|
3037
2947
|
const time = new Date(session.createdAt).getTime();
|
|
@@ -3134,6 +3044,122 @@
|
|
|
3134
3044
|
return findLatestCreatedSessionName(remaining, removedRef.containerName);
|
|
3135
3045
|
}
|
|
3136
3046
|
|
|
3047
|
+
let openTreeNodeMenu = null;
|
|
3048
|
+
|
|
3049
|
+
function closeOpenTreeNodeMenu() {
|
|
3050
|
+
if (openTreeNodeMenu) {
|
|
3051
|
+
const menu = openTreeNodeMenu;
|
|
3052
|
+
openTreeNodeMenu = null;
|
|
3053
|
+
menu.close();
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
function createTreeNodeMenu(items) {
|
|
3058
|
+
const wrap = document.createElement('div');
|
|
3059
|
+
wrap.className = 'tree-node-menu';
|
|
3060
|
+
|
|
3061
|
+
const trigger = document.createElement('button');
|
|
3062
|
+
trigger.type = 'button';
|
|
3063
|
+
trigger.className = 'secondary tree-node-menu-trigger';
|
|
3064
|
+
trigger.setAttribute('aria-haspopup', 'true');
|
|
3065
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3066
|
+
trigger.setAttribute('aria-label', '更多操作');
|
|
3067
|
+
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>';
|
|
3068
|
+
|
|
3069
|
+
const panel = document.createElement('div');
|
|
3070
|
+
panel.className = 'tree-node-menu-panel';
|
|
3071
|
+
panel.hidden = true;
|
|
3072
|
+
|
|
3073
|
+
function close() {
|
|
3074
|
+
panel.hidden = true;
|
|
3075
|
+
trigger.setAttribute('aria-expanded', 'false');
|
|
3076
|
+
wrap.classList.remove('is-open');
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
trigger.addEventListener('click', function (event) {
|
|
3080
|
+
event.stopPropagation();
|
|
3081
|
+
if (panel.hidden) {
|
|
3082
|
+
closeOpenTreeNodeMenu();
|
|
3083
|
+
panel.hidden = false;
|
|
3084
|
+
trigger.setAttribute('aria-expanded', 'true');
|
|
3085
|
+
wrap.classList.add('is-open');
|
|
3086
|
+
openTreeNodeMenu = { wrap, close };
|
|
3087
|
+
} else {
|
|
3088
|
+
close();
|
|
3089
|
+
openTreeNodeMenu = null;
|
|
3090
|
+
}
|
|
3091
|
+
});
|
|
3092
|
+
|
|
3093
|
+
(Array.isArray(items) ? items : []).forEach(function (item) {
|
|
3094
|
+
const itemBtn = document.createElement('button');
|
|
3095
|
+
itemBtn.type = 'button';
|
|
3096
|
+
itemBtn.className = 'tree-node-menu-panel-item' + (item.danger ? ' is-danger' : '');
|
|
3097
|
+
itemBtn.textContent = item.label;
|
|
3098
|
+
itemBtn.addEventListener('click', function (event) {
|
|
3099
|
+
event.stopPropagation();
|
|
3100
|
+
close();
|
|
3101
|
+
openTreeNodeMenu = null;
|
|
3102
|
+
if (typeof item.onClick === 'function') {
|
|
3103
|
+
item.onClick();
|
|
3104
|
+
}
|
|
3105
|
+
});
|
|
3106
|
+
panel.appendChild(itemBtn);
|
|
3107
|
+
});
|
|
3108
|
+
|
|
3109
|
+
wrap.appendChild(trigger);
|
|
3110
|
+
wrap.appendChild(panel);
|
|
3111
|
+
return wrap;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
async function removeContainerByName(containerName) {
|
|
3115
|
+
const target = String(containerName || '').trim();
|
|
3116
|
+
if (!target) return;
|
|
3117
|
+
const yes = confirm('确认删除容器 ' + target + ' ?');
|
|
3118
|
+
if (!yes) return;
|
|
3119
|
+
try {
|
|
3120
|
+
const wasActiveContainer = parseSessionKey(state.active).containerName === target;
|
|
3121
|
+
if (parseSessionKey(state.terminal.sessionName).containerName === target
|
|
3122
|
+
&& (state.terminal.connected || state.terminal.connecting)) {
|
|
3123
|
+
disconnectTerminal('容器删除,终端已断开', true);
|
|
3124
|
+
}
|
|
3125
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove', {
|
|
3126
|
+
method: 'POST'
|
|
3127
|
+
});
|
|
3128
|
+
await refreshSessions({
|
|
3129
|
+
preferredName: wasActiveContainer ? target : (state.active || ''),
|
|
3130
|
+
withLoading: true,
|
|
3131
|
+
reloadMessages: wasActiveContainer
|
|
3132
|
+
});
|
|
3133
|
+
} catch (e) {
|
|
3134
|
+
alert(e.message);
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
async function removeAgentSessionByName(sessionName, agentLabel) {
|
|
3139
|
+
const target = String(sessionName || '').trim();
|
|
3140
|
+
if (!target) return;
|
|
3141
|
+
const yes = confirm('确认删除 AGENT ' + (agentLabel || target) + ' ?');
|
|
3142
|
+
if (!yes) return;
|
|
3143
|
+
const isActive = target === state.active;
|
|
3144
|
+
try {
|
|
3145
|
+
const containerName = parseSessionKey(target).containerName;
|
|
3146
|
+
const fallbackSessionName = isActive
|
|
3147
|
+
? findPreferredSessionNameAfterRemoval(state.sessions, target)
|
|
3148
|
+
: '';
|
|
3149
|
+
await api('/api/sessions/' + encodeURIComponent(target) + '/remove-with-history', {
|
|
3150
|
+
method: 'POST'
|
|
3151
|
+
});
|
|
3152
|
+
await refreshSessions({
|
|
3153
|
+
preferredName: isActive ? (fallbackSessionName || '') : (state.active || ''),
|
|
3154
|
+
preferredContainerName: containerName,
|
|
3155
|
+
withLoading: true,
|
|
3156
|
+
reloadMessages: isActive
|
|
3157
|
+
});
|
|
3158
|
+
} catch (e) {
|
|
3159
|
+
alert(e.message);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3137
3163
|
function createDisclosureButton(expanded, label) {
|
|
3138
3164
|
const button = document.createElement('button');
|
|
3139
3165
|
button.type = 'button';
|
|
@@ -3272,18 +3298,21 @@
|
|
|
3272
3298
|
const status = sessionStatusInfo(containerGroup && containerGroup.status);
|
|
3273
3299
|
const historyClassName = status.tone === 'history' ? 'tree-node-tone-history' : '';
|
|
3274
3300
|
const containerName = String(containerGroup && containerGroup.containerName ? containerGroup.containerName : '').trim() || '未命名容器';
|
|
3275
|
-
const
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3301
|
+
const containerMenu = createTreeNodeMenu([
|
|
3302
|
+
{
|
|
3303
|
+
label: '新建 AGENT',
|
|
3304
|
+
onClick: function () {
|
|
3305
|
+
createAgentSession(containerName);
|
|
3306
|
+
}
|
|
3307
|
+
},
|
|
3308
|
+
{
|
|
3309
|
+
label: '删除容器',
|
|
3310
|
+
danger: true,
|
|
3311
|
+
onClick: function () {
|
|
3312
|
+
removeContainerByName(containerName);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
]);
|
|
3287
3316
|
|
|
3288
3317
|
return {
|
|
3289
3318
|
kind: 'container',
|
|
@@ -3294,18 +3323,28 @@
|
|
|
3294
3323
|
disclosureLabel: containerName,
|
|
3295
3324
|
expanded: isContainerExpanded(containerGroup),
|
|
3296
3325
|
hasActive: containerContainsActiveSession(containerGroup),
|
|
3297
|
-
overlayNode:
|
|
3326
|
+
overlayNode: containerMenu,
|
|
3298
3327
|
onToggle: function (expanded) {
|
|
3299
3328
|
setSidebarContainerExpanded(containerGroup.containerName, expanded);
|
|
3300
3329
|
},
|
|
3301
3330
|
children: (Array.isArray(containerGroup.sessions) ? containerGroup.sessions : []).map(function (session) {
|
|
3331
|
+
const agentTitle = session.agentName || session.name;
|
|
3302
3332
|
return {
|
|
3303
3333
|
kind: 'agent',
|
|
3304
|
-
title:
|
|
3334
|
+
title: agentTitle,
|
|
3305
3335
|
meta: formatDateTime(session.updatedAt) || '暂无更新',
|
|
3306
3336
|
className: historyClassName,
|
|
3307
3337
|
active: state.active === session.name,
|
|
3308
|
-
sessionName: session.name
|
|
3338
|
+
sessionName: session.name,
|
|
3339
|
+
overlayNode: createTreeNodeMenu([
|
|
3340
|
+
{
|
|
3341
|
+
label: '删除 AGENT',
|
|
3342
|
+
danger: true,
|
|
3343
|
+
onClick: function () {
|
|
3344
|
+
removeAgentSessionByName(session.name, agentTitle);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
])
|
|
3309
3348
|
};
|
|
3310
3349
|
})
|
|
3311
3350
|
};
|
|
@@ -3314,7 +3353,7 @@
|
|
|
3314
3353
|
});
|
|
3315
3354
|
}
|
|
3316
3355
|
|
|
3317
|
-
function renderSessionTreeNodes(nodes, parentNode, ancestorHasNext
|
|
3356
|
+
function renderSessionTreeNodes(nodes, parentNode, ancestorHasNext) {
|
|
3318
3357
|
(Array.isArray(nodes) ? nodes : []).forEach(function (node, index) {
|
|
3319
3358
|
const isLastSibling = index === nodes.length - 1;
|
|
3320
3359
|
const item = createTreeItem({
|
|
@@ -3336,8 +3375,6 @@
|
|
|
3336
3375
|
|
|
3337
3376
|
if (node.kind === 'agent') {
|
|
3338
3377
|
item.button.dataset.sessionName = node.sessionName || '';
|
|
3339
|
-
item.button.style.setProperty('--item-index', String(itemCounter.value));
|
|
3340
|
-
itemCounter.value += 1;
|
|
3341
3378
|
state.sessionNodeMap.set(node.sessionName, item.button);
|
|
3342
3379
|
item.button.addEventListener('click', function () {
|
|
3343
3380
|
handleSessionItemClick(node.sessionName || '');
|
|
@@ -3355,7 +3392,7 @@
|
|
|
3355
3392
|
childrenNode.className = `tree-node-children tree-node-children-${node.kind}`;
|
|
3356
3393
|
childrenNode.setAttribute('role', 'group');
|
|
3357
3394
|
childrenNode.hidden = !node.expanded;
|
|
3358
|
-
renderSessionTreeNodes(node.children || [], childrenNode, ancestorHasNext.concat(!isLastSibling)
|
|
3395
|
+
renderSessionTreeNodes(node.children || [], childrenNode, ancestorHasNext.concat(!isLastSibling));
|
|
3359
3396
|
block.appendChild(childrenNode);
|
|
3360
3397
|
parentNode.appendChild(block);
|
|
3361
3398
|
|
|
@@ -3451,8 +3488,7 @@
|
|
|
3451
3488
|
|
|
3452
3489
|
const grouped = groupSessionsByDirectory(state.sessions);
|
|
3453
3490
|
const treeNodes = buildSessionTreeNodes(grouped);
|
|
3454
|
-
|
|
3455
|
-
renderSessionTreeNodes(treeNodes, sessionList, [], itemCounter);
|
|
3491
|
+
renderSessionTreeNodes(treeNodes, sessionList, []);
|
|
3456
3492
|
updateSidebarActiveSelection();
|
|
3457
3493
|
|
|
3458
3494
|
scrollActiveSessionIntoView();
|
|
@@ -3493,10 +3529,12 @@
|
|
|
3493
3529
|
}
|
|
3494
3530
|
|
|
3495
3531
|
function getMessageRenderKey(msg, index) {
|
|
3532
|
+
const pairedTrace = msg && msg.pairedTrace ? msg.pairedTrace : null;
|
|
3533
|
+
const tracePart = pairedTrace ? `|paired:${String(pairedTrace.content || '')}` : '';
|
|
3496
3534
|
if (msg && msg.id && msg.streamingReply) {
|
|
3497
3535
|
const content = msg.content ? String(msg.content) : '';
|
|
3498
3536
|
const timestamp = msg.timestamp ? String(msg.timestamp) : '';
|
|
3499
|
-
return `id:${msg.id}|streaming|${timestamp}|${content}`;
|
|
3537
|
+
return `id:${msg.id}|streaming|${timestamp}|${content}${tracePart}`;
|
|
3500
3538
|
}
|
|
3501
3539
|
if (msg && msg.id && msg.streamTrace) {
|
|
3502
3540
|
const content = msg.content ? String(msg.content) : '';
|
|
@@ -3505,7 +3543,7 @@
|
|
|
3505
3543
|
return `id:${msg.id}|trace|${timestamp}|${content}|${running}`;
|
|
3506
3544
|
}
|
|
3507
3545
|
if (msg && msg.id) {
|
|
3508
|
-
return `id:${msg.id}`;
|
|
3546
|
+
return `id:${msg.id}${tracePart}`;
|
|
3509
3547
|
}
|
|
3510
3548
|
const role = msg && msg.role ? String(msg.role) : '';
|
|
3511
3549
|
const mode = msg && msg.mode ? String(msg.mode) : '';
|
|
@@ -3513,7 +3551,7 @@
|
|
|
3513
3551
|
const exitCode = msg && typeof msg.exitCode === 'number' ? String(msg.exitCode) : '';
|
|
3514
3552
|
const pending = msg && msg.pending ? '1' : '0';
|
|
3515
3553
|
const content = msg && msg.content ? String(msg.content) : '';
|
|
3516
|
-
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}`;
|
|
3554
|
+
return `idx:${index}|${role}|${mode}|${timestamp}|${exitCode}|${pending}|${content}${tracePart}`;
|
|
3517
3555
|
}
|
|
3518
3556
|
|
|
3519
3557
|
function resolveMessageOrigin(msg) {
|
|
@@ -3550,13 +3588,12 @@
|
|
|
3550
3588
|
const bubble = document.createElement('div');
|
|
3551
3589
|
bubble.className = 'bubble';
|
|
3552
3590
|
|
|
3591
|
+
if (msg && msg.pairedTrace) {
|
|
3592
|
+
appendStructuredTraceContent(bubble, msg.pairedTrace);
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3553
3595
|
const isStreamingReply = Boolean(msg && msg.streamingReply);
|
|
3554
|
-
const shouldRenderStructuredTrace = Boolean(
|
|
3555
|
-
msg
|
|
3556
|
-
&& msg.streamTrace
|
|
3557
|
-
&& Array.isArray(msg.traceEvents)
|
|
3558
|
-
&& msg.traceEvents.length
|
|
3559
|
-
);
|
|
3596
|
+
const shouldRenderStructuredTrace = Boolean(msg && msg.streamTrace);
|
|
3560
3597
|
const shouldRenderMarkdown = Boolean(!msg.streamTrace && !msg.streamingReply && markdownRenderer && markdownRenderer.shouldRenderMessage(msg));
|
|
3561
3598
|
if (isStreamingReply) {
|
|
3562
3599
|
bubble.classList.add('streaming-reply');
|
|
@@ -3596,7 +3633,7 @@
|
|
|
3596
3633
|
if (renderedMarkdown) {
|
|
3597
3634
|
markdownNode.innerHTML = renderedMarkdown;
|
|
3598
3635
|
bubble.appendChild(markdownNode);
|
|
3599
|
-
appendMessageCopyActions(
|
|
3636
|
+
appendMessageCopyActions(bubble, [
|
|
3600
3637
|
{ label: '复制文本', getText: function () { return markdownNode.innerText || markdownNode.textContent || ''; } },
|
|
3601
3638
|
{ label: '复制 Markdown', getText: function () { return msg.content; } }
|
|
3602
3639
|
]);
|
|
@@ -3606,7 +3643,7 @@
|
|
|
3606
3643
|
} else {
|
|
3607
3644
|
appendPlainMessageContent(bubble, msg.content);
|
|
3608
3645
|
if (msg.role === 'user') {
|
|
3609
|
-
appendMessageCopyActions(
|
|
3646
|
+
appendMessageCopyActions(bubble, [
|
|
3610
3647
|
{ label: '复制', getText: function () { return msg.content; } }
|
|
3611
3648
|
]);
|
|
3612
3649
|
}
|
|
@@ -3617,7 +3654,8 @@
|
|
|
3617
3654
|
return row;
|
|
3618
3655
|
}
|
|
3619
3656
|
|
|
3620
|
-
function renderMessages(
|
|
3657
|
+
function renderMessages(rawMessages, options) {
|
|
3658
|
+
const messages = window.ManyoyoChatBehavior.mergeTraceIntoReply(rawMessages);
|
|
3621
3659
|
const renderOptions = options && typeof options === 'object' ? options : {};
|
|
3622
3660
|
const stickToBottom = renderOptions.stickToBottom === true || isMessagesNearBottom(40);
|
|
3623
3661
|
|
|
@@ -4149,15 +4187,9 @@
|
|
|
4149
4187
|
});
|
|
4150
4188
|
}
|
|
4151
4189
|
|
|
4152
|
-
if (openCreateMenuBtn) {
|
|
4153
|
-
openCreateMenuBtn.addEventListener('click', function () {
|
|
4154
|
-
closeMobileActionsMenu();
|
|
4155
|
-
openCreateModal();
|
|
4156
|
-
});
|
|
4157
|
-
}
|
|
4158
|
-
|
|
4159
4190
|
if (agentTemplateBtn) {
|
|
4160
4191
|
agentTemplateBtn.addEventListener('click', function () {
|
|
4192
|
+
closeComposerOptionsMenu();
|
|
4161
4193
|
openAgentTemplateModal().catch(function (e) {
|
|
4162
4194
|
alert(e && e.message ? e.message : '加载 Agent 模板失败');
|
|
4163
4195
|
});
|
|
@@ -4349,10 +4381,29 @@
|
|
|
4349
4381
|
composer.addEventListener('submit', async function (event) {
|
|
4350
4382
|
event.preventDefault();
|
|
4351
4383
|
if (!state.active) return;
|
|
4352
|
-
if (state.sending) return;
|
|
4353
|
-
if (state.loadingSessions || state.loadingMessages) return;
|
|
4354
4384
|
if (state.activeTab !== 'activity') return;
|
|
4385
|
+
|
|
4355
4386
|
const mode = state.mode === 'agent' ? 'agent' : 'command';
|
|
4387
|
+
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
4388
|
+
if (mode === 'agent' && activeAgentRunning) {
|
|
4389
|
+
if (state.agentRun.stopping) return;
|
|
4390
|
+
state.agentRun.stopping = true;
|
|
4391
|
+
syncUi();
|
|
4392
|
+
try {
|
|
4393
|
+
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4394
|
+
method: 'POST',
|
|
4395
|
+
body: JSON.stringify({})
|
|
4396
|
+
});
|
|
4397
|
+
} catch (e) {
|
|
4398
|
+
alert(e.message);
|
|
4399
|
+
state.agentRun.stopping = false;
|
|
4400
|
+
syncUi();
|
|
4401
|
+
}
|
|
4402
|
+
return;
|
|
4403
|
+
}
|
|
4404
|
+
|
|
4405
|
+
if (state.sending) return;
|
|
4406
|
+
if (state.loadingSessions || state.loadingMessages) return;
|
|
4356
4407
|
if (mode === 'agent' && !isActiveAgentEnabled()) {
|
|
4357
4408
|
syncUi();
|
|
4358
4409
|
return;
|
|
@@ -4420,40 +4471,9 @@
|
|
|
4420
4471
|
} finally {
|
|
4421
4472
|
state.sending = false;
|
|
4422
4473
|
syncUi();
|
|
4423
|
-
commandInput.focus();
|
|
4424
4474
|
}
|
|
4425
4475
|
});
|
|
4426
4476
|
|
|
4427
|
-
if (stopBtn) {
|
|
4428
|
-
stopBtn.addEventListener('click', async function () {
|
|
4429
|
-
if (!state.active || !isAgentRunActiveForSession(state.active) || state.agentRun.stopping) {
|
|
4430
|
-
return;
|
|
4431
|
-
}
|
|
4432
|
-
state.agentRun.stopping = true;
|
|
4433
|
-
syncUi();
|
|
4434
|
-
try {
|
|
4435
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent/stop', {
|
|
4436
|
-
method: 'POST',
|
|
4437
|
-
body: JSON.stringify({})
|
|
4438
|
-
});
|
|
4439
|
-
} catch (e) {
|
|
4440
|
-
alert(e.message);
|
|
4441
|
-
state.agentRun.stopping = false;
|
|
4442
|
-
syncUi();
|
|
4443
|
-
}
|
|
4444
|
-
});
|
|
4445
|
-
}
|
|
4446
|
-
|
|
4447
|
-
if (composer) {
|
|
4448
|
-
composer.addEventListener('focusin', syncComposerExpanded);
|
|
4449
|
-
composer.addEventListener('focusout', function () {
|
|
4450
|
-
// 延后到下一个宏任务再判断,让浏览器先把焦点落到新的目标元素上
|
|
4451
|
-
// (比如 composer 内的 CLI/Agent 按钮),避免过早收起导致点击落空。
|
|
4452
|
-
window.setTimeout(syncComposerExpanded, 0);
|
|
4453
|
-
});
|
|
4454
|
-
}
|
|
4455
|
-
commandInput.addEventListener('input', syncComposerExpanded);
|
|
4456
|
-
|
|
4457
4477
|
commandInput.addEventListener('keydown', function (event) {
|
|
4458
4478
|
if (event.key !== 'Enter' || event.isComposing) {
|
|
4459
4479
|
return;
|
|
@@ -4476,6 +4496,7 @@
|
|
|
4476
4496
|
activityCommandBtn.addEventListener('click', function () {
|
|
4477
4497
|
state.mode = 'command';
|
|
4478
4498
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4499
|
+
closeComposerOptionsMenu();
|
|
4479
4500
|
syncUi();
|
|
4480
4501
|
commandInput.focus();
|
|
4481
4502
|
});
|
|
@@ -4485,11 +4506,18 @@
|
|
|
4485
4506
|
activityAgentBtn.addEventListener('click', function () {
|
|
4486
4507
|
state.mode = 'agent';
|
|
4487
4508
|
renderMessages(state.messages, { forceFullRender: true });
|
|
4509
|
+
closeComposerOptionsMenu();
|
|
4488
4510
|
syncUi();
|
|
4489
4511
|
commandInput.focus();
|
|
4490
4512
|
});
|
|
4491
4513
|
}
|
|
4492
4514
|
|
|
4515
|
+
if (composerOptionsToggle) {
|
|
4516
|
+
composerOptionsToggle.addEventListener('click', function () {
|
|
4517
|
+
setComposerOptionsMenu(!state.composerOptionsOpen);
|
|
4518
|
+
});
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4493
4521
|
if (viewActivityBtn) {
|
|
4494
4522
|
viewActivityBtn.addEventListener('click', function () {
|
|
4495
4523
|
closeWorkspaceSwitcherMenu();
|
|
@@ -4533,11 +4561,6 @@
|
|
|
4533
4561
|
});
|
|
4534
4562
|
}
|
|
4535
4563
|
|
|
4536
|
-
refreshBtn.addEventListener('click', function () {
|
|
4537
|
-
closeMobileActionsMenu();
|
|
4538
|
-
loadSessions(state.active).catch(function (e) { alert(e.message); });
|
|
4539
|
-
});
|
|
4540
|
-
|
|
4541
4564
|
const TERM_KEY_SEQUENCES = {
|
|
4542
4565
|
esc: '\x1b',
|
|
4543
4566
|
tab: '\x09',
|
|
@@ -4579,12 +4602,6 @@
|
|
|
4579
4602
|
});
|
|
4580
4603
|
}
|
|
4581
4604
|
|
|
4582
|
-
if (mobileActionsToggle) {
|
|
4583
|
-
mobileActionsToggle.addEventListener('click', function () {
|
|
4584
|
-
setMobileActionsMenu(!state.mobileActionsOpen);
|
|
4585
|
-
});
|
|
4586
|
-
}
|
|
4587
|
-
|
|
4588
4605
|
if (workspaceSwitcherToggle) {
|
|
4589
4606
|
workspaceSwitcherToggle.addEventListener('click', function () {
|
|
4590
4607
|
setWorkspaceSwitcherMenu(!state.workspaceSwitcherOpen);
|
|
@@ -4603,18 +4620,6 @@
|
|
|
4603
4620
|
});
|
|
4604
4621
|
}
|
|
4605
4622
|
|
|
4606
|
-
if (addAgentBtn) {
|
|
4607
|
-
addAgentBtn.addEventListener('click', function () {
|
|
4608
|
-
const activeSession = getActiveSession();
|
|
4609
|
-
const targetContainer = activeSession ? getSessionContainerName(activeSession) : '';
|
|
4610
|
-
if (!targetContainer) {
|
|
4611
|
-
return;
|
|
4612
|
-
}
|
|
4613
|
-
closeMobileActionsMenu();
|
|
4614
|
-
createAgentSession(targetContainer);
|
|
4615
|
-
});
|
|
4616
|
-
}
|
|
4617
|
-
|
|
4618
4623
|
if (configModal) {
|
|
4619
4624
|
configModal.addEventListener('click', function (event) {
|
|
4620
4625
|
if (event.target === configModal && !state.configSaving) {
|
|
@@ -4682,17 +4687,19 @@
|
|
|
4682
4687
|
if (event.key === 'Escape' && state.mobileSidebarOpen) {
|
|
4683
4688
|
closeMobileSessionPanel();
|
|
4684
4689
|
}
|
|
4685
|
-
if (event.key === 'Escape' && state.mobileActionsOpen) {
|
|
4686
|
-
closeMobileActionsMenu();
|
|
4687
|
-
}
|
|
4688
4690
|
if (event.key === 'Escape' && state.workspaceSwitcherOpen) {
|
|
4689
4691
|
closeWorkspaceSwitcherMenu();
|
|
4690
4692
|
}
|
|
4693
|
+
if (event.key === 'Escape' && state.composerOptionsOpen) {
|
|
4694
|
+
closeComposerOptionsMenu();
|
|
4695
|
+
}
|
|
4696
|
+
if (event.key === 'Escape' && openTreeNodeMenu) {
|
|
4697
|
+
closeOpenTreeNodeMenu();
|
|
4698
|
+
}
|
|
4691
4699
|
});
|
|
4692
4700
|
|
|
4693
4701
|
function onLayoutMediaChange() {
|
|
4694
4702
|
setMobileSessionPanel(state.mobileSidebarOpen);
|
|
4695
|
-
setMobileActionsMenu(state.mobileActionsOpen);
|
|
4696
4703
|
if (state.activeTab === 'terminal' && state.terminal.terminalReady) {
|
|
4697
4704
|
scheduleTerminalFit(false);
|
|
4698
4705
|
}
|
|
@@ -4736,64 +4743,22 @@
|
|
|
4736
4743
|
|
|
4737
4744
|
document.addEventListener('click', function (event) {
|
|
4738
4745
|
const target = event.target;
|
|
4739
|
-
if (state.mobileActionsOpen) {
|
|
4740
|
-
if (mobileActionsToggle && mobileActionsToggle.contains(target)) return;
|
|
4741
|
-
if (headerActions && headerActions.contains(target)) return;
|
|
4742
|
-
closeMobileActionsMenu();
|
|
4743
|
-
}
|
|
4744
4746
|
if (state.workspaceSwitcherOpen) {
|
|
4745
4747
|
if (workspaceSwitcherToggle && workspaceSwitcherToggle.contains(target)) return;
|
|
4746
4748
|
if (workspaceSwitcherPanel && workspaceSwitcherPanel.contains(target)) return;
|
|
4747
4749
|
closeWorkspaceSwitcherMenu();
|
|
4748
4750
|
}
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
closeMobileActionsMenu();
|
|
4754
|
-
const activeSession = getActiveSession();
|
|
4755
|
-
const targetContainer = activeSession && activeSession.containerName ? activeSession.containerName : state.active;
|
|
4756
|
-
const yes = confirm('确认删除容器 ' + targetContainer + ' ?');
|
|
4757
|
-
if (!yes) return;
|
|
4758
|
-
try {
|
|
4759
|
-
const current = state.active;
|
|
4760
|
-
if (state.terminal.sessionName === current && (state.terminal.connected || state.terminal.connecting)) {
|
|
4761
|
-
disconnectTerminal('容器删除,终端已断开', true);
|
|
4762
|
-
}
|
|
4763
|
-
await api('/api/sessions/' + encodeURIComponent(current) + '/remove', {
|
|
4764
|
-
method: 'POST'
|
|
4765
|
-
});
|
|
4766
|
-
await loadSessions(current);
|
|
4767
|
-
} catch (e) {
|
|
4768
|
-
alert(e.message);
|
|
4751
|
+
if (state.composerOptionsOpen) {
|
|
4752
|
+
if (composerOptionsToggle && composerOptionsToggle.contains(target)) return;
|
|
4753
|
+
if (composerOptionsPanel && composerOptionsPanel.contains(target)) return;
|
|
4754
|
+
closeComposerOptionsMenu();
|
|
4769
4755
|
}
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
removeAllBtn.addEventListener('click', async function () {
|
|
4773
|
-
if (!state.active) return;
|
|
4774
|
-
closeMobileActionsMenu();
|
|
4775
|
-
const activeSession = getActiveSession();
|
|
4776
|
-
const targetAgent = activeSession && activeSession.agentName ? activeSession.agentName : state.active;
|
|
4777
|
-
const yes = confirm('确认删除 AGENT ' + targetAgent + ' ?');
|
|
4778
|
-
if (!yes) return;
|
|
4779
|
-
try {
|
|
4780
|
-
const current = state.active;
|
|
4781
|
-
const targetContainerName = activeSession && activeSession.containerName ? activeSession.containerName : '';
|
|
4782
|
-
const fallbackSessionName = findPreferredSessionNameAfterRemoval(state.sessions, current);
|
|
4783
|
-
await api('/api/sessions/' + encodeURIComponent(state.active) + '/remove-with-history', {
|
|
4784
|
-
method: 'POST'
|
|
4785
|
-
});
|
|
4786
|
-
await refreshSessions({
|
|
4787
|
-
preferredName: fallbackSessionName || '',
|
|
4788
|
-
preferredContainerName: targetContainerName,
|
|
4789
|
-
withLoading: true,
|
|
4790
|
-
reloadMessages: true
|
|
4791
|
-
});
|
|
4792
|
-
} catch (e) {
|
|
4793
|
-
alert(e.message);
|
|
4756
|
+
if (openTreeNodeMenu && !openTreeNodeMenu.wrap.contains(target)) {
|
|
4757
|
+
closeOpenTreeNodeMenu();
|
|
4794
4758
|
}
|
|
4795
4759
|
});
|
|
4796
4760
|
|
|
4761
|
+
|
|
4797
4762
|
if (externalLinkCancelBtn) {
|
|
4798
4763
|
externalLinkCancelBtn.addEventListener('click', function () {
|
|
4799
4764
|
closeExternalLinkModalView();
|