{"record":{"id":"b27863a8f8a2b6b7","repo":"CherryHQ/cherry-studio","slug":"theme-contract-runtime-input-declaration-name-b27863","errorCode":null,"errorMessage":"[theme-contract] runtime input ${declaration.name} cannot depend on host-local ${reference}","messagePattern":"\\[theme-contract\\] runtime input (.+?) cannot depend on host-local (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":267,"sourceCode":"          reference.startsWith('--color-') ||\n          reference.startsWith('--app-')\n        ) {\n          throw new Error(`[theme-contract] foundation ${declaration.name} cannot depend on upper-layer ${reference}`)\n        }\n      }\n    }\n  }\n\n  for (const declaration of extractDeclarations(sources.themeInput, 'theme-input.css')) {\n    if (!runtimeVariables.has(declaration.name)) {\n      throw new Error(`[theme-contract] theme-input.css declares unregistered runtime input ${declaration.name}`)\n    }\n    for (const reference of extractReferences(declaration.value, declaration.source)) {\n      if (officialVariables.has(reference) || productVariables.has(reference) || reference.startsWith('--color-')) {\n        throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on upper-layer ${reference}`)\n      }\n      if (reference.startsWith('--app-')) {\n        throw new Error(`[theme-contract] runtime input ${declaration.name} cannot depend on host-local ${reference}`)\n      }\n    }\n  }\n\n  for (const declaration of extractDeclarations(sources.shadcn, 'shadcn.css')) {\n    if (declaration.name.startsWith(runtimeVariablePrefix)) {\n      throw new Error(`[theme-contract] shadcn.css cannot own runtime input ${declaration.name}`)\n    }\n    for (const reference of extractReferences(declaration.value, declaration.source)) {\n      if (productVariables.has(reference) || reference.startsWith('--color-') || reference.startsWith('--app-')) {\n        throw new Error(`[theme-contract] Shadcn ${declaration.name} cannot depend on product/adapter ${reference}`)\n      }\n    }\n  }\n\n  for (const declaration of extractDeclarations(sources.product, 'product.css')) {\n    for (const reference of extractReferences(declaration.value, declaration.source)) {\n      const validNamespace =","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L249-L285","documentation":"Thrown by assertLayerDependencies when a runtime-input declaration (--cs-theme-*) in theme-input.css references a host-local variable (prefix --app-*). Runtime inputs must be self-contained values the host writes into --cs-theme-* directly; depending on host-local state would create a hidden coupling between the theme input layer and arbitrary host CSS variables.","triggerScenarios":"Writing `--cs-theme-primary: var(--app-accent);` in theme-input.css; routing a host-injected color through theme-input via an --app-* reference.","commonSituations":"Migrating host-side theming into the contract and incorrectly wiring --app-* values into theme-input instead of having the host write --cs-theme-* directly.","solutions":["Have the host write the --cs-theme-* variable directly at runtime (that is the intended injection point), and remove the --app-* reference from theme-input.css.","If an --app-* value must be consumed by product CSS, declare the dependency in product.css instead (the product layer is where host-local concerns are allowed to surface, subject to its own rules).","Re-run `pnpm --filter @cherrystudio/ui theme:check`."],"exampleFix":"// before (theme-input.css)\n--cs-theme-primary: var(--app-accent);\n// after — host writes --cs-theme-accent directly; theme-input stays foundation-only\n--cs-theme-primary: var(--cs-primary);","handlingStrategy":"validation","validationCode":"// Reject --app-* references inside theme-input.css.\nconst hostRefs = [...sources.themeInput.matchAll(/var\\(\\s*(--app-[a-z0-9-]+)/g)].map((m) => m[1])\nif (hostRefs.length) throw new Error(`theme-input depends on host-local: ${hostRefs.join(', ')}`)","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /runtime input .* cannot depend on host-local/.test(error.message)) {\n    console.error(error.message)\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["Host code should write --cs-theme-* variables directly at runtime; do not reference --app-* from theme-input.css.","Keep --app-* consumption in product.css where host-local concerns are allowed.","Run theme:check after editing theme-input.css."],"tags":["theme-contract","css","build","validation","layering","host"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}