From 037f32973a95e4caac410020bd96be3c59462458 Mon Sep 17 00:00:00 2001 From: Dayuan Jiang <34411969+DayuanJiang@users.noreply.github.com> Date: Thu, 1 Jan 2026 14:45:46 +0900 Subject: [PATCH] fix: resolve biome lint errors blocking CI (#480) - Update biome schema version from 2.3.8 to 2.3.10 - Add radix parameter to parseInt in mcp-server - Remove unnecessary React fragment in model-config-dialog - Fix unused variable errors (err -> _err) - Auto-format code with biome --- biome.json | 2 +- components/chat-message-display.tsx | 2 +- components/model-config-dialog.tsx | 1622 +++++++++++++-------------- hooks/use-model-config.ts | 1 - lib/ai-providers.ts | 2 +- packages/mcp-server/src/index.ts | 2 +- scripts/electron-dev.mjs | 2 +- 7 files changed, 799 insertions(+), 834 deletions(-) diff --git a/biome.json b/biome.json index f6e8fd9..3287416 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/components/chat-message-display.tsx b/components/chat-message-display.tsx index b4c5be8..519c24c 100644 --- a/components/chat-message-display.tsx +++ b/components/chat-message-display.tsx @@ -283,7 +283,7 @@ export function ChatMessageDisplay({ try { await navigator.clipboard.writeText(text) setCopyState(messageId, isToolCall, true) - } catch (err) { + } catch (_err) { // Fallback for non-secure contexts (HTTP) or permission denied const textarea = document.createElement("textarea") textarea.value = text diff --git a/components/model-config-dialog.tsx b/components/model-config-dialog.tsx index 1fe2e33..500d8f4 100644 --- a/components/model-config-dialog.tsx +++ b/components/model-config-dialog.tsx @@ -21,7 +21,6 @@ import { Zap, } from "lucide-react" import { useCallback, useEffect, useRef, useState } from "react" -import { toast } from "sonner" import { AlertDialog, AlertDialogAction, @@ -517,183 +516,441 @@ export function ModelConfigDialog({ {/* Provider Details (Right Panel) */}
{selectedProvider ? ( - <> - -
- {/* Provider Header */} -
-
- + +
+ {/* Provider Header */} +
+
+ +
+
+

+ { + PROVIDER_INFO[ + selectedProvider + .provider + ].label + } +

+

+ {selectedProvider.models + .length === 0 + ? dict.modelConfig + .noModelsConfigured + : formatMessage( + dict.modelConfig + .modelsConfiguredCount, + { + count: selectedProvider + .models + .length, + }, + )} +

+
+ {selectedProvider.validated && ( +
+ + + {dict.modelConfig.verified} +
-
-

+ )} + +

+ + {/* Configuration Section */} + + + {/* Display Name */} +
+ + + handleProviderUpdate( + "name", + e.target.value, + ) + } + placeholder={ PROVIDER_INFO[ selectedProvider .provider ].label } - -

- {selectedProvider.models - .length === 0 - ? dict.modelConfig - .noModelsConfigured - : formatMessage( - dict.modelConfig - .modelsConfiguredCount, - { - count: selectedProvider - .models - .length, - }, - )} -

+ className="h-9" + />
- {selectedProvider.validated && ( -
- - - { - dict.modelConfig - .verified - } - -
- )} - -
- {/* Configuration Section */} - - - {/* Display Name */} -
- - - handleProviderUpdate( - "name", - e.target.value, - ) - } - placeholder={ - PROVIDER_INFO[ - selectedProvider - .provider - ].label - } - className="h-9" - /> -
+ {/* Credentials - different for Bedrock vs other providers */} + {selectedProvider.provider === + "bedrock" ? ( + <> + {/* AWS Access Key ID */} +
+ + + handleProviderUpdate( + "awsAccessKeyId", + e.target + .value, + ) + } + placeholder="AKIA..." + className="h-9 font-mono text-xs" + /> +
- {/* Credentials - different for Bedrock vs other providers */} - {selectedProvider.provider === - "bedrock" ? ( - <> - {/* AWS Access Key ID */} -
- + {/* AWS Secret Access Key */} +
+ +
handleProviderUpdate( - "awsAccessKeyId", + "awsSecretAccessKey", e.target .value, ) } - placeholder="AKIA..." - className="h-9 font-mono text-xs" - /> -
- - {/* AWS Secret Access Key */} -
- -
+ className="h-9 pr-10 font-mono text-xs" + /> + +
+
+ + {/* AWS Region */} +
+ + +
+ + {/* Test Button for Bedrock */} +
+ + {validationStatus === + "error" && + validationError && ( +

+ + { + validationError + } +

+ )} +
+ + ) : selectedProvider.provider === + "edgeone" ? ( +
+
+ + {validationStatus === + "error" && + validationError && ( +

+ + { + validationError + } +

+ )} +
+
+ ) : ( + <> + {/* API Key */} +
+ +
+
handleProviderUpdate( - "awsSecretAccessKey", + "apiKey", e .target .value, @@ -702,7 +959,7 @@ export function ModelConfigDialog({ placeholder={ dict .modelConfig - .enterSecretKey + .enterApiKey } className="h-9 pr-10 font-mono text-xs" /> @@ -715,8 +972,8 @@ export function ModelConfigDialog({ } aria-label={ showApiKey - ? "Hide secret access key" - : "Show secret access key" + ? "Hide API key" + : "Show API key" } className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded" > @@ -727,105 +984,6 @@ export function ModelConfigDialog({ )}
-
- - {/* AWS Region */} -
- - -
- - {/* Test Button for Bedrock */} -
- - ) : selectedProvider.provider === - "edgeone" ? ( -
-
- - {validationStatus === - "error" && - validationError && ( -

- - { - validationError - } -

- )} -
-
- ) : ( - <> - {/* API Key */} -
- -
-
- - handleProviderUpdate( - "apiKey", - e - .target - .value, - ) - } - placeholder={ - dict - .modelConfig - .enterApiKey - } - className="h-9 pr-10 font-mono text-xs" - /> - -
- -
- {validationStatus === - "error" && - validationError && ( -

- - { - validationError - } -

- )} -
- - {/* Base URL */} -
-
+ + {/* Base URL */} +
+
- - )} - - - - {/* Models Section */} - -
+ + { - setCustomModelInput( + onChange={(e) => + handleProviderUpdate( + "baseUrl", e.target .value, ) - if ( - duplicateError - ) { - setDuplicateError( - "", - ) - } - }} - onKeyDown={(e) => { - if ( - e.key === - "Enter" && - customModelInput.trim() - ) { - const success = - handleAddModel( - customModelInput.trim(), - ) - if ( - success - ) { - setCustomModelInput( - "", - ) - } - } - }} - className={cn( - "h-8 w-44 rounded-lg font-mono text-xs", - duplicateError && - "border-destructive focus-visible:ring-destructive", - )} + } + placeholder={ + PROVIDER_INFO[ + selectedProvider + .provider + ] + .defaultBaseUrl || + dict.modelConfig + .customEndpoint + } + className="h-9 rounded-xl font-mono text-xs" /> - {duplicateError && ( -

- {duplicateError} -

- )}
- - -
- } - > - {/* Model List */} -
- {selectedProvider.models - .length === 0 ? ( -
-
- -
-

- { - dict.modelConfig - .noModelsConfigured - } -

-
- ) : ( -
- {selectedProvider.models.map( - (model, index) => ( -
+ + + { - // Allow free typing - validation happens on blur - // Clear edit error when typing - if ( - editError?.modelId === - model.id - ) { - setEditError( - null, - ) - } - updateModel( - selectedProviderId!, - model.id, - { - modelId: - e - .target - .value, - validated: - undefined, - validationError: - undefined, - }, - ) - }} - onKeyDown={( - e, - ) => { - if ( - e.key === - "Enter" - ) { - e.currentTarget.blur() - } - }} - onBlur={( - e, - ) => { - const newModelId = - e.target.value.trim() - - // Helper to show error with shake - const showError = - ( - message: string, - ) => { - setEditError( - { - modelId: - model.id, - message, - }, - ) - e.target.animate( - [ - { - transform: - "translateX(0)", - }, - { - transform: - "translateX(-4px)", - }, - { - transform: - "translateX(4px)", - }, - { - transform: - "translateX(-4px)", - }, - { - transform: - "translateX(4px)", - }, - { - transform: - "translateX(0)", - }, - ], - { - duration: 400, - easing: "ease-in-out", - }, - ) - e.target.focus() - } - - // Check for empty model name - if ( - !newModelId - ) { - showError( - dict - .modelConfig - .modelIdEmpty, - ) - return - } - - // Check for duplicate - const otherModelIds = - selectedProvider?.models - .filter( - ( - m, - ) => - m.id !== - model.id, - ) - .map( - ( - m, - ) => - m.modelId, - ) || - [] - if ( - otherModelIds.includes( - newModelId, - ) - ) { - showError( - dict - .modelConfig - .modelIdExists, - ) - return - } - - // Clear error on valid blur + {modelId} + + ), + )} + + +
+ } + > + {/* Model List */} +
+ {selectedProvider.models.length === + 0 ? ( +
+
+ +
+

+ { + dict.modelConfig + .noModelsConfigured + } +

+
+ ) : ( +
+ {selectedProvider.models.map( + (model, index) => ( +
+
+ {/* Status icon */} +
+ {validatingModelIndex !== + null && + index === + validatingModelIndex ? ( + // Currently validating +
+ +
+ ) : validatingModelIndex !== + null && + index > + validatingModelIndex && + model.validated === + undefined ? ( + // Queued +
+ +
+ ) : model.validated === + true ? ( + // Valid +
+ +
+ ) : model.validated === + false ? ( + // Invalid +
+ +
+ ) : ( + // Not validated yet +
+ +
+ )} +
+ { + // Allow free typing - validation happens on blur + // Clear edit error when typing + if ( + editError?.modelId === + model.id + ) { setEditError( null, ) - }} - className="flex-1 min-w-0 font-mono text-sm h-8 border-0 bg-transparent focus-visible:bg-background focus-visible:ring-1" - /> - -
- {/* Show validation error inline */} - {model.validated === - false && - model.validationError && ( -

+ updateModel( + selectedProviderId!, + model.id, { - model.validationError + modelId: + e + .target + .value, + validated: + undefined, + validationError: + undefined, + }, + ) + }} + onKeyDown={( + e, + ) => { + if ( + e.key === + "Enter" + ) { + e.currentTarget.blur() + } + }} + onBlur={( + e, + ) => { + const newModelId = + e.target.value.trim() + + // Helper to show error with shake + const showError = + ( + message: string, + ) => { + setEditError( + { + modelId: + model.id, + message, + }, + ) + e.target.animate( + [ + { + transform: + "translateX(0)", + }, + { + transform: + "translateX(-4px)", + }, + { + transform: + "translateX(4px)", + }, + { + transform: + "translateX(-4px)", + }, + { + transform: + "translateX(4px)", + }, + { + transform: + "translateX(0)", + }, + ], + { + duration: 400, + easing: "ease-in-out", + }, + ) + e.target.focus() } -

- )} - {/* Show edit error inline */} - {editError?.modelId === - model.id && ( + + // Check for empty model name + if ( + !newModelId + ) { + showError( + dict + .modelConfig + .modelIdEmpty, + ) + return + } + + // Check for duplicate + const otherModelIds = + selectedProvider?.models + .filter( + ( + m, + ) => + m.id !== + model.id, + ) + .map( + ( + m, + ) => + m.modelId, + ) || + [] + if ( + otherModelIds.includes( + newModelId, + ) + ) { + showError( + dict + .modelConfig + .modelIdExists, + ) + return + } + + // Clear error on valid blur + setEditError( + null, + ) + }} + className="flex-1 min-w-0 font-mono text-sm h-8 border-0 bg-transparent focus-visible:bg-background focus-visible:ring-1" + /> + +
+ {/* Show validation error inline */} + {model.validated === + false && + model.validationError && (

{ - editError.message + model.validationError }

)} -
- ), - )} -
- )} -
- -
- - + {/* Show edit error inline */} + {editError?.modelId === + model.id && ( +

+ { + editError.message + } +

+ )} +
+ ), + )} +
+ )} +
+ +
+ ) : (
diff --git a/hooks/use-model-config.ts b/hooks/use-model-config.ts index 9904253..42d5159 100644 --- a/hooks/use-model-config.ts +++ b/hooks/use-model-config.ts @@ -11,7 +11,6 @@ import { flattenModels, type ModelConfig, type MultiModelConfig, - PROVIDER_INFO, type ProviderConfig, type ProviderName, } from "@/lib/types/model-config" diff --git a/lib/ai-providers.ts b/lib/ai-providers.ts index b482143..8e27be6 100644 --- a/lib/ai-providers.ts +++ b/lib/ai-providers.ts @@ -786,7 +786,7 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { `data: ${JSON.stringify(data)}\n\n`, ), ) - } catch (e) { + } catch (_e) { // If parsing fails, forward the original message to avoid breaking the stream. controller.enqueue( new TextEncoder().encode( diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 8c6f576..2b604b1 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -48,7 +48,7 @@ import { validateAndFixXml } from "./xml-validation.js" // Server configuration const config = { - port: parseInt(process.env.PORT || "6002"), + port: parseInt(process.env.PORT || "6002", 10), } // Session state (single session for simplicity) diff --git a/scripts/electron-dev.mjs b/scripts/electron-dev.mjs index c8eb946..bf5386a 100644 --- a/scripts/electron-dev.mjs +++ b/scripts/electron-dev.mjs @@ -253,7 +253,7 @@ async function main() { }, ) console.log("👀 Watching for preset configuration changes...") - } catch (err) { + } catch (_err) { // File might not exist yet, that's ok setTimeout(setupConfigWatcher, 5000) }