From 7f61020747525e2446a89a4e362cff560bbdeeca Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 20:38:54 +0800 Subject: [PATCH 1/8] feat(web-ui): add template editor to claude config panel --- web-ui/app.js | 1 + web-ui/modules/app.methods.claude-config.mjs | 15 +++++++++++++++ web-ui/modules/app.methods.codex-config.mjs | 14 +++++++++++--- web-ui/partials/index/panel-config-claude.html | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/web-ui/app.js b/web-ui/app.js index f89a21c6..a837be33 100644 --- a/web-ui/app.js +++ b/web-ui/app.js @@ -98,6 +98,7 @@ document.addEventListener('DOMContentLoaded', () => { confirmDialogResolver: null, configTemplateContent: '', configTemplateApplying: false, + configTemplateContext: 'codex', configTemplateDiffVisible: false, configTemplateDiffLoading: false, configTemplateDiffError: '', diff --git a/web-ui/modules/app.methods.claude-config.mjs b/web-ui/modules/app.methods.claude-config.mjs index b216fb15..e9093694 100644 --- a/web-ui/modules/app.methods.claude-config.mjs +++ b/web-ui/modules/app.methods.claude-config.mjs @@ -264,6 +264,21 @@ export function createClaudeConfigMethods(options = {}) { claudeLocalBridgeConfigured() { return this.claudeLocalBridgeCandidateProviders().some(p => p.hasKey); + }, + + async openClaudeConfigTemplateEditor() { + try { + const res = await api('get-claude-settings-raw'); + if (res.error) { + this.showMessage(res.error, 'error'); + return; + } + this.configTemplateContent = res.content || '{}'; + this.configTemplateContext = 'claude'; + this.showConfigTemplateModal = true; + } catch (e) { + this.showMessage('加载 Claude settings 失败', 'error'); + } } }; } diff --git a/web-ui/modules/app.methods.codex-config.mjs b/web-ui/modules/app.methods.codex-config.mjs index bc6b4505..3f0faded 100644 --- a/web-ui/modules/app.methods.codex-config.mjs +++ b/web-ui/modules/app.methods.codex-config.mjs @@ -558,6 +558,7 @@ export function createCodexConfigMethods(options = {}) { template = `${template.trimEnd()}\n\n${appendBlock}\n`; } this.configTemplateContent = template; + this.configTemplateContext = 'codex'; this.showConfigTemplateModal = true; } catch (e) { this.showMessage('加载模板失败', 'error'); @@ -807,9 +808,16 @@ export function createCodexConfigMethods(options = {}) { const performApply = async () => { this.configTemplateApplying = true; try { - const res = await api('apply-config-template', { - template: this.configTemplateContent - }); + let res; + if (this.configTemplateContext === 'claude') { + res = await api('apply-claude-settings-raw', { + content: this.configTemplateContent + }); + } else { + res = await api('apply-config-template', { + template: this.configTemplateContent + }); + } if (res.error) { this.showMessage(res.error, 'error'); return; diff --git a/web-ui/partials/index/panel-config-claude.html b/web-ui/partials/index/panel-config-claude.html index 449dabf2..48e3b4e5 100644 --- a/web-ui/partials/index/panel-config-claude.html +++ b/web-ui/partials/index/panel-config-claude.html @@ -82,6 +82,7 @@ :placeholder="t('claude.model.placeholder')" >
{{ t('claude.model.hint') }}
+
From e0da110995710a8825543e752252070c2795de18 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 21:43:52 +0800 Subject: [PATCH 2/8] feat(web-ui): move bridge pool status to local provider card - Show pool status summary above local provider title - Add modal dialog for pool management (Codex & Claude) - Add trigger button in local card actions - Remove standalone bridge-pool-panel --- web-ui/app.js | 2 + web-ui/partials/index/modals-basic.html | 50 ++++++++++++++ .../partials/index/panel-config-claude.html | 30 +++----- web-ui/partials/index/panel-config-codex.html | 28 ++------ web-ui/styles/bridge-pool.css | 69 +++++++++++++++++++ 5 files changed, 137 insertions(+), 42 deletions(-) diff --git a/web-ui/app.js b/web-ui/app.js index a837be33..a0520cff 100644 --- a/web-ui/app.js +++ b/web-ui/app.js @@ -71,6 +71,8 @@ document.addEventListener('DOMContentLoaded', () => { showAgentsModal: false, showSkillsModal: false, showHealthCheckModal: false, + showCodexBridgePoolModal: false, + showClaudeBridgePoolModal: false, // Plugins pluginsActiveId: 'prompt-templates', pluginsLoading: false, diff --git a/web-ui/partials/index/modals-basic.html b/web-ui/partials/index/modals-basic.html index 86c0e7da..86f3c22d 100644 --- a/web-ui/partials/index/modals-basic.html +++ b/web-ui/partials/index/modals-basic.html @@ -171,3 +171,53 @@
+ + + + + + diff --git a/web-ui/partials/index/panel-config-claude.html b/web-ui/partials/index/panel-config-claude.html index 48e3b4e5..2136b508 100644 --- a/web-ui/partials/index/panel-config-claude.html +++ b/web-ui/partials/index/panel-config-claude.html @@ -102,6 +102,10 @@
L
+
+ + 已启用 {{ Object.keys(claudeConfigs || {}).filter(name => !isClaudeLocalBridgeExcluded(name)).length }} / {{ Object.keys(claudeConfigs || {}).length }} +
local {{ t('config.badge.system') }} @@ -110,6 +114,11 @@
{{ claudeLocalBridgeConfigured() ? t('claude.configured') : t('claude.notConfigured') }} +
+ +
@@ -142,26 +151,5 @@
-
-
- - - - {{ t('claude.localBridge.poolTitle') }} - {{ t('claude.localBridge.poolHint') }} -
-
- - {{ t('claude.localBridge.noProviders') }} -
-
- -
-
- diff --git a/web-ui/partials/index/panel-config-codex.html b/web-ui/partials/index/panel-config-codex.html index 99d96223..b86d6d89 100644 --- a/web-ui/partials/index/panel-config-codex.html +++ b/web-ui/partials/index/panel-config-codex.html @@ -124,6 +124,10 @@
{{ provider.name.charAt(0).toUpperCase() }}
+
+ + 已启用 {{ localBridgeCandidateProviders().filter(cp => !isLocalBridgeExcluded(cp.name)).length }} / {{ localBridgeCandidateProviders().length }} +
{{ provider.name }} {{ t('config.badge.system') }} @@ -136,6 +140,9 @@ {{ formatLatency(speedResults[provider.name]) }} {{ providerPillText(provider) }}
+ @@ -166,26 +173,5 @@
- -
-
- - - - 轮询池 - 勾选参与负载均衡的提供商 -
-
- - 暂无可用上游 provider,请先添加直连 provider -
-
- -
-
\ No newline at end of file diff --git a/web-ui/styles/bridge-pool.css b/web-ui/styles/bridge-pool.css index d5005d19..a1e3607b 100644 --- a/web-ui/styles/bridge-pool.css +++ b/web-ui/styles/bridge-pool.css @@ -3,6 +3,43 @@ ============================================ */ +/* ---- 摘要状态(在卡片标题上方) ---- */ +.bridge-pool-summary { + display: flex; + align-items: center; + gap: 5px; + margin-bottom: 4px; +} + +.bridge-pool-summary-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + border-radius: 5px; + background: var(--color-brand-light); + color: var(--color-brand-dark); + flex-shrink: 0; +} + +.bridge-pool-summary-text { + font-size: 11px; + font-weight: 600; + color: var(--color-text-muted); + letter-spacing: -0.01em; +} + +/* ---- 轮询池触发按钮 ---- */ +.bridge-pool-trigger { + color: var(--color-brand); + background: rgba(200, 121, 99, 0.08); +} + +.bridge-pool-trigger:hover { + background: rgba(200, 121, 99, 0.16); +} + .bridge-pool-panel { margin-top: 18px; padding: 18px 20px 16px; @@ -195,3 +232,35 @@ padding: 10px 12px 10px 14px; } } + +/* ---- 模态框中的轮询池 ---- */ +.modal-bridge-pool { + max-width: 380px; +} + +.modal-title-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: 6px; + background: var(--color-brand-light); + color: var(--color-brand-dark); + margin-right: 8px; + vertical-align: middle; +} + +.bridge-pool-modal-hint { + font-size: 12px; + color: var(--color-text-muted); + margin-bottom: 14px; + padding-bottom: 12px; + border-bottom: 1px solid var(--color-border-soft); +} + +.modal-bridge-pool .bridge-pool-list { + max-height: 320px; + overflow-y: auto; + margin-bottom: 16px; +} From 91618c4c4659a15ab68ed604b7ec31a05b55c974 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 21:48:31 +0800 Subject: [PATCH 3/8] test(parity): add new modal state keys to allowlist --- tests/unit/web-ui-behavior-parity.test.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unit/web-ui-behavior-parity.test.mjs b/tests/unit/web-ui-behavior-parity.test.mjs index 57c637fb..d3eff097 100644 --- a/tests/unit/web-ui-behavior-parity.test.mjs +++ b/tests/unit/web-ui-behavior-parity.test.mjs @@ -411,6 +411,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus ]; allowedExtraCurrentKeys.push( 'lang', + 'configTemplateContext', 'configTemplateDiffVisible', 'configTemplateDiffLoading', 'configTemplateDiffError', @@ -424,6 +425,8 @@ test('captured bundled app skeleton only exposes expected data key drift versus 'healthCheckBatchDone', 'healthCheckBatchFailed', 'showHealthCheckModal', + 'showCodexBridgePoolModal', + 'showClaudeBridgePoolModal', 'pluginsActiveId', 'pluginsLoading', 'pluginsError', From 58ed56692e1ffbb59ab0aaa30a16cc6f8f44b996 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 21:51:36 +0800 Subject: [PATCH 4/8] test(parity): add openClaudeConfigTemplateEditor to allowlist --- tests/unit/web-ui-behavior-parity.test.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/web-ui-behavior-parity.test.mjs b/tests/unit/web-ui-behavior-parity.test.mjs index d3eff097..cda818d5 100644 --- a/tests/unit/web-ui-behavior-parity.test.mjs +++ b/tests/unit/web-ui-behavior-parity.test.mjs @@ -574,6 +574,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus 'normalizeConfigTemplateDiffConfirmEnabled', 'setConfigTemplateDiffConfirmEnabled', 'extractClaudeResumeKeyFromFilePath', + 'openClaudeConfigTemplateEditor', 'loadPluginsOverview', 'selectPlugin', 'createPromptTemplate', From 22a1d14a4cff5943dfcc51cf3772663fd64a3dc5 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 22:18:48 +0800 Subject: [PATCH 5/8] feat(web-ui): apply local bridge config when clicking local card - Add applyClaudeLocalBridge() method to enable local bridge - Local card click now calls API to write config to file - Refresh will persist local selection --- web-ui/modules/app.methods.claude-config.mjs | 22 +++++++++++++++++++ .../partials/index/panel-config-claude.html | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/web-ui/modules/app.methods.claude-config.mjs b/web-ui/modules/app.methods.claude-config.mjs index e9093694..41e698ea 100644 --- a/web-ui/modules/app.methods.claude-config.mjs +++ b/web-ui/modules/app.methods.claude-config.mjs @@ -266,6 +266,28 @@ export function createClaudeConfigMethods(options = {}) { return this.claudeLocalBridgeCandidateProviders().some(p => p.hasKey); }, + async applyClaudeLocalBridge() { + this.currentClaudeConfig = 'claude-local'; + try { localStorage.setItem('currentClaudeConfig', 'claude-local'); } catch (_) {} + this.refreshClaudeModelContext(); + + const candidates = this.claudeLocalBridgeCandidateProviders(); + if (candidates.length === 0) { + return this.showMessage('请先添加并配置至少一个 Claude 提供商', 'error'); + } + + try { + const res = await api('claude-local-bridge-toggle', { enable: true }); + if (res.error) { + this.showMessage(res.error || '启用本地负载均衡失败', 'error'); + return; + } + this.showMessage('Claude 本地负载均衡已启用', 'success'); + } catch (e) { + this.showMessage('启用本地负载均衡失败', 'error'); + } + }, + async openClaudeConfigTemplateEditor() { try { const res = await api('get-claude-settings-raw'); diff --git a/web-ui/partials/index/panel-config-claude.html b/web-ui/partials/index/panel-config-claude.html index 2136b508..0b7ab4b6 100644 --- a/web-ui/partials/index/panel-config-claude.html +++ b/web-ui/partials/index/panel-config-claude.html @@ -98,7 +98,7 @@
-
+
L
From d3a4ab300a503baae9cc4667ad4c5ad16eba96f5 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 22:22:41 +0800 Subject: [PATCH 6/8] test(parity): add applyClaudeLocalBridge to allowlist --- tests/unit/web-ui-behavior-parity.test.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/web-ui-behavior-parity.test.mjs b/tests/unit/web-ui-behavior-parity.test.mjs index cda818d5..0df77ac6 100644 --- a/tests/unit/web-ui-behavior-parity.test.mjs +++ b/tests/unit/web-ui-behavior-parity.test.mjs @@ -575,6 +575,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus 'setConfigTemplateDiffConfirmEnabled', 'extractClaudeResumeKeyFromFilePath', 'openClaudeConfigTemplateEditor', + 'applyClaudeLocalBridge', 'loadPluginsOverview', 'selectPlugin', 'createPromptTemplate', From 15dcd887f29b963e9fc690e99068934b2930c098 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 22:31:41 +0800 Subject: [PATCH 7/8] fix(web-ui): detect local bridge URL to avoid creating duplicate provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Match claude-local when URL contains /bridge/claude-local/ - Prevents creating '导入-127.0.0.1:xxxx' provider on refresh --- web-ui/logic.claude.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web-ui/logic.claude.mjs b/web-ui/logic.claude.mjs index 52d4d2ed..254157ac 100644 --- a/web-ui/logic.claude.mjs +++ b/web-ui/logic.claude.mjs @@ -111,6 +111,10 @@ export function matchClaudeConfigFromSettings(claudeConfigs = {}, env = {}) { if (!normalizedSettings.baseUrl || !normalizedSettings.model || !hasClaudeCredential(normalizedSettings)) { return ''; } + // 检测本地桥接 URL + if (typeof normalizedSettings.baseUrl === 'string' && normalizedSettings.baseUrl.includes('/bridge/claude-local/')) { + return 'claude-local'; + } const comparableSettingsUrl = normalizeClaudeComparableUrl(normalizedSettings.baseUrl); const entries = Object.entries(claudeConfigs || {}); for (const [name, config] of entries) { From 9789805f75fc379013078183d28f08ef4caccb56 Mon Sep 17 00:00:00 2001 From: ymkiux Date: Tue, 19 May 2026 23:25:09 +0800 Subject: [PATCH 8/8] feat(web-ui): temporarily disable Claude local provider - Remove local card from Claude config panel - Remove Claude bridge pool modal - Keep Codex local provider functional --- web-ui/partials/index/modals-basic.html | 24 ------------------- .../partials/index/panel-config-claude.html | 23 ------------------ 2 files changed, 47 deletions(-) diff --git a/web-ui/partials/index/modals-basic.html b/web-ui/partials/index/modals-basic.html index 86f3c22d..70c50dc6 100644 --- a/web-ui/partials/index/modals-basic.html +++ b/web-ui/partials/index/modals-basic.html @@ -197,27 +197,3 @@
- - diff --git a/web-ui/partials/index/panel-config-claude.html b/web-ui/partials/index/panel-config-claude.html index 0b7ab4b6..a93c7072 100644 --- a/web-ui/partials/index/panel-config-claude.html +++ b/web-ui/partials/index/panel-config-claude.html @@ -98,29 +98,6 @@
-
-
-
L
-
-
- - 已启用 {{ Object.keys(claudeConfigs || {}).filter(name => !isClaudeLocalBridgeExcluded(name)).length }} / {{ Object.keys(claudeConfigs || {}).length }} -
-
- local - {{ t('config.badge.system') }} -
-
-
-
- {{ claudeLocalBridgeConfigured() ? t('claude.configured') : t('claude.notConfigured') }} -
- -
-
-
{{ name.charAt(0).toUpperCase() }}