{"record":{"id":"196dd28925a58eda","repo":"CherryHQ/cherry-studio","slug":"theme-contract-shadcn-declaration-name-cannot","errorCode":null,"errorMessage":"[theme-contract] Shadcn ${declaration.name} cannot depend on product/adapter ${reference}","messagePattern":"\\[theme-contract\\] Shadcn (.+?) cannot depend on product/adapter (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/scripts/validate-theme-contract.ts","lineNumber":278,"sourceCode":"      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 =\n        reference.startsWith('--cs-') || officialVariables.has(reference) || productVariables.has(reference)\n      if (!validNamespace) {\n        throw new Error(`[theme-contract] product ${declaration.name} has invalid dependency ${reference}`)\n      }\n    }\n  }\n}\n\nfunction assertCatalogCoverage(sources: ThemeContractSources): void {\n  const requiredNames = [\n    ...RUNTIME_THEME_INPUT_TOKENS.map((token) => `--cs-theme-${token}`),","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/packages/ui/scripts/validate-theme-contract.ts#L260-L296","documentation":"Thrown by assertLayerDependencies when a declaration in shadcn.css references a product variable (--success, --link, etc.), a Tailwind adapter variable (--color-*), or a host-local variable (--app-*). Shadcn is the official upstream contract layer and must only depend on foundation and runtime inputs; referencing product/adapter/host concerns would couple the upstream contract to Cherry-specific or host-specific layers.","triggerScenarios":"Adding `--background: var(--success);` to shadcn.css (product dep); `--primary: var(--color-blue-500);` (adapter dep); `--background: var(--app-surface);` (host-local dep).","commonSituations":"Trying to reuse a product role inside the official contract; pulling a Tailwind utility color into a Shadcn variable.","solutions":["Re-point the Shadcn variable at a foundation variable (--cs-*) or a runtime input (--cs-theme-*).","If the dependency on a product/adapter variable is intentional, invert it: declare the value in product.css and have product.css reference the Shadcn variable (product layer may reference shadcn, not the reverse).","Re-run `pnpm --filter @cherrystudio/ui theme:check`."],"exampleFix":"// before (shadcn.css)\n--background: var(--success);\n// after — shadcn references foundation only\n--background: var(--cs-background);","handlingStrategy":"validation","validationCode":"// shadcn.css must not reference product/adapter/host variables.\nconst productNames = new Set(CHERRY_PRODUCT_VARIABLE_TOKENS.map((t) => `--${t}`))\nfor (const [, ref] of sources.shadcn.matchAll(/var\\(\\s*(--[a-z0-9-]+)/g)) {\n  if (productNames.has(ref) || ref.startsWith('--color-') || ref.startsWith('--app-')) {\n    throw new Error(`shadcn depends on product/adapter/host ${ref}`)\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  validateThemeContractSources(sources)\n} catch (error) {\n  if (error instanceof Error && /Shadcn .* cannot depend on product\\/adapter/.test(error.message)) {\n    console.error(error.message)\n    process.exitCode = 1\n    return\n  }\n  throw error\n}","preventionTips":["shadcn.css is the upstream contract: only foundation and runtime inputs.","To reuse a product value, invert the dependency in product.css (product may reference shadcn).","Run theme:check after editing shadcn.css."],"tags":["theme-contract","css","build","validation","layering"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}