codexmate 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +213 -0
- package/README.md +147 -346
- package/cli.js +3163 -224
- package/doc/CHANGELOG.md +13 -1
- package/doc/CHANGELOG.zh-CN.md +14 -0
- package/lib/cli-utils.js +16 -0
- package/lib/workflow-engine.js +340 -0
- package/package.json +10 -3
- package/web-ui/app.js +275 -65
- package/web-ui/index.html +279 -33
- package/web-ui/logic.mjs +147 -1
- package/web-ui/modules/config-mode.computed.mjs +123 -0
- package/web-ui/modules/skills.computed.mjs +82 -0
- package/web-ui/modules/skills.methods.mjs +344 -0
- package/web-ui/styles.css +648 -10
- package/README.zh-CN.md +0 -419
package/web-ui/app.js
CHANGED
|
@@ -7,8 +7,20 @@
|
|
|
7
7
|
formatLatency,
|
|
8
8
|
buildSpeedTestIssue,
|
|
9
9
|
isSessionQueryEnabled,
|
|
10
|
-
buildSessionListParams
|
|
10
|
+
buildSessionListParams,
|
|
11
|
+
normalizeSessionSource,
|
|
12
|
+
normalizeSessionPathFilter,
|
|
13
|
+
buildSessionFilterCacheState,
|
|
14
|
+
buildSessionTimelineNodes,
|
|
15
|
+
normalizeSessionMessageRole
|
|
11
16
|
} from './logic.mjs';
|
|
17
|
+
import {
|
|
18
|
+
CONFIG_MODE_SET,
|
|
19
|
+
getProviderConfigModeMeta,
|
|
20
|
+
createConfigModeComputed
|
|
21
|
+
} from './modules/config-mode.computed.mjs';
|
|
22
|
+
import { createSkillsComputed } from './modules/skills.computed.mjs';
|
|
23
|
+
import { createSkillsMethods } from './modules/skills.methods.mjs';
|
|
12
24
|
|
|
13
25
|
document.addEventListener('DOMContentLoaded', () => {
|
|
14
26
|
if (typeof Vue === 'undefined') {
|
|
@@ -81,6 +93,7 @@
|
|
|
81
93
|
showOpenclawConfigModal: false,
|
|
82
94
|
showConfigTemplateModal: false,
|
|
83
95
|
showAgentsModal: false,
|
|
96
|
+
showSkillsModal: false,
|
|
84
97
|
showInstallModal: false,
|
|
85
98
|
configTemplateContent: '',
|
|
86
99
|
configTemplateApplying: false,
|
|
@@ -94,6 +107,19 @@
|
|
|
94
107
|
agentsContext: 'codex',
|
|
95
108
|
agentsModalTitle: 'AGENTS.md 编辑器',
|
|
96
109
|
agentsModalHint: '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
|
|
110
|
+
skillsRootPath: '',
|
|
111
|
+
skillsList: [],
|
|
112
|
+
skillsSelectedNames: [],
|
|
113
|
+
skillsLoading: false,
|
|
114
|
+
skillsDeleting: false,
|
|
115
|
+
skillsKeyword: '',
|
|
116
|
+
skillsStatusFilter: 'all',
|
|
117
|
+
skillsImportList: [],
|
|
118
|
+
skillsImportSelectedKeys: [],
|
|
119
|
+
skillsScanningImports: false,
|
|
120
|
+
skillsImporting: false,
|
|
121
|
+
skillsZipImporting: false,
|
|
122
|
+
skillsExporting: false,
|
|
97
123
|
sessionsList: [],
|
|
98
124
|
sessionsLoading: false,
|
|
99
125
|
sessionFilterSource: 'all',
|
|
@@ -124,6 +150,13 @@
|
|
|
124
150
|
activeSessionDetailClipped: false,
|
|
125
151
|
sessionDetailLoading: false,
|
|
126
152
|
sessionDetailRequestSeq: 0,
|
|
153
|
+
sessionTimelineActiveKey: '',
|
|
154
|
+
sessionTimelineRafId: 0,
|
|
155
|
+
sessionMessageRefMap: Object.create(null),
|
|
156
|
+
sessionPreviewScrollEl: null,
|
|
157
|
+
sessionPreviewContainerEl: null,
|
|
158
|
+
sessionPreviewHeaderEl: null,
|
|
159
|
+
sessionPreviewHeaderResizeObserver: null,
|
|
127
160
|
sessionStandalone: false,
|
|
128
161
|
sessionStandaloneError: '',
|
|
129
162
|
sessionStandaloneText: '',
|
|
@@ -269,6 +302,8 @@
|
|
|
269
302
|
} else if (savedSessionYolo === '1' || savedSessionYolo === 'true') {
|
|
270
303
|
this.sessionResumeWithYolo = true;
|
|
271
304
|
}
|
|
305
|
+
this.restoreSessionFilterCache();
|
|
306
|
+
window.addEventListener('resize', this.onWindowResize);
|
|
272
307
|
const savedConfigs = localStorage.getItem('claudeConfigs');
|
|
273
308
|
if (savedConfigs) {
|
|
274
309
|
try {
|
|
@@ -304,11 +339,31 @@
|
|
|
304
339
|
}
|
|
305
340
|
this.loadAll();
|
|
306
341
|
},
|
|
342
|
+
beforeUnmount() {
|
|
343
|
+
this.cancelSessionTimelineSync();
|
|
344
|
+
this.disconnectSessionPreviewHeaderResizeObserver();
|
|
345
|
+
window.removeEventListener('resize', this.onWindowResize);
|
|
346
|
+
this.sessionPreviewScrollEl = null;
|
|
347
|
+
this.sessionPreviewContainerEl = null;
|
|
348
|
+
this.sessionPreviewHeaderEl = null;
|
|
349
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
350
|
+
},
|
|
307
351
|
|
|
308
352
|
computed: {
|
|
309
353
|
isSessionQueryEnabled() {
|
|
310
354
|
return isSessionQueryEnabled(this.sessionFilterSource);
|
|
311
355
|
},
|
|
356
|
+
sessionTimelineNodes() {
|
|
357
|
+
return buildSessionTimelineNodes(this.activeSessionMessages, {
|
|
358
|
+
getKey: (message, index) => this.getRecordRenderKey(message, index)
|
|
359
|
+
});
|
|
360
|
+
},
|
|
361
|
+
sessionTimelineActiveTitle() {
|
|
362
|
+
if (!this.sessionTimelineActiveKey) return '';
|
|
363
|
+
const nodes = Array.isArray(this.sessionTimelineNodes) ? this.sessionTimelineNodes : [];
|
|
364
|
+
const matched = nodes.find(node => node.key === this.sessionTimelineActiveKey);
|
|
365
|
+
return matched ? matched.title : '';
|
|
366
|
+
},
|
|
312
367
|
sessionQueryPlaceholder() {
|
|
313
368
|
if (this.isSessionQueryEnabled) {
|
|
314
369
|
return '关键词检索(支持 Codex/Claude,例:claude code)';
|
|
@@ -354,63 +409,10 @@
|
|
|
354
409
|
installRegistryPreview() {
|
|
355
410
|
return this.resolveInstallRegistryUrl(this.installRegistryPreset, this.installRegistryCustom);
|
|
356
411
|
},
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return '未知';
|
|
362
|
-
},
|
|
363
|
-
inspectorConfigModeLabel() {
|
|
364
|
-
if (this.mainTab !== 'config') return '--';
|
|
365
|
-
if (this.configMode === 'codex') return 'Codex';
|
|
366
|
-
if (this.configMode === 'claude') return 'Claude Code';
|
|
367
|
-
if (this.configMode === 'openclaw') return 'OpenClaw';
|
|
368
|
-
return '未选择';
|
|
369
|
-
},
|
|
370
|
-
inspectorCurrentConfigLabel() {
|
|
371
|
-
if (this.mainTab !== 'config') return '--';
|
|
372
|
-
if (this.configMode === 'codex') {
|
|
373
|
-
const provider = typeof this.currentProvider === 'string' ? this.currentProvider.trim() : '';
|
|
374
|
-
return provider || '未选择';
|
|
375
|
-
}
|
|
376
|
-
if (this.configMode === 'claude') {
|
|
377
|
-
const config = typeof this.currentClaudeConfig === 'string' ? this.currentClaudeConfig.trim() : '';
|
|
378
|
-
return config || '未选择';
|
|
379
|
-
}
|
|
380
|
-
const openclaw = typeof this.currentOpenclawConfig === 'string' ? this.currentOpenclawConfig.trim() : '';
|
|
381
|
-
return openclaw || '未选择';
|
|
382
|
-
},
|
|
383
|
-
inspectorCurrentModelLabel() {
|
|
384
|
-
if (this.mainTab !== 'config') return '--';
|
|
385
|
-
if (this.configMode === 'codex') {
|
|
386
|
-
const model = typeof this.currentModel === 'string' ? this.currentModel.trim() : '';
|
|
387
|
-
return model || '未选择';
|
|
388
|
-
}
|
|
389
|
-
if (this.configMode === 'claude') {
|
|
390
|
-
const model = typeof this.currentClaudeModel === 'string' ? this.currentClaudeModel.trim() : '';
|
|
391
|
-
return model || '未选择';
|
|
392
|
-
}
|
|
393
|
-
const model = this.openclawStructured && typeof this.openclawStructured.agentPrimary === 'string'
|
|
394
|
-
? this.openclawStructured.agentPrimary.trim()
|
|
395
|
-
: '';
|
|
396
|
-
return model || '按配置文件';
|
|
397
|
-
},
|
|
398
|
-
inspectorTemplateStatus() {
|
|
399
|
-
if (this.mainTab !== 'config') return '--';
|
|
400
|
-
if (this.configMode === 'codex') {
|
|
401
|
-
if (this.configTemplateApplying || this.codexApplying) {
|
|
402
|
-
return '模板应用中';
|
|
403
|
-
}
|
|
404
|
-
return '模板可编辑(手动确认应用)';
|
|
405
|
-
}
|
|
406
|
-
if (this.configMode === 'claude') {
|
|
407
|
-
return '即时写入 Claude settings';
|
|
408
|
-
}
|
|
409
|
-
if (this.openclawApplying || this.openclawSaving) {
|
|
410
|
-
return 'OpenClaw 保存/应用中';
|
|
411
|
-
}
|
|
412
|
-
return 'JSON5 可保存并应用';
|
|
413
|
-
},
|
|
412
|
+
...createSkillsComputed(),
|
|
413
|
+
|
|
414
|
+
...createConfigModeComputed(),
|
|
415
|
+
|
|
414
416
|
inspectorBusyStatus() {
|
|
415
417
|
const tasks = [];
|
|
416
418
|
if (this.loading) tasks.push('初始化');
|
|
@@ -418,6 +420,7 @@
|
|
|
418
420
|
if (this.codexModelsLoading || this.claudeModelsLoading) tasks.push('模型加载');
|
|
419
421
|
if (this.codexApplying || this.configTemplateApplying || this.openclawApplying) tasks.push('配置应用');
|
|
420
422
|
if (this.agentsSaving) tasks.push('AGENTS 保存');
|
|
423
|
+
if (this.skillsLoading || this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) tasks.push('Skills 管理');
|
|
421
424
|
if (this.proxySaving || this.proxyApplying || this.proxyStarting || this.proxyStopping) tasks.push('代理更新');
|
|
422
425
|
return tasks.length ? tasks.join(' / ') : '空闲';
|
|
423
426
|
},
|
|
@@ -721,9 +724,12 @@
|
|
|
721
724
|
},
|
|
722
725
|
|
|
723
726
|
switchConfigMode(mode) {
|
|
727
|
+
const normalizedMode = typeof mode === 'string'
|
|
728
|
+
? mode.trim().toLowerCase()
|
|
729
|
+
: '';
|
|
724
730
|
this.mainTab = 'config';
|
|
725
|
-
this.configMode =
|
|
726
|
-
if (
|
|
731
|
+
this.configMode = CONFIG_MODE_SET.has(normalizedMode) ? normalizedMode : 'codex';
|
|
732
|
+
if (this.configMode === 'claude') {
|
|
727
733
|
this.refreshClaudeModelContext();
|
|
728
734
|
}
|
|
729
735
|
},
|
|
@@ -799,6 +805,9 @@
|
|
|
799
805
|
this.activeSessionMessages = [];
|
|
800
806
|
this.activeSessionDetailError = '';
|
|
801
807
|
this.activeSessionDetailClipped = false;
|
|
808
|
+
this.cancelSessionTimelineSync();
|
|
809
|
+
this.sessionTimelineActiveKey = '';
|
|
810
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
802
811
|
this.sessionStandaloneError = '';
|
|
803
812
|
this.sessionStandaloneText = '';
|
|
804
813
|
this.sessionStandaloneTitle = this.activeSession.title || '会话';
|
|
@@ -1167,8 +1176,7 @@
|
|
|
1167
1176
|
},
|
|
1168
1177
|
|
|
1169
1178
|
normalizeSessionPathValue(value) {
|
|
1170
|
-
|
|
1171
|
-
return value.trim();
|
|
1179
|
+
return normalizeSessionPathFilter(value);
|
|
1172
1180
|
},
|
|
1173
1181
|
|
|
1174
1182
|
mergeSessionPathOptions(baseList = [], incomingList = []) {
|
|
@@ -1277,13 +1285,32 @@
|
|
|
1277
1285
|
const value = this.sessionResumeWithYolo ? '1' : '0';
|
|
1278
1286
|
localStorage.setItem('codexmateSessionResumeYolo', value);
|
|
1279
1287
|
},
|
|
1288
|
+
restoreSessionFilterCache() {
|
|
1289
|
+
const sourceCache = localStorage.getItem('codexmateSessionFilterSource');
|
|
1290
|
+
const pathCache = localStorage.getItem('codexmateSessionPathFilter');
|
|
1291
|
+
const cached = buildSessionFilterCacheState(sourceCache, pathCache);
|
|
1292
|
+
this.sessionFilterSource = cached.source;
|
|
1293
|
+
this.sessionPathFilter = cached.pathFilter;
|
|
1294
|
+
this.refreshSessionPathOptions(this.sessionFilterSource);
|
|
1295
|
+
},
|
|
1296
|
+
persistSessionFilterCache() {
|
|
1297
|
+
const cached = buildSessionFilterCacheState(this.sessionFilterSource, this.sessionPathFilter);
|
|
1298
|
+
localStorage.setItem('codexmateSessionFilterSource', cached.source);
|
|
1299
|
+
if (cached.pathFilter) {
|
|
1300
|
+
localStorage.setItem('codexmateSessionPathFilter', cached.pathFilter);
|
|
1301
|
+
} else {
|
|
1302
|
+
localStorage.removeItem('codexmateSessionPathFilter');
|
|
1303
|
+
}
|
|
1304
|
+
},
|
|
1280
1305
|
|
|
1281
1306
|
async onSessionSourceChange() {
|
|
1282
1307
|
this.refreshSessionPathOptions(this.sessionFilterSource);
|
|
1308
|
+
this.persistSessionFilterCache();
|
|
1283
1309
|
await this.loadSessions();
|
|
1284
1310
|
},
|
|
1285
1311
|
|
|
1286
1312
|
async onSessionPathFilterChange() {
|
|
1313
|
+
this.persistSessionFilterCache();
|
|
1287
1314
|
await this.loadSessions();
|
|
1288
1315
|
},
|
|
1289
1316
|
|
|
@@ -1297,8 +1324,156 @@
|
|
|
1297
1324
|
this.sessionQuery = '';
|
|
1298
1325
|
this.sessionRoleFilter = 'all';
|
|
1299
1326
|
this.sessionTimePreset = 'all';
|
|
1327
|
+
this.persistSessionFilterCache();
|
|
1300
1328
|
await this.onSessionSourceChange();
|
|
1301
1329
|
},
|
|
1330
|
+
setSessionPreviewContainerRef(el) {
|
|
1331
|
+
this.sessionPreviewContainerEl = el || null;
|
|
1332
|
+
this.updateSessionTimelineOffset();
|
|
1333
|
+
},
|
|
1334
|
+
disconnectSessionPreviewHeaderResizeObserver() {
|
|
1335
|
+
if (!this.sessionPreviewHeaderResizeObserver) return;
|
|
1336
|
+
this.sessionPreviewHeaderResizeObserver.disconnect();
|
|
1337
|
+
this.sessionPreviewHeaderResizeObserver = null;
|
|
1338
|
+
},
|
|
1339
|
+
observeSessionPreviewHeaderResize() {
|
|
1340
|
+
this.disconnectSessionPreviewHeaderResizeObserver();
|
|
1341
|
+
if (!this.sessionPreviewHeaderEl || typeof ResizeObserver !== 'function') return;
|
|
1342
|
+
this.sessionPreviewHeaderResizeObserver = new ResizeObserver(() => {
|
|
1343
|
+
this.updateSessionTimelineOffset();
|
|
1344
|
+
});
|
|
1345
|
+
this.sessionPreviewHeaderResizeObserver.observe(this.sessionPreviewHeaderEl);
|
|
1346
|
+
},
|
|
1347
|
+
setSessionPreviewHeaderRef(el) {
|
|
1348
|
+
this.disconnectSessionPreviewHeaderResizeObserver();
|
|
1349
|
+
this.sessionPreviewHeaderEl = el || null;
|
|
1350
|
+
this.observeSessionPreviewHeaderResize();
|
|
1351
|
+
this.updateSessionTimelineOffset();
|
|
1352
|
+
},
|
|
1353
|
+
setSessionPreviewScrollRef(el) {
|
|
1354
|
+
this.sessionPreviewScrollEl = el || null;
|
|
1355
|
+
if (this.sessionPreviewScrollEl) {
|
|
1356
|
+
this.scheduleSessionTimelineSync();
|
|
1357
|
+
} else {
|
|
1358
|
+
this.cancelSessionTimelineSync();
|
|
1359
|
+
}
|
|
1360
|
+
this.updateSessionTimelineOffset();
|
|
1361
|
+
},
|
|
1362
|
+
updateSessionTimelineOffset() {
|
|
1363
|
+
const container = this.sessionPreviewContainerEl || this.$refs.sessionPreviewContainer;
|
|
1364
|
+
if (!container || !container.style) return;
|
|
1365
|
+
const header = this.sessionPreviewHeaderEl
|
|
1366
|
+
|| (this.sessionPreviewScrollEl ? this.sessionPreviewScrollEl.querySelector('.session-preview-header') : null)
|
|
1367
|
+
|| container.querySelector('.session-preview-header');
|
|
1368
|
+
const headerHeight = header ? Math.ceil(header.getBoundingClientRect().height) : 0;
|
|
1369
|
+
const offset = headerHeight > 0 ? (headerHeight + 12) : 72;
|
|
1370
|
+
container.style.setProperty('--session-preview-header-offset', `${offset}px`);
|
|
1371
|
+
},
|
|
1372
|
+
bindSessionMessageRef(messageKey, el) {
|
|
1373
|
+
if (!messageKey) return;
|
|
1374
|
+
if (el) {
|
|
1375
|
+
this.sessionMessageRefMap[messageKey] = el;
|
|
1376
|
+
} else {
|
|
1377
|
+
delete this.sessionMessageRefMap[messageKey];
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
cancelSessionTimelineSync() {
|
|
1381
|
+
if (!this.sessionTimelineRafId) return;
|
|
1382
|
+
if (typeof cancelAnimationFrame === 'function') {
|
|
1383
|
+
cancelAnimationFrame(this.sessionTimelineRafId);
|
|
1384
|
+
}
|
|
1385
|
+
this.sessionTimelineRafId = 0;
|
|
1386
|
+
},
|
|
1387
|
+
scheduleSessionTimelineSync() {
|
|
1388
|
+
if (this.sessionTimelineRafId) return;
|
|
1389
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
1390
|
+
this.sessionTimelineRafId = requestAnimationFrame(() => {
|
|
1391
|
+
this.sessionTimelineRafId = 0;
|
|
1392
|
+
this.syncSessionTimelineActiveFromScroll();
|
|
1393
|
+
});
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
this.syncSessionTimelineActiveFromScroll();
|
|
1397
|
+
},
|
|
1398
|
+
onSessionPreviewScroll() {
|
|
1399
|
+
this.scheduleSessionTimelineSync();
|
|
1400
|
+
},
|
|
1401
|
+
onWindowResize() {
|
|
1402
|
+
this.updateSessionTimelineOffset();
|
|
1403
|
+
this.scheduleSessionTimelineSync();
|
|
1404
|
+
},
|
|
1405
|
+
syncSessionTimelineActiveFromScroll() {
|
|
1406
|
+
const nodes = Array.isArray(this.sessionTimelineNodes) ? this.sessionTimelineNodes : [];
|
|
1407
|
+
if (!nodes.length) {
|
|
1408
|
+
this.sessionTimelineActiveKey = '';
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
const scrollEl = this.sessionPreviewScrollEl || this.$refs.sessionPreviewScroll;
|
|
1412
|
+
if (!scrollEl) {
|
|
1413
|
+
this.sessionTimelineActiveKey = nodes[0].key;
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
const scrollRect = scrollEl.getBoundingClientRect();
|
|
1417
|
+
const headerEl = scrollEl.querySelector('.session-preview-header');
|
|
1418
|
+
const headerHeight = headerEl ? headerEl.getBoundingClientRect().height : 0;
|
|
1419
|
+
const anchorLine = scrollRect.top + headerHeight + 8;
|
|
1420
|
+
let activeKey = nodes[0].key;
|
|
1421
|
+
for (const node of nodes) {
|
|
1422
|
+
const messageEl = this.sessionMessageRefMap[node.key];
|
|
1423
|
+
if (!messageEl) continue;
|
|
1424
|
+
const messageRect = messageEl.getBoundingClientRect();
|
|
1425
|
+
if (messageRect.top <= anchorLine) {
|
|
1426
|
+
activeKey = node.key;
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
break;
|
|
1430
|
+
}
|
|
1431
|
+
this.sessionTimelineActiveKey = activeKey;
|
|
1432
|
+
},
|
|
1433
|
+
jumpToSessionTimelineNode(messageKey) {
|
|
1434
|
+
if (!messageKey) return;
|
|
1435
|
+
const scrollEl = this.sessionPreviewScrollEl || this.$refs.sessionPreviewScroll;
|
|
1436
|
+
if (!scrollEl) return;
|
|
1437
|
+
const messageEl = this.sessionMessageRefMap[messageKey];
|
|
1438
|
+
if (!messageEl) return;
|
|
1439
|
+
const headerEl = scrollEl.querySelector('.session-preview-header');
|
|
1440
|
+
const stickyOffset = headerEl ? (headerEl.offsetHeight + 8) : 8;
|
|
1441
|
+
const scrollRect = scrollEl.getBoundingClientRect();
|
|
1442
|
+
const messageRect = messageEl.getBoundingClientRect();
|
|
1443
|
+
const targetScrollTop = scrollEl.scrollTop + (messageRect.top - scrollRect.top) - stickyOffset;
|
|
1444
|
+
this.sessionTimelineActiveKey = messageKey;
|
|
1445
|
+
if (typeof scrollEl.scrollTo === 'function') {
|
|
1446
|
+
scrollEl.scrollTo({
|
|
1447
|
+
top: Math.max(0, targetScrollTop),
|
|
1448
|
+
behavior: 'smooth'
|
|
1449
|
+
});
|
|
1450
|
+
} else {
|
|
1451
|
+
messageEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1452
|
+
}
|
|
1453
|
+
},
|
|
1454
|
+
|
|
1455
|
+
normalizeSessionMessage(message) {
|
|
1456
|
+
const fallback = {
|
|
1457
|
+
role: 'assistant',
|
|
1458
|
+
normalizedRole: 'assistant',
|
|
1459
|
+
roleLabel: 'Assistant',
|
|
1460
|
+
text: typeof message === 'string' ? message : '',
|
|
1461
|
+
timestamp: ''
|
|
1462
|
+
};
|
|
1463
|
+
const safeMessage = message && typeof message === 'object' ? message : fallback;
|
|
1464
|
+
const normalizedRole = normalizeSessionMessageRole(
|
|
1465
|
+
safeMessage.normalizedRole || safeMessage.role
|
|
1466
|
+
);
|
|
1467
|
+
const roleLabel = normalizedRole === 'user'
|
|
1468
|
+
? 'User'
|
|
1469
|
+
: (normalizedRole === 'system' ? 'System' : 'Assistant');
|
|
1470
|
+
return {
|
|
1471
|
+
...safeMessage,
|
|
1472
|
+
role: normalizedRole,
|
|
1473
|
+
normalizedRole,
|
|
1474
|
+
roleLabel
|
|
1475
|
+
};
|
|
1476
|
+
},
|
|
1302
1477
|
|
|
1303
1478
|
getRecordKey(message) {
|
|
1304
1479
|
if (!message || !Number.isInteger(message.recordLineIndex) || message.recordLineIndex < 0) {
|
|
@@ -1347,6 +1522,9 @@
|
|
|
1347
1522
|
this.activeSession = null;
|
|
1348
1523
|
this.activeSessionMessages = [];
|
|
1349
1524
|
this.activeSessionDetailClipped = false;
|
|
1525
|
+
this.cancelSessionTimelineSync();
|
|
1526
|
+
this.sessionTimelineActiveKey = '';
|
|
1527
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1350
1528
|
} else {
|
|
1351
1529
|
this.sessionsList = Array.isArray(res.sessions) ? res.sessions : [];
|
|
1352
1530
|
this.syncSessionPathOptionsForSource(
|
|
@@ -1358,10 +1536,19 @@
|
|
|
1358
1536
|
this.activeSession = null;
|
|
1359
1537
|
this.activeSessionMessages = [];
|
|
1360
1538
|
this.activeSessionDetailClipped = false;
|
|
1539
|
+
this.cancelSessionTimelineSync();
|
|
1540
|
+
this.sessionTimelineActiveKey = '';
|
|
1541
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1361
1542
|
} else {
|
|
1362
1543
|
const oldKey = this.activeSession ? this.getSessionExportKey(this.activeSession) : '';
|
|
1363
1544
|
const matched = this.sessionsList.find(item => this.getSessionExportKey(item) === oldKey);
|
|
1364
1545
|
this.activeSession = matched || this.sessionsList[0];
|
|
1546
|
+
this.activeSessionMessages = [];
|
|
1547
|
+
this.activeSessionDetailError = '';
|
|
1548
|
+
this.activeSessionDetailClipped = false;
|
|
1549
|
+
this.cancelSessionTimelineSync();
|
|
1550
|
+
this.sessionTimelineActiveKey = '';
|
|
1551
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1365
1552
|
await this.loadActiveSessionDetail();
|
|
1366
1553
|
}
|
|
1367
1554
|
void this.loadSessionPathOptions({ source: this.sessionFilterSource });
|
|
@@ -1371,6 +1558,9 @@
|
|
|
1371
1558
|
this.activeSession = null;
|
|
1372
1559
|
this.activeSessionMessages = [];
|
|
1373
1560
|
this.activeSessionDetailClipped = false;
|
|
1561
|
+
this.cancelSessionTimelineSync();
|
|
1562
|
+
this.sessionTimelineActiveKey = '';
|
|
1563
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1374
1564
|
this.showMessage('加载会话失败', 'error');
|
|
1375
1565
|
} finally {
|
|
1376
1566
|
this.sessionsLoading = false;
|
|
@@ -1384,6 +1574,9 @@
|
|
|
1384
1574
|
this.activeSessionMessages = [];
|
|
1385
1575
|
this.activeSessionDetailError = '';
|
|
1386
1576
|
this.activeSessionDetailClipped = false;
|
|
1577
|
+
this.cancelSessionTimelineSync();
|
|
1578
|
+
this.sessionTimelineActiveKey = '';
|
|
1579
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1387
1580
|
await this.loadActiveSessionDetail();
|
|
1388
1581
|
},
|
|
1389
1582
|
|
|
@@ -1437,6 +1630,9 @@
|
|
|
1437
1630
|
this.activeSessionMessages = [];
|
|
1438
1631
|
this.activeSessionDetailError = '';
|
|
1439
1632
|
this.activeSessionDetailClipped = false;
|
|
1633
|
+
this.cancelSessionTimelineSync();
|
|
1634
|
+
this.sessionTimelineActiveKey = '';
|
|
1635
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1440
1636
|
return;
|
|
1441
1637
|
}
|
|
1442
1638
|
|
|
@@ -1459,10 +1655,14 @@
|
|
|
1459
1655
|
this.activeSessionMessages = [];
|
|
1460
1656
|
this.activeSessionDetailClipped = false;
|
|
1461
1657
|
this.activeSessionDetailError = res.error;
|
|
1658
|
+
this.cancelSessionTimelineSync();
|
|
1659
|
+
this.sessionTimelineActiveKey = '';
|
|
1660
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1462
1661
|
return;
|
|
1463
1662
|
}
|
|
1464
1663
|
|
|
1465
|
-
|
|
1664
|
+
const rawMessages = Array.isArray(res.messages) ? res.messages : [];
|
|
1665
|
+
this.activeSessionMessages = rawMessages.map((message) => this.normalizeSessionMessage(message));
|
|
1466
1666
|
this.activeSessionDetailClipped = !!res.clipped;
|
|
1467
1667
|
if (this.activeSession) {
|
|
1468
1668
|
if (res.sourceLabel) {
|
|
@@ -1487,6 +1687,10 @@
|
|
|
1487
1687
|
if (Number.isFinite(res.totalMessages)) {
|
|
1488
1688
|
this.syncActiveSessionMessageCount(res.totalMessages);
|
|
1489
1689
|
}
|
|
1690
|
+
this.$nextTick(() => {
|
|
1691
|
+
this.updateSessionTimelineOffset();
|
|
1692
|
+
this.scheduleSessionTimelineSync();
|
|
1693
|
+
});
|
|
1490
1694
|
} catch (e) {
|
|
1491
1695
|
if (requestSeq !== this.sessionDetailRequestSeq) {
|
|
1492
1696
|
return;
|
|
@@ -1494,6 +1698,9 @@
|
|
|
1494
1698
|
this.activeSessionMessages = [];
|
|
1495
1699
|
this.activeSessionDetailClipped = false;
|
|
1496
1700
|
this.activeSessionDetailError = '加载会话内容失败: ' + e.message;
|
|
1701
|
+
this.cancelSessionTimelineSync();
|
|
1702
|
+
this.sessionTimelineActiveKey = '';
|
|
1703
|
+
this.sessionMessageRefMap = Object.create(null);
|
|
1497
1704
|
} finally {
|
|
1498
1705
|
if (requestSeq === this.sessionDetailRequestSeq) {
|
|
1499
1706
|
this.sessionDetailLoading = false;
|
|
@@ -1550,7 +1757,9 @@
|
|
|
1550
1757
|
if (this.modelsSource === 'remote' && this.models.length > 0 && !this.models.includes(this.currentModel)) {
|
|
1551
1758
|
this.currentModel = this.models[0];
|
|
1552
1759
|
}
|
|
1553
|
-
|
|
1760
|
+
if (getProviderConfigModeMeta(this.configMode)) {
|
|
1761
|
+
await this.applyCodexConfigDirect({ silent: true });
|
|
1762
|
+
}
|
|
1554
1763
|
},
|
|
1555
1764
|
|
|
1556
1765
|
async onModelChange() {
|
|
@@ -1754,6 +1963,8 @@
|
|
|
1754
1963
|
}
|
|
1755
1964
|
},
|
|
1756
1965
|
|
|
1966
|
+
...createSkillsMethods({ api }),
|
|
1967
|
+
|
|
1757
1968
|
async openOpenclawAgentsEditor() {
|
|
1758
1969
|
this.setAgentsModalContext('openclaw');
|
|
1759
1970
|
this.agentsLoading = true;
|
|
@@ -3860,4 +4071,3 @@
|
|
|
3860
4071
|
app.mount('#app');
|
|
3861
4072
|
});
|
|
3862
4073
|
|
|
3863
|
-
|