codexmate 0.0.56 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.vi.md +1 -0
- package/README.zh.md +2 -2
- package/cli/openai-bridge-retry.js +62 -0
- package/cli/openai-bridge-runtime.js +1819 -0
- package/cli/openai-bridge.js +137 -2048
- package/cli.js +749 -133
- package/lib/task-orchestrator.js +90 -21
- package/lib/task-workspace-chat.js +292 -0
- package/package.json +2 -2
- package/web-ui/app.js +67 -131
- package/web-ui/modules/app.computed.main-tabs.mjs +304 -7
- package/web-ui/modules/app.methods.agents.mjs +192 -1
- package/web-ui/modules/app.methods.claude-config.mjs +65 -25
- package/web-ui/modules/app.methods.navigation.mjs +67 -83
- package/web-ui/modules/app.methods.openclaw-editing.mjs +3 -6
- package/web-ui/modules/app.methods.providers.mjs +40 -10
- package/web-ui/modules/app.methods.session-actions.mjs +1 -12
- package/web-ui/modules/app.methods.session-browser.mjs +23 -54
- package/web-ui/modules/app.methods.session-trash.mjs +0 -1
- package/web-ui/modules/app.methods.startup-claude.mjs +16 -31
- package/web-ui/modules/app.methods.task-orchestration.mjs +347 -8
- package/web-ui/modules/app.methods.tool-config-permissions.mjs +0 -3
- package/web-ui/modules/app.methods.web-ui-preferences.mjs +442 -68
- package/web-ui/modules/config-template-confirm-pref.mjs +2 -3
- package/web-ui/modules/i18n/locales/en.mjs +181 -30
- package/web-ui/modules/i18n/locales/ja.mjs +178 -27
- package/web-ui/modules/i18n/locales/vi.mjs +180 -29
- package/web-ui/modules/i18n/locales/zh-tw.mjs +181 -30
- package/web-ui/modules/i18n/locales/zh.mjs +183 -32
- package/web-ui/modules/i18n.mjs +5 -12
- package/web-ui/modules/sessions-filters-url.mjs +1 -2
- package/web-ui/partials/index/layout-header.html +44 -38
- package/web-ui/partials/index/modals-basic.html +26 -0
- package/web-ui/partials/index/panel-orchestration.html +489 -282
- package/web-ui/partials/index/panel-prompts.html +66 -3
- package/web-ui/res/web-ui-render.precompiled.js +1181 -604
- package/web-ui/styles/layout-shell.css +157 -1
- package/web-ui/styles/modals-core.css +173 -0
- package/web-ui/styles/navigation-panels.css +11 -0
- package/web-ui/styles/responsive.css +32 -0
- package/web-ui/styles/task-orchestration.css +2161 -4
|
@@ -8,8 +8,6 @@ function normalizeClaudeBaseUrl(value) {
|
|
|
8
8
|
return normalizeClaudeText(value).replace(/\/+$/g, '');
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
const DELETED_CLAUDE_SETTINGS_IMPORTS_KEY = 'deletedClaudeSettingsImports';
|
|
12
|
-
|
|
13
11
|
function buildDeletedClaudeSettingsFingerprint(config = {}) {
|
|
14
12
|
const safe = config && typeof config === 'object' ? config : {};
|
|
15
13
|
const baseUrl = normalizeClaudeBaseUrl(safe.baseUrl);
|
|
@@ -92,10 +90,41 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
92
90
|
return {
|
|
93
91
|
switchClaudeConfig(name) {
|
|
94
92
|
this.currentClaudeConfig = name;
|
|
95
|
-
|
|
93
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
94
|
+
this.persistWebUiPreferences({ currentClaudeConfig: name || '' });
|
|
95
|
+
}
|
|
96
96
|
this.refreshClaudeModelContext();
|
|
97
97
|
},
|
|
98
98
|
|
|
99
|
+
normalizeStoredClaudeConfigs() {
|
|
100
|
+
const configs = this.claudeConfigs && typeof this.claudeConfigs === 'object' && !Array.isArray(this.claudeConfigs)
|
|
101
|
+
? this.claudeConfigs
|
|
102
|
+
: {};
|
|
103
|
+
let changed = configs !== this.claudeConfigs;
|
|
104
|
+
for (const config of Object.values(configs)) {
|
|
105
|
+
if (!config || typeof config !== 'object') continue;
|
|
106
|
+
if (config.apiKey && config.apiKey.includes('****')) {
|
|
107
|
+
config.apiKey = '';
|
|
108
|
+
config.hasKey = false;
|
|
109
|
+
changed = true;
|
|
110
|
+
}
|
|
111
|
+
const targetApiRaw = typeof config.targetApi === 'string' ? config.targetApi.trim().toLowerCase() : '';
|
|
112
|
+
const previousTargetApi = config.targetApi;
|
|
113
|
+
if (targetApiRaw === 'chat_completions' || targetApiRaw === 'chat-completions' || targetApiRaw === 'chat/completions') {
|
|
114
|
+
config.targetApi = 'chat_completions';
|
|
115
|
+
} else if (targetApiRaw === 'ollama') {
|
|
116
|
+
config.targetApi = 'ollama';
|
|
117
|
+
} else {
|
|
118
|
+
config.targetApi = 'responses';
|
|
119
|
+
}
|
|
120
|
+
if (config.targetApi !== previousTargetApi) {
|
|
121
|
+
changed = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
this.claudeConfigs = configs;
|
|
125
|
+
return changed;
|
|
126
|
+
},
|
|
127
|
+
|
|
99
128
|
onClaudeModelChange() {
|
|
100
129
|
const name = this.currentClaudeConfig;
|
|
101
130
|
if (!name || name === 'claude-local') {
|
|
@@ -124,9 +153,14 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
124
153
|
},
|
|
125
154
|
|
|
126
155
|
saveClaudeConfigs() {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
156
|
+
if (typeof this.normalizeStoredClaudeConfigs === 'function') {
|
|
157
|
+
this.normalizeStoredClaudeConfigs();
|
|
158
|
+
}
|
|
159
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
160
|
+
this.persistWebUiPreferences({
|
|
161
|
+
claudeConfigs: this.claudeConfigs,
|
|
162
|
+
currentClaudeConfig: this.currentClaudeConfig || ''
|
|
163
|
+
});
|
|
130
164
|
}
|
|
131
165
|
this.syncClaudeBridgeProviders();
|
|
132
166
|
},
|
|
@@ -134,18 +168,17 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
134
168
|
rememberDeletedClaudeSettingsImport(config) {
|
|
135
169
|
const fingerprint = buildDeletedClaudeSettingsFingerprint(config);
|
|
136
170
|
if (!fingerprint) return;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
} catch (_) {}
|
|
171
|
+
const entries = Array.isArray(this.deletedClaudeSettingsImports) ? this.deletedClaudeSettingsImports : [];
|
|
172
|
+
const deduped = entries.filter((entry) => {
|
|
173
|
+
if (!entry || typeof entry !== 'object') return false;
|
|
174
|
+
return normalizeClaudeBaseUrl(entry.baseUrl) !== fingerprint.baseUrl
|
|
175
|
+
|| normalizeClaudeText(entry.model) !== fingerprint.model;
|
|
176
|
+
});
|
|
177
|
+
deduped.push(fingerprint);
|
|
178
|
+
this.deletedClaudeSettingsImports = deduped.slice(-50);
|
|
179
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
180
|
+
this.persistWebUiPreferences({ deletedClaudeSettingsImports: this.deletedClaudeSettingsImports });
|
|
181
|
+
}
|
|
149
182
|
},
|
|
150
183
|
|
|
151
184
|
async applyCurrentClaudeConfigSilently() {
|
|
@@ -227,15 +260,18 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
227
260
|
const current = normalizeClaudeText(this.currentClaudeConfig);
|
|
228
261
|
if (current && !configs[current]) {
|
|
229
262
|
this.currentClaudeConfig = firstCachedName || Object.keys(configs)[0] || '';
|
|
230
|
-
try { localStorage.setItem('currentClaudeConfig', this.currentClaudeConfig); } catch (_) {}
|
|
231
263
|
changed = true;
|
|
232
264
|
} else if (firstCachedName) {
|
|
233
|
-
let savedCurrent = '';
|
|
234
|
-
try { savedCurrent = localStorage.getItem('currentClaudeConfig') || ''; } catch (_) {}
|
|
235
265
|
const currentConfig = current && configs[current] ? configs[current] : null;
|
|
236
|
-
|
|
266
|
+
const currentApplyable = currentConfig && (
|
|
267
|
+
currentConfig.hasKey === true
|
|
268
|
+
|| !!normalizeClaudeText(currentConfig.apiKey)
|
|
269
|
+
|| !!normalizeClaudeText(currentConfig.providerCacheRef)
|
|
270
|
+
|| !!normalizeClaudeText(currentConfig.externalCredentialType)
|
|
271
|
+
|| normalizeClaudeText(currentConfig.targetApi) === 'ollama'
|
|
272
|
+
);
|
|
273
|
+
if (!currentApplyable) {
|
|
237
274
|
this.currentClaudeConfig = firstCachedName;
|
|
238
|
-
try { localStorage.setItem('currentClaudeConfig', firstCachedName); } catch (_) {}
|
|
239
275
|
changed = true;
|
|
240
276
|
}
|
|
241
277
|
}
|
|
@@ -458,7 +494,9 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
458
494
|
const silentSuccess = silent || !!(options && options.silentSuccess);
|
|
459
495
|
const silentError = silent || !!(options && options.silentError);
|
|
460
496
|
this.currentClaudeConfig = name;
|
|
461
|
-
|
|
497
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
498
|
+
this.persistWebUiPreferences({ currentClaudeConfig: name || '' });
|
|
499
|
+
}
|
|
462
500
|
this.refreshClaudeModelContext();
|
|
463
501
|
const config = this.claudeConfigs[name];
|
|
464
502
|
|
|
@@ -572,7 +610,9 @@ export function createClaudeConfigMethods(options = {}) {
|
|
|
572
610
|
|
|
573
611
|
async applyClaudeLocalBridge() {
|
|
574
612
|
this.currentClaudeConfig = 'claude-local';
|
|
575
|
-
|
|
613
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
614
|
+
this.persistWebUiPreferences({ currentClaudeConfig: 'claude-local' });
|
|
615
|
+
}
|
|
576
616
|
this.refreshClaudeModelContext();
|
|
577
617
|
|
|
578
618
|
const candidates = this.claudeLocalBridgeCandidateProviders();
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
switchMainTabHelper,
|
|
5
5
|
loadMoreSessionMessagesHelper
|
|
6
6
|
} = options;
|
|
7
|
-
const
|
|
8
|
-
const MAIN_TAB_SET = new Set([
|
|
7
|
+
const MAIN_TAB_ORDER = [
|
|
9
8
|
'dashboard',
|
|
10
9
|
'config',
|
|
11
10
|
'sessions',
|
|
@@ -17,7 +16,39 @@
|
|
|
17
16
|
'settings',
|
|
18
17
|
'trash',
|
|
19
18
|
'prompts'
|
|
20
|
-
]
|
|
19
|
+
];
|
|
20
|
+
const MAIN_TAB_SET = new Set(MAIN_TAB_ORDER);
|
|
21
|
+
const DISABLED_MAIN_TAB_SET = new Set(['orchestration']);
|
|
22
|
+
const normalizeMainTab = (tab) => typeof tab === 'string'
|
|
23
|
+
? tab.trim().toLowerCase()
|
|
24
|
+
: '';
|
|
25
|
+
const isMainTabSelectable = (tab) => {
|
|
26
|
+
const normalized = normalizeMainTab(tab);
|
|
27
|
+
return !!(normalized && MAIN_TAB_SET.has(normalized) && !DISABLED_MAIN_TAB_SET.has(normalized));
|
|
28
|
+
};
|
|
29
|
+
const getFirstSelectableMainTab = () => MAIN_TAB_ORDER.find((tab) => isMainTabSelectable(tab)) || 'dashboard';
|
|
30
|
+
const resolveSelectableMainTab = (tab) => {
|
|
31
|
+
const normalized = normalizeMainTab(tab);
|
|
32
|
+
if (isMainTabSelectable(normalized)) return normalized;
|
|
33
|
+
return getFirstSelectableMainTab();
|
|
34
|
+
};
|
|
35
|
+
const resolveSwitchMainTabTarget = (tab) => {
|
|
36
|
+
const normalized = normalizeMainTab(tab);
|
|
37
|
+
if (!normalized) return '';
|
|
38
|
+
if (isMainTabSelectable(normalized)) return normalized;
|
|
39
|
+
if (MAIN_TAB_SET.has(normalized) && DISABLED_MAIN_TAB_SET.has(normalized)) {
|
|
40
|
+
return getFirstSelectableMainTab();
|
|
41
|
+
}
|
|
42
|
+
return '';
|
|
43
|
+
};
|
|
44
|
+
const cancelDisabledMainTabEvent = (event) => {
|
|
45
|
+
if (event && typeof event.preventDefault === 'function') {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
}
|
|
48
|
+
if (event && typeof event.stopPropagation === 'function') {
|
|
49
|
+
event.stopPropagation();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
21
52
|
const loadDoctorOverview = async (vm, options = {}) => {
|
|
22
53
|
if (!vm || typeof vm !== 'object') return false;
|
|
23
54
|
if (vm.__doctorLoading) return false;
|
|
@@ -41,23 +72,6 @@
|
|
|
41
72
|
}
|
|
42
73
|
}
|
|
43
74
|
};
|
|
44
|
-
const readNavState = () => {
|
|
45
|
-
if (typeof localStorage === 'undefined') return null;
|
|
46
|
-
let raw = '';
|
|
47
|
-
try {
|
|
48
|
-
raw = localStorage.getItem(NAV_STATE_STORAGE_KEY) || '';
|
|
49
|
-
} catch (_) {
|
|
50
|
-
raw = '';
|
|
51
|
-
}
|
|
52
|
-
if (!raw) return null;
|
|
53
|
-
try {
|
|
54
|
-
const parsed = JSON.parse(raw);
|
|
55
|
-
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
56
|
-
} catch (_) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
75
|
const canonicalizeWebUiRuntimeUrl = () => {
|
|
62
76
|
if (typeof window === 'undefined' || !window.location) return;
|
|
63
77
|
try {
|
|
@@ -85,7 +99,6 @@
|
|
|
85
99
|
|
|
86
100
|
const persistNavState = (vm, overrides = null) => {
|
|
87
101
|
if (!vm || vm.__navStateRestoring) return;
|
|
88
|
-
if (typeof localStorage === 'undefined') return;
|
|
89
102
|
const resolvedOverrides = overrides && typeof overrides === 'object' ? overrides : null;
|
|
90
103
|
const mainTabSource = resolvedOverrides && typeof resolvedOverrides.mainTab === 'string'
|
|
91
104
|
? resolvedOverrides.mainTab
|
|
@@ -93,76 +106,36 @@
|
|
|
93
106
|
const configModeSource = resolvedOverrides && typeof resolvedOverrides.configMode === 'string'
|
|
94
107
|
? resolvedOverrides.configMode
|
|
95
108
|
: vm.configMode;
|
|
96
|
-
const mainTab =
|
|
109
|
+
const mainTab = normalizeMainTab(mainTabSource);
|
|
97
110
|
const configMode = typeof configModeSource === 'string' ? configModeSource.trim().toLowerCase() : '';
|
|
98
111
|
const settingsTab = typeof vm.settingsTab === 'string' ? vm.settingsTab.trim().toLowerCase() : 'general';
|
|
99
112
|
const skillsTargetApp = typeof vm.skillsTargetApp === 'string' && (vm.skillsTargetApp === 'codex' || vm.skillsTargetApp === 'claude') ? vm.skillsTargetApp : 'codex';
|
|
100
113
|
const promptTemplatesMode = typeof vm.promptTemplatesMode === 'string' && (vm.promptTemplatesMode === 'compose' || vm.promptTemplatesMode === 'manage') ? vm.promptTemplatesMode : 'compose';
|
|
101
114
|
const snapshot = {
|
|
102
115
|
settingsTab: settingsTab === 'data' ? 'data' : 'general',
|
|
103
|
-
mainTab:
|
|
116
|
+
mainTab: resolveSelectableMainTab(mainTab),
|
|
104
117
|
configMode: configModeSet && configModeSet.has(configMode) ? configMode : 'codex',
|
|
105
118
|
skillsTargetApp,
|
|
106
119
|
promptTemplatesMode
|
|
107
120
|
};
|
|
108
|
-
try {
|
|
109
|
-
localStorage.setItem(NAV_STATE_STORAGE_KEY, JSON.stringify(snapshot));
|
|
110
|
-
} catch (_) {}
|
|
111
121
|
if (typeof vm.persistWebUiPreferences === 'function') {
|
|
112
122
|
vm.persistWebUiPreferences({ navigation: snapshot });
|
|
113
123
|
}
|
|
114
124
|
};
|
|
115
125
|
|
|
116
126
|
return {
|
|
127
|
+
toggleSidebarCollapsed() {
|
|
128
|
+
this.sidebarCollapsed = !this.sidebarCollapsed;
|
|
129
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
130
|
+
this.persistWebUiPreferences({ sidebarCollapsed: this.sidebarCollapsed });
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
117
134
|
saveNavState() {
|
|
118
135
|
persistNavState(this);
|
|
119
136
|
},
|
|
120
137
|
restoreNavStateFromStorage() {
|
|
121
|
-
|
|
122
|
-
const restored = readNavState();
|
|
123
|
-
if (!restored) return false;
|
|
124
|
-
const nextMainTab = restored && typeof restored.mainTab === 'string'
|
|
125
|
-
? restored.mainTab.trim().toLowerCase()
|
|
126
|
-
: '';
|
|
127
|
-
const nextConfigMode = restored && typeof restored.configMode === 'string'
|
|
128
|
-
? restored.configMode.trim().toLowerCase()
|
|
129
|
-
: '';
|
|
130
|
-
const shouldUpdateConfigMode = !!(nextConfigMode && configModeSet && configModeSet.has(nextConfigMode));
|
|
131
|
-
const shouldUpdateMainTab = !!(nextMainTab && MAIN_TAB_SET.has(nextMainTab) && nextMainTab !== this.mainTab);
|
|
132
|
-
const nextSettingsTab = restored && typeof restored.settingsTab === 'string'
|
|
133
|
-
? restored.settingsTab.trim().toLowerCase()
|
|
134
|
-
: '';
|
|
135
|
-
const shouldUpdateSettingsTab = !!(nextSettingsTab && (nextSettingsTab === 'general' || nextSettingsTab === 'data') && nextSettingsTab !== this.settingsTab);
|
|
136
|
-
const nextSkillsTargetApp = restored && typeof restored.skillsTargetApp === 'string' && (restored.skillsTargetApp === 'codex' || restored.skillsTargetApp === 'claude')
|
|
137
|
-
? restored.skillsTargetApp : '';
|
|
138
|
-
const shouldUpdateSkillsTargetApp = !!(nextSkillsTargetApp && nextSkillsTargetApp !== this.skillsTargetApp);
|
|
139
|
-
const nextPromptTemplatesMode = restored && typeof restored.promptTemplatesMode === 'string' && (restored.promptTemplatesMode === 'compose' || restored.promptTemplatesMode === 'manage')
|
|
140
|
-
? restored.promptTemplatesMode : '';
|
|
141
|
-
const shouldUpdatePromptTemplatesMode = !!(nextPromptTemplatesMode && nextPromptTemplatesMode !== this.promptTemplatesMode);
|
|
142
|
-
if (!shouldUpdateConfigMode && !shouldUpdateMainTab && !shouldUpdateSettingsTab && !shouldUpdateSkillsTargetApp && !shouldUpdatePromptTemplatesMode) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
this.__navStateRestoring = true;
|
|
146
|
-
try {
|
|
147
|
-
if (shouldUpdateConfigMode) {
|
|
148
|
-
this.configMode = nextConfigMode;
|
|
149
|
-
}
|
|
150
|
-
if (shouldUpdateSettingsTab) {
|
|
151
|
-
this.settingsTab = nextSettingsTab;
|
|
152
|
-
}
|
|
153
|
-
if (shouldUpdateMainTab) {
|
|
154
|
-
this.switchMainTab(nextMainTab);
|
|
155
|
-
}
|
|
156
|
-
if (shouldUpdateSkillsTargetApp) {
|
|
157
|
-
this.skillsTargetApp = nextSkillsTargetApp;
|
|
158
|
-
}
|
|
159
|
-
if (shouldUpdatePromptTemplatesMode) {
|
|
160
|
-
this.promptTemplatesMode = nextPromptTemplatesMode;
|
|
161
|
-
}
|
|
162
|
-
} finally {
|
|
163
|
-
this.__navStateRestoring = false;
|
|
164
|
-
}
|
|
165
|
-
return true;
|
|
138
|
+
return false;
|
|
166
139
|
},
|
|
167
140
|
switchConfigMode(mode) {
|
|
168
141
|
const normalizedMode = typeof mode === 'string'
|
|
@@ -353,6 +326,10 @@
|
|
|
353
326
|
}
|
|
354
327
|
const normalizedTab = typeof tab === 'string' ? tab.trim().toLowerCase() : '';
|
|
355
328
|
if (!normalizedTab) return;
|
|
329
|
+
if (!isMainTabSelectable(normalizedTab)) {
|
|
330
|
+
cancelDisabledMainTabEvent(event);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
356
333
|
persistNavState(this, { mainTab: normalizedTab });
|
|
357
334
|
this.setMainTabSwitchIntent(normalizedTab);
|
|
358
335
|
this.applyImmediateNavIntent(normalizedTab);
|
|
@@ -394,8 +371,13 @@
|
|
|
394
371
|
this.switchConfigMode(normalizedMode);
|
|
395
372
|
},
|
|
396
373
|
onMainTabClick(tab) {
|
|
374
|
+
const event = arguments.length > 1 ? arguments[1] : null;
|
|
397
375
|
const normalizedTab = typeof tab === 'string' ? tab.trim().toLowerCase() : '';
|
|
398
376
|
if (!normalizedTab) return;
|
|
377
|
+
if (!isMainTabSelectable(normalizedTab)) {
|
|
378
|
+
cancelDisabledMainTabEvent(event);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
399
381
|
if (this.consumePointerNavCommit('main', normalizedTab)) return;
|
|
400
382
|
this.switchMainTab(normalizedTab);
|
|
401
383
|
},
|
|
@@ -437,16 +419,20 @@
|
|
|
437
419
|
}
|
|
438
420
|
return this.configMode === mode;
|
|
439
421
|
},
|
|
422
|
+
isMainTabDisabled(tab) {
|
|
423
|
+
const normalizedTab = normalizeMainTab(tab);
|
|
424
|
+
return !!(normalizedTab && MAIN_TAB_SET.has(normalizedTab) && DISABLED_MAIN_TAB_SET.has(normalizedTab));
|
|
425
|
+
},
|
|
426
|
+
getFirstSelectableMainTab() {
|
|
427
|
+
return getFirstSelectableMainTab();
|
|
428
|
+
},
|
|
440
429
|
switchMainTab(tab) {
|
|
441
430
|
const normalizedTab = typeof tab === 'string'
|
|
442
431
|
? tab.trim().toLowerCase()
|
|
443
432
|
: '';
|
|
444
|
-
const targetTab = normalizedTab || tab;
|
|
433
|
+
const targetTab = resolveSwitchMainTabTarget(normalizedTab || tab);
|
|
445
434
|
if (!targetTab) return;
|
|
446
435
|
canonicalizeWebUiRuntimeUrl();
|
|
447
|
-
if (targetTab === 'orchestration' && this.taskOrchestrationTabEnabled !== true) {
|
|
448
|
-
return this.switchMainTab('config');
|
|
449
|
-
}
|
|
450
436
|
persistNavState(this, {
|
|
451
437
|
mainTab: targetTab,
|
|
452
438
|
configMode: targetTab === 'config' ? this.configMode : this.configMode
|
|
@@ -473,13 +459,11 @@
|
|
|
473
459
|
switchState.ticket += 1;
|
|
474
460
|
switchState.pendingTarget = '';
|
|
475
461
|
if (targetTab === 'dashboard' && !this.__doctorLoadedOnce) {
|
|
476
|
-
if (targetTab === 'trash' && !this.sessionTrashLoadedOnce) {
|
|
477
|
-
if (typeof this.loadSessionTrash === 'function') {
|
|
478
|
-
void this.loadSessionTrash({ forceRefresh: false });
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
462
|
void loadDoctorOverview(this);
|
|
482
463
|
}
|
|
464
|
+
if (targetTab === 'trash' && !this.sessionTrashLoadedOnce && typeof this.loadSessionTrash === 'function') {
|
|
465
|
+
void this.loadSessionTrash({ forceRefresh: false });
|
|
466
|
+
}
|
|
483
467
|
if (
|
|
484
468
|
targetTab === 'sessions'
|
|
485
469
|
&& typeof this.prepareSessionTabRender === 'function'
|
|
@@ -488,7 +472,7 @@
|
|
|
488
472
|
this.prepareSessionTabRender();
|
|
489
473
|
}
|
|
490
474
|
this.scheduleAfterFrame(() => {
|
|
491
|
-
this.clearMainTabSwitchIntent(
|
|
475
|
+
this.clearMainTabSwitchIntent(targetTab);
|
|
492
476
|
});
|
|
493
477
|
return;
|
|
494
478
|
}
|
|
@@ -510,7 +494,7 @@
|
|
|
510
494
|
void loadDoctorOverview(this);
|
|
511
495
|
}
|
|
512
496
|
this.scheduleAfterFrame(() => {
|
|
513
|
-
this.clearMainTabSwitchIntent(
|
|
497
|
+
this.clearMainTabSwitchIntent(targetTab);
|
|
514
498
|
});
|
|
515
499
|
return result;
|
|
516
500
|
}
|
|
@@ -527,7 +511,7 @@
|
|
|
527
511
|
if (pendingTarget === 'dashboard') {
|
|
528
512
|
void loadDoctorOverview(this);
|
|
529
513
|
}
|
|
530
|
-
this.clearMainTabSwitchIntent(
|
|
514
|
+
this.clearMainTabSwitchIntent(pendingTarget);
|
|
531
515
|
});
|
|
532
516
|
},
|
|
533
517
|
|
|
@@ -360,13 +360,10 @@ export function createOpenclawEditingMethods() {
|
|
|
360
360
|
},
|
|
361
361
|
|
|
362
362
|
saveOpenclawConfigs() {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
return true;
|
|
366
|
-
} catch (_) {
|
|
367
|
-
this.showMessage('保存本地 OpenClaw 配置失败', 'error');
|
|
368
|
-
return false;
|
|
363
|
+
if (typeof this.persistWebUiPreferences === 'function') {
|
|
364
|
+
this.persistWebUiPreferences({ openclawConfigs: this.openclawConfigs });
|
|
369
365
|
}
|
|
366
|
+
return true;
|
|
370
367
|
},
|
|
371
368
|
|
|
372
369
|
// Accordion stepper methods
|
|
@@ -41,6 +41,13 @@ function findProviderByName(list, name) {
|
|
|
41
41
|
return (Array.isArray(list) ? list : []).find((item) => item && normalizeText(item.name) === target) || null;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function normalizeBridgeMaxRetries(value, fallback = 2) {
|
|
45
|
+
const raw = Number(value);
|
|
46
|
+
const fallbackRaw = Number(fallback);
|
|
47
|
+
const base = Number.isFinite(raw) ? raw : (Number.isFinite(fallbackRaw) ? fallbackRaw : 2);
|
|
48
|
+
return Math.min(10, Math.max(2, Math.floor(base)));
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
function normalizeProviderDraftState(target) {
|
|
45
52
|
if (!target || typeof target !== 'object') return;
|
|
46
53
|
if (typeof target.name === 'string') {
|
|
@@ -55,6 +62,9 @@ function normalizeProviderDraftState(target) {
|
|
|
55
62
|
if (typeof target.key === 'string') {
|
|
56
63
|
target.key = target.key.trim();
|
|
57
64
|
}
|
|
65
|
+
if (target.useTransform || target.openaiBridgeMaxRetries !== undefined) {
|
|
66
|
+
target.openaiBridgeMaxRetries = normalizeBridgeMaxRetries(target.openaiBridgeMaxRetries);
|
|
67
|
+
}
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
function maskKeyLocal(key) {
|
|
@@ -76,11 +86,14 @@ function getProviderValidationForContext(vm, mode = 'add') {
|
|
|
76
86
|
const url = normalizeProviderUrl(draft && draft.url);
|
|
77
87
|
const model = normalizeText(draft && draft.model);
|
|
78
88
|
const key = normalizeText(draft && draft.key);
|
|
89
|
+
const useTransform = !!(draft && draft.useTransform);
|
|
90
|
+
const openaiBridgeMaxRetries = normalizeBridgeMaxRetries(draft && draft.openaiBridgeMaxRetries);
|
|
79
91
|
const errors = {
|
|
80
92
|
name: '',
|
|
81
93
|
url: '',
|
|
82
94
|
key: '',
|
|
83
|
-
model: ''
|
|
95
|
+
model: '',
|
|
96
|
+
openaiBridgeMaxRetries: ''
|
|
84
97
|
};
|
|
85
98
|
|
|
86
99
|
if (mode === 'add') {
|
|
@@ -111,14 +124,20 @@ function getProviderValidationForContext(vm, mode = 'add') {
|
|
|
111
124
|
errors.model = '模型名称必填';
|
|
112
125
|
}
|
|
113
126
|
|
|
127
|
+
if (useTransform && openaiBridgeMaxRetries < 2) {
|
|
128
|
+
errors.openaiBridgeMaxRetries = '重试次数最小为 2';
|
|
129
|
+
}
|
|
130
|
+
|
|
114
131
|
return {
|
|
115
132
|
mode,
|
|
116
133
|
name,
|
|
117
134
|
url,
|
|
118
135
|
key,
|
|
119
136
|
model,
|
|
137
|
+
useTransform,
|
|
138
|
+
openaiBridgeMaxRetries,
|
|
120
139
|
errors,
|
|
121
|
-
ok: !errors.name && !errors.url && !errors.key && !errors.model
|
|
140
|
+
ok: !errors.name && !errors.url && !errors.key && !errors.model && !errors.openaiBridgeMaxRetries
|
|
122
141
|
};
|
|
123
142
|
}
|
|
124
143
|
|
|
@@ -172,7 +191,7 @@ export function createProvidersMethods(options = {}) {
|
|
|
172
191
|
normalizeProviderDraftState(this.newProvider);
|
|
173
192
|
const validation = getProviderValidationForContext(this, 'add');
|
|
174
193
|
if (!validation.ok) {
|
|
175
|
-
return this.showMessage(validation.errors.name || validation.errors.url || validation.errors.key || validation.errors.model || this.t('toast.provider.fieldsRequired'), 'error');
|
|
194
|
+
return this.showMessage(validation.errors.name || validation.errors.url || validation.errors.key || validation.errors.model || validation.errors.openaiBridgeMaxRetries || this.t('toast.provider.fieldsRequired'), 'error');
|
|
176
195
|
}
|
|
177
196
|
|
|
178
197
|
try {
|
|
@@ -184,6 +203,7 @@ export function createProvidersMethods(options = {}) {
|
|
|
184
203
|
};
|
|
185
204
|
if (this.newProvider && this.newProvider.useTransform) {
|
|
186
205
|
payload.useTransform = true;
|
|
206
|
+
payload.openaiBridgeMaxRetries = validation.openaiBridgeMaxRetries;
|
|
187
207
|
}
|
|
188
208
|
const suggestedModel = validation.model;
|
|
189
209
|
const res = await api('add-provider', payload);
|
|
@@ -198,6 +218,7 @@ export function createProvidersMethods(options = {}) {
|
|
|
198
218
|
url: validation.url,
|
|
199
219
|
upstreamUrl: '',
|
|
200
220
|
codexmate_bridge: payload.useTransform ? 'openai' : '',
|
|
221
|
+
openaiBridgeMaxRetries: payload.useTransform ? validation.openaiBridgeMaxRetries : undefined,
|
|
201
222
|
key: maskKeyLocal(payload.key),
|
|
202
223
|
hasKey: !!payload.key,
|
|
203
224
|
models: suggestedModel ? [{ id: suggestedModel, name: suggestedModel, cost: null, contextWindow: undefined, maxTokens: undefined }] : [],
|
|
@@ -323,7 +344,8 @@ export function createProvidersMethods(options = {}) {
|
|
|
323
344
|
url: cloneUrl,
|
|
324
345
|
key: '',
|
|
325
346
|
model: '',
|
|
326
|
-
useTransform: isTransform
|
|
347
|
+
useTransform: isTransform,
|
|
348
|
+
openaiBridgeMaxRetries: normalizeBridgeMaxRetries(provider.openaiBridgeMaxRetries)
|
|
327
349
|
};
|
|
328
350
|
this.showAddProviderKey = false;
|
|
329
351
|
this.showAddModal = true;
|
|
@@ -335,7 +357,8 @@ export function createProvidersMethods(options = {}) {
|
|
|
335
357
|
url: '',
|
|
336
358
|
key: '',
|
|
337
359
|
model: '',
|
|
338
|
-
useTransform: false
|
|
360
|
+
useTransform: false,
|
|
361
|
+
openaiBridgeMaxRetries: 2
|
|
339
362
|
};
|
|
340
363
|
this.showAddProviderKey = false;
|
|
341
364
|
this.showAddModal = true;
|
|
@@ -363,7 +386,8 @@ export function createProvidersMethods(options = {}) {
|
|
|
363
386
|
nonEditable: typeof provider.nonEditable === 'boolean'
|
|
364
387
|
? provider.nonEditable
|
|
365
388
|
: this.isNonDeletableProvider(provider),
|
|
366
|
-
useTransform: isTransformProvider
|
|
389
|
+
useTransform: isTransformProvider,
|
|
390
|
+
openaiBridgeMaxRetries: normalizeBridgeMaxRetries(provider.openaiBridgeMaxRetries)
|
|
367
391
|
};
|
|
368
392
|
this._editProviderOriginalKey = '';
|
|
369
393
|
this._editProviderRealKeyLoaded = false;
|
|
@@ -404,6 +428,9 @@ export function createProvidersMethods(options = {}) {
|
|
|
404
428
|
&& res.baseUrl.trim()
|
|
405
429
|
) {
|
|
406
430
|
this.editingProvider.url = normalizeProviderUrl(res.baseUrl);
|
|
431
|
+
if (res.maxRetries !== undefined) {
|
|
432
|
+
this.editingProvider.openaiBridgeMaxRetries = normalizeBridgeMaxRetries(res.maxRetries);
|
|
433
|
+
}
|
|
407
434
|
}
|
|
408
435
|
} catch (_) {
|
|
409
436
|
// ignore
|
|
@@ -420,12 +447,13 @@ export function createProvidersMethods(options = {}) {
|
|
|
420
447
|
normalizeProviderDraftState(this.editingProvider);
|
|
421
448
|
const validation = getProviderValidationForContext(this, 'edit');
|
|
422
449
|
if (!validation.ok) {
|
|
423
|
-
return this.showMessage(validation.errors.name || validation.errors.url || this.t('toast.provider.urlRequired'), 'error');
|
|
450
|
+
return this.showMessage(validation.errors.name || validation.errors.url || validation.errors.openaiBridgeMaxRetries || this.t('toast.provider.urlRequired'), 'error');
|
|
424
451
|
}
|
|
425
452
|
|
|
426
453
|
const params = { name: validation.name, url: validation.url };
|
|
427
454
|
if (this.editingProvider && this.editingProvider.useTransform) {
|
|
428
455
|
params.useTransform = true;
|
|
456
|
+
params.openaiBridgeMaxRetries = validation.openaiBridgeMaxRetries;
|
|
429
457
|
}
|
|
430
458
|
if (this._editProviderRealKeyLoaded) {
|
|
431
459
|
const currentKey = typeof this.editingProvider.key === 'string' ? this.editingProvider.key : '';
|
|
@@ -449,7 +477,9 @@ export function createProvidersMethods(options = {}) {
|
|
|
449
477
|
...p,
|
|
450
478
|
url: validation.url,
|
|
451
479
|
key: keyUpdated ? maskKeyLocal(params.key) : p.key,
|
|
452
|
-
hasKey: keyUpdated ? !!params.key : p.hasKey
|
|
480
|
+
hasKey: keyUpdated ? !!params.key : p.hasKey,
|
|
481
|
+
codexmate_bridge: params.useTransform ? 'openai' : p.codexmate_bridge,
|
|
482
|
+
openaiBridgeMaxRetries: params.useTransform ? validation.openaiBridgeMaxRetries : p.openaiBridgeMaxRetries
|
|
453
483
|
};
|
|
454
484
|
}
|
|
455
485
|
return p;
|
|
@@ -467,7 +497,7 @@ export function createProvidersMethods(options = {}) {
|
|
|
467
497
|
this.showEditProviderKey = false;
|
|
468
498
|
this._editProviderOriginalKey = '';
|
|
469
499
|
this._editProviderRealKeyLoaded = false;
|
|
470
|
-
this.editingProvider = { name: '', url: '', key: '', readOnly: false, nonEditable: false, useTransform: false };
|
|
500
|
+
this.editingProvider = { name: '', url: '', key: '', readOnly: false, nonEditable: false, useTransform: false, openaiBridgeMaxRetries: 2 };
|
|
471
501
|
},
|
|
472
502
|
|
|
473
503
|
toggleEditProviderKey() {
|
|
@@ -550,7 +580,7 @@ export function createProvidersMethods(options = {}) {
|
|
|
550
580
|
closeAddModal() {
|
|
551
581
|
this.showAddModal = false;
|
|
552
582
|
this.showAddProviderKey = false;
|
|
553
|
-
this.newProvider = { name: nextCodexProviderName(this.providersList), url: '', key: '', model: '', useTransform: false };
|
|
583
|
+
this.newProvider = { name: nextCodexProviderName(this.providersList), url: '', key: '', model: '', useTransform: false, openaiBridgeMaxRetries: 2 };
|
|
554
584
|
},
|
|
555
585
|
|
|
556
586
|
toggleAddProviderKey() {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
normalizeConfigTemplateDiffConfirmEnabled
|
|
3
|
-
persistConfigTemplateDiffConfirmEnabledToStorage
|
|
2
|
+
normalizeConfigTemplateDiffConfirmEnabled
|
|
4
3
|
} from './config-template-confirm-pref.mjs';
|
|
5
4
|
|
|
6
5
|
export function createSessionActionMethods(options = {}) {
|
|
@@ -302,9 +301,6 @@ export function createSessionActionMethods(options = {}) {
|
|
|
302
301
|
setSessionTrashEnabled(value) {
|
|
303
302
|
const enabled = this.normalizeSessionTrashEnabled(value);
|
|
304
303
|
this.sessionTrashEnabled = enabled;
|
|
305
|
-
try {
|
|
306
|
-
localStorage.setItem('codexmateSessionTrashEnabled', enabled ? 'true' : 'false');
|
|
307
|
-
} catch (_) {}
|
|
308
304
|
if (typeof this.persistWebUiPreferences === 'function') {
|
|
309
305
|
this.persistWebUiPreferences({ sessionTrashEnabled: enabled });
|
|
310
306
|
}
|
|
@@ -313,9 +309,6 @@ export function createSessionActionMethods(options = {}) {
|
|
|
313
309
|
setSessionTimelineStyle(style) {
|
|
314
310
|
const normalized = style === 'bar' ? 'bar' : 'dots';
|
|
315
311
|
this.sessionTimelineStyle = normalized;
|
|
316
|
-
try {
|
|
317
|
-
localStorage.setItem('codexmateSessionTimelineStyle', normalized);
|
|
318
|
-
} catch (_) {}
|
|
319
312
|
if (typeof this.persistWebUiPreferences === 'function') {
|
|
320
313
|
this.persistWebUiPreferences({ sessionTimelineStyle: normalized });
|
|
321
314
|
}
|
|
@@ -324,7 +317,6 @@ export function createSessionActionMethods(options = {}) {
|
|
|
324
317
|
setConfigTemplateDiffConfirmEnabled(value) {
|
|
325
318
|
const enabled = this.normalizeConfigTemplateDiffConfirmEnabled(value);
|
|
326
319
|
this.configTemplateDiffConfirmEnabled = enabled;
|
|
327
|
-
persistConfigTemplateDiffConfirmEnabledToStorage(enabled);
|
|
328
320
|
if (typeof this.persistWebUiPreferences === 'function') {
|
|
329
321
|
this.persistWebUiPreferences({ configTemplateDiffConfirmEnabled: enabled });
|
|
330
322
|
}
|
|
@@ -338,9 +330,6 @@ export function createSessionActionMethods(options = {}) {
|
|
|
338
330
|
setShareCommandPrefix(value) {
|
|
339
331
|
const normalized = this.normalizeShareCommandPrefix(value);
|
|
340
332
|
this.shareCommandPrefix = normalized;
|
|
341
|
-
try {
|
|
342
|
-
localStorage.setItem('codexmateShareCommandPrefix', normalized);
|
|
343
|
-
} catch (_) {}
|
|
344
333
|
if (typeof this.persistWebUiPreferences === 'function') {
|
|
345
334
|
this.persistWebUiPreferences({ shareCommandPrefix: normalized });
|
|
346
335
|
}
|