* fix(ci): harden workflows against cache poisoning and document unsigned tags
- Restrict TURBO_TOKEN/TURBO_TEAM to main-branch pushes only across
ci.yml, code-quality.yml, and react-doctor.yml. First-party PR branches
no longer have cache write access (preventing cache poisoning attacks).
PRs run with a cold cache.
- Add SECURITY comments in action-version-bump.yml explaining that tags
are unsigned and recommending SHA pinning for hardened CI.
- Update install-github-workflow.ts template to include security note
about @v2 floating major tag and SHA pinning recommendation.
Closes#1685
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(ci): make pull request cache read-only
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix(supply-chain): remove oxlint/oxc from minimumReleaseAge exemption
Remove oxlint/oxc packages from minimumReleaseAgeExclude to restore
the 2-hour release quarantine for these third-party dependencies.
Oxlint/oxc is the core analysis engine of react-doctor - the exact
dependency where a compromised or bad release has maximal impact.
The exclusion was removing the one guard that protects that path.
Keep only agent-install in the exclusion list, as it's documented
as a first-party package.
Closes#1680
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for oxlint release age fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore(deps): keep release-age policy internal
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* test: add comprehensive tests for barrel file directory imports
- Add tests for tsconfig path alias resolution to index.ts
- Add tests for baseUrl resolution to index.ts
- Add tests for relative directory imports to index.ts
- Add Next.js-specific test with auto-detected entries
- Add direct resolver tests to verify directory resolution
Tests confirm that barrel files imported via directory paths (e.g., @/features/foo -> foo/index.ts) are correctly resolved and not flagged as unused.
Related to issue #1699
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: add moduleResolution bundler test for directory imports
Test confirms that directory imports work correctly with moduleResolution: bundler setting (used by Next.js).
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test(core): cover directory barrel reachability
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix: check root directory for CI config instead of project count
Multi-project scans were unconditionally recommending GitHub Actions
even when already existed at the
repository root. The logic checked individual project directories for
the workflow, which would fail in monorepos where the workflow lives
at the root.
Fixed by checking whether CI is configured at the root directory
(where the scan is running) instead of:
1. Unconditionally for multi-project scans (projectScans.length > 1)
2. Per-project directory checks that miss root-level workflows
Closes#1696
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for CI recommendation fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: format code
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(cli): measure CI recommendations
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix(rerender-state-only-in-handlers): recognize state consumed via member expression hook calls
State consumed by hook calls through member expressions (e.g. styles.useVariants({ state }))
was incorrectly flagged as unused. This commonly occurs with react-native-unistyles,
where state selects style variants via StyleSheet.useVariants().
The rule now checks both direct identifier calls (useX) and member expression calls
(obj.useX) when collecting custom hook arguments, following the existing pattern used
throughout the codebase.
Fixes#1716
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for member expression hook fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: add edge case for non-hook member expressions
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(rules): preserve state setter bindings
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
* fix: ignore TypeScript type-only positions in no-unguarded-browser-global-at-module-scope
The rule was incorrectly flagging browser-global names (window, navigator, etc.) when they appeared as property keys in TypeScript interfaces and type aliases. These are type-only positions that TypeScript erases during compilation, so no runtime reference error occurs.
Add isTypeScriptTypePosition check to skip identifiers in TS type contexts before reporting. Add regression tests covering interface properties, type alias properties, and the preserved behavior for actual runtime references.
Fixes#1667
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for #1667 fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: add edge case tests for TypeScript type positions
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: preserve type-only browser global regression
* docs(changeset): clarify type-only global fix
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
* fix: extract entry points from implicit sub-projects outside workspace patterns
When the root package.json declares workspaces, sub-projects outside the
declared workspace globs were discovered but their entry points (main, bin,
exports) were skipped. This caused false positives in unused-file detection.
The fix removes the isDeclaredWorkspace predicate from entry extraction -
any package with a valid package.json should have its entry points extracted
regardless of workspace pattern matching.
Fixes#1665
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for issue #1665 fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: consolidate implicit workspace entry regression
* docs(changeset): clarify implicit entry fix
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
* fix: prevent stack overflow in function resolution with depth limiting
Add depth limiting to resolveExactLocalFunction to prevent infinite
recursion when resolving function references through deeply nested
expressions, TypeScript path aliases, or complex import chains.
The function now enforces a configurable depth limit
(FUNCTION_RESOLUTION_MAX_DEPTH = 15) and returns null when exhausted
rather than continuing to recurse.
- Add FUNCTION_RESOLUTION_MAX_DEPTH constant (15 levels)
- Thread remainingDepth parameter through all resolution helpers
- Add unit tests for depth limiting
- Add regression test for zustand + Next.js + path aliases case
Closes#1657
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* test: exercise function resolution stack guard
* refactor: share function chain fixture builder
* test: tighten function resolution regressions
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
* feat(cli): record React-aware browser traces
Add an interactive Playwright scanner that streams DevTools traces to disk and reports React rendering hotspots for humans and agents.
* fix(cli): use shared telemetry anonymizer
Keep runtime URL redaction on the canonical core utility after the telemetry helper consolidation.
* feat(cli): visualize component renders during traces
Flash labeled component outlines during runtime scans so users can connect slow interactions to the React work they trigger.
* feat(skill): add runtime performance workflow
Guide agents through repeatable React traces so performance findings stay tied to measured interactions.
* docs(cli): guide runtime scan setup
Explain the recording flow, browser isolation, authenticated sessions, output formats, and trace privacy directly in command help.
* fix(cli): harden runtime trace capture
Preserve evidence across navigations while keeping structured output, telemetry, trace files, and attached-browser cleanup safe under failures and cancellation.
* fix(cli): preserve latest navigation evidence
Keep cross-document layout shifts comparable and retain the most recent bounded performance entries so the recorded interaction remains represented.
* fix(cli): bound runtime scan browser resources
Prevent trace deadlocks, cross-tab capture, and unbounded browser evidence while preserving navigation data through an isolated validated relay.
* fix(cli): preserve busy-page runtime snapshots
Stop tracing concurrently with final probe collection and allow busy pages enough time to flush their bounded performance evidence.
* feat(cli): prompt for runtime scan URL
Let people start an interactive runtime scan without remembering the URL argument while keeping agents and CI deterministic.
* feat(cli): suggest local apps for runtime scans
Replace the bare URL field with a polished chooser that discovers common localhost development servers while preserving custom URL entry.
* fix(cli): use scan terminology in runtime flow
Keep the interactive copy aligned with the command users invoked instead of switching between recording and profiling language.
* fix(cli): center runtime chooser in full terminal
Render the interactive URL chooser as a terminal-sized view so it no longer appears anchored to the previous cursor position.
* fix(cli): harden runtime scan edge cases
Capture popup evidence without leaking browser pages, support redirected interactive output and IPv6 localhost apps, and keep bounded reports honest.