Commit graph

2 commits

Author SHA1 Message Date
chaoxiaoche
1f66c53203
feat(daemon): consume component manifests (#2053)
* feat(design-systems): extract component manifests

* feat(daemon): consume component manifests

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-18 16:50:52 +08:00
chaoxiaoche
e57e028222
feat(daemon): make design-system token channel default-on (PR-D) (#1544)
* feat(daemon): make design-system token channel default-on (PR-D)

Flip `OD_DESIGN_TOKEN_CHANNEL` from default-off to default-on. Every
chat that picks a brand with `tokens.css` + `components.html` siblings
(today: `default`, `kami`) now gets the structured token contract
appended to the system prompt automatically. `OD_DESIGN_TOKEN_CHANNEL=0`
keeps the DESIGN.md-only path as a kill switch.

Adds `scripts/check-design-system-flag-parity.ts`, registered in
`pnpm guard`. The guard walks every brand and asserts:

- 147 prose-only brands produce byte-identical prompts under flag-off
  vs flag-on (PR-D's "no-op for legacy brands" promise)
- 2 structured brands diverge as expected (catches a future regression
  that silently dropped the structured blocks)

Smoke evidence on #1385 (PR-C):
- `default` — 10/10 brand tokens used byte-for-byte in treatment vs
  0/10 invented colors in control
- `kami` — treatment recovers brand name (`Kami · 纸`), the two-tier
  surface (`--bg` parchment + `--surface` ivory), the CN font stack
  override, and the `components.html` card pattern; control invented
  "Replica" as a brand name

Co-authored-by: Cursor <cursoragent@cursor.com>

* review: address @nettee + @lefarcen feedback on parity guard

Two blocking findings from #1544 review:

1. @nettee — guard's inventory walk silently passed on unreadable
   filesystem state. `fileExists` swallowed every `stat` error and the
   bare `readdir` catch returned `[]` for any failure. A renamed
   `design-systems/` tree, a permission-denied DESIGN.md, or a
   directory at the brand path would have left `pnpm guard` happy
   after checking 0 brands — exactly the silent misconfiguration this
   guard exists to catch. Both error paths now treat only ENOENT /
   ENOTDIR as absence and rethrow everything else, mirroring the
   `readFileOptional` fix already applied to PR-C's
   `apps/daemon/src/design-systems.ts`.

2. @nettee — guard exercised `composeSystemPrompt` directly, bypassing
   the `process.env.OD_DESIGN_TOKEN_CHANNEL !== '0'` gate in server.ts
   that PR-D actually flipped. A regression that restored `=== '1'`,
   typo'd the env name, or stopped reading assets when the var is
   unset would still leave the guard green. Extracted the predicate
   into `isDesignTokenChannelEnabled(env)` next to
   `readDesignSystemAssets` and added 6 unit tests pinning every value
   that matters: unset / `'1'` / `'true'` / empty / `'0'` /
   whitespace-padded. server.ts now calls the predicate. Any
   regression on the env-flag semantics fails
   `tests/design-system-assets.test.ts` independently of the
   composer-level coverage.

Verified: pnpm guard (13/13), tsc -p scripts/tsconfig.json (clean),
@open-design/daemon typecheck (clean), 32/32 prompt + asset tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* review: pin server-layer asset resolution end-to-end (lefarcen P2)

Round-2 review feedback from @lefarcen on #1544: the predicate suite
in tests/design-system-assets.test.ts pinned the env-flag boolean but
did NOT exercise the server prompt-assembly path that PR-D actually
flipped — the seam where the daemon decides whether to read tokens.css
/ components.html from disk and hand them to composeSystemPrompt. A
regression that, say, restored an inline `=== '1'` gate or stopped
calling isDesignTokenChannelEnabled() from server.ts would still leave
the predicate test green.

Extracted that whole seam into `resolveDesignSystemAssets(id,
builtInRoot, userInstalledRoot, env)` on apps/daemon/src/design-systems.ts.
The function combines:
  1. the env-flag gate (kill switch on `OD_DESIGN_TOKEN_CHANNEL=0`)
  2. the built-in → user-installed root fallback chain (per-file)
  3. the DesignSystemAssets result shape consumed by composeSystemPrompt

server.ts at the prompt-assembly site is now a thin caller of this
function. The previous 13-line inline block (env check + per-file
fallback) collapses to one call, so the whole asset-resolution path
now has a single testable seam.

7 new tests in tests/design-system-assets.test.ts run the full pipeline
end-to-end against real disk fixtures:
  - env unset (default-on): returns built-in assets
  - env=`'0'` (kill switch): returns undefined even with files on disk
  - env=`'1'` (legacy opt-in): still works
  - mixed builtin/user-installed: per-file fallback merges correctly
  - both halves built-in: skips user-installed roundtrip verbatim
  - prose-only brand (no files): undefined / undefined
  - nonexistent brand directory: undefined / undefined

Verified: pnpm guard (13/13), tsc -p scripts/tsconfig.json (clean),
@open-design/daemon typecheck (clean), 39/39 prompt + asset tests
(was 32; +7 new server-layer-resolution tests).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(test): add missing projectKind to FileViewer deck preview test

The deck preview test added in #1556 (086be271) renders <FileViewer/>
without `projectKind`, which became a required prop in #1509. CI on
main is currently red on this; pick up the trivial fix here so PR-D
can land cleanly.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 14:14:19 +08:00