import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; const webuiRoot = resolve(import.meta.dirname, ".."); const repositoryRoot = resolve(webuiRoot, "..", ".."); const tokens = readFileSync(resolve(webuiRoot, "src/styles/tokens.css"), "utf8"); const app = readFileSync(resolve(webuiRoot, "src/App.tsx"), "utf8"); const settings = readFileSync(resolve(webuiRoot, "src/features/settings/SettingsPage.tsx"), "utf8"); assert.match(tokens, /:root\[data-theme="dark"\]/, "dark token overrides are required"); assert.match(tokens, /color-scheme:\s*dark/, "native controls must receive the dark color scheme"); assert.match(app, /matchMedia\?\.\("\(prefers-color-scheme: dark\)"\)/, "system theme must follow OS changes"); assert.match(app, /dataset\.themePreference/, "the selected preference must remain inspectable"); for (const theme of ["system", "light", "dark"]) { assert.match(settings, new RegExp(`value:\\s*"${theme}"`), `Settings must expose ${theme}`); } const representativeModules = [ "govoplan-campaign/webui/src/styles/campaign-workspace.css", "govoplan-calendar/webui/src/styles/calendar.css", "govoplan-files/webui/src/styles/file-manager.css", "govoplan-mail/webui/src/styles/mail-profiles.css", ]; for (const relativePath of representativeModules) { const css = readFileSync(resolve(repositoryRoot, relativePath), "utf8"); assert.match(css, /var\(--/, `${relativePath} must consume shared theme tokens`); } console.log("Theme contract passed for core and representative module surfaces.");