diff --git a/electron/main/index.ts b/electron/main/index.ts index f6c49584..75a52aa5 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -413,13 +413,8 @@ protocol.registerSchemesAsPrivileged([ process.env.APP_ROOT = MAIN_DIST; process.env.VITE_PUBLIC = VITE_PUBLIC; -// Respect system theme on Windows, keep light theme on macOS for consistency -const isWindows = process.platform === 'win32'; -if (isWindows) { - nativeTheme.themeSource = 'system'; // Respect Windows dark/light mode -} else { - nativeTheme.themeSource = 'light'; // Keep existing behavior for macOS -} +// Always follow OS appearance so renderer `prefers-color-scheme` stays accurate. +nativeTheme.themeSource = 'system'; // Set log level log.transports.console.level = 'info'; @@ -2737,6 +2732,7 @@ let installationLock: Promise = Promise.resolve({ // ==================== window create ==================== async function createWindow() { const isMac = process.platform === 'darwin'; + const isWindows = process.platform === 'win32'; // Ensure .eigent directories exist before anything else ensureEigentDirectories(); diff --git a/package.json b/package.json index a21c7821..a112aa90 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "test:e2e": "vitest run --config vitest.config.ts", "test:coverage": "vitest run --coverage", "check:i18n": "node scripts/check-i18n-locale-parity.js", + "verify:theme": "vite-node scripts/verify-theme-tokens.ts", "type-check": "tsc -p tsconfig.build.json --noEmit", "lint": "eslint . --no-warn-ignored", "lint:fix": "eslint . --fix --no-warn-ignored", diff --git a/scripts/verify-theme-tokens.ts b/scripts/verify-theme-tokens.ts new file mode 100644 index 00000000..da70a125 --- /dev/null +++ b/scripts/verify-theme-tokens.ts @@ -0,0 +1,195 @@ +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= + +// Standalone V2 design-token verification CLI. +// +// Runs the verifier over every registered theme/mode/contrast variant and +// prints a human-readable report. Exits with a non-zero code if any `error` +// findings are produced. Auxiliary contrast warnings do not fail the run +// unless `--strict` is passed. +// +// Usage: +// npm run verify:theme +// npm run verify:theme -- --strict # auxiliary warnings fail too +// npm run verify:theme -- --json # machine-readable output +// npm run verify:theme -- --contrast 0,50,100 + +import { + getDefaultContrastGrid, + listRegisteredThemes, + verifyThemeEngine, + type VerifyFinding, +} from '../src/lib/themeTokens/verifier'; + +type CliFlags = { + strict: boolean; + json: boolean; + contrastGrid: number[]; +}; + +function parseArgs(argv: string[]): CliFlags { + const flags: CliFlags = { + strict: false, + json: false, + contrastGrid: getDefaultContrastGrid(), + }; + for (let i = 0; i < argv.length; i++) { + const arg = argv[i]; + if (arg === '--strict') flags.strict = true; + else if (arg === '--json') flags.json = true; + else if (arg === '--contrast') { + const raw = argv[++i]; + if (raw) { + flags.contrastGrid = raw + .split(',') + .map((s) => Number(s.trim())) + .filter((n) => Number.isFinite(n)); + } + } else if (arg === '--help' || arg === '-h') { + process.stdout.write( + [ + 'Usage: verify-theme-tokens [options]', + '', + 'Options:', + ' --strict Treat auxiliary contrast warnings as errors', + ' --json Emit JSON report on stdout', + ' --contrast a,b,c Override contrast grid (default: 0,25,43,75,100)', + ' -h, --help Show this help', + '', + ].join('\n') + ); + process.exit(0); + } + } + return flags; +} + +const COLORS = { + reset: '\x1b[0m', + red: '\x1b[31m', + yellow: '\x1b[33m', + green: '\x1b[32m', + dim: '\x1b[2m', + bold: '\x1b[1m', + cyan: '\x1b[36m', +}; + +function colorize(text: string, code: string): string { + if (!process.stdout.isTTY) return text; + return `${code}${text}${COLORS.reset}`; +} + +function groupFindings( + findings: VerifyFinding[] +): Map { + const groups = new Map(); + for (const f of findings) { + const key = `${f.mode} / ${f.themeId} / contrast=${f.contrast}`; + const bucket = groups.get(key); + if (bucket) bucket.push(f); + else groups.set(key, [f]); + } + return groups; +} + +function printHumanReport( + themes: Array<{ mode: string; id: string }>, + flags: CliFlags, + report: ReturnType +): void { + const { summary, findings } = report; + + process.stdout.write( + `\n${colorize('Design Token Engine Verification (V2)', COLORS.bold)}\n` + ); + process.stdout.write( + colorize( + ` Registered themes: ${themes.map((t) => `${t.mode}/${t.id}`).join(', ')}\n`, + COLORS.dim + ) + ); + process.stdout.write( + colorize( + ` Contrast grid: ${flags.contrastGrid.join(', ')}\n`, + COLORS.dim + ) + ); + process.stdout.write( + colorize(` Variants checked: ${summary.variantsChecked}\n\n`, COLORS.dim) + ); + + if (findings.length === 0) { + process.stdout.write( + `${colorize('PASS', COLORS.green)} No findings — engine is clean.\n\n` + ); + return; + } + + const groups = groupFindings(findings); + for (const [variant, bucket] of groups) { + process.stdout.write(`${colorize(variant, COLORS.cyan)}\n`); + for (const f of bucket) { + const badge = + f.severity === 'error' + ? colorize('ERROR', COLORS.red) + : colorize('WARN ', COLORS.yellow); + const ratioSuffix = + f.ratio !== undefined && f.threshold !== undefined + ? colorize( + ` (ratio ${f.ratio.toFixed(2)} / threshold ${f.threshold})`, + COLORS.dim + ) + : ''; + process.stdout.write( + ` ${badge} [${f.code}] ${f.message}${ratioSuffix}\n` + ); + if (f.tokenKey && f.value) { + process.stdout.write( + colorize(` ↳ ${f.tokenKey} = ${f.value}\n`, COLORS.dim) + ); + } + } + process.stdout.write('\n'); + } + + const errBadge = + summary.errors === 0 + ? colorize(`${summary.errors} errors`, COLORS.green) + : colorize(`${summary.errors} errors`, COLORS.red); + const warnBadge = + summary.warnings === 0 + ? colorize(`${summary.warnings} warnings`, COLORS.green) + : colorize(`${summary.warnings} warnings`, COLORS.yellow); + process.stdout.write(`Summary: ${errBadge}, ${warnBadge}\n\n`); +} + +function main() { + const flags = parseArgs(process.argv.slice(2)); + const themes = listRegisteredThemes(); + const report = verifyThemeEngine({ + contrastGrid: flags.contrastGrid, + strictAuxContrast: flags.strict, + }); + + if (flags.json) { + process.stdout.write(JSON.stringify({ themes, ...report }, null, 2) + '\n'); + } else { + printHumanReport(themes, flags, report); + } + + const failed = report.summary.errors > 0; + process.exit(failed ? 1 : 0); +} + +main(); diff --git a/src/components/AddWorker/ToolSelect.tsx b/src/components/AddWorker/ToolSelect.tsx index 4db50bf6..ea798b87 100644 --- a/src/components/AddWorker/ToolSelect.tsx +++ b/src/components/AddWorker/ToolSelect.tsx @@ -758,12 +758,12 @@ const ToolSelect = forwardRef< {(initialSelectedTools || []).map((item: any) => ( {item.name || item.mcp_name || item.key || `tool_${item.id}`} -
+
removeOption(item)} />
@@ -852,7 +852,7 @@ const ToolSelect = forwardRef< >
{/* {getCategoryIcon(item.category?.name)} */} -
+
{item.mcp_name}
@@ -863,10 +863,7 @@ const ToolSelect = forwardRef<
-
@@ -889,7 +886,7 @@ const ToolSelect = forwardRef< inputRef.current?.focus(); setIsOpen(true); }} - className="gap-1 rounded-lg border-input-border-default bg-input-bg-default py-1 flex max-h-[120px] min-h-[60px] w-full flex-wrap justify-start overflow-y-auto border border-solid px-[6px]" + className="gap-1 rounded-lg border-ds-border-neutral-default-default bg-ds-bg-neutral-default-default py-1 flex max-h-[120px] min-h-[60px] w-full flex-wrap justify-start overflow-y-auto border border-solid px-[6px]" > {renderSelectedItems()}