Closes#113.
Picker chrome could become unclickable inside Radix Dialog portals, and
clicking it dismissed the host dialog. Three orthogonal issues surfaced
during manual verification:
1. Modal-aware chrome
- Add `defangOutsideHandlers` and apply it to bar, picker, params
panel, annotation overlay, global bar, and design panel host.
- Sets `pointer-events: auto !important` on interactive chrome so
Radix's `body { pointer-events: none }` modal scroll-lock can't
silence our UI.
- Stops `pointerdown` / `mousedown` / `focusin` propagation at the
chrome boundary so DismissableLayer / FocusScope outside-handlers
never fire for clicks that land on us.
2. detectPageTheme: misread transparent body as black
- `getComputedStyle(body).backgroundColor` returns `rgba(0,0,0,0)`
when no bg is set; the prior regex captured (0,0,0) and ignored
alpha, calling every default-bg page "dark."
- Honor alpha, walk body → html, fall back to
`prefers-color-scheme` only when both are transparent.
3. Exit X invisible on host pages with `button { padding: ... }`
- Every other chrome button sets padding inline; exitBtn didn't.
Host resets like `button { padding: 0.5rem 1rem }` (in the new
fixture, common in the wild) inflated the 24x24 button into 56x40
and pushed the SVG into a non-rendering region — DevTools showed
the right styles, the X just didn't paint.
- Pin `padding: 0` + `box-sizing: border-box`, match the toggle
icon spec (14 / stroke 1.5 / textDim → text on hover).
4. Toast no longer obscures the global bar
- Position the toast above globalBarEl's actual rect instead of a
fixed bottom: 16px that overlapped the bar's bottom: 14px.
Test coverage: new `vite8-react-radix-dialog` fixture exercises the
full pick → Go → cycle → Accept loop with `@radix-ui/react-dialog`
+ `Portal` + `Overlay` + `Content`. Without the fix, clicking Go
dismisses the dialog and unmounts the picked element. All 20 live
e2e fixtures pass; all 180 unit tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Marketplace source moved from "./" to "./plugin", a thin generated
subtree containing only the plugin manifest and the impeccable skill.
Per-version plugin cache shrinks ~378× (~770 KB instead of ~291 MB),
and the lockfile is no longer included in the source path so the
cache extraction never runs bun install. (#107)
- skills field in plugin.json now ends with a trailing slash to match
the documented schema (code.claude.com/docs/en/plugins-reference,
every directory example uses ./path/). Three reporters converged on
this fix because Claude Code's plugin loader skips command
registration on some setups when the slash is missing. (#86)
- Anti-patterns maintenance agent moved out of .claude/agents/ into
CLAUDE.md / AGENTS.md as concise inline guidance, since it is
repo-internal dev workflow, not user-facing. The plugin was also
the only place this agent was exposed to install users.
- Skills version bumped to 3.0.2 so existing users pick up the new
install path on next /plugin update.
- Top-level harness directories (.claude/skills/, .cursor/skills/, ...)
intentionally stay where they are; npx skills add reads them
directly from the GitHub repo and that path is unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>