Skip to content

feat(ui): token layer + rename to STANDARDS (slice #01)#442

Merged
Astro-Han merged 1 commit into
devfrom
claude/i440-slice-01-tokens
May 5, 2026
Merged

feat(ui): token layer + rename to STANDARDS (slice #01)#442
Astro-Han merged 1 commit into
devfrom
claude/i440-slice-01-tokens

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Rewrites `packages/ui/src/styles/theme.css` from scratch against PawWork STANDARDS L8-L42: warm neutrals, brand orange `#ff5910` ≤10% accent, 13px dense base, system-font stack only.
  • Fixes a latent dark-mode bug: upstream `@media`-only approach meant the Settings toggle had no effect on most tokens. Now `[data-color-scheme="dark"]` is the authoritative selector; `@media` block is a first-paint mirror only.
  • Rewrites `packages/ui/src/theme/themes/pawwork.json` to STANDARDS values with the new token names.
  • Rebuilds `packages/ui/script/colors.txt` (104 token names including legacy compat aliases) and regenerates `packages/ui/src/styles/tailwind/colors.css`.
  • Renames 50+ upstream token names to STANDARDS names across 144 component files in `packages/ui/src` and `packages/app/src`.
  • Fixes first-paint HTML entry files: updates `packages/app/index.html` and `packages/desktop-electron/src/renderer/{index,loading}.html` to use `var(--bg-base)` and syncs `theme-color` meta tag values.
  • Adds legacy compat token aliases (`button-brand-*`, `icon-success-base`, `icon-info-base`, `icon-on-interactive-base`) to the UNREGULATED section so existing consumers remain styled.
  • Fixes Tailwind shadow bridge aliases in `tailwind/index.css`: maps `shadow-xs` → `--shadow-raised`, `shadow-md` → `--shadow-floating`, `shadow-xs-border` → `--shadow-xs-border-base`.
  • Adds a Bun parity test (128 assertions) that enforces sync between `theme.css` and `pawwork.json`, including dark-completeness and `@media` mirror checks.
  • Adds a Bun undefined-token scan test that asserts every regulated `var(--xxx)` reference resolves to a definition in `theme.css`.
  • Adds `.gitattributes` carve-out entries with `merge=pawwork-keep-ours` driver plus `packages/ui/script/verify-merge-driver.sh`.

Why

PawWork's UI must permanently diverge from upstream opencode's cool-gray / Catppuccin token system. This slice establishes the token foundation that all subsequent component slices (#2#11) will build on.

Related Issue

Refs #440 (umbrella). This PR is slice #1 of eleven.

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • Token rename correctness: 50+ renames across 144 files — the undefined-tokens.test.ts scan verifies no regulated var(--xxx) is left dangling.
  • Dark-mode selector strategy: [data-color-scheme="dark"] is authoritative; @media block is mirror-only — confirm theme-parity.test.ts enforces exact value sync.
  • Compat alias wiring: five legacy tokens in the UNREGULATED section resolve to new canonical tokens — verify buttons and icon components render correctly.
  • .gitattributes carve-out: three HTML entry files newly added — confirm merge driver covers all intended paths.

Changed-file boundary check

All modified files are within the permanent carve-out paths declared in AGENTS.md and enforced in `.gitattributes`:

  • `packages/ui/**` ✓
  • `packages/app/src/app.tsx` ✓
  • `packages/app/src/components/**` ✓
  • `packages/app/src/context/**` ✓
  • `packages/app/src/index.css` ✓
  • `packages/app/src/pages/**` ✓
  • `packages/app/src/styles/**` ✓ (none touched this slice)
  • `packages/app/src/theme/**` ✓ (none touched this slice)
  • `packages/app/src/i18n/**` ✓ (none touched this slice)
  • `packages/app/src/utils/**` ✓
  • `packages/app/index.html` ✓ (now in carve-out)
  • `packages/desktop-electron/src/renderer/index.html` ✓ (now in carve-out)
  • `packages/desktop-electron/src/renderer/loading.html` ✓ (now in carve-out)

No `packages/opencode/**` or other out-of-scope paths were touched.

Merge driver setup

The `.gitattributes` carve-out uses a named driver that must be registered once per clone:

```bash
git config merge.pawwork-keep-ours.driver "true"
```

Verify before any upstream sync:

```bash
bash packages/ui/script/verify-merge-driver.sh
```

Without the driver, git falls back to three-way merge on the carve-out paths. The attribute entry is inert without registration.

How To Verify

```text
typecheck (packages/ui): tsgo --noEmit → 0 errors
typecheck (packages/app): tsgo -b → 0 errors

parity test: bun --cwd packages/ui run test test/theme-parity.test.ts
128 pass, 0 fail
Covers: light root, dark [data-color-scheme="dark"] overrides, dark completeness
(all light regulated tokens must have dark override or be in SAME_IN_DARK),
@media mirror exact-match against attribute dark block, extra/missing key
detection, value normalization, parser unit fixtures (extractBlock/parseDeclarations/normalize)

undefined-token scan: bun --cwd packages/ui run test test/undefined-tokens.test.ts
2 pass, 0 fail
Scans all CSS/TS/TSX var(--xxx) for regulated prefixes; asserts each resolves
to theme.css or known-gap allowlist (pierre diffs API, @property-registered lengths)

merge driver verify: bash packages/ui/script/verify-merge-driver.sh
✓ merge driver 'pawwork-keep-ours' is registered (driver = 'true')

note: session-diff.test.ts 2 failures are pre-existing; not caused by this PR
(session-diff.ts/test.ts untouched, confirmed via git diff)
```

Screenshots

Light mode

pawwork-ui-v2-light

Dark mode

pawwork-ui-v2-dark

Token rename key mappings

Old name → New name (abbreviated):

Old New
`text-strong`, `text-base`, `text-weak`, `text-weaker` `fg-strong`, `fg-base`, `fg-weak`, `fg-weaker`
`background-base`, `background-weak` `bg-base`, `bg-cream`
`surface-raised-base` `surface-raised`
`surface-inset-base` `surface-sunken`
`border-weak-base`, `border-strong-base` `border-weak`, `border-base`
`icon-strong-base`, `icon-weak-base` `icon-strong`, `icon-weak`
`button-primary-base`, `accent-brand` `brand-primary`
`text-interactive-base`, `border-focus` `brand-primary`

Legacy compat aliases (kept for existing consumers, UNREGULATED):

Legacy Resolves to
`button-brand-base` `brand-primary`
`button-brand-hover` `brand-primary-hover`
`icon-success-base` `success`
`icon-info-base` `brand-primary`
`icon-on-interactive-base` `fg-on-brand`

Known issues (scoped to later slices)

Risk Notes

This PR combines four categories of change with different risk profiles:

  1. Token rename across 144 files (~1800 ins / ~2300 del): mechanical find-and-replace; no logic changed. Risk: any missed reference silently produces an unstyled element — mitigated by the `undefined-tokens.test.ts` `var(--*)` scan.
  2. Theme contract changes (`theme.css`, `pawwork.json`, `colors.txt`): changes the actual color/shadow values rendered in the UI. Risk: visual regression — mitigated by parity test, screenshot comparison, and smoke test.
  3. Generated artifacts (`tailwind/colors.css`): regenerated from `colors.txt`; a stale file would misalign Tailwind utilities with runtime tokens. Risk: `bg-surface-sunken` utility would resolve to the wrong color — mitigated by manual regen + post-regen review; a generation consistency test (colors.txt ↔ colors.css) is planned for slice feat: split desktop panel and thread locale into skills #2.
  4. Merge-driver carve-out (`.gitattributes`, `verify-merge-driver.sh`): establishes upstream sync boundary. Risk: mis-configured driver silently loses PawWork customizations on upstream sync — mitigated by the verify script and PR documentation.

Component-local tokens (`shell-`, `diffs-`, `tool-motion-`, `h-`, `kb-*`, `radius-xs`) were intentionally left untouched. Unregulated tokens (avatar 12, markdown 14, syntax 19, agent-icon 4, surface-diff-hidden 5) preserved at original values.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting `dev`, and my PR title and commit messages use Conventional Commits in English

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 157 files, which is 7 over the limit of 150.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c75701f-844b-4d8b-b668-5011e2e16ed7

📥 Commits

Reviewing files that changed from the base of the PR and between 12889f1 and 273586e.

📒 Files selected for processing (157)
  • .gitattributes
  • packages/app/index.html
  • packages/app/src/app.tsx
  • packages/app/src/components/debug-bar.tsx
  • packages/app/src/components/dialog-connect-provider.tsx
  • packages/app/src/components/dialog-connect-websearch.tsx
  • packages/app/src/components/dialog-custom-provider.tsx
  • packages/app/src/components/dialog-delete-session.tsx
  • packages/app/src/components/dialog-edit-project.tsx
  • packages/app/src/components/dialog-fork.tsx
  • packages/app/src/components/dialog-release-notes.tsx
  • packages/app/src/components/dialog-select-directory.tsx
  • packages/app/src/components/dialog-select-file.tsx
  • packages/app/src/components/dialog-select-mcp.tsx
  • packages/app/src/components/dialog-select-model-unpaid.tsx
  • packages/app/src/components/dialog-select-model.tsx
  • packages/app/src/components/dialog-select-provider.tsx
  • packages/app/src/components/dialog-select-server.tsx
  • packages/app/src/components/file-tree.tsx
  • packages/app/src/components/link.tsx
  • packages/app/src/components/model-tooltip.tsx
  • packages/app/src/components/prompt-input.tsx
  • packages/app/src/components/prompt-input/context-items.tsx
  • packages/app/src/components/prompt-input/drag-overlay.tsx
  • packages/app/src/components/prompt-input/image-attachments.tsx
  • packages/app/src/components/prompt-input/send-button.tsx
  • packages/app/src/components/prompt-input/slash-popover.tsx
  • packages/app/src/components/prompt-input/workspace-chip.tsx
  • packages/app/src/components/server/server-row.tsx
  • packages/app/src/components/session-context-usage.tsx
  • packages/app/src/components/session/pawwork-skill-meta.ts
  • packages/app/src/components/session/session-context-tab.tsx
  • packages/app/src/components/session/session-header.tsx
  • packages/app/src/components/session/session-new-view.tsx
  • packages/app/src/components/session/session-sortable-shell-tab.tsx
  • packages/app/src/components/session/session-status-connections.tsx
  • packages/app/src/components/session/session-status-summary.tsx
  • packages/app/src/components/settings-general.tsx
  • packages/app/src/components/settings-keybinds.tsx
  • packages/app/src/components/settings-models.tsx
  • packages/app/src/components/settings-page.tsx
  • packages/app/src/components/settings-providers.tsx
  • packages/app/src/components/settings-worktree-row.tsx
  • packages/app/src/components/settings-worktrees.tsx
  • packages/app/src/components/status-popover-body.tsx
  • packages/app/src/components/status-popover.tsx
  • packages/app/src/context/layout.tsx
  • packages/app/src/index.css
  • packages/app/src/pages/error.tsx
  • packages/app/src/pages/home.tsx
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/pawwork-sidebar.tsx
  • packages/app/src/pages/layout/pawwork-titlebar.tsx
  • packages/app/src/pages/layout/pawwork-worktree-badge.tsx
  • packages/app/src/pages/layout/sidebar-items.tsx
  • packages/app/src/pages/layout/sidebar-workspace.tsx
  • packages/app/src/pages/session/composer/session-composer-region.tsx
  • packages/app/src/pages/session/composer/session-followup-dock.tsx
  • packages/app/src/pages/session/composer/session-permission-dock.tsx
  • packages/app/src/pages/session/composer/session-revert-dock.tsx
  • packages/app/src/pages/session/composer/session-todo-dock.tsx
  • packages/app/src/pages/session/file-tabs.tsx
  • packages/app/src/pages/session/files-tab.tsx
  • packages/app/src/pages/session/message-timeline.tsx
  • packages/app/src/pages/session/review-panel-view.tsx
  • packages/app/src/pages/session/session-main-view.tsx
  • packages/app/src/pages/session/session-side-panel.tsx
  • packages/app/src/pages/session/terminal-panel.tsx
  • packages/app/src/shell-frame-contract.test.ts
  • packages/app/src/utils/agent.ts
  • packages/desktop-electron/src/renderer/index.html
  • packages/desktop-electron/src/renderer/loading.html
  • packages/ui/script/colors.txt
  • packages/ui/script/verify-merge-driver.sh
  • packages/ui/src/components/accordion.css
  • packages/ui/src/components/accordion.stories.tsx
  • packages/ui/src/components/app-icon.stories.tsx
  • packages/ui/src/components/avatar.css
  • packages/ui/src/components/basic-tool.css
  • packages/ui/src/components/basic-tool.stories.tsx
  • packages/ui/src/components/button.css
  • packages/ui/src/components/card.css
  • packages/ui/src/components/card.tsx
  • packages/ui/src/components/checkbox.css
  • packages/ui/src/components/collapsible.css
  • packages/ui/src/components/collapsible.stories.tsx
  • packages/ui/src/components/context-menu.css
  • packages/ui/src/components/context-menu.stories.tsx
  • packages/ui/src/components/dialog.css
  • packages/ui/src/components/diff-changes.css
  • packages/ui/src/components/diff-changes.tsx
  • packages/ui/src/components/dock-surface.css
  • packages/ui/src/components/dropdown-menu.css
  • packages/ui/src/components/favicon.stories.tsx
  • packages/ui/src/components/file-icon.stories.tsx
  • packages/ui/src/components/file-media.tsx
  • packages/ui/src/components/file-search.tsx
  • packages/ui/src/components/file.css
  • packages/ui/src/components/hover-card.css
  • packages/ui/src/components/hover-card.stories.tsx
  • packages/ui/src/components/icon-button.css
  • packages/ui/src/components/icon.stories.tsx
  • packages/ui/src/components/image-preview.css
  • packages/ui/src/components/inline-input.css
  • packages/ui/src/components/keybind.css
  • packages/ui/src/components/line-comment-styles.ts
  • packages/ui/src/components/line-comment.stories.tsx
  • packages/ui/src/components/list.css
  • packages/ui/src/components/logo.stories.tsx
  • packages/ui/src/components/logo.tsx
  • packages/ui/src/components/markdown.css
  • packages/ui/src/components/message-nav.css
  • packages/ui/src/components/message-part.css
  • packages/ui/src/components/message-part.tsx
  • packages/ui/src/components/popover.css
  • packages/ui/src/components/progress-circle.css
  • packages/ui/src/components/progress.css
  • packages/ui/src/components/provider-icon.stories.tsx
  • packages/ui/src/components/radio-group.css
  • packages/ui/src/components/resize-handle.stories.tsx
  • packages/ui/src/components/scroll-view.css
  • packages/ui/src/components/select.css
  • packages/ui/src/components/session-review.css
  • packages/ui/src/components/session-review.tsx
  • packages/ui/src/components/session-turn.css
  • packages/ui/src/components/shell-submessage-motion.stories.tsx
  • packages/ui/src/components/sticky-accordion-header.css
  • packages/ui/src/components/sticky-accordion-header.stories.tsx
  • packages/ui/src/components/switch.css
  • packages/ui/src/components/tabs.css
  • packages/ui/src/components/tabs.stories.tsx
  • packages/ui/src/components/tag.css
  • packages/ui/src/components/text-field.css
  • packages/ui/src/components/text-reveal.stories.tsx
  • packages/ui/src/components/text-shimmer.css
  • packages/ui/src/components/text-shimmer.stories.tsx
  • packages/ui/src/components/text-strikethrough.stories.tsx
  • packages/ui/src/components/thinking-heading.stories.tsx
  • packages/ui/src/components/timeline-playground.stories.tsx
  • packages/ui/src/components/toast.css
  • packages/ui/src/components/todo-panel-motion.stories.tsx
  • packages/ui/src/components/tool-count-summary.stories.tsx
  • packages/ui/src/components/tool-error-card.css
  • packages/ui/src/components/tool-status-title.css
  • packages/ui/src/components/tooltip.css
  • packages/ui/src/context/marked.tsx
  • packages/ui/src/pierre/comment-hover.ts
  • packages/ui/src/pierre/file-find.ts
  • packages/ui/src/pierre/index.ts
  • packages/ui/src/styles/tailwind/colors.css
  • packages/ui/src/styles/tailwind/index.css
  • packages/ui/src/styles/theme.css
  • packages/ui/src/styles/utilities.css
  • packages/ui/src/theme/resolve.ts
  • packages/ui/src/theme/themes/pawwork.json
  • packages/ui/test/theme-parity.test.ts
  • packages/ui/test/undefined-tokens.test.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/i440-slice-01-tokens

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request executes a comprehensive migration of design tokens across the codebase to align with PawWork standards, replacing upstream opencode naming conventions. Key changes include the introduction of a custom git merge driver to protect forked UI paths, updated theme definitions for light and dark modes, and a new parity test to ensure consistency between CSS and JSON theme sources. Feedback was provided regarding a hardcoded absolute path in the token renaming script, which should be replaced with a portable workspace root discovery mechanism.

Comment thread packages/ui/script/slice-01-rename.ts Outdated
@Astro-Han Astro-Han added enhancement New feature or request ui Design system and user interface P1 High priority labels May 5, 2026
…ssue #440)

Slice #1 of eleven. Establishes the semantic token foundation for all subsequent
PawWork UI component slices (#2#11). This is a permanent carve-out from upstream
opencode — see AGENTS.md §Upstream Sync and .gitattributes.

## What changed

- theme.css: full rewrite against PawWork STANDARDS (warm neutrals, brand orange
  #ff5910, 13px dense, system-font). Three-selector structure:
    :root (light) → [data-color-scheme="dark"] (authoritative dark) → @media mirror
  Fixes a latent upstream bug: @media-only meant the Settings toggle had no effect.

- pawwork.json: rewritten to STANDARDS values with new token names.

- colors.txt → tailwind/colors.css: 104 tokens (incl. legacy compat aliases);
  regenerated Tailwind --color-* bridge via script/tailwind.ts.

- 50+ token renames across 144 component files in packages/ui/src and packages/app/src.

- HTML entry files (app/index.html, desktop-electron renderer/*.html): updated to
  var(--bg-base) and synced theme-color meta. Now in .gitattributes carve-out.

- UNREGULATED section in theme.css: holds legacy compat aliases (button-brand-*,
  icon-success-base, icon-info-base, icon-on-interactive-base, surface-base-active)
  so existing component consumers stay styled without entering STANDARDS managed set.

- .gitattributes: added merge=pawwork-keep-ours driver entries for packages/ui/**
  and key packages/app paths. Driver must be registered per-clone:
    git config merge.pawwork-keep-ours.driver "true"
  Verify before upstream sync: bash packages/ui/script/verify-merge-driver.sh

## Tests added

- packages/ui/test/theme-parity.test.ts (128 assertions, 0 fail):
  light root ↔ pawwork.json light.overrides, dark block ↔ dark.overrides,
  dark completeness (SAME_IN_DARK set), @media mirror exact-match, and two
  runtime-critical non-regulated token assertions (--text-mix-blend-mode: plus-lighter).

- packages/ui/test/undefined-tokens.test.ts:
  Scans every var(--xxx) in theme.css, Tailwind bridge, and HTML entry files;
  asserts each resolves to a definition.

## Deferred to slice #2

- colors.txt ↔ colors.css generation consistency test (manual regen + review for now)
- TSX/class utility audit (old token utility names, misspelled utilities)
- --surface-base-active classification (state token vs. compat bridge)
- Legacy runtime token deprecation checklist

## Key decisions for future agents

1. [data-color-scheme="dark"] is authoritative. @media block is mirror-only (first-paint).
   Both must stay in sync — theme-parity.test.ts enforces this.
2. UNREGULATED section in theme.css is intentional scope. Tokens there are consumed by
   components but not STANDARDS-managed. Do not promote to regulated without adding to
   pawwork.json and updating the parity test.
3. The merge driver only fires on two-sided conflicts. One-sided upstream changes still
   clean-merge. Always review upstream-sync PR diffs for carve-out paths.
4. colors.css is a generated file (do not hand-edit). Regen: bun run script/tailwind.ts.
@Astro-Han Astro-Han force-pushed the claude/i440-slice-01-tokens branch from 8abc50f to 273586e Compare May 5, 2026 09:10
@Astro-Han Astro-Han merged commit 09790e6 into dev May 5, 2026
20 checks passed
@Astro-Han Astro-Han deleted the claude/i440-slice-01-tokens branch May 5, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request P1 High priority ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant