Repository navigation
feat(desktop): find design-token sources in a picked folder - #486
Merged
Sun-sunshine06 merged 3 commits intoOct 13, 2026
Merged
Sun-sunshine06 merged 3 commits into
Sun-sunshine06 merged 3 commits into
Conversation
extractFromTailwindConfig, extractFromCssVars and importDtcgJson live in src/brand and are only reachable through deep imports. Re-export them from the package entry by name so the desktop main process can use them through the public entry. They are side-effect-free text parsers. Refs OpenCoworkAI#484
Add scanTokenSources, which walks a folder and runs the brand extractors
over the files that carry design tokens: tailwind.config.{js,cjs,mjs,ts},
CSS with :root, [data-theme] or @theme blocks, and DTCG tokens.json or
*.tokens.json. It returns the tokens per source file, plus the files it
skipped and whether the file cap cut the walk short, so a later preview
can show all three.
The walk shares the ignored-directory list with the existing design
system scan, never follows symlinks, and is bounded by named limits for
depth, file count and file size. Files are read as text and nothing in
the folder is executed. Nothing calls the scan yet.
Refs OpenCoworkAI#484
Contributor
There was a problem hiding this comment.
Findings
- [Minor] A single structurally-invalid token file can abort the whole scan —
readTokensonly translates aSyntaxError(fromJSON.parse) into a skippableinvalid-jsonresult, while every other throw is re-thrown (apps/desktop/src/main/design-system-tokens.ts:99-106).importDtcgJson(...)runs inside the sametry, so if it throws for valid JSON that is not DTCG-shaped (e.g. a plaintokens.jsonfrom another tool), or ifextractFromTailwindConfig/extractFromCssVarsthrow on an unusualtailwind.config.*/ CSS file,scanTokenSourcesrejects and the whole folder import fails over one unrelated file. This is the exact case the scan is meant to tolerate: it already reportsinvalid-jsonandtoo-largeas data rather than failing.
Suggested fix / next action: either broaden the recoverable branch to cover extractor/shape failures (add askippedreason such asinvalid-tokens) so a bad file only excludes itself, or confirm and document thatimportDtcgJsonand the extractors only throw for genuine I/O errors. Add a test for (a) valid JSON with a non-DTCG shape and (b) a malformedtailwind.config.js, since the current tests only cover'{ not json'(apps/desktop/src/main/design-system-tokens.test.ts).
Questions
- Can
importDtcgJsonthrow anything other thanSyntaxErrorfor in-size files? Theerror instanceof SyntaxErrornarrowing implies a deliberate choice to re-throw everything else, but the intent isn't obvious from the diff.
Summary
- Review mode: initial
- The re-export and the scan are small, focused, and consistent with the project constraints I could check in the public repo: no new dependencies, no direct provider SDK import, all LLM/parsing work stays in the existing
packages/coreextractors,IGNORED_DIRSis only widened fromconsttoexport const(apps/desktop/src/main/design-system.ts:9), and nothing referencesscanTokenSourcesyet, so there is no startup-path cost. Symlink and size limits are enforced and tested. - Highest-severity item is the Minor above. No Blocker or Major issues found.
- Issue validation for #484 could not be performed in this run (no issue fetch available); the PR uses
Refs #484and describes itself as PR 1 of 4, which is the correct link style for a partial slice, so no closure claim is being over-asserted. - Residual risk:
skippedcan list any over-cap.cssfile (every.cssis a candidate viasourceKind, and the size check runs before token detection), so a large token-less stylesheet may appear as a skipped token source in the PR 3 preview. Worth a look when the preview surfaces this list, but not a merge concern here. - Deferring the changeset to PR 3 is reasonable as long as a changeset covering the new
@open-codesign/coreexports is added before the next version/release.
Testing
- Not run (automation). The added
design-system-tokens.test.tscovers ordering, both CSS block forms, ignored dirs, depth/file/size caps, invalid JSON, text-only config parsing, and symlink non-following. Gap: no coverage for non-SyntaxErrorfailures from the DTCG importer or the extractors (see finding above).
Open-CoDesign Bot
Pin what the token scan does with a file that is not what its name says: valid JSON that is not shaped like DTCG tokens, and a Tailwind config or CSS file with unbalanced braces. The extractors return no tokens for all of them, so the scan lists no source and does not fail. Say in the code why only malformed JSON marks a file as skipped: read errors have to surface, and importDtcgJson accepts any parsed value. Refs OpenCoworkAI#484
Contributor
There was a problem hiding this comment.
Findings
No new findings. The single Minor from the previous review is addressed:
- The prior concern was that
readTokensnarrows recovery toSyntaxError, so a token file that makesimportDtcgJsonthrow for another reason would reject the whole scan (apps/desktop/src/main/design-system-tokens.ts:99-108). The intent is now documented atapps/desktop/src/main/design-system-tokens.ts:100-101:importDtcgJsonaccepts any parsed value, so only malformed JSON is treated as skippable, and read errors propagate deliberately. - New tests exercise exactly the cases the prior review asked for: valid JSON that is not DTCG-shaped (
[1, 2, 3],null, apackage.json-shaped object) and a malformedtailwind.config.jsplus unbalanced CSS both return{ sources: [], skipped: [], truncated: false }(apps/desktop/src/main/design-system-tokens.test.ts:126-147). These assertions would fail ifimportDtcgJsonor the extractors threw for those inputs, so the tests validate the documented behavior rather than merely restating it.
Questions
None. The prior open question — whether importDtcgJson can throw anything other than SyntaxError for in-size files — is answered by the added comment and the new non-DTCG-shape tests.
Summary
- Review mode: follow-up after new commits
- Scope is unchanged from the prior review: re-export three
packages/corebrand extractors by name (noexport *) and add an unusedscanTokenSourceswalker. No new dependencies, no direct provider SDK imports, all parsing stays in the existingpackages/coreextractors, andIGNORED_DIRSis only widened fromconsttoexport const(apps/desktop/src/main/design-system.ts:9). Nothing referencesscanTokenSources, so there is no startup-path cost and the lazy-load constraint is respected. - The diff since the previously reviewed commit is test-only plus a two-line comment; no behavioral change beyond the recoverable branch now being backed by tests.
- Residual risk (unchanged, non-blocking):
readTokensstill re-throws any non-SyntaxErrorfromextractFromTailwindConfig/extractFromCssVarson the config/CSS paths (apps/desktop/src/main/design-system-tokens.ts:98,:111-112), so an unexpected extractor throw would abort the scan for the whole folder. There is no evidence the extractors throw on in-size text today; if the PR 3 preview ever surfaces such a case, add a dedicatedskippedreason (e.g.invalid-tokens) instead of failing the import. - Residual risk (unchanged, non-blocking):
skippedcan list any over-cap.cssfile, because every.cssis a candidate and the size check runs before token detection, so a large token-less stylesheet can appear as a skipped token source. Worth re-checking when PR 3 renders the list. - Linked issue: the PR uses
Refs #484and describes itself as PR 1 of 4, which is the correct link style for a partial slice; there is no closure claim to validate. The issue #484 body was not available in this run, so I could not re-check its acceptance criteria against this slice. - Deferring the changeset to PR 3 is reasonable as long as the new
@open-codesign/coreexport addition is covered before the next version bump.
Testing
- Not run (automation). The added
design-system-tokens.test.tscovers ordering, both CSS block forms, ignored dirs, depth/file/size caps, invalid JSON, non-DTCG-shaped JSON, malformed config/CSS, text-only config parsing, and symlink non-following. No Playwright coverage is expected for an unused main-process helper.
Open-CoDesign Bot
1 task done
5 tasks
9 of 15 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First slice of #484: re-export the three brand token extractors from the core entry, and add
scanTokenSources, which finds the files in a folder that carry design tokens and runs the extractors over them. Nothing calls the scan yet. PR 3 of the series wires it to the import action and loads it withawait import(...)at the IPC handler, so it stays off the startup path (CLAUDE.md constraint 5). The two changes are separate commits so the re-export and the scan can be reviewed apart.packages/core/src/index.ts):extractFromTailwindConfig,extractFromCssVarsandimportDtcgJsonby name, noexport *. They are side-effect-free text parsers, and the scan is not reachable from core's entry.apps/desktop/src/main/design-system-tokens.ts): returns the tokens per source file fortailwind.config.{js,cjs,mjs,ts}, CSS containing:root,[data-theme]or@theme, andtokens.json/*.tokens.json. It also reports the files it skipped (over the size cap, invalid JSON) and whether the file cap cut the walk short, as data for the preview and not as log lines.What the scan does and does not do:
node_modules,.git, build output and the rest of the existing ignore list (IGNORED_DIRS, now exported fromdesign-system.ts), and never follows symlinks.DEFAULT_TOKEN_SCAN_LIMITS): depth 6, 10,000 files looked at, 256,000 bytes per file.The existing "Link design system repo" scan (
scanDesignSystem) is unchanged, and the two write to different stores. The existing scan keeps an app-scoped list of candidate values in the app config. The import this series builds writes<workspace>/DESIGN.md, per design, and will be its own action with its own IPC channel (PR 3); it does not read or replace the snapshot.One difference from the plan on #484: the walk is new and the existing one is not reused. The existing walk stops after 160 candidate files in directory order and keeps only a prompt summary, so on a larger repo it can stop before it reaches the token files, and it has no tests. This scan shares its ignore list (
IGNORED_DIRS) and has its own limits, named constants that tests override. They are separate from the snapshot's caps, so the two scans do not share a budget.Run on real folders: open-cowork (3 sources, 39 tokens) and this repo (6 sources, 190 tokens), about 12 ms each, neither truncated.
Type of change
Linked issue
Refs #484 (PR 1 of 4)
Checklist
pnpm lint && pnpm typecheck && pnpm testpasses locallypnpm changeset) if user-visibleNothing is user-visible until the scan is wired in, so the changeset comes with that PR. The docs page is PR 4.
Principles
exportonIGNORED_DIRS.Checks
pnpm -r typecheck,pnpm lint,pnpm test: 10 tasks passed; core 560 tests, shared 326, desktop 181 files / 2,640 tests.design-system-tokens.test.ts(11 tests): a Tailwind config,:rootCSS,@themeCSS and DTCG JSON in one folder, in a stable order;@themeand:rootin one file; ignored directories; depth limit; file cap with the truncation flag; size cap; invalid JSON; valid JSON that is not DTCG-shaped; a malformed config and CSS; a config that is parsed and not run; symlinks to a directory and to a file are not followed.