* 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>
* feat(core): add Axiom OTLP transport and an anonymizing tracer
Adds the export path for shipping traces and metrics to Axiom, plus the
anonymization guarantee that has to come with it. Nothing emits yet — the CLI
still routes telemetry to Sentry; this is the engine-side groundwork.
`layerAxiomTraces` and `layerAxiomMetrics` are composed by hand rather than
through `Otlp.layer`, because Axiom routes each signal to a different dataset
via a different header and `Otlp.layer` passes one `headers` object to every
signal. Serialization is protobuf, not JSON: Axiom's `/v1/metrics` accepts
`application/x-protobuf` only. `OtlpSerialization.layerProtobuf` ships with
Effect, so this adds no dependency.
They are separate layers on purpose. Effect tracks delta-temporality state on
the metrics exporter instance, so a second exporter in one process starts with
no previous snapshot and re-reports every counter's full value — doubling every
metric. `telemetry-payload.test.ts` pins that behavior so a future refactor that
merges them fails loudly instead of silently doubling data.
OTLP has no `beforeSend` hook, so Sentry's central scrubber has no equivalent.
`makeScrubbingTracer` wraps the tracer and runs every span name, attribute, and
event payload through `anonymizeText` on the way to the exporter, and is applied
inside `layerAxiomTraces` so an attribute added later cannot bypass it.
`anonymize-text.ts` moves to core (both its scrubbers already lived there) and
`run-inspect.ts` now scrubs `inspect.directory` at the source rather than relying
on the backstop.
`TELEMETRY_SHUTDOWN_TIMEOUT_MS` is 1s, tighter than Sentry's 2s error flush: the
metrics exporter passes `maxBatchSize: "disabled"` internally, which skips
Effect's empty-buffer short-circuit, so it POSTs on every scope close whether or
not anything was recorded. On a firewalled machine that request cannot fail fast,
and unlike the Sentry flush it would run on every scan rather than only on crashes.
Verified against a local collector: correct per-signal datasets and protobuf
content type, and no home directory, username, or secret reaches the wire.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(core): close three review findings in the Axiom transport
Scrub the failure a span ended with. The OTLP tracer runs `Cause.prettyErrors`
over the exit and exports each result as `exception.type` / `exception.message` /
`exception.stacktrace`. None of those go through `span.attribute`, so they
bypassed the scrubbing tracer entirely — and stack traces are full of absolute
paths, meaning any failing scan shipped the user's home directory. This was the
one route into the payload the backstop didn't cover. Interrupt-only causes are
left alone; the exporter emits a fixed label for them and never touches the
error text.
Honor `exportIntervalMs` for traces. It was threaded through to the metrics
exporter but not the tracer, so a long-lived process — the language server —
would hold spans for the full ten-minute default no matter what interval it
asked for.
Trim trailing slashes without a regex. `/\/+$/` backtracks quadratically on a
domain made mostly of slashes, which CodeQL flags as a polynomial-regex denial
of service because the value comes from the caller.
Also corrects a doc comment that still described metrics as being built at exit,
which stopped being true when the CLI moved to a single shared scope.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(rules): correct form and fragment diagnostics
* fix(rules): handle fragment review edge cases
* fix: handle document-top fragment links
* fix(a11y): parse ids from html tags only
* fix(a11y): resolve static fragment aliases
* fix(a11y): retain known fragment targets
* fix(a11y): tokenize html id attributes
* fix: preserve known fragment IDs in mixed spreads
* fix: preserve known fragment ID defaults
* fix(core): handle invisible Unicode characters in disable comments (#1472)
When TERMINAL_EMULATOR=JetBrains-JediTerm is set (or similar IDE/terminal
configurations), invisible Unicode characters like zero-width spaces
(U+200B, U+200C, U+200D) and zero-width no-break spaces (U+FEFF/BOM) can
appear at the end of lines. These characters are not matched by JavaScript's
\s regex class, causing the $ anchor in react-doctor-disable patterns to
fail despite the characters being invisible in editors and terminal output.
This fix adds explicit matching for common invisible Unicode characters
before the $ anchor in both DISABLE_NEXT_LINE_PATTERN and DISABLE_LINE_PATTERN,
making them resilient to these characters while maintaining the $ precision
that near-miss detection relies on.
The foreign disable patterns (eslint-disable, oxlint-disable) never anchored
to $ and were unaffected, which is why oxlint-disable-next-line worked while
react-doctor-disable-next-line failed in the reproduction case.
Fixes#1472
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* chore: add changeset for invisible Unicode fix
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
* fix(core): resolve file URL diagnostic paths
---------
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>