Skip to content

fix(runner): resolve every @source path and stop scanning test files - #8472

Merged
os-justin merged 1 commit into
mainfrom
claude/issue-8454-runner-css-source
Sep 8, 2026
Merged

fix(runner): resolve every @source path and stop scanning test files#8472
os-justin merged 1 commit into
mainfrom
claude/issue-8454-runner-css-source

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #8454

packages/runner/src/index.css is a published input: this package is private: false with files: ["dist"]. The card reported two defects in it. Both are real, but the first one is not what the card says it is, and the second is five times larger than reported. Everything below was measured from packages/runner/, which is where pnpm build runs.

What the measurement found

Tailwind resolves a relative @source against the directory of the entry CSS — packages/runner/src/ — and @tailwindcss/postcss compiles with base = dirname(path.resolve(opts.from)). Under that arithmetic all five @source lines named a directory that does not exist, not just line 10:

declared resolved to on disk
./src/**/*.{ts,tsx} packages/runner/src/src missing
../../packages/components/src/** packages/packages/components/src missing
../../packages/react/src/** packages/packages/react/src missing
../../packages/plugin-kanban/src/** packages/packages/plugin-kanban/src missing
../../packages/plugin-charts/src/** packages/packages/plugin-charts/src missing

A glob whose base directory is missing scans nothing and raises no error. Decisive reading: deleting all five lines and rebuilding produced a byte-identical artifact — same content hash index-BgwNVuMG.css, same 20 969 bytes, same 219 rules.

So the sheet's only real input was Tailwind's automatic source detection, whose base defaults to the process CWD (base?: string"The base directory to scan for class candidates. Defaults to the current working directory", @tailwindcss/postcss's own type declaration). That root is packages/runner, which covers this package's own tree and nothing else.

The card's defect 1 is falsified as stated. components' test-sourced classes were never reaching this sheet through the ../../packages/components/src/** line, because that line was dead. What was leaking is this package's own tests, via the CWD root.

The two deltas, separately

Readings are unique compiled selectors from packages/runner/dist/assets/index-*.css, produced by pnpm build in packages/runner/, from a clean dist each time. On-disk file set: the committed tree at a407bd654 plus, for each row, only the stated edit to src/index.css.

Delta 1 — repairing the paths ADDS. 20 969 B / 219 rules / 228 selectors136 310 B / 1553 rules / 1456 selectors. +1228 selectors, −0. bg-popover, bg-accent, bg-destructive, animate-out, aspect-square and 1223 more had no source anywhere in the world: the published runner app was shipping without the utilities every one of its dependencies needs.

Delta 2 — the exclusions REMOVE. 136 310 B / 1553 rules / 1456 selectors135 842 B / 1545 rules / 1447 selectors. −9, +0: flex-grow, flex-nowrap, h-[125px], h-[400px], invert, paused, slide-in-from-bottom, text-green-500, w-[250px]. Several are ordinary English words lifted out of prose comments — paused comes from "while its trap listeners stay active and paused is still false".

Applied to today's shipping bytes instead (broken paths kept, exclusions added), the removal is −1: .block, whose only source is the word "block" in the sentence "the built-in 404 block instead of the ComponentRegistry" in src/App.navigation.test.tsx. The shipped md:block is a different candidate and survives.

⚠️ Why the repo-root reading would have inverted the sign

The card warns that a repo-root reading under-reports. Here it does worse. Same two trees, built from the repo root (pnpm exec vite build packages/runner):

reading before after delta
package dir (authoritative — where pnpm build runs) 228 selectors 1447 +1228 / −9
repo root 3315 selectors 3299 +0 / −16

From the repo root the automatic root has already scanned the whole monorepo, so the path repair adds nothing there and the change reads as a pure removal. A reviewer measuring from the repo root would never see that this PR restores 1228 missing utilities.

Which sibling spelling applies, and why both lines

plugin-kanban's two-line form, not fields' one-line form — anchored one level up (../../, base packages/) because this entry scans four sibling packages rather than only its own tree. Negations do reach files the automatic root found; that was measured, not assumed (adding only @source not './**/...' to the unrepaired tree removed .block, which the CWD root had supplied).

The card asked which line is load-bearing here rather than assuming. Measured both ways:

  • The file line accounts for all nine removals. With only that line, the artifact is byte-identical to having both (index-CLMWcOzp.css, 135 842 B) — so today the directory line removes nothing extra.
  • The directory line is nonetheless the only cover for packages/components/src/__tests__/test-utils.tsx and page-header-action-ids.dist.spec.tsx — non-*.test.* sources that the repaired ../../components/src/** line reaches. Ablated: a marker class injected into test-utils.tsx compiles into the sheet with the file line alone (.z-\[8454\] present, lit control .flex{ present) and is absent with both lines (marker 0, lit control still 1). Both files restored by state afterwards.

That is the condition the card named, so both lines stay.

The guard test

packages/runner/src/__tests__/published-stylesheet-sources.test.ts compiles the real entry through the real @tailwindcss/postcss, with base pinned to the package root so the reading does not depend on where vitest started. It does not read dist/ — CI runs the suite on an unbuilt worktree, where that would pass vacuously.

A sheet compiled from nothing satisfies "no test-sourced rules" perfectly — which is exactly the state defect 2 had put this package in. So the negative assertion is paired:

  • positive: bg-popover is present. Ten shipped files under packages/components/src use it and nothing in this package does, so it can only arrive through the sibling @source line. Lit control: flex-col, from this package's own source.
  • negative: taken as a difference against a second compile with the @source not lines stripped, so an exclusion that silently stopped matching fails here instead of passing quietly.
  • paths: every @source glob base must exist, with a non-vacuity floor of five positive directives and a control asserting the two historical spellings really do resolve to nothing.

Ablations, from the committed implementation, each restored by state (git diff HEAD empty and hash equal to git rev-parse HEAD:PATH):

mutation on-disk hash red
paths re-broken to ../../packages/... 6b7ec85c vs HEAD dd5f1a18 resolves every @source path… + compiles utilities that only a dependency can supply (2 failed, 2 passed)
both @source not lines deleted e272958d vs HEAD dd5f1a18 keeps test-sourced classes out…expected [ '@container', …(1387) ] to not include 'paused' (1 failed, 3 passed)

The new test file lives inside the scanned tree and is itself excluded: adding it left the artifact byte-identical (index-CLMWcOzp.css), despite carrying six class-shaped literals.

Changeset

node scripts/check-changeset-presence.mjs before: "❌ 1 source file(s) of 1 released package(s) changed, and this change adds no changeset". After: "✅ 1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)". check-changeset-no-major ✅, check-changeset-fixed ✅, check-changeset-overwrite ✅.

patch, argued from the diff: this package exposes no importable surface at all — no main, module, types, exports, sideEffects or peerDependencies; it publishes a built application under dist. Nothing a consumer imports changes shape, and the nine removed classes are unreachable from the app's own markup by construction (that is precisely why the scan had no shipped source for them). major is forbidden repo-wide; minor would claim a surface change this package does not have.

Verification

  • pnpm --workspace-concurrency=2 --filter '@object-ui/runner^...' build — exit 0 (closure built before type-check).
  • pnpm --filter @object-ui/runner run type-check — exit 0. --listFiles confirms the new test is in the program (1 hit; lit control App.navigation.test.tsx 1 hit; 1420 files), so this is a measurement and not an exclusion.
  • pnpm exec vitest run packages/runner/ from the repo root — 5 files, 21 tests passed.
  • pnpm --filter @object-ui/runner run lint — exit 0; 17 warnings, all pre-existing in files this PR does not touch.
  • turbo ls --affected against the merge base: @object-ui/runner, one package.
  • Gate families: check:control-bytes ✅ · type-check:coverage ✅ · check:unreferenced-sources ✅ · check:phantom-deps ✅ · check:unused-deps ✅ · check:published-tsconfig-exclude ✅ · check:published-dist --all ✅ (+ the four changeset gates above). The repo-wide pnpm lint / full pnpm test are left to CI.

Out of scope — reported, not swept in

Per the fence, packages/runner only. A repo-wide @source resolution sweep (run after this fix) says every @source path in the repo now resolves — packages/runner was the sole offender. Two refinements for objectui#8455, whose census column is only "test exclusion":

  1. Its table records packages/fields/src/index.css as "✅ one line". That package has src/__tests__/numberInputBrowserReadings.ts — a non-*.test.* source inside its own scanned tree — so the missing directory line is actually leaking there, not merely stylistically absent. @object-ui/fields publishes a stylesheet consumers import.
  2. A gate that only looks for @source not lines would have passed packages/runner while all five of its positive @source lines were dead. Whatever objectui#8455 builds needs a second assertion — every @source base resolves — and that half has zero current backlog, so it is cheap to add now.

source(none) for this entry is objectui#8455's option A and is deliberately not in this PR: the automatic root stays on, which is why the first @source line is a no-op today and still belongs there.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S


Generated by Claude Code

`packages/runner/src/index.css` compiles into a published artifact
(`private: false`, `files: ["dist"]`). All five of its `@source` lines were
wrong by one path segment: Tailwind resolves a relative `@source` against
`dirname(<entry css>)`, i.e. `packages/runner/src/`, so `./src/**` meant
`packages/runner/src/src` and `../../packages/<pkg>/src` meant
`packages/packages/<pkg>/src`. A glob whose base does not exist scans nothing
and raises no error — deleting all five lines was measured byte-identical.

The sheet stayed non-empty only through Tailwind's automatic source detection,
whose base defaults to the process CWD (`packages/runner`, where `pnpm build`
runs). Two consequences, in opposite directions, measured from the package dir:

  - the four sibling trees were never scanned. Repairing them takes the
    compiled sheet from 228 to 1456 selectors (21 kB -> 136 kB): `bg-popover`,
    `bg-accent`, `bg-destructive` and 1225 more had no source anywhere.
  - the CWD root swept this package's own tests into the published bytes. Two
    `@source not` lines (plugin-kanban's spelling, anchored one level up
    because this entry scans four sibling packages) remove nine test-sourced
    classes, several of them English words lifted from prose comments.

`src/__tests__/published-stylesheet-sources.test.ts` pins both halves: a
positive assertion that a utility only `@object-ui/components` can supply is
present (a sheet compiled from nothing fails it) and a negative one taken as a
difference against a second compile with the exclusions stripped, so an
exclusion that stopped matching fails rather than passing quietly. It pins
`base` to the package root so the reading does not depend on where vitest ran.

`tsconfig.test.json` gains `node` in `types` for that test's `node:fs` imports,
the way `packages/components/tsconfig.test.json` already does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YBWFb5YgMU5dw8p2VKj16S
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3473.5 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-CjjYG-tk.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.87KB 114.10KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 191.36KB 53.16KB
fields (index.js) 243.15KB 61.40KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.52KB 46.34KB
plugin-dashboard (index.js) 131.48KB 34.45KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.78KB 63.98KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 55.40KB 15.71KB
plugin-list (index.js) 112.74KB 27.70KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.54KB 20.84KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-justin
os-justin marked this pull request as ready for review September 8, 2026 01:25

Copy link
Copy Markdown
Collaborator Author

PM contract review — accepted, flipped to ready, auto-merge armed. This falsifies the card I wrote, and the correction is the most valuable thing in the report.

My card's defect 1 is wrong, and the real defect points the other way

I wrote that runner's sheet "still compiles the same eight test-sourced classes" from components. Measured false. Tailwind resolves a relative @source against dirname(entry css) = packages/runner/src/, so:

'./src/**'                    → packages/runner/src/src        (missing)
'../../packages/PKG/src/**'   → packages/packages/PKG/src      (missing)

all five @source lines named a missing directory, not just line 10 — and the decisive reading is unanswerable: deleting all five and rebuilding gives a byte-identical artifact (index-BgwNVuMG.css, 20969 B, 219 rules). Those lines were dead. components' test classes were never arriving.

The sheet's only real input was automatic source detection, whose base defaults to process.cwd() = packages/runner — this package's own tree and nothing else. So what leaked was runner's own tests, and what was missing was every utility belonging to components / react / plugin-kanban / plugin-charts.

⇒ a published package was shipping a stylesheet 1228 rules short of what its own components need. That is a much bigger defect than the one I filed, and it was invisible from the direction my card was looking.

The sign inversion, which is sharper than my warning

I told you a repo-root reading "under-reports". Measured:

package dir   +1228 / −9
repo root     +0    / −16     ← the sign INVERTS

A repo-root reviewer would classify this PR as a pure removal. I am carrying that correction forward in place of the weaker one.

Related: my brief and the card both predicted "fixing the broken @source adds rules (runner's own source finally gets scanned)". False for that line — fixing only line 10 is byte-identical, because the CWD-rooted automatic root already covers packages/runner/**. The entire +1228 comes from the four sibling lines my card did not flag as broken at all.

The two-line choice, ablated rather than assumed

The file line alone accounts for all nine removals — the artifact is byte-identical with or without the directory line today. But you kept the directory line and proved why with a marker class: it is the only cover for components/src/__tests__/test-utils.tsx and page-header-action-ids.dist.spec.tsx, non-*.test.* sources that the repaired components @source now reaches. Injected .z-[8454], file-line-only build ships it, both-lines build does not, lit control firing in both. That is the right way to choose between two spellings that look equivalent on today's tree.

Two corrections to my rules, both accepted

① The pnpm --filter PKG run test ban. You are right that the two documents disagree: AGENTS.md records objectui#3240 rewriting every package test script to vitest run --root ../.. packages/PKG/, and scripts/vitest-invocation-guard.mjs mechanically refuses a non-repo-root root. But objectui#8394 measured a real 93-test false red from pnpm --filter @object-ui/example-schema-catalog run test. The reconciliation is almost certainly that examples/* is not packages/* and was never rewritten by objectui#3240 — so the guard covers packages and the hazard survives in examples. I am narrowing the rule to that rather than dropping it, and I will say which it is instead of stating it flatly.

scripts/pm/os-verify-lock.sh does not exist in objectui — it is an objectstack path that my generic dispatch preamble still carries. Removing it; keeping heavy work serial by hand is the correct substitute here.

Your two refinements go to objectui#8455, not here

Both are right and both are corrections to a card I wrote:

  • fields/src/index.css is recorded in that census as "one line" as if adequate; it has src/__tests__/numberInputBrowserReadings.ts, a non-*.test.* source inside its own scanned tree, so its missing directory line is actually leaking — and @object-ui/fields publishes a stylesheet consumers import.
  • ⭐ objectui#8455's census column is only "test exclusion", so a gate built to that shape would have passed packages/runner while all five of its @source lines were dead. The gate needs a second assertion — every @source base resolves — and your post-fix sweep says that half has zero backlog, so it is cheap to add.

Adding both to objectui#8455 now.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(runner): a PUBLISHED package's stylesheet scans components' test files, and its own @source points at a directory that does not exist

2 participants