codexmate 0.0.21 → 0.0.22

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.
Files changed (114) hide show
  1. package/README.md +389 -284
  2. package/README.zh.md +321 -0
  3. package/cli/agents-files.js +224 -162
  4. package/cli/archive-helpers.js +446 -446
  5. package/cli/auth-profiles.js +359 -359
  6. package/cli/builtin-proxy.js +1044 -580
  7. package/cli/claude-proxy.js +998 -998
  8. package/cli/config-bootstrap.js +384 -384
  9. package/cli/config-health.js +338 -338
  10. package/cli/openai-bridge.js +950 -0
  11. package/cli/openclaw-config.js +629 -629
  12. package/cli/session-usage.concurrent.js +28 -0
  13. package/cli/session-usage.js +112 -0
  14. package/cli/session-usage.models.js +176 -0
  15. package/cli/skills.js +1141 -1141
  16. package/cli/zip-commands.js +510 -510
  17. package/cli.js +13214 -13129
  18. package/lib/cli-file-utils.js +151 -151
  19. package/lib/cli-models-utils.js +419 -419
  20. package/lib/cli-network-utils.js +164 -164
  21. package/lib/cli-path-utils.js +69 -69
  22. package/lib/cli-session-utils.js +121 -121
  23. package/lib/cli-sessions.js +386 -386
  24. package/lib/cli-utils.js +155 -155
  25. package/lib/download-artifacts.js +77 -77
  26. package/lib/mcp-stdio.js +440 -440
  27. package/lib/task-orchestrator.js +869 -869
  28. package/lib/text-diff.js +303 -303
  29. package/lib/workflow-engine.js +340 -340
  30. package/package.json +74 -74
  31. package/res/json5.min.js +1 -1
  32. package/res/logo.png +0 -0
  33. package/res/vue.global.prod.js +13 -13
  34. package/web-ui/app.js +575 -530
  35. package/web-ui/index.html +34 -33
  36. package/web-ui/logic.agents-diff.mjs +386 -386
  37. package/web-ui/logic.claude.mjs +168 -168
  38. package/web-ui/logic.mjs +5 -5
  39. package/web-ui/logic.runtime.mjs +128 -124
  40. package/web-ui/logic.sessions.mjs +614 -581
  41. package/web-ui/modules/api.mjs +90 -90
  42. package/web-ui/modules/app.computed.dashboard.mjs +126 -113
  43. package/web-ui/modules/app.computed.index.mjs +17 -15
  44. package/web-ui/modules/app.computed.main-tabs.mjs +198 -195
  45. package/web-ui/modules/app.computed.session.mjs +653 -507
  46. package/web-ui/modules/app.constants.mjs +15 -15
  47. package/web-ui/modules/app.methods.agents.mjs +544 -493
  48. package/web-ui/modules/app.methods.claude-config.mjs +174 -174
  49. package/web-ui/modules/app.methods.codex-config.mjs +795 -640
  50. package/web-ui/modules/app.methods.index.mjs +92 -88
  51. package/web-ui/modules/app.methods.install.mjs +161 -149
  52. package/web-ui/modules/app.methods.navigation.mjs +619 -619
  53. package/web-ui/modules/app.methods.openclaw-core.mjs +814 -814
  54. package/web-ui/modules/app.methods.openclaw-editing.mjs +372 -372
  55. package/web-ui/modules/app.methods.openclaw-persist.mjs +369 -369
  56. package/web-ui/modules/app.methods.providers.mjs +404 -363
  57. package/web-ui/modules/app.methods.runtime.mjs +323 -323
  58. package/web-ui/modules/app.methods.session-actions.mjs +537 -520
  59. package/web-ui/modules/app.methods.session-browser.mjs +626 -626
  60. package/web-ui/modules/app.methods.session-timeline.mjs +448 -448
  61. package/web-ui/modules/app.methods.session-trash.mjs +422 -422
  62. package/web-ui/modules/app.methods.startup-claude.mjs +405 -412
  63. package/web-ui/modules/app.methods.task-orchestration.mjs +471 -471
  64. package/web-ui/modules/config-mode.computed.mjs +126 -126
  65. package/web-ui/modules/config-template-confirm-pref.mjs +33 -0
  66. package/web-ui/modules/i18n.mjs +1609 -0
  67. package/web-ui/modules/plugins.computed.mjs +220 -0
  68. package/web-ui/modules/plugins.methods.mjs +620 -0
  69. package/web-ui/modules/plugins.storage.mjs +37 -0
  70. package/web-ui/modules/skills.computed.mjs +107 -107
  71. package/web-ui/modules/skills.methods.mjs +481 -481
  72. package/web-ui/partials/index/layout-footer.html +13 -13
  73. package/web-ui/partials/index/layout-header.html +461 -402
  74. package/web-ui/partials/index/modal-config-template-agents.html +175 -125
  75. package/web-ui/partials/index/modal-confirm-toast.html +32 -32
  76. package/web-ui/partials/index/modal-health-check.html +72 -72
  77. package/web-ui/partials/index/modal-openclaw-config.html +280 -280
  78. package/web-ui/partials/index/modal-skills.html +200 -184
  79. package/web-ui/partials/index/modals-basic.html +165 -156
  80. package/web-ui/partials/index/panel-config-claude.html +138 -126
  81. package/web-ui/partials/index/panel-config-codex.html +234 -237
  82. package/web-ui/partials/index/panel-config-openclaw.html +78 -78
  83. package/web-ui/partials/index/panel-docs.html +147 -130
  84. package/web-ui/partials/index/panel-market.html +174 -174
  85. package/web-ui/partials/index/panel-orchestration.html +397 -397
  86. package/web-ui/partials/index/panel-plugins.html +243 -0
  87. package/web-ui/partials/index/panel-sessions.html +292 -292
  88. package/web-ui/partials/index/panel-settings.html +258 -190
  89. package/web-ui/partials/index/panel-usage.html +353 -213
  90. package/web-ui/session-helpers.mjs +573 -559
  91. package/web-ui/source-bundle.cjs +233 -233
  92. package/web-ui/styles/base-theme.css +264 -271
  93. package/web-ui/styles/controls-forms.css +362 -360
  94. package/web-ui/styles/docs-panel.css +247 -182
  95. package/web-ui/styles/feedback.css +108 -108
  96. package/web-ui/styles/health-check-dialog.css +144 -144
  97. package/web-ui/styles/layout-shell.css +596 -376
  98. package/web-ui/styles/modals-core.css +464 -464
  99. package/web-ui/styles/navigation-panels.css +382 -348
  100. package/web-ui/styles/openclaw-structured.css +266 -266
  101. package/web-ui/styles/plugins-panel.css +518 -0
  102. package/web-ui/styles/responsive.css +456 -450
  103. package/web-ui/styles/sessions-list.css +400 -400
  104. package/web-ui/styles/sessions-preview.css +411 -411
  105. package/web-ui/styles/sessions-toolbar-trash.css +268 -243
  106. package/web-ui/styles/sessions-usage.css +851 -628
  107. package/web-ui/styles/settings-panel.css +166 -0
  108. package/web-ui/styles/skills-list.css +303 -296
  109. package/web-ui/styles/skills-market.css +396 -335
  110. package/web-ui/styles/task-orchestration.css +776 -776
  111. package/web-ui/styles/titles-cards.css +408 -408
  112. package/web-ui/styles.css +20 -18
  113. package/web-ui.html +17 -17
  114. package/README.en.md +0 -349
package/web-ui/app.js CHANGED
@@ -1,530 +1,575 @@
1
- import {
2
- DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT,
3
- DEFAULT_MODEL_CONTEXT_WINDOW,
4
- DEFAULT_OPENCLAW_TEMPLATE,
5
- SESSION_TRASH_PAGE_SIZE
6
- } from './modules/app.constants.mjs';
7
- import { createAppComputed } from './modules/app.computed.index.mjs';
8
- import { createAppMethods } from './modules/app.methods.index.mjs';
9
-
10
- document.addEventListener('DOMContentLoaded', () => {
11
- if (typeof Vue === 'undefined') {
12
- console.error('Vue 库未能在 DOMContentLoaded 触发前加载完成。');
13
- const fallbackTarget = document.querySelector('#app') || document.querySelector('[v-cloak]');
14
- if (fallbackTarget) {
15
- fallbackTarget.removeAttribute('v-cloak');
16
- fallbackTarget.classList.remove('v-cloak');
17
- fallbackTarget.innerHTML = '';
18
- const notice = document.createElement('div');
19
- notice.className = 'fallback-message';
20
- notice.textContent = 'Web UI 加载失败:Vue 未加载。请检查网络或刷新页面。';
21
- fallbackTarget.appendChild(notice);
22
- }
23
- return;
24
- }
25
-
26
- const { createApp } = Vue;
27
-
28
- const app = createApp({
29
- data() {
30
- return {
31
- mainTab: 'config',
32
- configMode: 'codex',
33
- currentProvider: '',
34
- currentModel: '',
35
- serviceTier: 'fast',
36
- modelReasoningEffort: 'medium',
37
- modelContextWindowInput: String(DEFAULT_MODEL_CONTEXT_WINDOW),
38
- modelAutoCompactTokenLimitInput: String(DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT),
39
- editingCodexBudgetField: '',
40
- providersList: [],
41
- models: [],
42
- codexModelsLoading: false,
43
- modelsSource: 'remote',
44
- modelsHasCurrent: true,
45
- claudeModels: [],
46
- claudeModelsSource: 'idle',
47
- claudeModelsHasCurrent: true,
48
- claudeModelsLoading: false,
49
- codexModelsRequestSeq: 0,
50
- claudeModelsRequestSeq: 0,
51
- loading: true,
52
- initError: '',
53
- message: '',
54
- messageType: '',
55
- showAddModal: false,
56
- showEditModal: false,
57
- showModelModal: false,
58
- showModelListModal: false,
59
- showClaudeConfigModal: false,
60
- showEditConfigModal: false,
61
- showOpenclawConfigModal: false,
62
- showConfigTemplateModal: false,
63
- showHealthCheckDialog: false,
64
- showAgentsModal: false,
65
- showSkillsModal: false,
66
- showConfirmDialog: false,
67
- confirmDialogTitle: '',
68
- confirmDialogMessage: '',
69
- confirmDialogConfirmText: '确认',
70
- confirmDialogCancelText: '取消',
71
- confirmDialogDanger: false,
72
- confirmDialogConfirmDisabled: false,
73
- confirmDialogDisableWhen: null,
74
- confirmDialogResolver: null,
75
- configTemplateContent: '',
76
- configTemplateApplying: false,
77
- codexApplying: false,
78
- _pendingCodexApplyOptions: null,
79
- agentsContent: '',
80
- agentsPath: '',
81
- agentsExists: false,
82
- agentsLineEnding: '\n',
83
- agentsLoading: false,
84
- agentsSaving: false,
85
- agentsOriginalContent: '',
86
- agentsDiffVisible: false,
87
- agentsDiffLoading: false,
88
- agentsDiffError: '',
89
- agentsDiffLines: [],
90
- agentsDiffStats: {
91
- added: 0,
92
- removed: 0,
93
- unchanged: 0
94
- },
95
- agentsDiffTruncated: false,
96
- agentsDiffHasChangesValue: false,
97
- agentsDiffFingerprint: '',
98
- agentsContext: 'codex',
99
- agentsModalTitle: 'AGENTS.md 编辑器',
100
- agentsModalHint: '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
101
- skillsTargetApp: 'codex',
102
- skillsRootPath: '',
103
- skillsList: [],
104
- skillsSelectedNames: [],
105
- skillsLoading: false,
106
- skillsDeleting: false,
107
- skillsKeyword: '',
108
- skillsStatusFilter: 'all',
109
- skillsImportList: [],
110
- skillsImportSelectedKeys: [],
111
- skillsScanningImports: false,
112
- skillsImporting: false,
113
- skillsZipImporting: false,
114
- skillsExporting: false,
115
- skillsMarketLoading: false,
116
- skillsMarketLocalLoadedOnce: false,
117
- skillsMarketImportLoadedOnce: false,
118
- sessionPinnedMap: {},
119
- __mainTabSwitchState: {
120
- intent: '',
121
- pendingTarget: '',
122
- pendingConfigMode: '',
123
- ticket: 0
124
- },
125
- sessionsViewMode: 'browser',
126
- sessionsUsageTimeRange: '7d',
127
- sessionsUsageList: [],
128
- sessionsUsageLoadedOnce: false,
129
- sessionsUsageLoading: false,
130
- sessionsUsageError: '',
131
- sessionsList: [],
132
- sessionsLoadedOnce: false,
133
- sessionsLoading: false,
134
- sessionFilterSource: 'all',
135
- sessionPathFilter: '',
136
- sessionQuery: '',
137
- sessionRoleFilter: 'all',
138
- sessionTimePreset: 'all',
139
- sessionResumeWithYolo: true,
140
- sessionPathOptions: [],
141
- sessionPathOptionsLoading: false,
142
- sessionPathOptionsMap: {
143
- all: [],
144
- codex: [],
145
- claude: []
146
- },
147
- sessionPathOptionsLoadedMap: {
148
- all: false,
149
- codex: false,
150
- claude: false
151
- },
152
- sessionPathRequestSeqMap: {
153
- all: 0,
154
- codex: 0,
155
- claude: 0
156
- },
157
- sessionExporting: {},
158
- sessionCloning: {},
159
- sessionDeleting: {},
160
- activeSession: null,
161
- activeSessionMessages: [],
162
- activeSessionDetailError: '',
163
- activeSessionDetailClipped: false,
164
- sessionDetailLoading: false,
165
- sessionDetailRequestSeq: 0,
166
- sessionDetailInitialMessageLimit: 80,
167
- sessionDetailFetchStep: 80,
168
- sessionDetailMessageLimit: 80,
169
- sessionDetailMessageLimitCap: 1000,
170
- sessionTimelineActiveKey: '',
171
- sessionTimelineRafId: 0,
172
- sessionTimelineLastSyncAt: 0,
173
- sessionTimelineLastScrollTop: 0,
174
- sessionTimelineLastAnchorY: 0,
175
- sessionTimelineLastDirection: 0,
176
- sessionTimelineEnabled: true,
177
- sessionMessageRefMap: Object.create(null),
178
- sessionMessageRefBinderMap: Object.create(null),
179
- sessionPreviewScrollEl: null,
180
- sessionPreviewContainerEl: null,
181
- sessionPreviewHeaderEl: null,
182
- sessionPreviewHeaderResizeObserver: null,
183
- sessionListRenderEnabled: false,
184
- sessionListVisibleCount: 0,
185
- sessionListInitialBatchSize: 20,
186
- sessionListLoadStep: 40,
187
- sessionPreviewRenderEnabled: false,
188
- sessionTabRenderTicket: 0,
189
- sessionPreviewVisibleCount: 0,
190
- sessionPreviewInitialBatchSize: 12,
191
- sessionPreviewLoadStep: 24,
192
- sessionPreviewPendingVisibleCount: 0,
193
- sessionPreviewLoadingMore: false,
194
- sessionStandalone: false,
195
- sessionStandaloneError: '',
196
- sessionStandaloneText: '',
197
- sessionStandaloneTitle: '',
198
- sessionStandaloneSourceLabel: '',
199
- sessionStandaloneLoading: false,
200
- sessionStandaloneRequestSeq: 0,
201
- speedResults: {},
202
- speedLoading: {},
203
- claudeSpeedResults: {},
204
- claudeSpeedLoading: {},
205
- claudeShareLoading: {},
206
- providerShareLoading: {},
207
- shareCommandPrefix: 'npm start',
208
- providerSwitchInProgress: false,
209
- pendingProviderSwitch: '',
210
- providerSwitchDisplayTarget: '',
211
- healthCheckDialogLockedProvider: '',
212
- healthCheckDialogSelectedProvider: '',
213
- healthCheckDialogPrompt: '请简短回复:当前提供商连接正常。',
214
- healthCheckDialogMessages: [],
215
- healthCheckDialogSending: false,
216
- healthCheckDialogLastResult: null,
217
- installPackageManager: 'npm',
218
- installCommandAction: 'install',
219
- installRegistryPreset: 'default',
220
- installRegistryCustom: '',
221
- installStatusTargets: [
222
- {
223
- id: 'claude',
224
- name: 'Claude Code CLI',
225
- packageName: '@anthropic-ai/claude-code',
226
- installed: false,
227
- bin: 'claude',
228
- version: '',
229
- commandPath: '',
230
- error: ''
231
- },
232
- {
233
- id: 'codex',
234
- name: 'Codex CLI',
235
- packageName: '@openai/codex',
236
- installed: false,
237
- bin: 'codex',
238
- version: '',
239
- commandPath: '',
240
- error: ''
241
- }
242
- ],
243
- newProvider: { name: '', url: '', key: '' },
244
- resetConfigLoading: false,
245
- editingProvider: { name: '', url: '', key: '', readOnly: false, nonEditable: false },
246
- newModelName: '',
247
- currentClaudeConfig: '',
248
- currentClaudeModel: '',
249
- editingConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
250
- claudeConfigs: {
251
- '智谱GLM': {
252
- apiKey: '',
253
- baseUrl: 'https://open.bigmodel.cn/api/anthropic',
254
- model: 'glm-4.7',
255
- hasKey: false
256
- }
257
- },
258
- newClaudeConfig: {
259
- name: '',
260
- apiKey: '',
261
- baseUrl: 'https://open.bigmodel.cn/api/anthropic',
262
- model: 'glm-4.7'
263
- },
264
- currentOpenclawConfig: '',
265
- openclawConfigs: {
266
- '默认配置': {
267
- content: DEFAULT_OPENCLAW_TEMPLATE
268
- }
269
- },
270
- openclawEditing: { name: '', content: '', lockName: false },
271
- openclawEditorTitle: '添加 OpenClaw 配置',
272
- openclawConfigPath: '',
273
- openclawConfigExists: false,
274
- openclawLineEnding: '\n',
275
- openclawAuthProfilesByProvider: {},
276
- openclawPendingAuthProfileUpdates: {},
277
- openclawFileLoading: false,
278
- openclawSaving: false,
279
- openclawApplying: false,
280
- openclawWorkspaceFileName: 'SOUL.md',
281
- agentsWorkspaceFileName: '',
282
- openclawStructured: {
283
- agentPrimary: '',
284
- agentFallbacks: [],
285
- workspace: '',
286
- timeout: '',
287
- contextTokens: '',
288
- maxConcurrent: '',
289
- envItems: [],
290
- toolsProfile: 'default',
291
- toolsAllow: [],
292
- toolsDeny: []
293
- },
294
- openclawQuick: {
295
- providerName: '',
296
- baseUrl: '',
297
- baseUrlReadOnly: false,
298
- baseUrlDisplayKind: 'missing',
299
- apiKey: '',
300
- apiKeyReadOnly: false,
301
- apiKeyDisplayKind: 'missing',
302
- apiKeySourceKind: '',
303
- apiKeySourceProfileId: '',
304
- apiKeySourceWriteField: '',
305
- apiKeySourceOriginalValue: '',
306
- apiKeySourceCredentialType: '',
307
- apiType: 'openai-responses',
308
- modelId: '',
309
- modelName: '',
310
- contextWindow: '',
311
- maxTokens: '',
312
- setPrimary: true,
313
- overrideProvider: true,
314
- overrideModels: true,
315
- showKey: false
316
- },
317
- openclawAgentsList: [],
318
- openclawProviders: [],
319
- openclawMissingProviders: [],
320
- healthCheckLoading: false,
321
- healthCheckResult: null,
322
- healthCheckRemote: false,
323
- claudeDownloadLoading: false,
324
- claudeDownloadProgress: 0,
325
- claudeDownloadTimer: null,
326
- codexDownloadLoading: false,
327
- codexDownloadProgress: 0,
328
- codexDownloadTimer: null,
329
- settingsTab: 'backup',
330
- sessionTrashEnabled: true,
331
- sessionTrashItems: [],
332
- sessionTrashVisibleCount: SESSION_TRASH_PAGE_SIZE,
333
- sessionTrashTotalCount: 0,
334
- sessionTrashCountLoadedOnce: false,
335
- sessionTrashLoadedOnce: false,
336
- sessionTrashLastLoadFailed: false,
337
- sessionTrashCountRequestToken: 0,
338
- sessionTrashListRequestToken: 0,
339
- sessionTrashCountPendingOptions: null,
340
- sessionTrashPendingOptions: null,
341
- sessionTrashCountLoading: false,
342
- sessionTrashLoading: false,
343
- sessionTrashRestoring: {},
344
- sessionTrashPurging: {},
345
- sessionTrashClearing: false,
346
- claudeImportLoading: false,
347
- codexImportLoading: false,
348
- codexAuthProfiles: [],
349
- forceCompactLayout: false,
350
- taskOrchestrationTabEnabled: false,
351
- taskOrchestration: {
352
- loading: false,
353
- planning: false,
354
- running: false,
355
- queueAdding: false,
356
- queueStarting: false,
357
- retrying: false,
358
- target: '',
359
- title: '',
360
- notes: '',
361
- followUpsText: '',
362
- workflowIdsText: '',
363
- selectedEngine: 'codex',
364
- allowWrite: false,
365
- dryRun: false,
366
- concurrency: 2,
367
- autoFixRounds: 1,
368
- plan: null,
369
- planIssues: [],
370
- planWarnings: [],
371
- overviewWarnings: [],
372
- workflows: [],
373
- queue: [],
374
- runs: [],
375
- selectedRunId: '',
376
- workspaceTab: 'queue',
377
- selectedRunDetail: null,
378
- selectedRunLoading: false,
379
- selectedRunError: '',
380
- detailRequestToken: 0,
381
- lastLoadedAt: '',
382
- lastError: ''
383
- },
384
- _taskOrchestrationPollTimer: 0
385
- };
386
- },
387
-
388
- mounted() {
389
- this.initSessionStandalone();
390
- this.updateCompactLayoutMode();
391
- if (!this.taskOrchestrationTabEnabled && this.mainTab === 'orchestration') {
392
- this.mainTab = 'config';
393
- }
394
- const savedSessionYolo = localStorage.getItem('codexmateSessionResumeYolo');
395
- if (savedSessionYolo === '0' || savedSessionYolo === 'false') {
396
- this.sessionResumeWithYolo = false;
397
- } else if (savedSessionYolo === '1' || savedSessionYolo === 'true') {
398
- this.sessionResumeWithYolo = true;
399
- }
400
- this.restoreSessionFilterCache();
401
- this.restoreSessionPinnedMap();
402
- this.shareCommandPrefix = this.normalizeShareCommandPrefix(localStorage.getItem('codexmateShareCommandPrefix'));
403
- this.sessionTrashEnabled = this.normalizeSessionTrashEnabled(localStorage.getItem('codexmateSessionTrashEnabled'));
404
- window.addEventListener('resize', this.onWindowResize);
405
- window.addEventListener('keydown', this.handleGlobalKeydown);
406
- window.addEventListener('beforeunload', this.handleBeforeUnload);
407
- const savedConfigs = localStorage.getItem('claudeConfigs');
408
- if (savedConfigs) {
409
- try {
410
- this.claudeConfigs = JSON.parse(savedConfigs);
411
- for (const [name, config] of Object.entries(this.claudeConfigs)) {
412
- if (config.apiKey && config.apiKey.includes('****')) {
413
- config.apiKey = '';
414
- config.hasKey = false;
415
- }
416
- }
417
- localStorage.setItem('claudeConfigs', JSON.stringify(this.claudeConfigs));
418
- } catch (e) {
419
- console.error('加载 Claude 配置失败:', e);
420
- }
421
- }
422
- const normalizeOpenclawConfigs = (configs) => {
423
- const source = configs && typeof configs === 'object' && !Array.isArray(configs)
424
- ? configs
425
- : {};
426
- const defaultEntry = source['默认配置']
427
- && typeof source['默认配置'] === 'object'
428
- && !Array.isArray(source['默认配置'])
429
- ? source['默认配置']
430
- : { content: DEFAULT_OPENCLAW_TEMPLATE };
431
- const normalized = {
432
- '默认配置': {
433
- content: typeof defaultEntry.content === 'string' ? defaultEntry.content : DEFAULT_OPENCLAW_TEMPLATE
434
- }
435
- };
436
- for (const [name, value] of Object.entries(source)) {
437
- if (name === '默认配置') continue;
438
- normalized[name] = value;
439
- }
440
- return normalized;
441
- };
442
- const savedOpenclawConfigs = localStorage.getItem('openclawConfigs');
443
- if (savedOpenclawConfigs) {
444
- try {
445
- this.openclawConfigs = normalizeOpenclawConfigs(JSON.parse(savedOpenclawConfigs));
446
- } catch (e) {
447
- console.error('加载 OpenClaw 配置失败:', e);
448
- this.openclawConfigs = normalizeOpenclawConfigs(this.openclawConfigs);
449
- }
450
- } else {
451
- this.openclawConfigs = normalizeOpenclawConfigs(this.openclawConfigs);
452
- }
453
- const configNames = Object.keys(this.openclawConfigs);
454
- if (configNames.length > 0) {
455
- this.currentOpenclawConfig = this.openclawConfigs['默认配置'] ? '默认配置' : configNames[0];
456
- }
457
- const runInitialLoad = () => {
458
- const triggerLoad = async () => {
459
- this._initialLoadTimer = 0;
460
- const startupOk = await this.loadAll();
461
- if (!startupOk) {
462
- return;
463
- }
464
- void this.refreshClaudeSelectionFromSettings({ silent: true });
465
- void this.syncDefaultOpenclawConfigEntry({ silent: true });
466
- };
467
- if (typeof requestAnimationFrame === 'function') {
468
- this._initialLoadRafId = requestAnimationFrame(() => {
469
- this._initialLoadRafId = 0;
470
- if (typeof setTimeout === 'function') {
471
- this._initialLoadTimer = setTimeout(triggerLoad, 120);
472
- return;
473
- }
474
- triggerLoad();
475
- });
476
- return;
477
- }
478
- if (typeof setTimeout === 'function') {
479
- this._initialLoadTimer = setTimeout(triggerLoad, 120);
480
- return;
481
- }
482
- triggerLoad();
483
- };
484
- if (document.readyState === 'complete') {
485
- runInitialLoad();
486
- } else {
487
- this._initialLoadOnWindowLoad = () => {
488
- if (typeof window !== 'undefined' && typeof window.removeEventListener === 'function') {
489
- window.removeEventListener('load', this._initialLoadOnWindowLoad);
490
- }
491
- this._initialLoadOnWindowLoad = null;
492
- runInitialLoad();
493
- };
494
- window.addEventListener('load', this._initialLoadOnWindowLoad, { once: true });
495
- }
496
- },
497
-
498
- beforeUnmount() {
499
- this.teardownSessionTabRender();
500
- this.cancelScheduledSessionTabDeferredTeardown();
501
- this.disconnectSessionPreviewHeaderResizeObserver();
502
- if (this._initialLoadOnWindowLoad) {
503
- window.removeEventListener('load', this._initialLoadOnWindowLoad);
504
- this._initialLoadOnWindowLoad = null;
505
- }
506
- if (this._initialLoadRafId) {
507
- cancelAnimationFrame(this._initialLoadRafId);
508
- this._initialLoadRafId = 0;
509
- }
510
- if (this._initialLoadTimer) {
511
- clearTimeout(this._initialLoadTimer);
512
- this._initialLoadTimer = 0;
513
- }
514
- window.removeEventListener('resize', this.onWindowResize);
515
- window.removeEventListener('keydown', this.handleGlobalKeydown);
516
- window.removeEventListener('beforeunload', this.handleBeforeUnload);
517
- this.applyCompactLayoutClass(false);
518
- this.stopTaskOrchestrationPolling();
519
- this.sessionPreviewScrollEl = null;
520
- this.sessionPreviewContainerEl = null;
521
- this.sessionPreviewHeaderEl = null;
522
- this.clearSessionTimelineRefs();
523
- },
524
-
525
- computed: createAppComputed(),
526
- methods: createAppMethods()
527
- });
528
-
529
- app.mount('#app');
530
- });
1
+ import {
2
+ DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT,
3
+ DEFAULT_MODEL_CONTEXT_WINDOW,
4
+ DEFAULT_OPENCLAW_TEMPLATE,
5
+ SESSION_TRASH_PAGE_SIZE
6
+ } from './modules/app.constants.mjs';
7
+ import { createAppComputed } from './modules/app.computed.index.mjs';
8
+ import { createAppMethods } from './modules/app.methods.index.mjs';
9
+ import { loadConfigTemplateDiffConfirmEnabledFromStorage } from './modules/config-template-confirm-pref.mjs';
10
+
11
+ document.addEventListener('DOMContentLoaded', () => {
12
+ if (typeof Vue === 'undefined') {
13
+ console.error('Vue 库未能在 DOMContentLoaded 触发前加载完成。');
14
+ const fallbackTarget = document.querySelector('#app') || document.querySelector('[v-cloak]');
15
+ if (fallbackTarget) {
16
+ fallbackTarget.removeAttribute('v-cloak');
17
+ fallbackTarget.classList.remove('v-cloak');
18
+ fallbackTarget.innerHTML = '';
19
+ const notice = document.createElement('div');
20
+ notice.className = 'fallback-message';
21
+ notice.textContent = 'Web UI 加载失败:Vue 未加载。请检查网络或刷新页面。';
22
+ fallbackTarget.appendChild(notice);
23
+ }
24
+ return;
25
+ }
26
+
27
+ const { createApp } = Vue;
28
+
29
+ const app = createApp({
30
+ data() {
31
+ return {
32
+ lang: 'zh',
33
+ // 默认选中首个主标签:Docs
34
+ mainTab: 'docs',
35
+ configMode: 'codex',
36
+ currentProvider: '',
37
+ currentModel: '',
38
+ serviceTier: 'fast',
39
+ modelReasoningEffort: 'medium',
40
+ modelContextWindowInput: String(DEFAULT_MODEL_CONTEXT_WINDOW),
41
+ modelAutoCompactTokenLimitInput: String(DEFAULT_MODEL_AUTO_COMPACT_TOKEN_LIMIT),
42
+ editingCodexBudgetField: '',
43
+ providersList: [],
44
+ models: [],
45
+ codexModelsLoading: false,
46
+ modelsSource: 'remote',
47
+ modelsHasCurrent: true,
48
+ claudeModels: [],
49
+ claudeModelsSource: 'idle',
50
+ claudeModelsHasCurrent: true,
51
+ claudeModelsLoading: false,
52
+ codexModelsRequestSeq: 0,
53
+ claudeModelsRequestSeq: 0,
54
+ loading: true,
55
+ initError: '',
56
+ message: '',
57
+ messageType: '',
58
+ showAddModal: false,
59
+ showEditModal: false,
60
+ showModelModal: false,
61
+ showModelListModal: false,
62
+ showClaudeConfigModal: false,
63
+ showEditConfigModal: false,
64
+ showOpenclawConfigModal: false,
65
+ showConfigTemplateModal: false,
66
+ showHealthCheckDialog: false,
67
+ showAgentsModal: false,
68
+ showSkillsModal: false,
69
+ // Plugins
70
+ pluginsActiveId: 'prompt-templates',
71
+ pluginsLoading: false,
72
+ promptTemplatesListRaw: [],
73
+ promptTemplatesLoadedOnce: false,
74
+ promptTemplatesKeyword: '',
75
+ promptTemplateSelectedId: '',
76
+ promptTemplateDraftRaw: null,
77
+ promptTemplateVarValuesRaw: {},
78
+ promptTemplatesMode: 'compose',
79
+ promptComposerCommand: '',
80
+ promptComposerPickerVisible: false,
81
+ promptComposerPickerKeyword: '',
82
+ promptComposerSelectedTemplateId: '',
83
+ promptComposerVarValuesRaw: {},
84
+ showPromptTemplateVarModal: false,
85
+ promptTemplateVarDraftName: '',
86
+ promptTemplateVarDraftError: '',
87
+ showConfirmDialog: false,
88
+ confirmDialogTitle: '',
89
+ confirmDialogMessage: '',
90
+ confirmDialogConfirmText: '确认',
91
+ confirmDialogCancelText: '取消',
92
+ confirmDialogDanger: false,
93
+ confirmDialogConfirmDisabled: false,
94
+ confirmDialogDisableWhen: null,
95
+ confirmDialogResolver: null,
96
+ configTemplateContent: '',
97
+ configTemplateApplying: false,
98
+ configTemplateDiffVisible: false,
99
+ configTemplateDiffLoading: false,
100
+ configTemplateDiffError: '',
101
+ configTemplateDiffLines: [],
102
+ configTemplateDiffStats: {
103
+ added: 0,
104
+ removed: 0,
105
+ unchanged: 0
106
+ },
107
+ configTemplateDiffHasChangesValue: false,
108
+ configTemplateDiffFingerprint: '',
109
+ _configTemplateDiffPreviewRequestToken: null,
110
+ configTemplateDiffConfirmEnabled: true,
111
+ codexApplying: false,
112
+ _pendingCodexApplyOptions: null,
113
+ agentsContent: '',
114
+ agentsPath: '',
115
+ agentsPath: '',
116
+ agentsExists: false,
117
+ agentsLineEnding: '\n',
118
+ agentsLoading: false,
119
+ agentsSaving: false,
120
+ agentsOriginalContent: '',
121
+ agentsDiffVisible: false,
122
+ agentsDiffLoading: false,
123
+ agentsDiffError: '',
124
+ agentsDiffLines: [],
125
+ agentsDiffStats: {
126
+ added: 0,
127
+ removed: 0,
128
+ unchanged: 0
129
+ },
130
+ agentsDiffTruncated: false,
131
+ agentsDiffHasChangesValue: false,
132
+ agentsDiffFingerprint: '',
133
+ agentsContext: 'codex',
134
+ agentsModalTitle: 'AGENTS.md 编辑器',
135
+ agentsModalHint: '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
136
+ skillsTargetApp: 'codex',
137
+ skillsRootPath: '',
138
+ skillsList: [],
139
+ skillsSelectedNames: [],
140
+ skillsLoading: false,
141
+ skillsDeleting: false,
142
+ skillsKeyword: '',
143
+ skillsStatusFilter: 'all',
144
+ skillsImportList: [],
145
+ skillsImportSelectedKeys: [],
146
+ skillsScanningImports: false,
147
+ skillsImporting: false,
148
+ skillsZipImporting: false,
149
+ skillsExporting: false,
150
+ skillsMarketLoading: false,
151
+ skillsMarketLocalLoadedOnce: false,
152
+ skillsMarketImportLoadedOnce: false,
153
+ sessionPinnedMap: {},
154
+ __mainTabSwitchState: {
155
+ intent: '',
156
+ pendingTarget: '',
157
+ pendingConfigMode: '',
158
+ ticket: 0
159
+ },
160
+ sessionsViewMode: 'browser',
161
+ sessionsUsageTimeRange: '7d',
162
+ sessionsUsageList: [],
163
+ sessionsUsageLoadedOnce: false,
164
+ sessionsUsageLoading: false,
165
+ sessionsUsageError: '',
166
+ sessionsList: [],
167
+ sessionsLoadedOnce: false,
168
+ sessionsLoading: false,
169
+ sessionFilterSource: 'all',
170
+ sessionPathFilter: '',
171
+ sessionQuery: '',
172
+ sessionRoleFilter: 'all',
173
+ sessionTimePreset: 'all',
174
+ sessionResumeWithYolo: true,
175
+ sessionPathOptions: [],
176
+ sessionPathOptionsLoading: false,
177
+ sessionPathOptionsMap: {
178
+ all: [],
179
+ codex: [],
180
+ claude: []
181
+ },
182
+ sessionPathOptionsLoadedMap: {
183
+ all: false,
184
+ codex: false,
185
+ claude: false
186
+ },
187
+ sessionPathRequestSeqMap: {
188
+ all: 0,
189
+ codex: 0,
190
+ claude: 0
191
+ },
192
+ sessionExporting: {},
193
+ sessionCloning: {},
194
+ sessionDeleting: {},
195
+ activeSession: null,
196
+ activeSessionMessages: [],
197
+ activeSessionDetailError: '',
198
+ activeSessionDetailClipped: false,
199
+ sessionDetailLoading: false,
200
+ sessionDetailRequestSeq: 0,
201
+ sessionDetailInitialMessageLimit: 80,
202
+ sessionDetailFetchStep: 80,
203
+ sessionDetailMessageLimit: 80,
204
+ sessionDetailMessageLimitCap: 1000,
205
+ sessionTimelineActiveKey: '',
206
+ sessionTimelineRafId: 0,
207
+ sessionTimelineLastSyncAt: 0,
208
+ sessionTimelineLastScrollTop: 0,
209
+ sessionTimelineLastAnchorY: 0,
210
+ sessionTimelineLastDirection: 0,
211
+ sessionTimelineEnabled: true,
212
+ sessionMessageRefMap: Object.create(null),
213
+ sessionMessageRefBinderMap: Object.create(null),
214
+ sessionPreviewScrollEl: null,
215
+ sessionPreviewContainerEl: null,
216
+ sessionPreviewHeaderEl: null,
217
+ sessionPreviewHeaderResizeObserver: null,
218
+ sessionListRenderEnabled: false,
219
+ sessionListVisibleCount: 0,
220
+ sessionListInitialBatchSize: 20,
221
+ sessionListLoadStep: 40,
222
+ sessionPreviewRenderEnabled: false,
223
+ sessionTabRenderTicket: 0,
224
+ sessionPreviewVisibleCount: 0,
225
+ sessionPreviewInitialBatchSize: 12,
226
+ sessionPreviewLoadStep: 24,
227
+ sessionPreviewPendingVisibleCount: 0,
228
+ sessionPreviewLoadingMore: false,
229
+ sessionStandalone: false,
230
+ sessionStandaloneError: '',
231
+ sessionStandaloneText: '',
232
+ sessionStandaloneTitle: '',
233
+ sessionStandaloneSourceLabel: '',
234
+ sessionStandaloneLoading: false,
235
+ sessionStandaloneRequestSeq: 0,
236
+ speedResults: {},
237
+ speedLoading: {},
238
+ claudeSpeedResults: {},
239
+ claudeSpeedLoading: {},
240
+ claudeShareLoading: {},
241
+ providerShareLoading: {},
242
+ shareCommandPrefix: 'npm start',
243
+ providerSwitchInProgress: false,
244
+ pendingProviderSwitch: '',
245
+ providerSwitchDisplayTarget: '',
246
+ healthCheckDialogLockedProvider: '',
247
+ healthCheckDialogSelectedProvider: '',
248
+ healthCheckDialogPrompt: '请简短回复:连接正常。',
249
+ healthCheckDialogMessages: [],
250
+ healthCheckDialogSending: false,
251
+ healthCheckDialogLastResult: null,
252
+ installPackageManager: 'npm',
253
+ installCommandAction: 'install',
254
+ installRegistryPreset: 'default',
255
+ installRegistryCustom: '',
256
+ installStatusTargets: [
257
+ {
258
+ id: 'claude',
259
+ name: 'Claude Code CLI',
260
+ packageName: '@anthropic-ai/claude-code',
261
+ installed: false,
262
+ bin: 'claude',
263
+ version: '',
264
+ commandPath: '',
265
+ error: ''
266
+ },
267
+ {
268
+ id: 'codex',
269
+ name: 'Codex CLI',
270
+ packageName: '@openai/codex',
271
+ installed: false,
272
+ bin: 'codex',
273
+ version: '',
274
+ commandPath: '',
275
+ error: ''
276
+ }
277
+ ],
278
+ newProvider: { name: '', url: '', key: '', useTransform: false },
279
+ resetConfigLoading: false,
280
+ editingProvider: { name: '', url: '', key: '', readOnly: false, nonEditable: false },
281
+ newModelName: '',
282
+ currentClaudeConfig: '',
283
+ currentClaudeModel: '',
284
+ editingConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
285
+ claudeConfigs: {
286
+ '智谱GLM': {
287
+ apiKey: '',
288
+ baseUrl: 'https://open.bigmodel.cn/api/anthropic',
289
+ model: 'glm-4.7',
290
+ hasKey: false
291
+ }
292
+ },
293
+ newClaudeConfig: {
294
+ name: '',
295
+ apiKey: '',
296
+ baseUrl: 'https://open.bigmodel.cn/api/anthropic',
297
+ model: 'glm-4.7'
298
+ },
299
+ currentOpenclawConfig: '',
300
+ openclawConfigs: {
301
+ '默认配置': {
302
+ content: DEFAULT_OPENCLAW_TEMPLATE
303
+ }
304
+ },
305
+ openclawEditing: { name: '', content: '', lockName: false },
306
+ openclawEditorTitle: '添加 OpenClaw 配置',
307
+ openclawConfigPath: '',
308
+ openclawConfigExists: false,
309
+ openclawLineEnding: '\n',
310
+ openclawAuthProfilesByProvider: {},
311
+ openclawPendingAuthProfileUpdates: {},
312
+ openclawFileLoading: false,
313
+ openclawSaving: false,
314
+ openclawApplying: false,
315
+ openclawWorkspaceFileName: 'SOUL.md',
316
+ agentsWorkspaceFileName: '',
317
+ openclawStructured: {
318
+ agentPrimary: '',
319
+ agentFallbacks: [],
320
+ workspace: '',
321
+ timeout: '',
322
+ contextTokens: '',
323
+ maxConcurrent: '',
324
+ envItems: [],
325
+ toolsProfile: 'default',
326
+ toolsAllow: [],
327
+ toolsDeny: []
328
+ },
329
+ openclawQuick: {
330
+ providerName: '',
331
+ baseUrl: '',
332
+ baseUrlReadOnly: false,
333
+ baseUrlDisplayKind: 'missing',
334
+ apiKey: '',
335
+ apiKeyReadOnly: false,
336
+ apiKeyDisplayKind: 'missing',
337
+ apiKeySourceKind: '',
338
+ apiKeySourceProfileId: '',
339
+ apiKeySourceWriteField: '',
340
+ apiKeySourceOriginalValue: '',
341
+ apiKeySourceCredentialType: '',
342
+ apiType: 'openai-responses',
343
+ modelId: '',
344
+ modelName: '',
345
+ contextWindow: '',
346
+ maxTokens: '',
347
+ setPrimary: true,
348
+ overrideProvider: true,
349
+ overrideModels: true,
350
+ showKey: false
351
+ },
352
+ openclawAgentsList: [],
353
+ openclawProviders: [],
354
+ openclawMissingProviders: [],
355
+ healthCheckLoading: false,
356
+ healthCheckResult: null,
357
+ healthCheckRemote: false,
358
+ claudeDownloadLoading: false,
359
+ claudeDownloadProgress: 0,
360
+ claudeDownloadTimer: null,
361
+ codexDownloadLoading: false,
362
+ codexDownloadProgress: 0,
363
+ codexDownloadTimer: null,
364
+ settingsTab: 'backup',
365
+ sessionTrashEnabled: true,
366
+ sessionTrashItems: [],
367
+ sessionTrashVisibleCount: SESSION_TRASH_PAGE_SIZE,
368
+ sessionTrashTotalCount: 0,
369
+ sessionTrashCountLoadedOnce: false,
370
+ sessionTrashLoadedOnce: false,
371
+ sessionTrashLastLoadFailed: false,
372
+ sessionTrashCountRequestToken: 0,
373
+ sessionTrashListRequestToken: 0,
374
+ sessionTrashCountPendingOptions: null,
375
+ sessionTrashPendingOptions: null,
376
+ sessionTrashCountLoading: false,
377
+ sessionTrashLoading: false,
378
+ sessionTrashRestoring: {},
379
+ sessionTrashPurging: {},
380
+ sessionTrashClearing: false,
381
+ claudeImportLoading: false,
382
+ codexImportLoading: false,
383
+ codexAuthProfiles: [],
384
+ forceCompactLayout: false,
385
+ taskOrchestrationTabEnabled: false,
386
+ taskOrchestration: {
387
+ loading: false,
388
+ planning: false,
389
+ running: false,
390
+ queueAdding: false,
391
+ queueStarting: false,
392
+ retrying: false,
393
+ target: '',
394
+ title: '',
395
+ notes: '',
396
+ followUpsText: '',
397
+ workflowIdsText: '',
398
+ selectedEngine: 'codex',
399
+ allowWrite: false,
400
+ dryRun: false,
401
+ concurrency: 2,
402
+ autoFixRounds: 1,
403
+ plan: null,
404
+ planIssues: [],
405
+ planWarnings: [],
406
+ overviewWarnings: [],
407
+ workflows: [],
408
+ queue: [],
409
+ runs: [],
410
+ selectedRunId: '',
411
+ workspaceTab: 'queue',
412
+ selectedRunDetail: null,
413
+ selectedRunLoading: false,
414
+ selectedRunError: '',
415
+ detailRequestToken: 0,
416
+ lastLoadedAt: '',
417
+ lastError: ''
418
+ },
419
+ _taskOrchestrationPollTimer: 0
420
+ };
421
+ },
422
+
423
+ mounted() {
424
+ if (typeof this.initI18n === 'function') {
425
+ this.initI18n();
426
+ }
427
+ if (typeof this.t === 'function') {
428
+ this.confirmDialogConfirmText = this.t('confirm.ok');
429
+ this.confirmDialogCancelText = this.t('confirm.cancel');
430
+ this.agentsModalTitle = this.t('modal.agents.title');
431
+ this.agentsModalHint = this.t('modal.agents.hint');
432
+ }
433
+ this.initSessionStandalone();
434
+ this.updateCompactLayoutMode();
435
+ if (!this.taskOrchestrationTabEnabled && this.mainTab === 'orchestration') {
436
+ this.mainTab = 'config';
437
+ }
438
+ const savedSessionYolo = localStorage.getItem('codexmateSessionResumeYolo');
439
+ if (savedSessionYolo === '0' || savedSessionYolo === 'false') {
440
+ this.sessionResumeWithYolo = false;
441
+ } else if (savedSessionYolo === '1' || savedSessionYolo === 'true') {
442
+ this.sessionResumeWithYolo = true;
443
+ }
444
+ this.restoreSessionFilterCache();
445
+ this.restoreSessionPinnedMap();
446
+ this.shareCommandPrefix = this.normalizeShareCommandPrefix(localStorage.getItem('codexmateShareCommandPrefix'));
447
+ this.sessionTrashEnabled = this.normalizeSessionTrashEnabled(localStorage.getItem('codexmateSessionTrashEnabled'));
448
+ this.configTemplateDiffConfirmEnabled = loadConfigTemplateDiffConfirmEnabledFromStorage(localStorage);
449
+ window.addEventListener('resize', this.onWindowResize);
450
+ window.addEventListener('keydown', this.handleGlobalKeydown);
451
+ window.addEventListener('beforeunload', this.handleBeforeUnload);
452
+ const savedConfigs = localStorage.getItem('claudeConfigs');
453
+ if (savedConfigs) {
454
+ try {
455
+ this.claudeConfigs = JSON.parse(savedConfigs);
456
+ for (const [name, config] of Object.entries(this.claudeConfigs)) {
457
+ if (config.apiKey && config.apiKey.includes('****')) {
458
+ config.apiKey = '';
459
+ config.hasKey = false;
460
+ }
461
+ }
462
+ localStorage.setItem('claudeConfigs', JSON.stringify(this.claudeConfigs));
463
+ } catch (e) {
464
+ console.error('加载 Claude 配置失败:', e);
465
+ }
466
+ }
467
+ const normalizeOpenclawConfigs = (configs) => {
468
+ const source = configs && typeof configs === 'object' && !Array.isArray(configs)
469
+ ? configs
470
+ : {};
471
+ const defaultEntry = source['默认配置']
472
+ && typeof source['默认配置'] === 'object'
473
+ && !Array.isArray(source['默认配置'])
474
+ ? source['默认配置']
475
+ : { content: DEFAULT_OPENCLAW_TEMPLATE };
476
+ const normalized = {
477
+ '默认配置': {
478
+ content: typeof defaultEntry.content === 'string' ? defaultEntry.content : DEFAULT_OPENCLAW_TEMPLATE
479
+ }
480
+ };
481
+ for (const [name, value] of Object.entries(source)) {
482
+ if (name === '默认配置') continue;
483
+ normalized[name] = value;
484
+ }
485
+ return normalized;
486
+ };
487
+ const savedOpenclawConfigs = localStorage.getItem('openclawConfigs');
488
+ if (savedOpenclawConfigs) {
489
+ try {
490
+ this.openclawConfigs = normalizeOpenclawConfigs(JSON.parse(savedOpenclawConfigs));
491
+ } catch (e) {
492
+ console.error('加载 OpenClaw 配置失败:', e);
493
+ this.openclawConfigs = normalizeOpenclawConfigs(this.openclawConfigs);
494
+ }
495
+ } else {
496
+ this.openclawConfigs = normalizeOpenclawConfigs(this.openclawConfigs);
497
+ }
498
+ const configNames = Object.keys(this.openclawConfigs);
499
+ if (configNames.length > 0) {
500
+ this.currentOpenclawConfig = this.openclawConfigs['默认配置'] ? '默认配置' : configNames[0];
501
+ }
502
+ const runInitialLoad = () => {
503
+ const triggerLoad = async () => {
504
+ this._initialLoadTimer = 0;
505
+ const startupOk = await this.loadAll();
506
+ if (!startupOk) {
507
+ return;
508
+ }
509
+ void this.refreshClaudeSelectionFromSettings({ silent: true });
510
+ void this.syncDefaultOpenclawConfigEntry({ silent: true });
511
+ };
512
+ if (typeof requestAnimationFrame === 'function') {
513
+ this._initialLoadRafId = requestAnimationFrame(() => {
514
+ this._initialLoadRafId = 0;
515
+ if (typeof setTimeout === 'function') {
516
+ this._initialLoadTimer = setTimeout(triggerLoad, 120);
517
+ return;
518
+ }
519
+ triggerLoad();
520
+ });
521
+ return;
522
+ }
523
+ if (typeof setTimeout === 'function') {
524
+ this._initialLoadTimer = setTimeout(triggerLoad, 120);
525
+ return;
526
+ }
527
+ triggerLoad();
528
+ };
529
+ if (document.readyState === 'complete') {
530
+ runInitialLoad();
531
+ } else {
532
+ this._initialLoadOnWindowLoad = () => {
533
+ if (typeof window !== 'undefined' && typeof window.removeEventListener === 'function') {
534
+ window.removeEventListener('load', this._initialLoadOnWindowLoad);
535
+ }
536
+ this._initialLoadOnWindowLoad = null;
537
+ runInitialLoad();
538
+ };
539
+ window.addEventListener('load', this._initialLoadOnWindowLoad, { once: true });
540
+ }
541
+ },
542
+
543
+ beforeUnmount() {
544
+ this.teardownSessionTabRender();
545
+ this.cancelScheduledSessionTabDeferredTeardown();
546
+ this.disconnectSessionPreviewHeaderResizeObserver();
547
+ if (this._initialLoadOnWindowLoad) {
548
+ window.removeEventListener('load', this._initialLoadOnWindowLoad);
549
+ this._initialLoadOnWindowLoad = null;
550
+ }
551
+ if (this._initialLoadRafId) {
552
+ cancelAnimationFrame(this._initialLoadRafId);
553
+ this._initialLoadRafId = 0;
554
+ }
555
+ if (this._initialLoadTimer) {
556
+ clearTimeout(this._initialLoadTimer);
557
+ this._initialLoadTimer = 0;
558
+ }
559
+ window.removeEventListener('resize', this.onWindowResize);
560
+ window.removeEventListener('keydown', this.handleGlobalKeydown);
561
+ window.removeEventListener('beforeunload', this.handleBeforeUnload);
562
+ this.applyCompactLayoutClass(false);
563
+ this.stopTaskOrchestrationPolling();
564
+ this.sessionPreviewScrollEl = null;
565
+ this.sessionPreviewContainerEl = null;
566
+ this.sessionPreviewHeaderEl = null;
567
+ this.clearSessionTimelineRefs();
568
+ },
569
+
570
+ computed: createAppComputed(),
571
+ methods: createAppMethods()
572
+ });
573
+
574
+ app.mount('#app');
575
+ });