@xcanwin/manyoyo 5.8.11 → 5.9.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 +182 -1
- package/lib/web/frontend/app.html +4 -0
- package/lib/web/frontend/app.js +186 -9
- package/lib/web/frontend/codemirror-entry.js +98 -0
- package/lib/web/frontend/codemirror.bundle.js +31648 -0
- package/lib/web/frontend/file-browser.js +406 -0
- package/lib/web/server.js +374 -12
- package/package.json +15 -1
package/lib/web/frontend/app.css
CHANGED
|
@@ -1140,6 +1140,177 @@ body.mobile-actions-open .header-actions {
|
|
|
1140
1140
|
background: #131923;
|
|
1141
1141
|
}
|
|
1142
1142
|
|
|
1143
|
+
.files-pane {
|
|
1144
|
+
min-height: 0;
|
|
1145
|
+
border: 1px solid var(--line);
|
|
1146
|
+
border-radius: 14px;
|
|
1147
|
+
overflow: hidden;
|
|
1148
|
+
background:
|
|
1149
|
+
linear-gradient(180deg, rgba(255, 255, 255, 0.88) 0%, rgba(252, 246, 236, 0.88) 100%);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
.files-browser {
|
|
1153
|
+
height: 100%;
|
|
1154
|
+
min-height: 0;
|
|
1155
|
+
display: grid;
|
|
1156
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
.files-toolbar {
|
|
1160
|
+
display: flex;
|
|
1161
|
+
align-items: center;
|
|
1162
|
+
gap: 8px;
|
|
1163
|
+
padding: 12px 14px;
|
|
1164
|
+
border-bottom: 1px solid var(--line);
|
|
1165
|
+
background: rgba(255, 251, 244, 0.96);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
.files-toolbar-path {
|
|
1169
|
+
flex: 1;
|
|
1170
|
+
min-width: 0;
|
|
1171
|
+
padding: 8px 10px;
|
|
1172
|
+
border: 1px solid rgba(181, 146, 99, 0.35);
|
|
1173
|
+
border-radius: 10px;
|
|
1174
|
+
background: #fffdf9;
|
|
1175
|
+
color: var(--text);
|
|
1176
|
+
font-family: var(--font-mono);
|
|
1177
|
+
font-size: 12px;
|
|
1178
|
+
line-height: 1.5;
|
|
1179
|
+
word-break: break-all;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
.files-toolbar-status {
|
|
1183
|
+
color: var(--muted);
|
|
1184
|
+
font-size: 12px;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
.files-layout {
|
|
1188
|
+
min-height: 0;
|
|
1189
|
+
display: grid;
|
|
1190
|
+
grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
.files-sidebar {
|
|
1194
|
+
min-height: 0;
|
|
1195
|
+
border-right: 1px solid var(--line);
|
|
1196
|
+
background: rgba(255, 251, 244, 0.84);
|
|
1197
|
+
overflow: auto;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.files-list {
|
|
1201
|
+
display: flex;
|
|
1202
|
+
flex-direction: column;
|
|
1203
|
+
gap: 6px;
|
|
1204
|
+
padding: 12px;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
.files-entry {
|
|
1208
|
+
width: 100%;
|
|
1209
|
+
display: flex;
|
|
1210
|
+
align-items: center;
|
|
1211
|
+
justify-content: space-between;
|
|
1212
|
+
gap: 10px;
|
|
1213
|
+
padding: 10px 12px;
|
|
1214
|
+
border: 1px solid rgba(181, 146, 99, 0.28);
|
|
1215
|
+
border-radius: 12px;
|
|
1216
|
+
background: rgba(255, 255, 255, 0.92);
|
|
1217
|
+
color: var(--text);
|
|
1218
|
+
text-align: left;
|
|
1219
|
+
cursor: pointer;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
.files-entry.is-active {
|
|
1223
|
+
border-color: rgba(120, 78, 27, 0.45);
|
|
1224
|
+
background: rgba(255, 244, 224, 0.9);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
.files-entry-name {
|
|
1228
|
+
min-width: 0;
|
|
1229
|
+
display: flex;
|
|
1230
|
+
flex-direction: column;
|
|
1231
|
+
gap: 0;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
.files-entry-title {
|
|
1235
|
+
font-size: 13px;
|
|
1236
|
+
font-weight: 600;
|
|
1237
|
+
word-break: break-word;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
.files-entry-meta {
|
|
1241
|
+
color: var(--muted);
|
|
1242
|
+
font-size: 11px;
|
|
1243
|
+
white-space: nowrap;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.files-preview {
|
|
1247
|
+
min-height: 0;
|
|
1248
|
+
display: grid;
|
|
1249
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
.files-preview-head {
|
|
1253
|
+
display: flex;
|
|
1254
|
+
flex-direction: column;
|
|
1255
|
+
gap: 6px;
|
|
1256
|
+
padding: 12px 14px;
|
|
1257
|
+
border-bottom: 1px solid var(--line);
|
|
1258
|
+
background: rgba(255, 251, 244, 0.96);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
.files-preview-title {
|
|
1262
|
+
font-family: var(--font-display);
|
|
1263
|
+
font-size: 15px;
|
|
1264
|
+
font-weight: 700;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
.files-preview-meta {
|
|
1268
|
+
color: var(--muted);
|
|
1269
|
+
font-size: 12px;
|
|
1270
|
+
word-break: break-all;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.files-preview-body {
|
|
1274
|
+
min-height: 0;
|
|
1275
|
+
overflow: auto;
|
|
1276
|
+
padding: 14px;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
.files-empty,
|
|
1280
|
+
.files-note {
|
|
1281
|
+
padding: 18px;
|
|
1282
|
+
border: 1px dashed rgba(181, 146, 99, 0.45);
|
|
1283
|
+
border-radius: 12px;
|
|
1284
|
+
background: rgba(255, 255, 255, 0.7);
|
|
1285
|
+
color: var(--muted);
|
|
1286
|
+
line-height: 1.6;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.files-pre {
|
|
1290
|
+
margin: 0;
|
|
1291
|
+
white-space: pre-wrap;
|
|
1292
|
+
word-break: break-word;
|
|
1293
|
+
font-family: var(--font-mono);
|
|
1294
|
+
font-size: 12px;
|
|
1295
|
+
line-height: 1.6;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
.files-editor-host {
|
|
1299
|
+
min-height: 100%;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
.files-editor-host .cm-editor {
|
|
1303
|
+
height: 100%;
|
|
1304
|
+
border: 1px solid rgba(181, 146, 99, 0.32);
|
|
1305
|
+
border-radius: 12px;
|
|
1306
|
+
overflow: hidden;
|
|
1307
|
+
background: rgba(255, 255, 255, 0.94);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
.files-editor-host .cm-scroller {
|
|
1311
|
+
font-family: var(--font-mono);
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1143
1314
|
.inspector-pane {
|
|
1144
1315
|
overflow-y: auto;
|
|
1145
1316
|
padding: 0;
|
|
@@ -1939,7 +2110,7 @@ details.trace-card > .trace-card-summary {
|
|
|
1939
2110
|
|
|
1940
2111
|
.workbench-tabs {
|
|
1941
2112
|
display: grid;
|
|
1942
|
-
grid-template-columns: repeat(
|
|
2113
|
+
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
1943
2114
|
gap: 6px;
|
|
1944
2115
|
}
|
|
1945
2116
|
|
|
@@ -1953,6 +2124,16 @@ details.trace-card > .trace-card-summary {
|
|
|
1953
2124
|
align-items: flex-start;
|
|
1954
2125
|
}
|
|
1955
2126
|
|
|
2127
|
+
.files-layout {
|
|
2128
|
+
grid-template-columns: minmax(0, 1fr);
|
|
2129
|
+
grid-template-rows: minmax(180px, 38%) minmax(0, 1fr);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
.files-sidebar {
|
|
2133
|
+
border-right: 0;
|
|
2134
|
+
border-bottom: 1px solid var(--line);
|
|
2135
|
+
}
|
|
2136
|
+
|
|
1956
2137
|
.composer-toolbar-meta {
|
|
1957
2138
|
width: 100%;
|
|
1958
2139
|
justify-content: space-between;
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
<div class="workbench-tabs" id="workbenchTabs" aria-label="工作台视图">
|
|
69
69
|
<button type="button" id="viewActivityBtn" class="secondary is-active">活动</button>
|
|
70
70
|
<button type="button" id="viewTerminalBtn" class="secondary">终端</button>
|
|
71
|
+
<button type="button" id="viewFilesBtn" class="secondary">文件</button>
|
|
71
72
|
<button type="button" id="viewDetailBtn" class="secondary">详情</button>
|
|
72
73
|
<button type="button" id="viewConfigBtn" class="secondary">配置</button>
|
|
73
74
|
<button type="button" id="viewCheckBtn" class="secondary">检查</button>
|
|
@@ -90,6 +91,7 @@
|
|
|
90
91
|
</div>
|
|
91
92
|
<div id="terminalScreen" aria-label="终端输出区域"></div>
|
|
92
93
|
</section>
|
|
94
|
+
<section id="filesPanel" class="workspace-pane files-pane" hidden></section>
|
|
93
95
|
<section id="detailPanel" class="workspace-pane inspector-pane" hidden>
|
|
94
96
|
<div id="detailSummary" class="inspector-stack"></div>
|
|
95
97
|
</section>
|
|
@@ -297,6 +299,8 @@
|
|
|
297
299
|
<script src="/app/vendor/xterm-addon-fit.js"></script>
|
|
298
300
|
<script src="/app/vendor/marked.min.js"></script>
|
|
299
301
|
<script src="/app/frontend/markdown-renderer.js"></script>
|
|
302
|
+
<script src="/app/frontend/codemirror.bundle.js"></script>
|
|
303
|
+
<script src="/app/frontend/file-browser.js"></script>
|
|
300
304
|
<script src="/app/frontend/app.js"></script>
|
|
301
305
|
</body>
|
|
302
306
|
</html>
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -92,6 +92,10 @@
|
|
|
92
92
|
controller: null,
|
|
93
93
|
traceMessageId: ''
|
|
94
94
|
},
|
|
95
|
+
agentRecovery: {
|
|
96
|
+
sessionName: '',
|
|
97
|
+
timer: null
|
|
98
|
+
},
|
|
95
99
|
terminal: {
|
|
96
100
|
term: null,
|
|
97
101
|
fitAddon: null,
|
|
@@ -118,6 +122,7 @@
|
|
|
118
122
|
const headerActions = document.getElementById('headerActions');
|
|
119
123
|
const viewActivityBtn = document.getElementById('viewActivityBtn');
|
|
120
124
|
const viewTerminalBtn = document.getElementById('viewTerminalBtn');
|
|
125
|
+
const viewFilesBtn = document.getElementById('viewFilesBtn');
|
|
121
126
|
const viewDetailBtn = document.getElementById('viewDetailBtn');
|
|
122
127
|
const viewConfigBtn = document.getElementById('viewConfigBtn');
|
|
123
128
|
const viewCheckBtn = document.getElementById('viewCheckBtn');
|
|
@@ -174,6 +179,7 @@
|
|
|
174
179
|
const activityModelChip = document.getElementById('activityModelChip');
|
|
175
180
|
const messagesNode = document.getElementById('messages');
|
|
176
181
|
const terminalPanel = document.getElementById('terminalPanel');
|
|
182
|
+
const filesPanel = document.getElementById('filesPanel');
|
|
177
183
|
const detailPanel = document.getElementById('detailPanel');
|
|
178
184
|
const configPanel = document.getElementById('configPanel');
|
|
179
185
|
const checkPanel = document.getElementById('checkPanel');
|
|
@@ -248,6 +254,7 @@
|
|
|
248
254
|
&& typeof window.ManyoyoMarkdown.render === 'function'
|
|
249
255
|
? window.ManyoyoMarkdown
|
|
250
256
|
: null;
|
|
257
|
+
let fileBrowser = null;
|
|
251
258
|
function normalizeBooleanMap(source) {
|
|
252
259
|
const result = {};
|
|
253
260
|
if (!source || typeof source !== 'object' || Array.isArray(source)) {
|
|
@@ -1331,6 +1338,114 @@
|
|
|
1331
1338
|
);
|
|
1332
1339
|
}
|
|
1333
1340
|
|
|
1341
|
+
function clearAgentRecoveryPoll() {
|
|
1342
|
+
if (state.agentRecovery && state.agentRecovery.timer) {
|
|
1343
|
+
window.clearTimeout(state.agentRecovery.timer);
|
|
1344
|
+
state.agentRecovery.timer = null;
|
|
1345
|
+
}
|
|
1346
|
+
if (state.agentRecovery) {
|
|
1347
|
+
state.agentRecovery.sessionName = '';
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
function hasPendingAgentMessagesForSession(sessionName) {
|
|
1352
|
+
const targetSession = String(sessionName || '').trim();
|
|
1353
|
+
if (!targetSession || state.active !== targetSession) {
|
|
1354
|
+
return false;
|
|
1355
|
+
}
|
|
1356
|
+
return state.messages.some(function (message) {
|
|
1357
|
+
return Boolean(
|
|
1358
|
+
message
|
|
1359
|
+
&& message.mode === 'agent'
|
|
1360
|
+
&& (message.pending === true || message.streamingReply === true)
|
|
1361
|
+
);
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
function scheduleAgentRecoveryPoll(sessionName, immediate) {
|
|
1366
|
+
const targetSession = String(sessionName || '').trim();
|
|
1367
|
+
if (!targetSession || state.active !== targetSession) {
|
|
1368
|
+
clearAgentRecoveryPoll();
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if (isAgentRunActiveForSession(targetSession)) {
|
|
1372
|
+
clearAgentRecoveryPoll();
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
if (!hasPendingAgentMessagesForSession(targetSession)) {
|
|
1376
|
+
clearAgentRecoveryPoll();
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
if (state.agentRecovery.sessionName !== targetSession) {
|
|
1380
|
+
clearAgentRecoveryPoll();
|
|
1381
|
+
state.agentRecovery.sessionName = targetSession;
|
|
1382
|
+
}
|
|
1383
|
+
if (state.agentRecovery.timer) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const delay = immediate === true ? 0 : 1500;
|
|
1388
|
+
state.agentRecovery.timer = window.setTimeout(async function () {
|
|
1389
|
+
state.agentRecovery.timer = null;
|
|
1390
|
+
if (state.active !== targetSession || isAgentRunActiveForSession(targetSession)) {
|
|
1391
|
+
clearAgentRecoveryPoll();
|
|
1392
|
+
syncUi();
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
try {
|
|
1396
|
+
await refreshSessionsSilent({ preferredName: targetSession });
|
|
1397
|
+
await Promise.all([
|
|
1398
|
+
loadMessagesForSession(targetSession, { silent: true }),
|
|
1399
|
+
loadSessionDetailForSession(targetSession)
|
|
1400
|
+
]);
|
|
1401
|
+
} catch (e) {
|
|
1402
|
+
// 静默失败,等待下一轮轮询
|
|
1403
|
+
}
|
|
1404
|
+
if (state.active === targetSession && !isAgentRunActiveForSession(targetSession) && hasPendingAgentMessagesForSession(targetSession)) {
|
|
1405
|
+
scheduleAgentRecoveryPoll(targetSession, false);
|
|
1406
|
+
} else {
|
|
1407
|
+
clearAgentRecoveryPoll();
|
|
1408
|
+
}
|
|
1409
|
+
syncUi();
|
|
1410
|
+
}, delay);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
function syncAgentRecoveryForSession(sessionName) {
|
|
1414
|
+
const targetSession = String(sessionName || '').trim();
|
|
1415
|
+
if (!targetSession || state.active !== targetSession) {
|
|
1416
|
+
clearAgentRecoveryPoll();
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
if (isAgentRunActiveForSession(targetSession)) {
|
|
1420
|
+
clearAgentRecoveryPoll();
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
if (hasPendingAgentMessagesForSession(targetSession)) {
|
|
1424
|
+
scheduleAgentRecoveryPoll(targetSession, false);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
if (state.agentRecovery.sessionName === targetSession) {
|
|
1428
|
+
clearAgentRecoveryPoll();
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
async function recoverAgentRunFromServer(sessionName) {
|
|
1433
|
+
const targetSession = String(sessionName || '').trim();
|
|
1434
|
+
if (!targetSession) {
|
|
1435
|
+
return false;
|
|
1436
|
+
}
|
|
1437
|
+
try {
|
|
1438
|
+
await refreshSessionsSilent({ preferredName: targetSession });
|
|
1439
|
+
await Promise.all([
|
|
1440
|
+
loadMessagesForSession(targetSession, { silent: true }),
|
|
1441
|
+
loadSessionDetailForSession(targetSession)
|
|
1442
|
+
]);
|
|
1443
|
+
} catch (e) {
|
|
1444
|
+
return false;
|
|
1445
|
+
}
|
|
1446
|
+
return hasPendingAgentMessagesForSession(targetSession);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1334
1449
|
function isActiveSessionHistoryOnly() {
|
|
1335
1450
|
const session = getActiveSession();
|
|
1336
1451
|
return sessionStatusInfo(session && session.status).tone === 'history';
|
|
@@ -1723,6 +1838,7 @@
|
|
|
1723
1838
|
const VIEW_LABELS = {
|
|
1724
1839
|
activity: '活动',
|
|
1725
1840
|
terminal: '终端',
|
|
1841
|
+
files: '文件',
|
|
1726
1842
|
detail: '详情',
|
|
1727
1843
|
config: '配置',
|
|
1728
1844
|
check: '检查'
|
|
@@ -2001,6 +2117,7 @@
|
|
|
2001
2117
|
|
|
2002
2118
|
const activityTab = state.activeTab === 'activity';
|
|
2003
2119
|
const terminalTab = state.activeTab === 'terminal';
|
|
2120
|
+
const filesTab = state.activeTab === 'files';
|
|
2004
2121
|
const detailTab = state.activeTab === 'detail';
|
|
2005
2122
|
const configTab = state.activeTab === 'config';
|
|
2006
2123
|
const checkTab = state.activeTab === 'check';
|
|
@@ -2011,6 +2128,7 @@
|
|
|
2011
2128
|
document.body.classList.toggle('command-mode', commandMode);
|
|
2012
2129
|
document.body.classList.toggle('agent-mode', agentMode);
|
|
2013
2130
|
document.body.classList.toggle('terminal-mode', terminalTab);
|
|
2131
|
+
document.body.classList.toggle('files-tab', filesTab);
|
|
2014
2132
|
document.body.classList.toggle('detail-tab', detailTab);
|
|
2015
2133
|
document.body.classList.toggle('config-tab', configTab);
|
|
2016
2134
|
document.body.classList.toggle('check-tab', checkTab);
|
|
@@ -2036,6 +2154,7 @@
|
|
|
2036
2154
|
}
|
|
2037
2155
|
if (viewActivityBtn) viewActivityBtn.classList.toggle('is-active', activityTab);
|
|
2038
2156
|
if (viewTerminalBtn) viewTerminalBtn.classList.toggle('is-active', terminalTab);
|
|
2157
|
+
if (viewFilesBtn) viewFilesBtn.classList.toggle('is-active', filesTab);
|
|
2039
2158
|
if (viewDetailBtn) viewDetailBtn.classList.toggle('is-active', detailTab);
|
|
2040
2159
|
if (viewConfigBtn) viewConfigBtn.classList.toggle('is-active', configTab);
|
|
2041
2160
|
if (viewCheckBtn) viewCheckBtn.classList.toggle('is-active', checkTab);
|
|
@@ -2045,6 +2164,9 @@
|
|
|
2045
2164
|
if (terminalPanel) {
|
|
2046
2165
|
terminalPanel.hidden = !terminalTab;
|
|
2047
2166
|
}
|
|
2167
|
+
if (filesPanel) {
|
|
2168
|
+
filesPanel.hidden = !filesTab;
|
|
2169
|
+
}
|
|
2048
2170
|
if (detailPanel) {
|
|
2049
2171
|
detailPanel.hidden = !detailTab;
|
|
2050
2172
|
}
|
|
@@ -2057,8 +2179,16 @@
|
|
|
2057
2179
|
if (terminalTab && state.terminal.terminalReady) {
|
|
2058
2180
|
scheduleTerminalFit(false);
|
|
2059
2181
|
}
|
|
2182
|
+
if (fileBrowser) {
|
|
2183
|
+
fileBrowser.sync({
|
|
2184
|
+
visible: filesTab,
|
|
2185
|
+
session: getActiveSession(),
|
|
2186
|
+
detail: state.sessionDetail,
|
|
2187
|
+
historyOnly: isActiveSessionHistoryOnly()
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2060
2190
|
|
|
2061
|
-
const activeAgentRunning = isAgentRunActiveForSession(state.active);
|
|
2191
|
+
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
2062
2192
|
const busy = state.loadingSessions || state.loadingMessages || state.sending;
|
|
2063
2193
|
refreshBtn.disabled = busy;
|
|
2064
2194
|
if (addAgentBtn) {
|
|
@@ -2066,14 +2196,14 @@
|
|
|
2066
2196
|
}
|
|
2067
2197
|
removeBtn.disabled = !state.active || busy;
|
|
2068
2198
|
removeAllBtn.disabled = !state.active || busy;
|
|
2069
|
-
sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && !agentEnabled);
|
|
2199
|
+
sendBtn.disabled = !activityTab || !state.active || busy || (agentMode && (!agentEnabled || activeAgentRunning));
|
|
2070
2200
|
if (stopBtn) {
|
|
2071
2201
|
stopBtn.disabled = !activityTab || !agentMode || !activeAgentRunning || state.agentRun.stopping;
|
|
2072
2202
|
}
|
|
2073
2203
|
if (agentTemplateBtn) {
|
|
2074
2204
|
agentTemplateBtn.disabled = !state.active || state.agentTemplateSaving;
|
|
2075
2205
|
}
|
|
2076
|
-
commandInput.disabled = !activityTab || !state.active || (agentMode && !agentEnabled);
|
|
2206
|
+
commandInput.disabled = !activityTab || !state.active || (agentMode && (!agentEnabled || activeAgentRunning));
|
|
2077
2207
|
if (commandInput) {
|
|
2078
2208
|
commandInput.placeholder = agentMode
|
|
2079
2209
|
? '输入提示词,例如:请帮我分析当前项目结构并给出重构建议'
|
|
@@ -3264,6 +3394,7 @@
|
|
|
3264
3394
|
state.messageRequestId += 1;
|
|
3265
3395
|
state.messages = [];
|
|
3266
3396
|
state.loadingMessages = false;
|
|
3397
|
+
clearAgentRecoveryPoll();
|
|
3267
3398
|
renderMessages(state.messages);
|
|
3268
3399
|
syncUi();
|
|
3269
3400
|
return;
|
|
@@ -3296,6 +3427,9 @@
|
|
|
3296
3427
|
state.messages = Array.isArray(data && data.messages) ? data.messages : [];
|
|
3297
3428
|
}
|
|
3298
3429
|
if (!requestError || targetSession === state.active) {
|
|
3430
|
+
if (targetSession === state.active) {
|
|
3431
|
+
syncAgentRecoveryForSession(targetSession);
|
|
3432
|
+
}
|
|
3299
3433
|
renderMessages(state.messages);
|
|
3300
3434
|
syncUi();
|
|
3301
3435
|
} else {
|
|
@@ -3433,6 +3567,7 @@
|
|
|
3433
3567
|
state.agentRun.stopping = false;
|
|
3434
3568
|
state.agentRun.sessionName = '';
|
|
3435
3569
|
state.agentRun.traceMessageId = '';
|
|
3570
|
+
clearAgentRecoveryPoll();
|
|
3436
3571
|
}
|
|
3437
3572
|
|
|
3438
3573
|
function appendAssistantMessageLocal(sessionName, result, mode) {
|
|
@@ -3506,6 +3641,7 @@
|
|
|
3506
3641
|
state.agentRun.stopping = false;
|
|
3507
3642
|
state.agentRun.controller = new window.AbortController();
|
|
3508
3643
|
state.agentRun.traceMessageId = traceMessageId;
|
|
3644
|
+
clearAgentRecoveryPoll();
|
|
3509
3645
|
renderMessages(state.messages, { stickToBottom: true });
|
|
3510
3646
|
syncUi();
|
|
3511
3647
|
|
|
@@ -3866,13 +4002,20 @@
|
|
|
3866
4002
|
});
|
|
3867
4003
|
}
|
|
3868
4004
|
} catch (e) {
|
|
3869
|
-
if (
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
4005
|
+
if (mode === 'agent') {
|
|
4006
|
+
const recovered = await recoverAgentRunFromServer(submitSession);
|
|
4007
|
+
if (!recovered && document.visibilityState !== 'hidden') {
|
|
4008
|
+
alert(e.message);
|
|
4009
|
+
}
|
|
4010
|
+
} else {
|
|
4011
|
+
if (state.active === submitSession) {
|
|
4012
|
+
state.messages = state.messages.filter(function (message) {
|
|
4013
|
+
return !(message && message.id === pendingMessage.id);
|
|
4014
|
+
});
|
|
4015
|
+
renderMessages(state.messages, { stickToBottom: true });
|
|
4016
|
+
}
|
|
4017
|
+
alert(e.message);
|
|
3874
4018
|
}
|
|
3875
|
-
alert(e.message);
|
|
3876
4019
|
} finally {
|
|
3877
4020
|
state.sending = false;
|
|
3878
4021
|
syncUi();
|
|
@@ -3949,6 +4092,12 @@
|
|
|
3949
4092
|
});
|
|
3950
4093
|
}
|
|
3951
4094
|
|
|
4095
|
+
if (viewFilesBtn) {
|
|
4096
|
+
viewFilesBtn.addEventListener('click', function () {
|
|
4097
|
+
setActiveTab('files');
|
|
4098
|
+
});
|
|
4099
|
+
}
|
|
4100
|
+
|
|
3952
4101
|
if (viewDetailBtn) {
|
|
3953
4102
|
viewDetailBtn.addEventListener('click', function () {
|
|
3954
4103
|
setActiveTab('detail');
|
|
@@ -4129,6 +4278,24 @@
|
|
|
4129
4278
|
}
|
|
4130
4279
|
});
|
|
4131
4280
|
|
|
4281
|
+
document.addEventListener('visibilitychange', function () {
|
|
4282
|
+
if (document.visibilityState !== 'visible' || !state.active) {
|
|
4283
|
+
return;
|
|
4284
|
+
}
|
|
4285
|
+
recoverAgentRunFromServer(state.active).catch(function () {
|
|
4286
|
+
// 静默恢复失败不打断当前交互
|
|
4287
|
+
});
|
|
4288
|
+
});
|
|
4289
|
+
|
|
4290
|
+
window.addEventListener('focus', function () {
|
|
4291
|
+
if (!state.active) {
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4294
|
+
recoverAgentRunFromServer(state.active).catch(function () {
|
|
4295
|
+
// 静默恢复失败不打断当前交互
|
|
4296
|
+
});
|
|
4297
|
+
});
|
|
4298
|
+
|
|
4132
4299
|
if (typeof MOBILE_LAYOUT_MEDIA.addEventListener === 'function') {
|
|
4133
4300
|
MOBILE_LAYOUT_MEDIA.addEventListener('change', onLayoutMediaChange);
|
|
4134
4301
|
} else if (typeof MOBILE_LAYOUT_MEDIA.addListener === 'function') {
|
|
@@ -4210,6 +4377,16 @@
|
|
|
4210
4377
|
});
|
|
4211
4378
|
}
|
|
4212
4379
|
|
|
4380
|
+
if (window.ManyoyoFileBrowser && typeof window.ManyoyoFileBrowser.create === 'function') {
|
|
4381
|
+
fileBrowser = window.ManyoyoFileBrowser.create({
|
|
4382
|
+
root: filesPanel,
|
|
4383
|
+
api,
|
|
4384
|
+
onError: function (message) {
|
|
4385
|
+
alert(message);
|
|
4386
|
+
}
|
|
4387
|
+
});
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4213
4390
|
window.addEventListener('beforeunload', function () {
|
|
4214
4391
|
disconnectTerminal('', true);
|
|
4215
4392
|
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { basicSetup } from 'codemirror';
|
|
2
|
+
import { Compartment, EditorState } from '@codemirror/state';
|
|
3
|
+
import { EditorView } from '@codemirror/view';
|
|
4
|
+
import { css } from '@codemirror/lang-css';
|
|
5
|
+
import { html } from '@codemirror/lang-html';
|
|
6
|
+
import { javascript } from '@codemirror/lang-javascript';
|
|
7
|
+
import { json } from '@codemirror/lang-json';
|
|
8
|
+
import { markdown } from '@codemirror/lang-markdown';
|
|
9
|
+
import { python } from '@codemirror/lang-python';
|
|
10
|
+
import { yaml } from '@codemirror/lang-yaml';
|
|
11
|
+
|
|
12
|
+
function resolveLanguageExtension(language) {
|
|
13
|
+
switch (String(language || '').trim()) {
|
|
14
|
+
case 'css':
|
|
15
|
+
return css();
|
|
16
|
+
case 'html':
|
|
17
|
+
return html();
|
|
18
|
+
case 'javascript':
|
|
19
|
+
return javascript({ jsx: true, typescript: true });
|
|
20
|
+
case 'json':
|
|
21
|
+
return json();
|
|
22
|
+
case 'markdown':
|
|
23
|
+
return markdown();
|
|
24
|
+
case 'python':
|
|
25
|
+
return python();
|
|
26
|
+
case 'yaml':
|
|
27
|
+
return yaml();
|
|
28
|
+
default:
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function createEditor(parent, options = {}) {
|
|
34
|
+
const target = parent;
|
|
35
|
+
const initialDoc = String(options.doc || '');
|
|
36
|
+
const initialLanguage = String(options.language || 'text').trim();
|
|
37
|
+
const initialReadOnly = options.readOnly !== false;
|
|
38
|
+
const languageCompartment = new Compartment();
|
|
39
|
+
const readOnlyCompartment = new Compartment();
|
|
40
|
+
const view = new EditorView({
|
|
41
|
+
parent: target,
|
|
42
|
+
state: EditorState.create({
|
|
43
|
+
doc: initialDoc,
|
|
44
|
+
extensions: [
|
|
45
|
+
basicSetup,
|
|
46
|
+
EditorView.lineWrapping,
|
|
47
|
+
readOnlyCompartment.of([
|
|
48
|
+
EditorState.readOnly.of(initialReadOnly),
|
|
49
|
+
EditorView.editable.of(!initialReadOnly)
|
|
50
|
+
]),
|
|
51
|
+
languageCompartment.of(resolveLanguageExtension(initialLanguage)),
|
|
52
|
+
EditorView.theme({
|
|
53
|
+
'&': {
|
|
54
|
+
height: '100%',
|
|
55
|
+
fontSize: '12px'
|
|
56
|
+
},
|
|
57
|
+
'.cm-scroller': {
|
|
58
|
+
overflow: 'auto'
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
setValue(nextValue) {
|
|
67
|
+
const text = String(nextValue == null ? '' : nextValue);
|
|
68
|
+
view.dispatch({
|
|
69
|
+
changes: {
|
|
70
|
+
from: 0,
|
|
71
|
+
to: view.state.doc.length,
|
|
72
|
+
insert: text
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
setLanguage(nextLanguage) {
|
|
77
|
+
view.dispatch({
|
|
78
|
+
effects: languageCompartment.reconfigure(resolveLanguageExtension(nextLanguage))
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
setReadOnly(readOnly) {
|
|
82
|
+
const value = readOnly !== false;
|
|
83
|
+
view.dispatch({
|
|
84
|
+
effects: readOnlyCompartment.reconfigure([
|
|
85
|
+
EditorState.readOnly.of(value),
|
|
86
|
+
EditorView.editable.of(!value)
|
|
87
|
+
])
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
destroy() {
|
|
91
|
+
view.destroy();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
window.ManyoyoCodeEditor = {
|
|
97
|
+
create: createEditor
|
|
98
|
+
};
|