Unify apex + web on one shared @agent-paste/ui design system#454
Conversation
… as Vite SSG Add @agent-paste/ui: shared React primitives + a single globals.css generated from @agent-paste/brand. Migrate web to import it and delete the brand-tokens parity test (parity is now structural). Rebuild apex from hono/jsx string-rendering into a plain Vite + React app prerendered to static HTML: zero client React, one vanilla enhancement script (client.ts), a static CSP with a build-time sha256-pinned pre-paint theme-init. Per-env builds gate /pricing on BILLING_ENABLED; a thin worker shim (server.ts) serves redirects, headers, and text assets while HTML/CSS/JS/fonts go through the ASSETS binding. Wire deploy.mjs, deploy-pr-preview.mjs, and turbo.json for the new build. Split the old index.test.ts into render/server/security-headers/entry-server suites; ledger-exclude browser-only client.ts from coverage and render every doc slug. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ibrary) The prior refactor claimed Button/Card/Badge/Table/cn were shared but only Prose ever landed in the package; web kept its own copies and apex hand-wrote CSS. Move the actual primitives into @agent-paste/ui so both apps render ONE copy and cannot drift. - Move Button, Card, Badge, Table, cn from apps/web/src into packages/ui/src - Export them from the package barrel; add clsx + tailwind-merge deps - Repoint all web import sites (~38 files) to @agent-paste/ui; delete the emptied originals - Cross-package Tailwind content scan verified: package-only utilities (accent-dim, live-pulse) appear in web's built CSS through the pnpm symlink apex conversion to Tailwind + shared components follows next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ibrary Unify apex + web on ONE styling system. apex was hand-written semantic CSS (1,411 lines across base/sections/home/home-foot.css); web was Tailwind. Now both render the SAME @agent-paste/ui components in Tailwind utilities and cannot drift. - Promote Wordmark into @agent-paste/ui; web Topbar/index + apex chrome render it - Convert apex chrome, Shell, and all pages (Home/About/HowItWorks/Pricing/Legal/ Docs) from semantic classes to inline Tailwind utilities, token-driven colors - Delete base/sections/home/home-foot.css; apex.css keeps only the marketing-only effects that can't be inline utilities (scroll-reveal, live-pulse dot, gesture) - Move the shared `.code` inline-code chip into brand globalsCss() (Prose is shared) so both surfaces match; regenerate ui/styles.css - render.test.tsx: assert hrefs/structure, not class strings (test the rule, not the presentation) — drop vestigial content/docs-layout/head-link/docs-inline-link class hooks from markup - Drop now-unused deps: @agent-paste/brand from apex, clsx/tailwind-merge from web - Bump react/react-dom to ^19.2.7 (latest), @types to match; single React copy Net -1063 lines. verify + per-package coverage green; apex prerenders 18 routes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-component utilities; sync theme across surfaces Unify apex + web on the shared @agent-paste/ui design system and kill the arbitrary-value soup in the DOM. Everything type/spacing/color/motion is now a theme utility; structural layout literals stay (and are the only brackets left). Scale + de-bracket - Register the full type/leading/tracking/easing scale in the brand @theme block (driven from TYPE/EASE_OUT), so named utilities exist for every size, line height, tracking step, and the ease-out curve. - Convert ~520 arbitrary type/leading/tracking/easing brackets to named utilities across apex, web, and packages/ui (710 -> 189 brackets; the rest are logged structural literals). - Snap ALL spacing utilities to the integer scale {0,1,2,3,4,5,6,8,10,12,16,20, 24,32}: no .5 half-steps, no off-rhythm integers. Single styling authority - Add shared <ButtonAnchor> + buttonClasses() so link CTAs and button CTAs share one definition; replace 5 divergent inline accent-fill anchor copies. - Add apex marketing primitives (PageHeader/Eyebrow/SectionHeading/ProseBlock/ RailLink + shared comparison-table classes); 6 marketing pages compose them instead of re-declaring the same header/section markup inline. - apex docs carry accent splashes (section ticks, eyebrow dot, card hover, code chip) through the shared system; footer stays multi-column on named utilities. Fix dropped shared-component utilities (the "missing padding" bug) - Both apex.css and web globals.css now @source packages/ui/src. Tailwind only emits utilities it sees used in scanned files, so utilities unique to shared components (Card p-5, the lg button h-[40px]/px-4) were silently dropped and rendered unstyled (Cards flush against the rule, buttons with no height). Cross-surface theme sync - Persist the theme in a cookie scoped to the registrable parent (.agent-paste.sh) so apex (marketing) and web (app) share one preference; localStorage can't cross subdomains. Shared helpers in @agent-paste/brand, re-exported via @agent-paste/ui. - apex inline pre-paint script + toggle and web theme-provider all read/write the shared agp_theme cookie. Verified bidirectional on preview. - Derive the apex CSP theme-init hash on the fly from THEME_INIT_JS (node:crypto works in Workers under nodejs_compat), removing the hand-pinned hash + its byte-stability re-pin chore. Env-correct preview links - apex bakes app/api/mcp base URLs at build from AGENT_PASTE_ENV, so the preview build links to preview, not production. deploy.mjs now passes AGENT_PASTE_ENV into the apex build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…utton wrap + section-label overlap Make the marketing (apex) and dashboard (web) headers read as one product by sharing the static look while each app keeps its own dynamic driver. - New @agent-paste/ui/themeToggle: one source for the header toggle's class, icon set (system/dark/light SVGs), cycle order, and aria copy. apex's framework-free client.ts script and web's React <ThemeToggle> both render the identical button + glyph and write the same agp_theme cookie, so the two toggles cannot drift. apex's toggle gains the "system" state it lacked. - apex header toggle is now the shared icon-only square button (was a bordered "Theme" chip); web is unchanged in behavior but re-skinned from the shared source instead of lucide icons + bespoke classes. Bug fixes (both via the shared primitives, so every call site is fixed at once): - buttonClasses: add whitespace-nowrap so fixed-height small buttons (e.g. "Copy URL") never wrap and overflow their height. - SectionLabel: add an `action` slot so a trailing link sits past the hairline rule instead of overlapping it; dashboard Recent/Activity headers use it (kills the "ALL ARTIFACTS" / rule overlap). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-cccdcc # Conflicts: # apps/web/src/components/claim/ClaimSuccessPanel.tsx
The format check ignored only root-level .wrangler/.turbo (e.g. `!.wrangler`), not nested ones, so a build artifact like apps/web/.wrangler/deploy/config.json tripped `biome format` and failed the local gate + pre-push hook. Mirror the recursive `!dist` + `!**/dist` pattern already used for dist. Issue: AP-276 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 20 minutes and 54 seconds. Learn how PR review limits work. To continue reviewing without waiting, purchase usage credits in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe PR adds a shared UI/brand package, switches Apex to prerendered SSR output with a new server entry, and migrates the web app to shared components, shared theme cookies, and tokenized styling. ChangesShared design system rollout
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
agent-paste PR preview is ready. API: https://agent-paste-api-pr-454.isaac-a46.workers.dev |
…assertion
CodeQL flagged two regexes on this branch:
- packages/ui Prose PROSE_PATTERN was polynomial ("Polynomial regular expression
used on uncontrolled data"): the naive [^\]]+ / [^)]+ classes let the engine
backtrack quadratically on adversarial input like "[" + "[\\".repeat(n)
(measured ~2s at 50k chars). Exclude each capture's OWN opening delimiter
([^\][] and [^()]) so the alternatives are unambiguous and the match is linear
(~0.2ms at 50k). Tokenization of valid prose is byte-identical. Prose is shared
shipping code in @agent-paste/ui, so this is a real fix, not a suppression.
Add deterministic tests: inner-pair-wins on nested brackets + no over-match on
an adversarial bracket run (no wall-clock assertion, so it can't flake).
- apps/apex render.test.tsx counted inline scripts with /<script>/g; CodeQL's
"bad HTML filtering regexp" rule wants case-insensitivity. Use /<script>/gi —
the count is over our own rendered SSG output, but the i flag is strictly safer
and clears the alert.
Issue: AP-276
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
agent-paste PR preview is ready. API: https://agent-paste-api-pr-454.isaac-a46.workers.dev |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/apex/src/copy.ts`:
- Around line 1-14: The prerendered URLs in apps/apex/src/copy.ts are determined
by process.env.AGENT_PASTE_ENV (ENV) but deploy-pr-preview.mjs does not pass
AGENT_PASTE_ENV into the apex build, so preview builds bake production links;
update the apex build invocation in deploy-pr-preview.mjs to pass
AGENT_PASTE_ENV: "preview" (or call/reuse apexBuildEnv()) via the env option you
give to spawnCommand so the child process sees AGENT_PASTE_ENV and
apps/apex/src/copy.ts will produce preview URLs (look for spawnCommand and
apexBuildEnv references to implement the change).
In `@apps/apex/src/pages/PricingPage.tsx`:
- Around line 38-56: The Pro plan uses a different fallback for its amount
(proPrice?.amount ?? "") than the Free plan (freePrice?.amount ?? "$0"), causing
an empty price display; update the Pro rendering to use a consistent fallback
(e.g., proPrice?.amount ?? "$0" or a shared placeholder like "Contact us") or
centralize price formatting into a helper used by both freePrice and proPrice
(referencing PLANS.free.name, PLANS.pro.name, freePrice, proPrice in the
PricingPage component) so the price span always shows a sensible default rather
than an empty string.
In `@apps/web/src/components/chrome/command-palette/CommandPaletteSearch.tsx`:
- Line 40: The input padding change from pl-[34px] to pl-8 reduces the gap
between the Search icon (left-3, size={16}) and the input text to ~4px; confirm
against the design and either (A) restore the explicit padding-left value (e.g.,
pl-[34px]) on the input in CommandPaletteSearch or (B) adjust the icon
positioning/size (the Search icon usage with left-3 and size={16}) so the right
edge sits ~28px and yields the intended ~6px gap—pick one approach and update
the input className or icon container accordingly so the spacing matches design.
In `@packages/brand/src/index.ts`:
- Around line 144-534: globalsCss() is too large and should be split into
focused helpers for readability and testability; create small functions like
themeVarsCss(), themeDefinitionsCss(), baseStylesCss(), and keyframesCss() that
return the corresponding CSS blocks (reusing fontFaceCss() for the font faces),
move the root + [data-theme="dark"/light] variable declarations into
themeVarsCss(), move the `@theme` block into themeDefinitionsCss(), move the
element/base rules into baseStylesCss(), and move all `@keyframes` and small
utility classes into keyframesCss(), then make globalsCss() assemble them in
order (keeping the initial `@import "tailwindcss";` and `${fontFaceCss()}`
calls) so callers of globalsCss() see the exact same output but the
implementation is modular and testable.
In `@packages/ui/src/components/Button.tsx`:
- Around line 13-40: The Button component currently uses forwardRef
(forwardRef<HTMLButtonElement, Props>) — update it to the React 19 ref-as-prop
pattern by removing forwardRef and accepting a ref prop directly on the Props
interface (e.g., ref?: React.Ref<HTMLButtonElement>), update the function
signature for Button to take props including ref (instead of the forwarded ref
parameter), and pass that ref into the underlying <button> element; retain
existing props like variant, size, loading, disabled, type and keep using
buttonClasses and data-loading/aria-busy behavior unchanged.
In `@packages/ui/src/components/Prose.tsx`:
- Around line 15-23: The regex in PROSE_PATTERN used by parseProse is vulnerable
to catastrophic backtracking; update PROSE_PATTERN to a non-backtracking-safe
form (e.g., make the quantified groups non-greedy so they cannot cause
exponential backtracking: change ([^\]]+) to ([^\]]+?) and ([^)]+) to ([^)]+?)
and `([^`]+)` to `([^`]+?)`), and add a defensive input length check at the
start of parseProse to bail out or truncate overly long inputs before running
the regex to further mitigate ReDoS risk.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ce2bae97-5abf-4eba-9a84-ccab85690384
⛔ Files ignored due to path filters (10)
apps/apex/public/fonts/BricolageGrotesque-Variable.woff2is excluded by!**/*.woff2apps/apex/public/fonts/CabinetGrotesk-Variable.woff2is excluded by!**/*.woff2apps/apex/public/fonts/IBMPlexMono-Medium.woff2is excluded by!**/*.woff2apps/apex/public/fonts/IBMPlexMono-Regular.woff2is excluded by!**/*.woff2apps/apex/public/fonts/SplineSansMono-Variable.woff2is excluded by!**/*.woff2apps/apex/public/fonts/Switzer-Variable.woff2is excluded by!**/*.woff2apps/web/public/fonts/CabinetGrotesk-Variable.woff2is excluded by!**/*.woff2apps/web/public/fonts/SplineSansMono-Variable.woff2is excluded by!**/*.woff2apps/web/public/fonts/Switzer-Variable.woff2is excluded by!**/*.woff2pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (164)
apps/apex/package.jsonapps/apex/scripts/prerender.mjsapps/apex/src/agents.tsapps/apex/src/app/Shell.tsxapps/apex/src/app/chrome.tsxapps/apex/src/app/scripts.tsapps/apex/src/build/text-assets.tsapps/apex/src/client.tsapps/apex/src/components/SourceRepository.tsxapps/apex/src/components/about.tsxapps/apex/src/components/chrome.tsxapps/apex/src/components/docs.tsxapps/apex/src/components/home.tsxapps/apex/src/components/how-it-works.tsxapps/apex/src/components/legal.tsxapps/apex/src/components/marketing.tsxapps/apex/src/components/pricing.tsxapps/apex/src/components/source-repository.tsxapps/apex/src/copy.tsapps/apex/src/docs/markdown.tsapps/apex/src/docs/pages/artifact-model.tsapps/apex/src/docs/pages/billing.tsapps/apex/src/docs/pages/cli.tsapps/apex/src/docs/pages/dashboard.tsapps/apex/src/docs/pages/ephemeral.tsapps/apex/src/docs/pages/getting-started.tsapps/apex/src/docs/pages/limits.tsapps/apex/src/docs/pages/mcp.tsapps/apex/src/docs/pages/rest-api.tsapps/apex/src/docs/pages/safety.tsapps/apex/src/docs/pages/sharing.tsapps/apex/src/docs/registry.tsapps/apex/src/entry-server.test.tsapps/apex/src/entry-server.tsxapps/apex/src/home-styles.tsapps/apex/src/index.test.tsapps/apex/src/index.tsapps/apex/src/legal-privacy.tsapps/apex/src/legal-terms.tsapps/apex/src/legal.tsapps/apex/src/llms.tsapps/apex/src/meta.tsapps/apex/src/pages/AboutPage.tsxapps/apex/src/pages/DocsIndexPage.tsxapps/apex/src/pages/DocsPageView.tsxapps/apex/src/pages/HomePage.tsxapps/apex/src/pages/HowItWorksPage.tsxapps/apex/src/pages/LegalPage.tsxapps/apex/src/pages/PricingPage.tsxapps/apex/src/plan-tiers.test.tsapps/apex/src/pricing.tsapps/apex/src/render.test.tsxapps/apex/src/routes.tsapps/apex/src/routes.tsxapps/apex/src/security-headers.test.tsapps/apex/src/security-headers.tsapps/apex/src/server.test.tsapps/apex/src/server.tsapps/apex/src/styles.tsapps/apex/src/styles/apex.cssapps/apex/tsconfig.jsonapps/apex/vite.config.tsapps/apex/vitest.config.tsapps/apex/wrangler.jsoncapps/web/README.mdapps/web/package.jsonapps/web/src/components/access-links/AccessLinkLockdownToggle.tsxapps/web/src/components/access-links/AccessLinksTable.tsxapps/web/src/components/access-links/CreateAccessLinkPanel.tsxapps/web/src/components/access-links/MintedUrlReveal.tsxapps/web/src/components/admin/AbuseTriageGuide.tsxapps/web/src/components/admin/LockdownForm.tsxapps/web/src/components/admin/LockdownList.tsxapps/web/src/components/admin/OperatorEventsPanel.tsxapps/web/src/components/billing/BillingHero.tsxapps/web/src/components/billing/BillingNote.tsxapps/web/src/components/billing/InvoiceTable.tsxapps/web/src/components/billing/PlanPanel.tsxapps/web/src/components/billing/SubscriptionPanel.tsxapps/web/src/components/chrome/NavigationProgress.tsxapps/web/src/components/chrome/Sidebar.tsxapps/web/src/components/chrome/SignOutForm.tsxapps/web/src/components/chrome/ThemeToggle.tsxapps/web/src/components/chrome/Topbar.tsxapps/web/src/components/chrome/Wordmark.tsxapps/web/src/components/chrome/command-palette/CommandPaletteDialogView.tsxapps/web/src/components/chrome/command-palette/CommandPaletteOption.tsxapps/web/src/components/chrome/command-palette/CommandPaletteResults.tsxapps/web/src/components/chrome/command-palette/CommandPaletteSearch.tsxapps/web/src/components/chrome/command-palette/CommandPaletteTrigger.tsxapps/web/src/components/claim/ClaimGuestGate.tsxapps/web/src/components/claim/ClaimSuccessPanel.tsxapps/web/src/components/dashboard/FirstRunKeyCard.tsxapps/web/src/components/dashboard/RecentArtifacts.tsxapps/web/src/components/dashboard/RecentAudit.tsxapps/web/src/components/dashboard/UsagePolicyCard.tsxapps/web/src/components/keys/KeyCreateForm.tsxapps/web/src/components/keys/KeysTable.tsxapps/web/src/components/keys/NewKeySecretCard.tsxapps/web/src/components/settings/SettingsForm.tsxapps/web/src/components/theme-provider.tsxapps/web/src/components/ui/Button.tsxapps/web/src/components/ui/DataTable.tsxapps/web/src/components/ui/EmptyState.tsxapps/web/src/components/ui/ErrorBanner.tsxapps/web/src/components/ui/HeroStat.tsxapps/web/src/components/ui/Identifier.tsxapps/web/src/components/ui/Input.tsxapps/web/src/components/ui/PageHeader.tsxapps/web/src/components/ui/RevokedActionPlaceholder.tsxapps/web/src/components/ui/StatBand.tsxapps/web/src/components/ui/StateBadge.tsxapps/web/src/components/ui/ToastList.tsxapps/web/src/lib/artifact-status.tsapps/web/src/lib/revocable-entity-state.tsapps/web/src/routes/__root.tsxapps/web/src/routes/_authed.artifacts.$artifactId.tsxapps/web/src/routes/_authed.artifacts.index.tsxapps/web/src/routes/_authed.audit.tsxapps/web/src/routes/_authed.claim.tsxapps/web/src/routes/_authed.keys.tsxapps/web/src/routes/_authed.settings.tsxapps/web/src/routes/_authed.tsxapps/web/src/routes/al.$publicId.tsxapps/web/src/routes/healthz.tsxapps/web/src/routes/index.tsxapps/web/src/styles/globals.cssapps/web/test/brand-tokens-parity.test.tsapps/web/test/chrome.test.tsxapps/web/test/theme-provider.test.tsxapps/web/test/ui-primitives.test.tsxbiome.jsondocs/development.mddocs/marketing-brand-guide.mddocs/ops/status/coverage.mddocs/specs/style-guide.mdknip.jsonpackages/brand/README.mdpackages/brand/src/index.test.tspackages/brand/src/index.tspackages/brand/src/theme-cookie.test.tspackages/brand/src/theme-cookie.tspackages/brand/src/tokens.tspackages/ui/README.mdpackages/ui/package.jsonpackages/ui/src/components/Badge.tsxpackages/ui/src/components/Button.tsxpackages/ui/src/components/ButtonAnchor.tsxpackages/ui/src/components/Card.tsxpackages/ui/src/components/Prose.tsxpackages/ui/src/components/Table.tsxpackages/ui/src/components/Wordmark.tsxpackages/ui/src/components/buttonClasses.tspackages/ui/src/components/themeToggle.tspackages/ui/src/index.tspackages/ui/src/lib/cn.tspackages/ui/src/styles/globals.csspackages/ui/test/globals-css.test.tspackages/ui/test/prose.test.tspackages/ui/tsconfig.jsonscripts/deploy-pr-preview.mjsscripts/deploy.mjsturbo.jsonvitest.shared.config.ts
💤 Files with no reviewable changes (17)
- apps/apex/src/components/pricing.tsx
- apps/apex/src/components/legal.tsx
- apps/apex/src/home-styles.ts
- apps/apex/src/components/source-repository.tsx
- apps/apex/src/components/how-it-works.tsx
- apps/apex/src/styles.ts
- apps/apex/src/components/docs.tsx
- apps/web/src/components/chrome/Wordmark.tsx
- apps/web/test/brand-tokens-parity.test.ts
- apps/apex/src/index.test.ts
- apps/apex/src/components/home.tsx
- apps/apex/src/legal.ts
- apps/apex/src/components/about.tsx
- apps/web/src/components/ui/Button.tsx
- apps/apex/src/index.ts
- apps/apex/src/components/chrome.tsx
- apps/apex/src/routes.ts
…prop; pricing fallback Address CodeRabbit review on #454: - deploy-pr-preview.mjs: the apex prerender build ran with only BILLING_ENABLED, so AGENT_PASTE_ENV was unset and copy.ts baked PRODUCTION cross-app URLs into every per-PR preview's HTML. Pass AGENT_PASTE_ENV=preview (the standing-preview deploy.mjs path already did this; the PR-preview path was missed). [Major] - Button + ButtonAnchor: drop forwardRef for React 19's ref-as-prop. These are new components and the repo bans unnecessary legacy patterns; no call site passed a ref, so this is API-compatible. [Nitpick, per coding guidelines] - PricingPage: the Pro price fell back to "" (rendering a bare "/ mo") while Free fell back to "$0"; use "—" for both missing-price fallbacks. Real prices are unaffected. [Minor] Issue: AP-276 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
agent-paste PR preview is ready. API: https://agent-paste-api-pr-454.isaac-a46.workers.dev |
|
agent-paste PR preview resources were cleaned up. The shared Preview GitHub Environment is retained for future preview deploys. |
Summary
Make the marketing site (apps/apex,
agent-paste.sh) and the dashboard (apps/web,app.agent-paste.sh) render one shared design system so a look change is a one-file edit and the two surfaces cannot drift. This is a large branch (5 feature commits, ~173 files, +4666/-5665) that ends a long-standing split where apex was hand-written semantic CSS and web was Tailwind with its own copies of the primitives.Changes
@agent-paste/uishared package + apex rebuild — new package of shared React primitives + a singleglobals.cssgenerated from@agent-paste/brand. apex rebuilt from hono/jsx string-rendering into a Vite + React static SSG: zero client React, one vanilla enhancement script, static CSP with a build-time pre-paint theme-init. Deleted the brand-tokens parity test (parity is now structural).Button,Card,Badge,Table,cnmoved fromapps/web/srcintopackages/ui/src; ~38 web import sites repointed; emptied originals deleted. One copy, both apps.base/sections/home/home-foot.cssdeleted. Net -1063 lines.@theme; ~520 arbitrary brackets converted to named utilities (710 → 189, rest are logged structural literals); all spacing snapped to the integer scale. Fixed the dropped shared-component utilities ("missing padding") bug in both apps (each must@source packages/ui/src). Cross-surface theme sync via a cookie on.agent-paste.sh. Env-correct preview links (apex bakes app/api/mcp URLs fromAGENT_PASTE_ENV). apex CSP theme-init hash derived on the fly (node:crypto in Workers).whitespace-nowrap) and the dashboard section-label/rule overlap (SectionLabelactionslot).Plus
chore(lint): biome now ignores nested.wrangler/.turbo(a build artifact was tripping the format gate).Risk: MEDIUM
packages/ui,packages/brand,apps/apex,apps/web(styling/components only); apex build pipeline + CSP; deploy.mjs apex env passthrough; biome ignore config.Test plan
pnpm verify(lint, typecheck, test, openapi:check, db:check, knip, dupes, format) greenpnpm test:coveragegreen (lines 91.46%, above the 88/82/88/88 floors)Issue: AP-276
Summary by CodeRabbit