@xcanwin/manyoyo 5.7.14 → 5.8.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 +211 -233
- package/lib/web/frontend/app.html +30 -2
- package/lib/web/frontend/app.js +485 -221
- package/lib/web/server.js +207 -22
- package/package.json +1 -1
package/lib/web/frontend/app.js
CHANGED
|
@@ -50,14 +50,17 @@
|
|
|
50
50
|
mobileActionsOpen: false,
|
|
51
51
|
configModalOpen: false,
|
|
52
52
|
createModalOpen: false,
|
|
53
|
+
agentTemplateModalOpen: false,
|
|
53
54
|
configLoading: false,
|
|
54
55
|
configSaving: false,
|
|
55
56
|
createLoading: false,
|
|
56
57
|
createSubmitting: false,
|
|
58
|
+
agentTemplateSaving: false,
|
|
57
59
|
configSnapshot: null,
|
|
58
60
|
sessionDetail: null,
|
|
59
61
|
sessionDetailError: '',
|
|
60
62
|
sessionDetailRequestId: 0,
|
|
63
|
+
agentTemplateError: '',
|
|
61
64
|
createAgentPromptAuto: false,
|
|
62
65
|
createContainerPathBase: '',
|
|
63
66
|
createDefaults: null,
|
|
@@ -167,6 +170,8 @@
|
|
|
167
170
|
const activeMeta = document.getElementById('activeMeta');
|
|
168
171
|
const activityCommandBtn = document.getElementById('activityCommandBtn');
|
|
169
172
|
const activityAgentBtn = document.getElementById('activityAgentBtn');
|
|
173
|
+
const agentTemplateBtn = document.getElementById('agentTemplateBtn');
|
|
174
|
+
const activityModelChip = document.getElementById('activityModelChip');
|
|
170
175
|
const messagesNode = document.getElementById('messages');
|
|
171
176
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
172
177
|
const detailPanel = document.getElementById('detailPanel');
|
|
@@ -182,6 +187,15 @@
|
|
|
182
187
|
const sendState = document.getElementById('sendState');
|
|
183
188
|
const sendBtn = document.getElementById('sendBtn');
|
|
184
189
|
const stopBtn = document.getElementById('stopBtn');
|
|
190
|
+
const agentTemplateModal = document.getElementById('agentTemplateModal');
|
|
191
|
+
const agentTemplateTip = document.getElementById('agentTemplateTip');
|
|
192
|
+
const containerAgentPromptEditor = document.getElementById('containerAgentPromptEditor');
|
|
193
|
+
const agentTemplateOverrideGroup = document.getElementById('agentTemplateOverrideGroup');
|
|
194
|
+
const agentPromptOverrideEditor = document.getElementById('agentPromptOverrideEditor');
|
|
195
|
+
const agentTemplateError = document.getElementById('agentTemplateError');
|
|
196
|
+
const agentTemplateCancelBtn = document.getElementById('agentTemplateCancelBtn');
|
|
197
|
+
const agentTemplateResetBtn = document.getElementById('agentTemplateResetBtn');
|
|
198
|
+
const agentTemplateSaveBtn = document.getElementById('agentTemplateSaveBtn');
|
|
185
199
|
const refreshBtn = document.getElementById('refreshBtn');
|
|
186
200
|
const removeBtn = document.getElementById('removeBtn');
|
|
187
201
|
const removeAllBtn = document.getElementById('removeAllBtn');
|
|
@@ -192,6 +206,8 @@
|
|
|
192
206
|
const TERMINAL_MIN_ROWS = 12;
|
|
193
207
|
const TERMINAL_DEFAULT_COLS = 120;
|
|
194
208
|
const TERMINAL_DEFAULT_ROWS = 36;
|
|
209
|
+
const WEB_SESSION_KEY_SEPARATOR = '~';
|
|
210
|
+
const WEB_DEFAULT_AGENT_ID = 'default';
|
|
195
211
|
const YOLO_COMMAND_MAP = {
|
|
196
212
|
claude: 'IS_SANDBOX=1 claude --dangerously-skip-permissions',
|
|
197
213
|
cc: 'IS_SANDBOX=1 claude --dangerously-skip-permissions',
|
|
@@ -1055,6 +1071,133 @@
|
|
|
1055
1071
|
}) || null;
|
|
1056
1072
|
}
|
|
1057
1073
|
|
|
1074
|
+
function parseSessionKey(sessionName) {
|
|
1075
|
+
const raw = String(sessionName || '').trim();
|
|
1076
|
+
if (!raw) {
|
|
1077
|
+
return {
|
|
1078
|
+
containerName: '',
|
|
1079
|
+
agentId: WEB_DEFAULT_AGENT_ID
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
const separatorIndex = raw.indexOf(WEB_SESSION_KEY_SEPARATOR);
|
|
1083
|
+
if (separatorIndex === -1) {
|
|
1084
|
+
return {
|
|
1085
|
+
containerName: raw,
|
|
1086
|
+
agentId: WEB_DEFAULT_AGENT_ID
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
return {
|
|
1090
|
+
containerName: raw.slice(0, separatorIndex),
|
|
1091
|
+
agentId: raw.slice(separatorIndex + 1) || WEB_DEFAULT_AGENT_ID
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function isActiveAgentOverrideEditable() {
|
|
1096
|
+
const sessionRef = parseSessionKey(state.active);
|
|
1097
|
+
return Boolean(state.active && sessionRef.agentId && sessionRef.agentId !== WEB_DEFAULT_AGENT_ID);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
function showAgentTemplateError(message) {
|
|
1101
|
+
state.agentTemplateError = String(message || '').trim();
|
|
1102
|
+
if (!agentTemplateError) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
agentTemplateError.hidden = !state.agentTemplateError;
|
|
1106
|
+
agentTemplateError.textContent = state.agentTemplateError;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
function fillAgentTemplateForm(detail) {
|
|
1110
|
+
const currentDetail = detail && typeof detail === 'object' ? detail : {};
|
|
1111
|
+
if (containerAgentPromptEditor) {
|
|
1112
|
+
containerAgentPromptEditor.value = currentDetail.containerAgentPromptCommand || '';
|
|
1113
|
+
}
|
|
1114
|
+
if (agentPromptOverrideEditor) {
|
|
1115
|
+
agentPromptOverrideEditor.value = currentDetail.agentPromptCommandOverride || '';
|
|
1116
|
+
}
|
|
1117
|
+
if (agentTemplateOverrideGroup) {
|
|
1118
|
+
agentTemplateOverrideGroup.hidden = !isActiveAgentOverrideEditable();
|
|
1119
|
+
}
|
|
1120
|
+
if (agentTemplateTip) {
|
|
1121
|
+
const sessionName = currentDetail.agentName || state.active || '当前会话';
|
|
1122
|
+
const sourceMap = {
|
|
1123
|
+
agent: '当前 AGENT 覆盖',
|
|
1124
|
+
container: '容器默认模板',
|
|
1125
|
+
inferred: '从容器启动命令推导',
|
|
1126
|
+
none: '未配置'
|
|
1127
|
+
};
|
|
1128
|
+
const sourceLabel = sourceMap[currentDetail.agentPromptSource] || '未配置';
|
|
1129
|
+
const effectiveTemplate = currentDetail.agentPromptCommand || '—';
|
|
1130
|
+
agentTemplateTip.textContent = `${sessionName} · 当前生效来源:${sourceLabel} · 生效模板:${effectiveTemplate}`;
|
|
1131
|
+
}
|
|
1132
|
+
showAgentTemplateError('');
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
async function ensureActiveSessionDetail() {
|
|
1136
|
+
if (!state.active) {
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
if (state.sessionDetail && state.active === (state.sessionDetail.name || state.active)) {
|
|
1140
|
+
return state.sessionDetail;
|
|
1141
|
+
}
|
|
1142
|
+
await loadSessionDetailForSession(state.active);
|
|
1143
|
+
return state.sessionDetail;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
async function openAgentTemplateModal() {
|
|
1147
|
+
if (!state.active || state.agentTemplateSaving) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1150
|
+
const detail = await ensureActiveSessionDetail();
|
|
1151
|
+
if (!detail) {
|
|
1152
|
+
alert(state.sessionDetailError || '当前会话详情暂时不可用');
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
state.agentTemplateModalOpen = true;
|
|
1156
|
+
fillAgentTemplateForm(detail);
|
|
1157
|
+
syncUi();
|
|
1158
|
+
if (containerAgentPromptEditor) {
|
|
1159
|
+
containerAgentPromptEditor.focus();
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
function closeAgentTemplateModal() {
|
|
1164
|
+
state.agentTemplateModalOpen = false;
|
|
1165
|
+
showAgentTemplateError('');
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
function resetAgentTemplateModal() {
|
|
1169
|
+
fillAgentTemplateForm(state.sessionDetail || {});
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
async function saveAgentTemplateModal() {
|
|
1173
|
+
if (!state.active || state.agentTemplateSaving) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
state.agentTemplateSaving = true;
|
|
1177
|
+
showAgentTemplateError('');
|
|
1178
|
+
syncUi();
|
|
1179
|
+
try {
|
|
1180
|
+
const payload = {
|
|
1181
|
+
containerAgentPromptCommand: containerAgentPromptEditor ? String(containerAgentPromptEditor.value || '').trim() : ''
|
|
1182
|
+
};
|
|
1183
|
+
if (isActiveAgentOverrideEditable() && agentPromptOverrideEditor) {
|
|
1184
|
+
payload.agentPromptCommandOverride = String(agentPromptOverrideEditor.value || '').trim();
|
|
1185
|
+
}
|
|
1186
|
+
const data = await api('/api/sessions/' + encodeURIComponent(state.active) + '/agent-template', {
|
|
1187
|
+
method: 'PUT',
|
|
1188
|
+
body: JSON.stringify(payload)
|
|
1189
|
+
});
|
|
1190
|
+
state.sessionDetail = data && data.detail ? data.detail : state.sessionDetail;
|
|
1191
|
+
await refreshSessionsSilent({ preferredName: state.active });
|
|
1192
|
+
closeAgentTemplateModal();
|
|
1193
|
+
} catch (e) {
|
|
1194
|
+
showAgentTemplateError(e && e.message ? e.message : '保存失败');
|
|
1195
|
+
} finally {
|
|
1196
|
+
state.agentTemplateSaving = false;
|
|
1197
|
+
syncUi();
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1058
1201
|
function isAgentRunActiveForSession(sessionName) {
|
|
1059
1202
|
return Boolean(
|
|
1060
1203
|
state.agentRun
|
|
@@ -1078,6 +1221,24 @@
|
|
|
1078
1221
|
return Boolean(active && active.agentEnabled);
|
|
1079
1222
|
}
|
|
1080
1223
|
|
|
1224
|
+
function resolveToolbarCliLabel() {
|
|
1225
|
+
const activeSession = getActiveSession();
|
|
1226
|
+
const detail = state.sessionDetail && state.active ? state.sessionDetail : null;
|
|
1227
|
+
const agentProgram = String(
|
|
1228
|
+
(detail && detail.agentProgram)
|
|
1229
|
+
|| (activeSession && activeSession.agentProgram)
|
|
1230
|
+
|| ''
|
|
1231
|
+
).trim();
|
|
1232
|
+
return agentProgram || '未配置';
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
function resolveToolbarModelLabel() {
|
|
1236
|
+
if (!state.active) {
|
|
1237
|
+
return '—';
|
|
1238
|
+
}
|
|
1239
|
+
return '自动';
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1081
1242
|
function buildActiveMeta(session) {
|
|
1082
1243
|
if (!session) {
|
|
1083
1244
|
return '会话不可用';
|
|
@@ -1566,6 +1727,13 @@
|
|
|
1566
1727
|
let resumeStatusDetail = detail.resumeSupported
|
|
1567
1728
|
? '支持 resume,但当前会话还没有最近一次执行记录。'
|
|
1568
1729
|
: '当前 Agent 程序或模板不支持 resume。';
|
|
1730
|
+
const templateSourceMap = {
|
|
1731
|
+
agent: '当前 AGENT 覆盖',
|
|
1732
|
+
container: '容器默认模板',
|
|
1733
|
+
inferred: '从启动命令推导',
|
|
1734
|
+
none: '未配置'
|
|
1735
|
+
};
|
|
1736
|
+
const templateSourceLabel = templateSourceMap[detail.agentPromptSource] || '未配置';
|
|
1569
1737
|
if (detail.lastResumeOk === true) {
|
|
1570
1738
|
resumeStatusValue = '最近成功';
|
|
1571
1739
|
resumeStatusTone = 'ok';
|
|
@@ -1596,6 +1764,7 @@
|
|
|
1596
1764
|
commandEntries.push({ label: '启动命令', value: applied.defaultCommand || '—' });
|
|
1597
1765
|
}
|
|
1598
1766
|
commandEntries.push({ label: 'Agent 模板', value: detail.agentPromptCommand || '—' });
|
|
1767
|
+
commandEntries.push({ label: '模板来源', value: templateSourceLabel });
|
|
1599
1768
|
commandEntries.push({ label: 'yolo', value: applied.yolo || '—' });
|
|
1600
1769
|
|
|
1601
1770
|
if (detailSummary) {
|
|
@@ -1611,6 +1780,7 @@
|
|
|
1611
1780
|
renderKeyValueCard(detailSummary, 'Agent 运行', [
|
|
1612
1781
|
{ label: '已启用', value: detail.agentEnabled ? '是' : '否', tone: detail.agentEnabled ? 'ok' : 'warn' },
|
|
1613
1782
|
{ label: '程序', value: detail.agentProgram || '—' },
|
|
1783
|
+
{ label: '模板来源', value: templateSourceLabel },
|
|
1614
1784
|
{ label: '支持 resume', value: detail.resumeSupported ? '是' : '否', tone: detail.resumeSupported ? 'ok' : 'warn' },
|
|
1615
1785
|
{ label: '最近 resume', value: lastResumeText },
|
|
1616
1786
|
{ label: '最近结果', value: detail.lastResumeOk == null ? '暂无' : (detail.lastResumeOk ? '成功' : '失败'), tone: detail.lastResumeOk == null ? 'info' : (detail.lastResumeOk ? 'ok' : 'danger') }
|
|
@@ -1728,6 +1898,18 @@
|
|
|
1728
1898
|
activityAgentBtn.classList.toggle('is-active', agentMode);
|
|
1729
1899
|
activityAgentBtn.setAttribute('aria-pressed', agentMode ? 'true' : 'false');
|
|
1730
1900
|
}
|
|
1901
|
+
if (agentTemplateBtn) {
|
|
1902
|
+
agentTemplateBtn.textContent = `CLI · ${resolveToolbarCliLabel()}`;
|
|
1903
|
+
agentTemplateBtn.title = state.active
|
|
1904
|
+
? '查看或修改当前会话的 CLI 模板'
|
|
1905
|
+
: '请先选择会话';
|
|
1906
|
+
}
|
|
1907
|
+
if (activityModelChip) {
|
|
1908
|
+
activityModelChip.textContent = `模型 · ${resolveToolbarModelLabel()}`;
|
|
1909
|
+
activityModelChip.title = state.active
|
|
1910
|
+
? '当前版本暂不单独配置模型,默认跟随 CLI 或容器内配置'
|
|
1911
|
+
: '请先选择会话';
|
|
1912
|
+
}
|
|
1731
1913
|
if (viewActivityBtn) viewActivityBtn.classList.toggle('is-active', activityTab);
|
|
1732
1914
|
if (viewTerminalBtn) viewTerminalBtn.classList.toggle('is-active', terminalTab);
|
|
1733
1915
|
if (viewDetailBtn) viewDetailBtn.classList.toggle('is-active', detailTab);
|
|
@@ -1764,6 +1946,9 @@
|
|
|
1764
1946
|
if (stopBtn) {
|
|
1765
1947
|
stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
|
|
1766
1948
|
}
|
|
1949
|
+
if (agentTemplateBtn) {
|
|
1950
|
+
agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
|
|
1951
|
+
}
|
|
1767
1952
|
commandInput.disabled = !activityTab || !state.active || (agentMode && !agentEnabled);
|
|
1768
1953
|
if (commandInput) {
|
|
1769
1954
|
commandInput.placeholder = agentMode
|
|
@@ -1823,9 +2008,21 @@
|
|
|
1823
2008
|
if (directoryPickerModal) {
|
|
1824
2009
|
directoryPickerModal.hidden = !state.directoryPicker.open;
|
|
1825
2010
|
}
|
|
2011
|
+
if (agentTemplateModal) {
|
|
2012
|
+
agentTemplateModal.hidden = !state.agentTemplateModalOpen;
|
|
2013
|
+
}
|
|
2014
|
+
if (agentTemplateSaveBtn) {
|
|
2015
|
+
agentTemplateSaveBtn.disabled = state.agentTemplateSaving || !state.active;
|
|
2016
|
+
}
|
|
2017
|
+
if (agentTemplateResetBtn) {
|
|
2018
|
+
agentTemplateResetBtn.disabled = state.agentTemplateSaving;
|
|
2019
|
+
}
|
|
2020
|
+
if (agentTemplateCancelBtn) {
|
|
2021
|
+
agentTemplateCancelBtn.disabled = state.agentTemplateSaving;
|
|
2022
|
+
}
|
|
1826
2023
|
document.body.classList.toggle(
|
|
1827
2024
|
'modal-open',
|
|
1828
|
-
state.configModalOpen || state.createModalOpen || state.directoryPicker.open
|
|
2025
|
+
state.configModalOpen || state.createModalOpen || state.directoryPicker.open || state.agentTemplateModalOpen
|
|
1829
2026
|
);
|
|
1830
2027
|
if (!state.active) {
|
|
1831
2028
|
sendState.textContent = '未选择会话';
|
|
@@ -2222,7 +2419,7 @@
|
|
|
2222
2419
|
}
|
|
2223
2420
|
}
|
|
2224
2421
|
}
|
|
2225
|
-
|
|
2422
|
+
updateSidebarActiveSelection();
|
|
2226
2423
|
syncUi();
|
|
2227
2424
|
Promise.all([
|
|
2228
2425
|
loadMessagesForSession(sessionName),
|
|
@@ -2310,173 +2507,244 @@
|
|
|
2310
2507
|
return (parts || []).filter(Boolean).join(' · ');
|
|
2311
2508
|
}
|
|
2312
2509
|
|
|
2313
|
-
function
|
|
2314
|
-
const opts = options && typeof options === 'object' ? options : {};
|
|
2510
|
+
function createDisclosureButton(expanded, label) {
|
|
2315
2511
|
const button = document.createElement('button');
|
|
2316
2512
|
button.type = 'button';
|
|
2317
|
-
button.className =
|
|
2318
|
-
button.
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
const kicker = document.createElement('div');
|
|
2324
|
-
kicker.className = opts.kickerClassName || 'workbench-group-kicker';
|
|
2325
|
-
kicker.textContent = opts.kicker || '';
|
|
2326
|
-
main.appendChild(kicker);
|
|
2327
|
-
|
|
2328
|
-
const title = document.createElement('div');
|
|
2329
|
-
title.className = opts.titleClassName || 'workbench-group-title';
|
|
2330
|
-
title.textContent = opts.title || '';
|
|
2331
|
-
title.title = opts.title || '';
|
|
2332
|
-
main.appendChild(title);
|
|
2333
|
-
|
|
2334
|
-
const metaText = createTreeMetaText(opts.metaParts);
|
|
2335
|
-
if (metaText) {
|
|
2336
|
-
const meta = document.createElement('div');
|
|
2337
|
-
meta.className = 'tree-toggle-meta';
|
|
2338
|
-
meta.textContent = metaText;
|
|
2339
|
-
main.appendChild(meta);
|
|
2340
|
-
}
|
|
2341
|
-
|
|
2342
|
-
const caret = document.createElement('span');
|
|
2343
|
-
caret.className = 'tree-toggle-caret';
|
|
2344
|
-
caret.setAttribute('aria-hidden', 'true');
|
|
2345
|
-
caret.textContent = '›';
|
|
2346
|
-
|
|
2347
|
-
button.appendChild(main);
|
|
2348
|
-
button.appendChild(caret);
|
|
2349
|
-
|
|
2350
|
-
if (typeof opts.onClick === 'function') {
|
|
2351
|
-
button.addEventListener('click', opts.onClick);
|
|
2352
|
-
}
|
|
2353
|
-
|
|
2513
|
+
button.className = 'disclosure-toggle';
|
|
2514
|
+
button.dataset.disclosureLabel = label || '';
|
|
2515
|
+
button.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
|
2516
|
+
button.setAttribute('aria-label', `${expanded ? '折叠' : '展开'}${label ? ` ${label}` : ''}`);
|
|
2517
|
+
button.innerHTML = '<svg viewBox="0 0 12 12" aria-hidden="true" focusable="false"><path d="M4 2.5L8 6L4 9.5"></path></svg>';
|
|
2354
2518
|
return button;
|
|
2355
2519
|
}
|
|
2356
2520
|
|
|
2357
|
-
function
|
|
2358
|
-
const
|
|
2359
|
-
|
|
2360
|
-
|
|
2521
|
+
function createTreePrefixSegment() {
|
|
2522
|
+
const segment = document.createElement('span');
|
|
2523
|
+
segment.className = 'tree-prefix-segment';
|
|
2524
|
+
segment.setAttribute('aria-hidden', 'true');
|
|
2525
|
+
return segment;
|
|
2526
|
+
}
|
|
2361
2527
|
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2528
|
+
function createTreePrefix(ancestorHasNext, isLastSibling, options) {
|
|
2529
|
+
const opts = options && typeof options === 'object' ? options : {};
|
|
2530
|
+
const prefix = document.createElement('div');
|
|
2531
|
+
prefix.className = 'tree-prefix';
|
|
2532
|
+
|
|
2533
|
+
(Array.isArray(ancestorHasNext) ? ancestorHasNext : []).forEach(function () {
|
|
2534
|
+
prefix.appendChild(createTreePrefixSegment());
|
|
2535
|
+
});
|
|
2536
|
+
|
|
2537
|
+
const branch = document.createElement('span');
|
|
2538
|
+
branch.className = `tree-prefix-branch ${isLastSibling ? 'is-last' : 'is-mid'}`;
|
|
2539
|
+
branch.setAttribute('aria-hidden', 'true');
|
|
2540
|
+
prefix.appendChild(branch);
|
|
2541
|
+
|
|
2542
|
+
let disclosure = null;
|
|
2543
|
+
let disclosureWrap = null;
|
|
2544
|
+
if (opts.expandable) {
|
|
2545
|
+
disclosure = createDisclosureButton(!!opts.expanded, opts.label || '');
|
|
2546
|
+
disclosureWrap = document.createElement('span');
|
|
2547
|
+
disclosureWrap.className = 'tree-prefix-toggle';
|
|
2548
|
+
disclosureWrap.appendChild(disclosure);
|
|
2549
|
+
prefix.appendChild(disclosureWrap);
|
|
2550
|
+
} else {
|
|
2551
|
+
const leaf = document.createElement('span');
|
|
2552
|
+
leaf.className = 'tree-prefix-leaf';
|
|
2553
|
+
leaf.setAttribute('aria-hidden', 'true');
|
|
2554
|
+
prefix.appendChild(leaf);
|
|
2370
2555
|
}
|
|
2371
2556
|
|
|
2372
|
-
return
|
|
2557
|
+
return { root: prefix, disclosure, disclosureWrap };
|
|
2373
2558
|
}
|
|
2374
2559
|
|
|
2375
|
-
function
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2560
|
+
function setDisclosureExpanded(control, expanded) {
|
|
2561
|
+
if (!control) {
|
|
2562
|
+
return;
|
|
2563
|
+
}
|
|
2564
|
+
const nextValue = expanded ? 'true' : 'false';
|
|
2565
|
+
if (control.button) {
|
|
2566
|
+
control.button.setAttribute('aria-expanded', nextValue);
|
|
2567
|
+
}
|
|
2568
|
+
if (control.disclosure) {
|
|
2569
|
+
control.disclosure.setAttribute('aria-expanded', nextValue);
|
|
2570
|
+
const label = control.disclosure.dataset.disclosureLabel || '';
|
|
2571
|
+
control.disclosure.setAttribute('aria-label', `${expanded ? '折叠' : '展开'}${label ? ` ${label}` : ''}`);
|
|
2572
|
+
}
|
|
2380
2573
|
}
|
|
2381
2574
|
|
|
2382
|
-
function
|
|
2383
|
-
const
|
|
2575
|
+
function createTreeItem(options) {
|
|
2576
|
+
const opts = options && typeof options === 'object' ? options : {};
|
|
2577
|
+
const row = document.createElement('div');
|
|
2578
|
+
row.className = `tree-node-row tree-node-row-${opts.kind || 'item'} ${opts.rowClassName || ''}`.trim();
|
|
2579
|
+
row.classList.toggle('has-active', !!opts.hasActive);
|
|
2580
|
+
row.setAttribute('role', 'none');
|
|
2581
|
+
|
|
2582
|
+
const prefixControl = createTreePrefix(opts.ancestorHasNext, !!opts.isLastSibling, {
|
|
2583
|
+
expandable: !!opts.expandable,
|
|
2584
|
+
expanded: !!opts.expanded,
|
|
2585
|
+
label: opts.disclosureLabel || opts.title || ''
|
|
2586
|
+
});
|
|
2587
|
+
row.appendChild(prefixControl.root);
|
|
2588
|
+
|
|
2384
2589
|
const button = document.createElement('button');
|
|
2385
2590
|
button.type = 'button';
|
|
2386
|
-
button.className =
|
|
2387
|
-
button.setAttribute('
|
|
2591
|
+
button.className = `tree-node-button tree-node-button-${opts.kind || 'item'} ${opts.className || ''}`.trim();
|
|
2592
|
+
button.setAttribute('role', 'treeitem');
|
|
2593
|
+
button.setAttribute('aria-level', String(opts.level || 1));
|
|
2594
|
+
if (opts.expandable) {
|
|
2595
|
+
button.setAttribute('aria-expanded', opts.expanded ? 'true' : 'false');
|
|
2596
|
+
}
|
|
2597
|
+
if (opts.kind === 'agent') {
|
|
2598
|
+
button.setAttribute('aria-selected', opts.active ? 'true' : 'false');
|
|
2599
|
+
}
|
|
2600
|
+
button.classList.toggle('active', !!opts.active);
|
|
2388
2601
|
|
|
2389
2602
|
const main = document.createElement('div');
|
|
2390
|
-
main.className = '
|
|
2391
|
-
|
|
2392
|
-
const titleRow = document.createElement('div');
|
|
2393
|
-
titleRow.className = 'container-title-row';
|
|
2394
|
-
titleRow.appendChild(createSidebarIcon('cube'));
|
|
2395
|
-
|
|
2396
|
-
const titleStack = document.createElement('div');
|
|
2397
|
-
titleStack.className = 'container-title-stack';
|
|
2398
|
-
|
|
2399
|
-
const kicker = document.createElement('div');
|
|
2400
|
-
kicker.className = 'container-card-kicker';
|
|
2401
|
-
kicker.textContent = '容器';
|
|
2603
|
+
main.className = 'tree-node-main';
|
|
2402
2604
|
|
|
2403
2605
|
const title = document.createElement('div');
|
|
2404
|
-
title.className = '
|
|
2405
|
-
title.textContent =
|
|
2406
|
-
title.title = title
|
|
2407
|
-
|
|
2408
|
-
titleStack.appendChild(kicker);
|
|
2409
|
-
titleStack.appendChild(title);
|
|
2410
|
-
titleRow.appendChild(titleStack);
|
|
2411
|
-
main.appendChild(titleRow);
|
|
2606
|
+
title.className = opts.titleClassName || 'tree-node-title';
|
|
2607
|
+
title.textContent = opts.title || '';
|
|
2608
|
+
title.title = opts.title || '';
|
|
2609
|
+
main.appendChild(title);
|
|
2412
2610
|
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
const infoText = createTreeMetaText([
|
|
2420
|
-
containerGroup && containerGroup.image ? containerGroup.image : '',
|
|
2421
|
-
formatDateTime(containerGroup && containerGroup.updatedAt) || '暂无更新'
|
|
2422
|
-
]);
|
|
2423
|
-
if (infoText) {
|
|
2424
|
-
const info = document.createElement('div');
|
|
2425
|
-
info.className = 'container-card-info';
|
|
2426
|
-
info.textContent = infoText;
|
|
2427
|
-
info.title = infoText;
|
|
2428
|
-
main.appendChild(info);
|
|
2429
|
-
}
|
|
2430
|
-
|
|
2431
|
-
const caret = document.createElement('span');
|
|
2432
|
-
caret.className = 'tree-toggle-caret';
|
|
2433
|
-
caret.setAttribute('aria-hidden', 'true');
|
|
2434
|
-
caret.textContent = '›';
|
|
2611
|
+
if (opts.meta) {
|
|
2612
|
+
const meta = document.createElement('div');
|
|
2613
|
+
meta.className = `tree-node-meta ${opts.metaClassName || ''}`.trim();
|
|
2614
|
+
meta.textContent = opts.meta;
|
|
2615
|
+
main.appendChild(meta);
|
|
2616
|
+
}
|
|
2435
2617
|
|
|
2436
2618
|
button.appendChild(main);
|
|
2437
|
-
|
|
2619
|
+
row.appendChild(button);
|
|
2620
|
+
if (opts.overlayNode) {
|
|
2621
|
+
row.appendChild(opts.overlayNode);
|
|
2622
|
+
}
|
|
2438
2623
|
|
|
2439
|
-
|
|
2624
|
+
const control = {
|
|
2625
|
+
root: row,
|
|
2626
|
+
button,
|
|
2627
|
+
disclosure: prefixControl.disclosure
|
|
2628
|
+
};
|
|
2629
|
+
setDisclosureExpanded(control, !!opts.expanded);
|
|
2630
|
+
return control;
|
|
2440
2631
|
}
|
|
2441
2632
|
|
|
2442
|
-
function
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2633
|
+
function buildSessionTreeNodes(grouped) {
|
|
2634
|
+
return (Array.isArray(grouped) ? grouped : []).map(function (directoryGroup) {
|
|
2635
|
+
return {
|
|
2636
|
+
kind: 'directory',
|
|
2637
|
+
title: directoryGroup.path,
|
|
2638
|
+
disclosureLabel: directoryGroup.path,
|
|
2639
|
+
expanded: isDirectoryExpanded(directoryGroup),
|
|
2640
|
+
hasActive: directoryContainsActiveSession(directoryGroup),
|
|
2641
|
+
onToggle: function (expanded) {
|
|
2642
|
+
setSidebarDirectoryExpanded(directoryGroup.path, expanded);
|
|
2643
|
+
},
|
|
2644
|
+
children: (Array.isArray(directoryGroup.containers) ? directoryGroup.containers : []).map(function (containerGroup) {
|
|
2645
|
+
const status = sessionStatusInfo(containerGroup && containerGroup.status);
|
|
2646
|
+
const historyClassName = status.tone === 'history' ? 'tree-node-tone-history' : '';
|
|
2647
|
+
const containerName = String(containerGroup && containerGroup.containerName ? containerGroup.containerName : '').trim() || '未命名容器';
|
|
2648
|
+
const hoverMenu = document.createElement('div');
|
|
2649
|
+
hoverMenu.className = 'tree-node-hover-menu';
|
|
2650
|
+
|
|
2651
|
+
const addAgentBtn = document.createElement('button');
|
|
2652
|
+
addAgentBtn.type = 'button';
|
|
2653
|
+
addAgentBtn.className = 'secondary tree-node-menu-item';
|
|
2654
|
+
addAgentBtn.textContent = '新建AGENT';
|
|
2655
|
+
addAgentBtn.addEventListener('click', function (event) {
|
|
2656
|
+
event.stopPropagation();
|
|
2657
|
+
createAgentSession(containerName);
|
|
2658
|
+
});
|
|
2659
|
+
hoverMenu.appendChild(addAgentBtn);
|
|
2660
|
+
|
|
2661
|
+
return {
|
|
2662
|
+
kind: 'container',
|
|
2663
|
+
title: containerName,
|
|
2664
|
+
meta: status.label,
|
|
2665
|
+
metaClassName: `tree-node-status ${status.tone}`,
|
|
2666
|
+
className: historyClassName,
|
|
2667
|
+
disclosureLabel: containerName,
|
|
2668
|
+
expanded: isContainerExpanded(containerGroup),
|
|
2669
|
+
hasActive: containerContainsActiveSession(containerGroup),
|
|
2670
|
+
overlayNode: hoverMenu,
|
|
2671
|
+
onToggle: function (expanded) {
|
|
2672
|
+
setSidebarContainerExpanded(containerGroup.containerName, expanded);
|
|
2673
|
+
},
|
|
2674
|
+
children: (Array.isArray(containerGroup.sessions) ? containerGroup.sessions : []).map(function (session) {
|
|
2675
|
+
return {
|
|
2676
|
+
kind: 'agent',
|
|
2677
|
+
title: session.agentName || session.name,
|
|
2678
|
+
meta: formatDateTime(session.updatedAt) || '暂无更新',
|
|
2679
|
+
className: historyClassName,
|
|
2680
|
+
active: state.active === session.name,
|
|
2681
|
+
sessionName: session.name
|
|
2682
|
+
};
|
|
2683
|
+
})
|
|
2684
|
+
};
|
|
2685
|
+
})
|
|
2686
|
+
};
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2457
2689
|
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2690
|
+
function renderSessionTreeNodes(nodes, parentNode, ancestorHasNext, itemCounter) {
|
|
2691
|
+
(Array.isArray(nodes) ? nodes : []).forEach(function (node, index) {
|
|
2692
|
+
const isLastSibling = index === nodes.length - 1;
|
|
2693
|
+
const item = createTreeItem({
|
|
2694
|
+
kind: node.kind,
|
|
2695
|
+
title: node.title,
|
|
2696
|
+
meta: node.meta,
|
|
2697
|
+
className: node.className,
|
|
2698
|
+
metaClassName: node.metaClassName,
|
|
2699
|
+
disclosureLabel: node.disclosureLabel,
|
|
2700
|
+
expandable: Array.isArray(node.children) && node.children.length > 0,
|
|
2701
|
+
expanded: !!node.expanded,
|
|
2702
|
+
active: !!node.active,
|
|
2703
|
+
hasActive: !!node.hasActive,
|
|
2704
|
+
level: ancestorHasNext.length + 1,
|
|
2705
|
+
ancestorHasNext: ancestorHasNext,
|
|
2706
|
+
isLastSibling: isLastSibling,
|
|
2707
|
+
overlayNode: node.overlayNode
|
|
2708
|
+
});
|
|
2461
2709
|
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2710
|
+
if (node.kind === 'agent') {
|
|
2711
|
+
item.button.dataset.sessionName = node.sessionName || '';
|
|
2712
|
+
item.button.style.setProperty('--item-index', String(itemCounter.value));
|
|
2713
|
+
itemCounter.value += 1;
|
|
2714
|
+
state.sessionNodeMap.set(node.sessionName, item.button);
|
|
2715
|
+
item.button.addEventListener('click', function () {
|
|
2716
|
+
handleSessionItemClick(node.sessionName || '');
|
|
2717
|
+
});
|
|
2718
|
+
parentNode.appendChild(item.root);
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2465
2721
|
|
|
2466
|
-
|
|
2467
|
-
|
|
2722
|
+
const block = document.createElement('section');
|
|
2723
|
+
block.className = `tree-node-block tree-node-block-${node.kind}`;
|
|
2724
|
+
block.classList.toggle('has-active', !!node.hasActive);
|
|
2725
|
+
block.appendChild(item.root);
|
|
2468
2726
|
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2727
|
+
const childrenNode = document.createElement('div');
|
|
2728
|
+
childrenNode.className = `tree-node-children tree-node-children-${node.kind}`;
|
|
2729
|
+
childrenNode.setAttribute('role', 'group');
|
|
2730
|
+
childrenNode.hidden = !node.expanded;
|
|
2731
|
+
renderSessionTreeNodes(node.children || [], childrenNode, ancestorHasNext.concat(!isLastSibling), itemCounter);
|
|
2732
|
+
block.appendChild(childrenNode);
|
|
2733
|
+
parentNode.appendChild(block);
|
|
2472
2734
|
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2735
|
+
const toggleNode = function () {
|
|
2736
|
+
const nextExpanded = childrenNode.hidden;
|
|
2737
|
+
if (typeof node.onToggle === 'function') {
|
|
2738
|
+
node.onToggle(nextExpanded);
|
|
2739
|
+
}
|
|
2740
|
+
setDisclosureExpanded(item, nextExpanded);
|
|
2741
|
+
childrenNode.hidden = !nextExpanded;
|
|
2742
|
+
};
|
|
2743
|
+
item.button.addEventListener('click', toggleNode);
|
|
2744
|
+
if (item.disclosure) {
|
|
2745
|
+
item.disclosure.addEventListener('click', toggleNode);
|
|
2746
|
+
}
|
|
2478
2747
|
});
|
|
2479
|
-
return btn;
|
|
2480
2748
|
}
|
|
2481
2749
|
|
|
2482
2750
|
function scrollActiveSessionIntoView() {
|
|
@@ -2492,6 +2760,37 @@
|
|
|
2492
2760
|
}
|
|
2493
2761
|
}
|
|
2494
2762
|
|
|
2763
|
+
function updateSidebarActiveSelection() {
|
|
2764
|
+
state.sessionNodeMap.forEach(function (buttonNode, sessionName) {
|
|
2765
|
+
const isActive = sessionName === state.active;
|
|
2766
|
+
if (!buttonNode) {
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
buttonNode.classList.toggle('active', isActive);
|
|
2770
|
+
buttonNode.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
|
2771
|
+
});
|
|
2772
|
+
|
|
2773
|
+
if (!sessionList) {
|
|
2774
|
+
return;
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
sessionList.querySelectorAll('.tree-node-block.has-active').forEach(function (blockNode) {
|
|
2778
|
+
blockNode.classList.remove('has-active');
|
|
2779
|
+
});
|
|
2780
|
+
|
|
2781
|
+
const activeNode = state.sessionNodeMap.get(state.active);
|
|
2782
|
+
let cursor = activeNode ? activeNode.parentElement : null;
|
|
2783
|
+
while (cursor && cursor !== sessionList) {
|
|
2784
|
+
if (cursor.classList && cursor.classList.contains('tree-node-children')) {
|
|
2785
|
+
const blockNode = cursor.parentElement;
|
|
2786
|
+
if (blockNode && blockNode.classList && blockNode.classList.contains('tree-node-block')) {
|
|
2787
|
+
blockNode.classList.add('has-active');
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
cursor = cursor.parentElement;
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
|
|
2495
2794
|
function renderSessions() {
|
|
2496
2795
|
const containerCount = new Set(state.sessions.map(function (session) {
|
|
2497
2796
|
return session && session.containerName ? session.containerName : '';
|
|
@@ -2521,88 +2820,10 @@
|
|
|
2521
2820
|
state.sessionRenderMode = 'tree';
|
|
2522
2821
|
|
|
2523
2822
|
const grouped = groupSessionsByDirectory(state.sessions);
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
const directoryHasActive = directoryContainsActiveSession(directoryGroup);
|
|
2529
|
-
const group = document.createElement('section');
|
|
2530
|
-
group.className = 'workbench-group';
|
|
2531
|
-
group.classList.toggle('has-active', directoryHasActive);
|
|
2532
|
-
|
|
2533
|
-
const groupHead = createTreeToggle({
|
|
2534
|
-
className: 'workbench-group-head workbench-path-bar',
|
|
2535
|
-
kickerClassName: 'workbench-group-kicker',
|
|
2536
|
-
titleClassName: 'workbench-group-title',
|
|
2537
|
-
kicker: '路径分组',
|
|
2538
|
-
title: directoryGroup.path,
|
|
2539
|
-
expanded: directoryExpanded,
|
|
2540
|
-
metaParts: [
|
|
2541
|
-
`${directoryGroup.containers.length} 容器`,
|
|
2542
|
-
`${directoryGroup.containers.reduce(function (count, containerGroup) {
|
|
2543
|
-
return count + containerGroup.sessions.length;
|
|
2544
|
-
}, 0)} AGENT`,
|
|
2545
|
-
formatDateTime(directoryGroup.updatedAt) || '暂无更新'
|
|
2546
|
-
]
|
|
2547
|
-
});
|
|
2548
|
-
group.appendChild(groupHead);
|
|
2549
|
-
|
|
2550
|
-
const containerStack = document.createElement('div');
|
|
2551
|
-
containerStack.className = 'container-stack workbench-group-body';
|
|
2552
|
-
containerStack.hidden = !directoryExpanded;
|
|
2553
|
-
groupHead.addEventListener('click', function () {
|
|
2554
|
-
const nextExpanded = containerStack.hidden;
|
|
2555
|
-
setSidebarDirectoryExpanded(directoryGroup.path, nextExpanded);
|
|
2556
|
-
groupHead.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
|
|
2557
|
-
containerStack.hidden = !nextExpanded;
|
|
2558
|
-
});
|
|
2559
|
-
|
|
2560
|
-
directoryGroup.containers.forEach(function (containerGroup) {
|
|
2561
|
-
const containerExpanded = isContainerExpanded(containerGroup);
|
|
2562
|
-
const containerHasActive = containerContainsActiveSession(containerGroup);
|
|
2563
|
-
const containerCard = document.createElement('section');
|
|
2564
|
-
containerCard.className = 'container-card';
|
|
2565
|
-
containerCard.classList.toggle('has-active', containerHasActive);
|
|
2566
|
-
|
|
2567
|
-
const containerHead = document.createElement('div');
|
|
2568
|
-
containerHead.className = 'container-card-head';
|
|
2569
|
-
|
|
2570
|
-
const containerToggle = createContainerToggle(containerGroup, containerExpanded);
|
|
2571
|
-
|
|
2572
|
-
const addAgentBtn = document.createElement('button');
|
|
2573
|
-
addAgentBtn.type = 'button';
|
|
2574
|
-
addAgentBtn.className = 'secondary add-agent-btn';
|
|
2575
|
-
addAgentBtn.textContent = '新建AGENT';
|
|
2576
|
-
addAgentBtn.addEventListener('click', function () {
|
|
2577
|
-
createAgentSession(containerGroup.containerName);
|
|
2578
|
-
});
|
|
2579
|
-
|
|
2580
|
-
containerHead.appendChild(containerToggle);
|
|
2581
|
-
containerCard.appendChild(containerHead);
|
|
2582
|
-
|
|
2583
|
-
const agentList = document.createElement('div');
|
|
2584
|
-
agentList.className = 'agent-list container-card-body';
|
|
2585
|
-
agentList.hidden = !containerExpanded;
|
|
2586
|
-
containerToggle.addEventListener('click', function () {
|
|
2587
|
-
const nextExpanded = agentList.hidden;
|
|
2588
|
-
setSidebarContainerExpanded(containerGroup.containerName, nextExpanded);
|
|
2589
|
-
containerToggle.setAttribute('aria-expanded', nextExpanded ? 'true' : 'false');
|
|
2590
|
-
agentList.hidden = !nextExpanded;
|
|
2591
|
-
});
|
|
2592
|
-
agentList.appendChild(addAgentBtn);
|
|
2593
|
-
containerGroup.sessions.forEach(function (session) {
|
|
2594
|
-
const row = createAgentRow(session, itemIndex);
|
|
2595
|
-
state.sessionNodeMap.set(session.name, row);
|
|
2596
|
-
agentList.appendChild(row);
|
|
2597
|
-
itemIndex += 1;
|
|
2598
|
-
});
|
|
2599
|
-
containerCard.appendChild(agentList);
|
|
2600
|
-
containerStack.appendChild(containerCard);
|
|
2601
|
-
});
|
|
2602
|
-
|
|
2603
|
-
group.appendChild(containerStack);
|
|
2604
|
-
sessionList.appendChild(group);
|
|
2605
|
-
});
|
|
2823
|
+
const treeNodes = buildSessionTreeNodes(grouped);
|
|
2824
|
+
const itemCounter = { value: 0 };
|
|
2825
|
+
renderSessionTreeNodes(treeNodes, sessionList, [], itemCounter);
|
|
2826
|
+
updateSidebarActiveSelection();
|
|
2606
2827
|
|
|
2607
2828
|
scrollActiveSessionIntoView();
|
|
2608
2829
|
}
|
|
@@ -2985,6 +3206,9 @@
|
|
|
2985
3206
|
return;
|
|
2986
3207
|
}
|
|
2987
3208
|
state.sessionDetail = data && data.detail ? data.detail : null;
|
|
3209
|
+
if (state.agentTemplateModalOpen && targetSession === state.active) {
|
|
3210
|
+
fillAgentTemplateForm(state.sessionDetail || {});
|
|
3211
|
+
}
|
|
2988
3212
|
} catch (e) {
|
|
2989
3213
|
if (requestId !== state.sessionDetailRequestId) {
|
|
2990
3214
|
return;
|
|
@@ -3272,6 +3496,14 @@
|
|
|
3272
3496
|
});
|
|
3273
3497
|
}
|
|
3274
3498
|
|
|
3499
|
+
if (agentTemplateBtn) {
|
|
3500
|
+
agentTemplateBtn.addEventListener('click', function () {
|
|
3501
|
+
openAgentTemplateModal().catch(function (e) {
|
|
3502
|
+
alert(e && e.message ? e.message : '加载 Agent 模板失败');
|
|
3503
|
+
});
|
|
3504
|
+
});
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3275
3507
|
if (configCancelBtn) {
|
|
3276
3508
|
configCancelBtn.addEventListener('click', function () {
|
|
3277
3509
|
closeConfigModal();
|
|
@@ -3336,6 +3568,25 @@
|
|
|
3336
3568
|
});
|
|
3337
3569
|
}
|
|
3338
3570
|
|
|
3571
|
+
if (agentTemplateCancelBtn) {
|
|
3572
|
+
agentTemplateCancelBtn.addEventListener('click', function () {
|
|
3573
|
+
closeAgentTemplateModal();
|
|
3574
|
+
syncUi();
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
if (agentTemplateResetBtn) {
|
|
3579
|
+
agentTemplateResetBtn.addEventListener('click', function () {
|
|
3580
|
+
resetAgentTemplateModal();
|
|
3581
|
+
});
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
if (agentTemplateSaveBtn) {
|
|
3585
|
+
agentTemplateSaveBtn.addEventListener('click', function () {
|
|
3586
|
+
saveAgentTemplateModal();
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3339
3590
|
if (createRun) {
|
|
3340
3591
|
createRun.addEventListener('change', function () {
|
|
3341
3592
|
applyCurrentRunDefaults();
|
|
@@ -3662,6 +3913,15 @@
|
|
|
3662
3913
|
});
|
|
3663
3914
|
}
|
|
3664
3915
|
|
|
3916
|
+
if (agentTemplateModal) {
|
|
3917
|
+
agentTemplateModal.addEventListener('click', function (event) {
|
|
3918
|
+
if (event.target === agentTemplateModal && !state.agentTemplateSaving) {
|
|
3919
|
+
closeAgentTemplateModal();
|
|
3920
|
+
syncUi();
|
|
3921
|
+
}
|
|
3922
|
+
});
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3665
3925
|
window.addEventListener('keydown', function (event) {
|
|
3666
3926
|
if (event.key === 'Escape' && state.configModalOpen) {
|
|
3667
3927
|
closeConfigModal();
|
|
@@ -3674,6 +3934,10 @@
|
|
|
3674
3934
|
if (event.key === 'Escape' && state.directoryPicker.open) {
|
|
3675
3935
|
closeDirectoryPicker();
|
|
3676
3936
|
}
|
|
3937
|
+
if (event.key === 'Escape' && state.agentTemplateModalOpen) {
|
|
3938
|
+
closeAgentTemplateModal();
|
|
3939
|
+
syncUi();
|
|
3940
|
+
}
|
|
3677
3941
|
if (event.key === 'Escape' && state.mobileSidebarOpen) {
|
|
3678
3942
|
closeMobileSessionPanel();
|
|
3679
3943
|
}
|