* feat(web): add dark mode support with system/light/dark toggle
Closes#93.
Adds a three-way theme toggle (System / Light / Dark) to Settings >
Appearance. The chosen preference is persisted in localStorage alongside
the existing config and applied immediately via a data-theme attribute on
<html>.
Implementation
- AppTheme type ('system' | 'light' | 'dark') added to AppConfig
- CSS custom properties for the dark palette defined under
[data-theme="dark"] and @media (prefers-color-scheme: dark) so the
System option follows the OS without JavaScript
- Appearance section added to SettingsDialog with a sun-moon icon
- Several hardcoded light-only colour values replaced with CSS variable
equivalents so they adapt correctly in dark mode
- i18n: appearance/theme strings added to all 11 supported locales
Note: theme variables are currently inlined in index.css. A follow-up
could extract them into per-theme files to support community themes
(e.g. Catppuccin) -- happy to explore that direction if it fits the
project roadmap.
Also fixes (pre-existing)
- Syntax error in locales/tr.ts that was masking missing-key errors
- Missing translation keys in de, es-ES, ja, tr locales
- locales.test.ts EXPECTED_LOCALES not updated after Korean was added
* fix(web): apply theme before first paint to prevent FOUC
Add a synchronous inline script in layout.tsx that reads the saved theme
from localStorage and sets data-theme on <html> before React hydrates,
eliminating the flash of unstyled content that occurred when the theme
was only applied inside a useEffect.
* fix(web): use useLayoutEffect for theme sync to avoid 1-frame flash
useEffect fires after the browser paints, so switching themes in Settings
could show a single-frame flicker of the old theme. useLayoutEffect fires
synchronously before the paint, making theme transitions atomic. Safe
because the component tree is rendered with ssr:false.
* fix(web): fix 3-column theme selector layout and add seg-title overflow guard
.seg-control used a hardcoded 2-column grid; the theme toggle has 3 buttons
so Dark was falling onto a second row. Switch to a CSS custom property
(--seg-cols, default 2) so each usage can declare its own column count.
Also add white-space/overflow/text-overflow to .seg-title so long
translations never overflow their cell.
* fix(i18n): add missing maxTokens keys to Dict and Korean locale
settings.maxTokens and settings.maxTokensHint were used in SettingsDialog
and present in all locale files but absent from the Dict interface, causing
typecheck to fail. Also adds the two keys to the Korean locale to restore
full locale parity.
Fixes the blocking typecheck failure flagged in PR review.
* fix(i18n): remove duplicate maxTokens keys in ko.ts and Dict
Rebase introduced duplicate settings.maxTokens and settings.maxTokensHint
in both ko.ts and types.ts (Dict interface), causing TS1117/TS2300 errors.
Remove the second occurrence of each to restore clean typecheck.
* test(i18n): add pl to EXPECTED_LOCALES in locales.test.ts
Polish locale was added upstream in #273; update the hard-coded list so
the locale parity test passes on CI.
* fix(web): live-preview theme in Settings before Save
AppearanceSection now applies data-theme to <html> immediately on toggle
via useLayoutEffect, so the page re-themes in real time while the dialog
is open. SettingsDialogs useLayoutEffect cleanup reverts to the original
saved theme when the dialog is dismissed without saving.
Browser extensions (e.g. YouMind, Grammarly, ColorZilla) inject
attributes onto <body> before React hydrates, producing a
"server rendered HTML didn't match client" console error in dev.
`<html>` already had suppressHydrationWarning; mirror it on `<body>`
so any extension that targets the body element no longer surfaces
a false-positive hydration mismatch to end users.
Closes#243
* feat(dev): add desktop tools-dev control plane
* refactor(sidecar): split Open Design contracts
Move Open Design-specific sidecar protocol definitions into @open-design/contracts so sidecar and platform can remain descriptor-driven primitives.
* refactor(daemon): organize package sources
Keep daemon app code, tests, and sidecar entrypoints in separate package directories so each layer can be built and verified independently.
* chore(repo): streamline maintenance entrypoints
Centralize agent guidance by directory and reduce root command chains while preserving the existing build scope.
* docs: translate agent guidance to English
* fix(sidecar): tolerate stale IPC sockets
Remove stale Unix socket files only after confirming no listener is active, so tools-dev can restart after unclean shutdowns.