codexmate 0.0.20 → 0.0.21

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 (102) hide show
  1. package/README.en.md +349 -259
  2. package/README.md +284 -252
  3. package/cli/agents-files.js +162 -0
  4. package/cli/archive-helpers.js +446 -0
  5. package/cli/auth-profiles.js +359 -0
  6. package/cli/builtin-proxy.js +580 -0
  7. package/cli/claude-proxy.js +998 -0
  8. package/cli/config-bootstrap.js +384 -0
  9. package/cli/config-health.js +338 -338
  10. package/cli/openclaw-config.js +629 -0
  11. package/cli/skills.js +1141 -0
  12. package/cli/zip-commands.js +510 -0
  13. package/cli.js +13101 -13497
  14. package/lib/cli-file-utils.js +151 -151
  15. package/lib/cli-models-utils.js +419 -311
  16. package/lib/cli-network-utils.js +164 -164
  17. package/lib/cli-path-utils.js +69 -0
  18. package/lib/cli-session-utils.js +121 -121
  19. package/lib/cli-sessions.js +386 -0
  20. package/lib/cli-utils.js +155 -155
  21. package/lib/download-artifacts.js +77 -0
  22. package/lib/mcp-stdio.js +440 -440
  23. package/lib/task-orchestrator.js +869 -0
  24. package/lib/text-diff.js +303 -303
  25. package/lib/workflow-engine.js +340 -340
  26. package/package.json +74 -70
  27. package/res/json5.min.js +1 -1
  28. package/res/vue.global.prod.js +13 -0
  29. package/web-ui/app.js +530 -397
  30. package/web-ui/index.html +33 -30
  31. package/web-ui/logic.agents-diff.mjs +386 -386
  32. package/web-ui/logic.claude.mjs +168 -108
  33. package/web-ui/logic.mjs +5 -5
  34. package/web-ui/logic.runtime.mjs +124 -124
  35. package/web-ui/logic.sessions.mjs +581 -263
  36. package/web-ui/modules/api.mjs +90 -69
  37. package/web-ui/modules/app.computed.dashboard.mjs +113 -113
  38. package/web-ui/modules/app.computed.index.mjs +15 -13
  39. package/web-ui/modules/app.computed.main-tabs.mjs +195 -0
  40. package/web-ui/modules/app.computed.session.mjs +507 -141
  41. package/web-ui/modules/app.constants.mjs +15 -15
  42. package/web-ui/modules/app.methods.agents.mjs +493 -493
  43. package/web-ui/modules/app.methods.claude-config.mjs +174 -174
  44. package/web-ui/modules/app.methods.codex-config.mjs +640 -640
  45. package/web-ui/modules/app.methods.index.mjs +88 -86
  46. package/web-ui/modules/app.methods.install.mjs +149 -157
  47. package/web-ui/modules/app.methods.navigation.mjs +619 -478
  48. package/web-ui/modules/app.methods.openclaw-core.mjs +814 -514
  49. package/web-ui/modules/app.methods.openclaw-editing.mjs +372 -337
  50. package/web-ui/modules/app.methods.openclaw-persist.mjs +369 -251
  51. package/web-ui/modules/app.methods.providers.mjs +363 -265
  52. package/web-ui/modules/app.methods.runtime.mjs +323 -323
  53. package/web-ui/modules/app.methods.session-actions.mjs +520 -457
  54. package/web-ui/modules/app.methods.session-browser.mjs +626 -435
  55. package/web-ui/modules/app.methods.session-timeline.mjs +448 -441
  56. package/web-ui/modules/app.methods.session-trash.mjs +422 -419
  57. package/web-ui/modules/app.methods.startup-claude.mjs +412 -406
  58. package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
  59. package/web-ui/modules/config-mode.computed.mjs +126 -124
  60. package/web-ui/modules/skills.computed.mjs +107 -107
  61. package/web-ui/modules/skills.methods.mjs +481 -481
  62. package/web-ui/partials/index/layout-footer.html +13 -69
  63. package/web-ui/partials/index/layout-header.html +402 -337
  64. package/web-ui/partials/index/modal-config-template-agents.html +125 -125
  65. package/web-ui/partials/index/modal-confirm-toast.html +32 -32
  66. package/web-ui/partials/index/modal-health-check.html +72 -72
  67. package/web-ui/partials/index/modal-openclaw-config.html +280 -275
  68. package/web-ui/partials/index/modal-skills.html +184 -184
  69. package/web-ui/partials/index/modals-basic.html +156 -196
  70. package/web-ui/partials/index/panel-config-claude.html +126 -100
  71. package/web-ui/partials/index/panel-config-codex.html +237 -237
  72. package/web-ui/partials/index/panel-config-openclaw.html +78 -84
  73. package/web-ui/partials/index/panel-docs.html +130 -0
  74. package/web-ui/partials/index/panel-market.html +174 -174
  75. package/web-ui/partials/index/panel-orchestration.html +397 -0
  76. package/web-ui/partials/index/panel-sessions.html +292 -387
  77. package/web-ui/partials/index/panel-settings.html +190 -166
  78. package/web-ui/partials/index/panel-usage.html +213 -0
  79. package/web-ui/session-helpers.mjs +559 -362
  80. package/web-ui/source-bundle.cjs +233 -233
  81. package/web-ui/styles/base-theme.css +271 -373
  82. package/web-ui/styles/controls-forms.css +360 -354
  83. package/web-ui/styles/docs-panel.css +182 -0
  84. package/web-ui/styles/feedback.css +108 -108
  85. package/web-ui/styles/health-check-dialog.css +144 -144
  86. package/web-ui/styles/layout-shell.css +376 -330
  87. package/web-ui/styles/modals-core.css +464 -449
  88. package/web-ui/styles/navigation-panels.css +348 -381
  89. package/web-ui/styles/openclaw-structured.css +266 -266
  90. package/web-ui/styles/responsive.css +450 -416
  91. package/web-ui/styles/sessions-list.css +400 -414
  92. package/web-ui/styles/sessions-preview.css +411 -405
  93. package/web-ui/styles/sessions-toolbar-trash.css +243 -243
  94. package/web-ui/styles/sessions-usage.css +628 -276
  95. package/web-ui/styles/skills-list.css +296 -298
  96. package/web-ui/styles/skills-market.css +335 -335
  97. package/web-ui/styles/task-orchestration.css +776 -0
  98. package/web-ui/styles/titles-cards.css +408 -407
  99. package/web-ui/styles.css +18 -16
  100. package/web-ui.html +17 -17
  101. package/res/screenshot.png +0 -0
  102. package/res/vue.global.js +0 -18552
package/web-ui/app.js CHANGED
@@ -1,397 +1,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
-
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
- showInstallModal: false,
67
- showConfirmDialog: false,
68
- confirmDialogTitle: '',
69
- confirmDialogMessage: '',
70
- confirmDialogConfirmText: '确认',
71
- confirmDialogCancelText: '取消',
72
- confirmDialogDanger: false,
73
- confirmDialogConfirmDisabled: false,
74
- confirmDialogDisableWhen: null,
75
- confirmDialogResolver: null,
76
- configTemplateContent: '',
77
- configTemplateApplying: false,
78
- codexApplying: false,
79
- _pendingCodexApplyOptions: null,
80
- agentsContent: '',
81
- agentsPath: '',
82
- agentsExists: false,
83
- agentsLineEnding: '\n',
84
- agentsLoading: false,
85
- agentsSaving: false,
86
- agentsOriginalContent: '',
87
- agentsDiffVisible: false,
88
- agentsDiffLoading: false,
89
- agentsDiffError: '',
90
- agentsDiffLines: [],
91
- agentsDiffStats: {
92
- added: 0,
93
- removed: 0,
94
- unchanged: 0
95
- },
96
- agentsDiffTruncated: false,
97
- agentsDiffHasChangesValue: false,
98
- agentsDiffFingerprint: '',
99
- agentsContext: 'codex',
100
- agentsModalTitle: 'AGENTS.md 编辑器',
101
- agentsModalHint: '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
102
- skillsTargetApp: 'codex',
103
- skillsRootPath: '',
104
- skillsList: [],
105
- skillsSelectedNames: [],
106
- skillsLoading: false,
107
- skillsDeleting: false,
108
- skillsKeyword: '',
109
- skillsStatusFilter: 'all',
110
- skillsImportList: [],
111
- skillsImportSelectedKeys: [],
112
- skillsScanningImports: false,
113
- skillsImporting: false,
114
- skillsZipImporting: false,
115
- skillsExporting: false,
116
- skillsMarketLoading: false,
117
- skillsMarketLocalLoadedOnce: false,
118
- skillsMarketImportLoadedOnce: false,
119
- sessionPinnedMap: {},
120
- sessionsViewMode: 'browser',
121
- sessionsUsageTimeRange: '7d',
122
- sessionsList: [],
123
- sessionsLoadedOnce: false,
124
- sessionsLoading: false,
125
- sessionFilterSource: 'all',
126
- sessionPathFilter: '',
127
- sessionQuery: '',
128
- sessionRoleFilter: 'all',
129
- sessionTimePreset: 'all',
130
- sessionResumeWithYolo: true,
131
- sessionPathOptions: [],
132
- sessionPathOptionsLoading: false,
133
- sessionPathOptionsMap: {
134
- all: [],
135
- codex: [],
136
- claude: []
137
- },
138
- sessionPathOptionsLoadedMap: {
139
- all: false,
140
- codex: false,
141
- claude: false
142
- },
143
- sessionPathRequestSeqMap: {
144
- all: 0,
145
- codex: 0,
146
- claude: 0
147
- },
148
- sessionExporting: {},
149
- sessionCloning: {},
150
- sessionDeleting: {},
151
- activeSession: null,
152
- activeSessionMessages: [],
153
- activeSessionDetailError: '',
154
- activeSessionDetailClipped: false,
155
- sessionDetailLoading: false,
156
- sessionDetailRequestSeq: 0,
157
- sessionDetailInitialMessageLimit: 80,
158
- sessionDetailFetchStep: 80,
159
- sessionDetailMessageLimit: 80,
160
- sessionDetailMessageLimitCap: 1000,
161
- sessionTimelineActiveKey: '',
162
- sessionTimelineRafId: 0,
163
- sessionTimelineLastSyncAt: 0,
164
- sessionTimelineLastScrollTop: 0,
165
- sessionTimelineLastAnchorY: 0,
166
- sessionTimelineLastDirection: 0,
167
- sessionTimelineEnabled: true,
168
- sessionMessageRefMap: Object.create(null),
169
- sessionMessageRefBinderMap: Object.create(null),
170
- sessionPreviewScrollEl: null,
171
- sessionPreviewContainerEl: null,
172
- sessionPreviewHeaderEl: null,
173
- sessionPreviewHeaderResizeObserver: null,
174
- sessionListRenderEnabled: false,
175
- sessionPreviewRenderEnabled: false,
176
- sessionTabRenderTicket: 0,
177
- sessionPreviewVisibleCount: 0,
178
- sessionPreviewInitialBatchSize: 12,
179
- sessionPreviewLoadStep: 24,
180
- sessionPreviewPendingVisibleCount: 0,
181
- sessionPreviewLoadingMore: false,
182
- sessionStandalone: false,
183
- sessionStandaloneError: '',
184
- sessionStandaloneText: '',
185
- sessionStandaloneTitle: '',
186
- sessionStandaloneSourceLabel: '',
187
- sessionStandaloneLoading: false,
188
- sessionStandaloneRequestSeq: 0,
189
- speedResults: {},
190
- speedLoading: {},
191
- claudeSpeedResults: {},
192
- claudeSpeedLoading: {},
193
- claudeShareLoading: {},
194
- providerShareLoading: {},
195
- providerSwitchInProgress: false,
196
- pendingProviderSwitch: '',
197
- providerSwitchDisplayTarget: '',
198
- healthCheckDialogLockedProvider: '',
199
- healthCheckDialogSelectedProvider: '',
200
- healthCheckDialogPrompt: '请简短回复:当前提供商连接正常。',
201
- healthCheckDialogMessages: [],
202
- healthCheckDialogSending: false,
203
- healthCheckDialogLastResult: null,
204
- installPackageManager: 'npm',
205
- installCommandAction: 'install',
206
- installRegistryPreset: 'default',
207
- installRegistryCustom: '',
208
- installStatusTargets: [
209
- {
210
- id: 'claude',
211
- name: 'Claude Code CLI',
212
- packageName: '@anthropic-ai/claude-code',
213
- installed: false,
214
- bin: 'claude',
215
- version: '',
216
- commandPath: '',
217
- error: ''
218
- },
219
- {
220
- id: 'codex',
221
- name: 'Codex CLI',
222
- packageName: '@openai/codex',
223
- installed: false,
224
- bin: 'codex',
225
- version: '',
226
- commandPath: '',
227
- error: ''
228
- }
229
- ],
230
- newProvider: { name: '', url: '', key: '' },
231
- resetConfigLoading: false,
232
- editingProvider: { name: '', url: '', key: '', readOnly: false, nonEditable: false },
233
- newModelName: '',
234
- currentClaudeConfig: '',
235
- currentClaudeModel: '',
236
- editingConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
237
- claudeConfigs: {
238
- '智谱GLM': {
239
- apiKey: '',
240
- baseUrl: 'https://open.bigmodel.cn/api/anthropic',
241
- model: 'glm-4.7',
242
- hasKey: false
243
- }
244
- },
245
- newClaudeConfig: {
246
- name: '',
247
- apiKey: '',
248
- baseUrl: 'https://open.bigmodel.cn/api/anthropic',
249
- model: 'glm-4.7'
250
- },
251
- currentOpenclawConfig: '',
252
- openclawConfigs: {
253
- '默认配置': {
254
- content: DEFAULT_OPENCLAW_TEMPLATE
255
- }
256
- },
257
- openclawEditing: { name: '', content: '', lockName: false },
258
- openclawEditorTitle: '添加 OpenClaw 配置',
259
- openclawConfigPath: '',
260
- openclawConfigExists: false,
261
- openclawLineEnding: '\n',
262
- openclawFileLoading: false,
263
- openclawSaving: false,
264
- openclawApplying: false,
265
- openclawWorkspaceFileName: 'SOUL.md',
266
- agentsWorkspaceFileName: '',
267
- openclawStructured: {
268
- agentPrimary: '',
269
- agentFallbacks: [],
270
- workspace: '',
271
- timeout: '',
272
- contextTokens: '',
273
- maxConcurrent: '',
274
- envItems: [],
275
- toolsProfile: 'default',
276
- toolsAllow: [],
277
- toolsDeny: []
278
- },
279
- openclawQuick: {
280
- providerName: '',
281
- baseUrl: '',
282
- apiKey: '',
283
- apiType: 'openai-responses',
284
- modelId: '',
285
- modelName: '',
286
- contextWindow: '',
287
- maxTokens: '',
288
- setPrimary: true,
289
- overrideProvider: true,
290
- overrideModels: true,
291
- showKey: false
292
- },
293
- openclawAgentsList: [],
294
- openclawProviders: [],
295
- openclawMissingProviders: [],
296
- healthCheckLoading: false,
297
- healthCheckResult: null,
298
- healthCheckRemote: false,
299
- claudeDownloadLoading: false,
300
- claudeDownloadProgress: 0,
301
- claudeDownloadTimer: null,
302
- codexDownloadLoading: false,
303
- codexDownloadProgress: 0,
304
- codexDownloadTimer: null,
305
- settingsTab: 'backup',
306
- sessionTrashItems: [],
307
- sessionTrashVisibleCount: SESSION_TRASH_PAGE_SIZE,
308
- sessionTrashTotalCount: 0,
309
- sessionTrashCountLoadedOnce: false,
310
- sessionTrashLoadedOnce: false,
311
- sessionTrashLastLoadFailed: false,
312
- sessionTrashCountRequestToken: 0,
313
- sessionTrashListRequestToken: 0,
314
- sessionTrashCountPendingOptions: null,
315
- sessionTrashPendingOptions: null,
316
- sessionTrashCountLoading: false,
317
- sessionTrashLoading: false,
318
- sessionTrashRestoring: {},
319
- sessionTrashPurging: {},
320
- sessionTrashClearing: false,
321
- claudeImportLoading: false,
322
- codexImportLoading: false,
323
- codexAuthProfiles: [],
324
- forceCompactLayout: false
325
- };
326
- },
327
-
328
- mounted() {
329
- this.initSessionStandalone();
330
- this.updateCompactLayoutMode();
331
- const savedSessionYolo = localStorage.getItem('codexmateSessionResumeYolo');
332
- if (savedSessionYolo === '0' || savedSessionYolo === 'false') {
333
- this.sessionResumeWithYolo = false;
334
- } else if (savedSessionYolo === '1' || savedSessionYolo === 'true') {
335
- this.sessionResumeWithYolo = true;
336
- }
337
- this.restoreSessionFilterCache();
338
- this.restoreSessionPinnedMap();
339
- window.addEventListener('resize', this.onWindowResize);
340
- window.addEventListener('keydown', this.handleGlobalKeydown);
341
- window.addEventListener('beforeunload', this.handleBeforeUnload);
342
- const savedConfigs = localStorage.getItem('claudeConfigs');
343
- if (savedConfigs) {
344
- try {
345
- this.claudeConfigs = JSON.parse(savedConfigs);
346
- for (const [name, config] of Object.entries(this.claudeConfigs)) {
347
- if (config.apiKey && config.apiKey.includes('****')) {
348
- config.apiKey = '';
349
- config.hasKey = false;
350
- }
351
- }
352
- localStorage.setItem('claudeConfigs', JSON.stringify(this.claudeConfigs));
353
- } catch (e) {
354
- console.error('加载 Claude 配置失败:', e);
355
- }
356
- }
357
- void this.refreshClaudeSelectionFromSettings({ silent: true });
358
- const savedOpenclawConfigs = localStorage.getItem('openclawConfigs');
359
- if (savedOpenclawConfigs) {
360
- try {
361
- this.openclawConfigs = JSON.parse(savedOpenclawConfigs);
362
- const configNames = Object.keys(this.openclawConfigs);
363
- if (configNames.length > 0) {
364
- this.currentOpenclawConfig = configNames[0];
365
- }
366
- } catch (e) {
367
- console.error('加载 OpenClaw 配置失败:', e);
368
- }
369
- } else {
370
- const configNames = Object.keys(this.openclawConfigs);
371
- if (configNames.length > 0) {
372
- this.currentOpenclawConfig = configNames[0];
373
- }
374
- }
375
- this.loadAll();
376
- },
377
-
378
- beforeUnmount() {
379
- this.teardownSessionTabRender();
380
- this.cancelScheduledSessionTabDeferredTeardown();
381
- this.disconnectSessionPreviewHeaderResizeObserver();
382
- window.removeEventListener('resize', this.onWindowResize);
383
- window.removeEventListener('keydown', this.handleGlobalKeydown);
384
- window.removeEventListener('beforeunload', this.handleBeforeUnload);
385
- this.applyCompactLayoutClass(false);
386
- this.sessionPreviewScrollEl = null;
387
- this.sessionPreviewContainerEl = null;
388
- this.sessionPreviewHeaderEl = null;
389
- this.clearSessionTimelineRefs();
390
- },
391
-
392
- computed: createAppComputed(),
393
- methods: createAppMethods()
394
- });
395
-
396
- app.mount('#app');
397
- });
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
+ });