{"owner":"aidenybai","repo":"react-scan","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"files":{"AGENTS.md":"## General Rules\n\n- MUST: Use TypeScript interfaces over types.\n- MUST: Keep all types in the global scope.\n- MUST: Use arrow functions over function declarations.\n- MUST: Default to NO comments. Only add a comment when the user explicitly asks, or when the \"why\" is truly non-obvious - browser quirks, platform bugs, performance tradeoffs, fragile internal patching, or counter-intuitive design decisions. Never add comments that restate what the code does or what a well-named function/variable already conveys. When in doubt, leave the comment out.\n  - If a hack is required (like a `setTimeout` that hides a race), prefix with `// HACK: reason for hack`.\n  - Do not delete descriptive comments >3 lines without confirming with the user.\n- MUST: Use kebab-case for files.\n- MUST: Use descriptive names for variables (avoid shorthands, or 1-2 character names).\n  - Example: for `.map()`, use `innerNode` instead of `n`.\n  - Example: instead of `moved` use `didPositionChange`.\n- MUST: Frequently re-evaluate and refactor variable names to be more accurate and descriptive.\n- MUST: Do not type cast (`as`) unless absolutely necessary.\n- MUST: Remove unused code and don't repeat yourself.\n- MUST: Always search the codebase, think of many solutions, then implement the most _elegant_ solution.\n- MUST: Put all magic numbers in `constants.ts` using `SCREAMING_SNAKE_CASE` with unit suffixes (`_MS`, `_PX`).\n- MUST: Put small, focused utility functions in `utils/` with one utility per file.\n- MUST: Use `Boolean(x)` over `!!x`.\n\n## Preact + @preact/signals Rules\n\nReact Scan's overlay UI runs as a Preact app mounted inside a Shadow DOM (see [`packages/scan/src/core/index.ts`](packages/scan/src/core/index.ts)). Reactivity is driven by `@preact/signals`, not React state.\n\n### Signals\n\n- MUST: Read signals via `.value` inside JSX/effects: `signalWidget.value` not `signalWidget()`.\n- MUST: Write signals atomically: `signalWidget.value = { ...signalWidget.value, dimensions: ... }`. One signal per logical slice.\n- MUST: Use `useSignal(initial)` for component-local reactive state, `useComputed(() => ...)` for derived values, `useSignalEffect(() => ...)` for subscriptions/DOM imperative work.\n- MUST: Wrap module-level signals exported from a tree-shaken bundle with `/* @__PURE__ */ signal(...)` so production builds can drop unused state.\n- SHOULD: Persist user-facing state via `readLocalStorage`/`saveLocalStorage` from [`~web/utils/helpers`](packages/scan/src/web/utils/helpers.ts) and seed the signal with the persisted value.\n- NEVER: Mirror one signal into another inside `useSignalEffect` - find the single source of truth (compute on read).\n\n### Effects\n\nBefore reaching for `useEffect`/`useSignalEffect`, classify the work:\n\n- MUST: Use `useComputed` when the result is pure derived state from other signals. If no external system is touched, it is not an effect.\n- MUST: Use event handlers and direct action calls when work happens because the user clicked, dragged, or navigated. Do not watch a flag in an effect to trigger imperative logic.\n- MUST: Use `useEffect(..., [])` (or `useSignalEffect` with no deps) for one-time mount/cleanup of subscriptions, timers, listeners, and `MutationObserver`s. Always return the cleanup.\n- MUST: Keep each effect single-purpose - one effect, one external bridge. Split mixed-responsibility effects.\n- NEVER: Use an effect just to copy one signal into another.\n- NEVER: Use an effect as an event bus (watching a trigger signal to run a command). Call the action directly from the event source.\n\n### Props\n\n- MUST: Access props via `props.title`, not destructuring, when the prop is read inside an event handler that fires later or inside an effect.\n- SHOULD: Destructure props at the top of the body for purely-rendered values (read once during render).\n- NEVER: Destructure a prop that is itself a signal-driven slice if you intend to re-read it after async work.\n\n### JSX & DOM\n\n- MUST: Use `className` (we render via Preact's React-compat JSX in [`tsconfig.json`](tsconfig.json) `jsxImportSource: preact`).\n- MUST: Combine static `className=\"btn\"` with reactive `className={cn(\"btn\", isActive.value && \"active\")}` via [`cn`](packages/scan/src/web/utils/helpers.ts).\n- MUST: Read refs in `useEffect` or via the callback ref pattern - DOM refs are populated after render.\n- MUST: Mount overlay UI under the existing shadow root from `initRootContainer()` in [`core/index.ts`](packages/scan/src/core/index.ts). Do not append directly to `document.body`.\n- SHOULD: Use `style={{ \"--css-var\": value }}` for dynamic CSS variables; class toggles for boolean states.\n- SHOULD: Type refs as `let element: HTMLElement | null = null` with a guard.\n\n## Build & Toolchain\n\nThis is a pnpm 10 monorepo with `packages/*` (libraries, extension, website) and a top-level `kitchen-sink/` (Playwright target). The toolchain is [Vite+](https://viteplus.dev) (`vp lint`, `vp fmt`, `vp check`) and `turbo` for pipeline orchestration.\n\n### Approved built dependencies\n\nThe root [`package.json`](package.json) declares `pnpm.onlyBuiltDependencies` for `@parcel/watcher`, `esbuild`, `sharp`, `spawn-sync`, `unrs-resolver`. Without this list, `pnpm install` skips their native build steps and downstream packages fail.\n\n### Build before test\n\n`pnpm build` must complete before `pnpm test`, `pnpm test:e2e`, or `pnpm lint`. After modifying source files, always rebuild before running tests. Turbo enforces this via `dependsOn: [\"^build\"]` in [`turbo.json`](turbo.json).\n\n### Playwright\n\n`pnpm test:e2e` runs Playwright against the `kitchen-sink` Vite dev server on port 5173 (auto-started by [`playwright.config.ts`](playwright.config.ts)). Chromium must be installed: `npx playwright install chromium --with-deps`.\n\n### Key commands\n\n| Task           | Command                                      |\n| -------------- | -------------------------------------------- |\n| Install        | `pnpm install`                               |\n| Build          | `pnpm build`                                 |\n| Dev watch      | `pnpm dev` (watches `react-scan` + kitchen-sink) |\n| Unit tests     | `pnpm test`                                  |\n| E2E tests      | `pnpm test:e2e`                              |\n| Lint           | `pnpm lint` (oxlint via vite-plus)           |\n| Lint + fix     | `pnpm lint:fix`                              |\n| Format         | `pnpm format` (oxfmt via vite-plus)          |\n| Format check   | `pnpm format:check`                          |\n| Typecheck      | `pnpm typecheck`                             |\n| Combined       | `pnpm check` (lint + fmt check + typecheck)  |\n\n## Testing\n\nRun checks always before committing with:\n\n```bash\npnpm build\npnpm lint\npnpm format\npnpm typecheck\npnpm test:e2e\n```\n"}}