svelte-vitals 0.47.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,10 +3,10 @@
3
3
  [![npm](https://img.shields.io/npm/v/svelte-vitals)](https://www.npmjs.com/package/svelte-vitals)
4
4
  [![MIT](https://img.shields.io/npm/l/svelte-vitals)](https://opensource.org/licenses/MIT)
5
5
 
6
- > **A static SvelteKit code-health scanner not a runtime Web Vitals reporter.**
7
- > Diagnose your project's SEO, Performance, Correctness, Security, Architecture, and Accessibility health by statically analyzing your source code, before it ships. No browser, no build server, no headless Chrome.
6
+ > **Your SvelteKit app's code health, checked before it ships. Statically, no browser.**
7
+ > Scores SEO, Performance, Correctness, Security, Architecture, and Accessibility by reading your source code.
8
8
  >
9
- > **ESM-only** (Node 22.13+). Ships ES modules only; `require()` is unsupported by design.
9
+ > **ESM-only** (Node 24.16+). Ships ES modules only; `require()` is unsupported by design.
10
10
 
11
11
  ```bash
12
12
  npx svelte-vitals@latest
@@ -71,7 +71,7 @@ Useful as a CI gate.
71
71
 
72
72
  ### Ramping up on an existing project
73
73
 
74
- `--diff [ref]` / `--staged` scope findings to changed/staged files; `--baseline <ref>` scopes to findings that are genuinely new versus a ref; `--update-suppressions` records today's findings once so only newly-introduced issues gate the build afterward. `--rules`/`--ignore`/`--category` select which rules run, `--weights` reweights the combined Health score, and `--min-health`/`--score` gate or print just the number. A `svelte-vitals.config.{mjs,js,ts}` file (scaffolded via `svelte-vitals install --client config-file`) can set any of these once instead of repeating flags.
74
+ `--diff [ref]` / `--staged` scope findings to changed/staged files; `--baseline <ref>` scopes to findings that are genuinely new versus a ref; `--update-suppressions` records today's findings once so only newly-introduced issues gate the build afterward. `--rules`/`--ignore`/`--category` select which rules run, `--weights` reweights the combined Health score, and `--min-health`/`--score` gate or print just the number. A `svelte-vitals.config.{js,ts}` file (scaffolded via `svelte-vitals install --client config-file`) can set any of these once instead of repeating flags.
75
75
 
76
76
  ### `svelte-vitals install`
77
77
 
package/dist/bin.js CHANGED
@@ -1,43 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runAnalyzeCliGunshi
4
- } from "./chunk-MZO3HVTN.js";
5
- import "./chunk-5UQ6P2M2.js";
6
- import "./chunk-43FGGQQZ.js";
7
- import "./chunk-M5KM5SV7.js";
4
+ } from "./chunk-4LSRQXJ6.js";
5
+ import "./chunk-DZVXCUHG.js";
6
+ import {
7
+ realIO
8
+ } from "./chunk-RSSMIHIM.js";
9
+ import "./chunk-LJPABOWU.js";
10
+ import "./chunk-WGFXFKBB.js";
8
11
  import {
9
12
  consoleIO
10
13
  } from "./chunk-SLUMRYUD.js";
11
- import "./chunk-TFBLQUAC.js";
12
- import {
13
- realIO
14
- } from "./chunk-GE7TKVTX.js";
15
14
  import {
16
15
  resolveLocale
17
16
  } from "./chunk-NMVBVKLX.js";
17
+ import "./chunk-AI24FJ5Q.js";
18
18
 
19
19
  // src/cli.ts
20
20
  async function runCli(argv, io = consoleIO, env = process.env) {
21
21
  try {
22
22
  const locale = resolveLocale(env);
23
23
  if (argv[0] === "complete") {
24
- const { runCompleteCliGunshi } = await import("./complete-BDKGAUQX.js");
24
+ const { runCompleteCliGunshi } = await import("./complete-IOAMJRBY.js");
25
25
  return { code: await runCompleteCliGunshi(argv, io), exit: "natural" };
26
26
  }
27
27
  if (argv[0] === "docs") {
28
- const { runDocsCliGunshi } = await import("./docs-XNKZQBBZ.js");
28
+ const { runDocsCliGunshi } = await import("./docs-AGHALPIU.js");
29
29
  return { code: await runDocsCliGunshi(argv.slice(1), io, locale), exit: "natural" };
30
30
  }
31
31
  if (argv[0] === "explain") {
32
- const { runExplainCliGunshi } = await import("./explain-YPWGQE5N.js");
32
+ const { runExplainCliGunshi } = await import("./explain-WOKUZJVY.js");
33
33
  return { code: await runExplainCliGunshi(argv.slice(1), io, locale), exit: "natural" };
34
34
  }
35
35
  if (argv[0] === "install") {
36
- const { runInstallCliGunshi } = await import("./install-HE76S4ID.js");
36
+ const { runInstallCliGunshi } = await import("./install-EVGFAILR.js");
37
37
  return { code: await runInstallCliGunshi(argv.slice(1), io, locale), exit: "immediate" };
38
38
  }
39
39
  if (argv[0] === "ci") {
40
- const { runCiCliGunshi } = await import("./ci-J7PGFHK3.js");
40
+ const { runCiCliGunshi } = await import("./ci-PIAMUGAP.js");
41
41
  const code = await runCiCliGunshi(argv.slice(1), { ...realIO(), log: io.log, errorLog: io.errorLog }, locale);
42
42
  return { code, exit: "immediate" };
43
43
  }
@@ -1,21 +1,21 @@
1
- import {
2
- run
3
- } from "./chunk-5UQ6P2M2.js";
4
1
  import {
5
2
  VALUE_FLAGS,
6
3
  parseRunArgs,
7
4
  resolveArgs
8
- } from "./chunk-43FGGQQZ.js";
5
+ } from "./chunk-DZVXCUHG.js";
6
+ import {
7
+ selectAppPrompt
8
+ } from "./chunk-RSSMIHIM.js";
9
+ import {
10
+ run
11
+ } from "./chunk-LJPABOWU.js";
9
12
  import {
10
13
  readCoreVersion,
11
14
  readPackageVersion
12
- } from "./chunk-M5KM5SV7.js";
15
+ } from "./chunk-WGFXFKBB.js";
13
16
  import {
14
17
  consoleIO
15
18
  } from "./chunk-SLUMRYUD.js";
16
- import {
17
- selectAppPrompt
18
- } from "./chunk-GE7TKVTX.js";
19
19
  import {
20
20
  guardArgs,
21
21
  localizedOptionsSection,
@@ -127,7 +127,7 @@ function neutralizeBareDiffAndBaseline(argv) {
127
127
  }
128
128
  async function buildHelpText(rootCommand, locale) {
129
129
  if (locale === "ja") {
130
- const { JA_ARG_DESCRIPTIONS, rootHelpJa } = await import("./ja-GAQSBSXF.js");
130
+ const { JA_ARG_DESCRIPTIONS, rootHelpJa } = await import("./ja-YYZQ62AJ.js");
131
131
  const optionsSection2 = await localizedOptionsSection(
132
132
  rootCommand,
133
133
  "svelte-vitals",
@@ -143,7 +143,7 @@ Usage:
143
143
  svelte-vitals [path] [options]
144
144
  svelte-vitals docs list List the bundled guides (docs show <name> prints one)
145
145
  svelte-vitals explain --list List every rule (explain <rule-id> explains one)
146
- svelte-vitals install Set up the Vite integration, agent skills/rules, config file, or CI
146
+ svelte-vitals install Set up the Vite integration, Cursor rules, config file, or CI
147
147
  svelte-vitals ci install Add a GitHub Actions PR gate (annotations + summary comment)
148
148
  svelte-vitals ci upgrade Refresh the pinned @svelte-vitals/action in an existing workflow
149
149
  svelte-vitals complete <shell> Print a shell completion script (bash, zsh, fish, powershell)
@@ -151,7 +151,7 @@ Usage:
151
151
  ${optionsSection}
152
152
 
153
153
  Config file:
154
- svelte-vitals.config.{mjs,js,ts} in the analyzed directory; flags override it.
154
+ svelte-vitals.config.{js,ts} in the analyzed directory; flags override it.
155
155
 
156
156
  Exit codes:
157
157
  0 no failing findings
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  consoleIO
3
3
  } from "./chunk-SLUMRYUD.js";
4
- import {
5
- knownRuleIds
6
- } from "./chunk-TFBLQUAC.js";
7
4
  import {
8
5
  guardArgs,
9
6
  localizedOptionsSection,
@@ -12,12 +9,15 @@ import {
12
9
  stripUnknownFlags,
13
10
  suggestClosest
14
11
  } from "./chunk-NMVBVKLX.js";
12
+ import {
13
+ knownRuleIds
14
+ } from "./chunk-AI24FJ5Q.js";
15
15
 
16
16
  // src/gunshi/docs.ts
17
17
  import { cli } from "gunshi/bone";
18
18
  import { define } from "gunshi/definition";
19
19
  import "gunshi/generator";
20
- import { docsUrlFor } from "@svelte-vitals/core";
20
+ import { docsUrlFor } from "@svelte-vitals/core/internal";
21
21
 
22
22
  // src/docs/generated.ts
23
23
  var EMBEDDED_DOCS = [
@@ -25,19 +25,19 @@ var EMBEDDED_DOCS = [
25
25
  name: "ci",
26
26
  title: "Running in CI",
27
27
  description: "Scaffold a GitHub Actions PR gate with `ci install`, what the generated workflow does, and how to gate a pipeline without the Action.",
28
- body: "# Running in CI\n\n## Scaffold the GitHub Actions gate\n\n```bash\nnpx svelte-vitals@latest ci install # writes .github/workflows/svelte-vitals.yml\nnpx svelte-vitals@latest ci upgrade # bump only the pinned action ref in an existing file\n```\n\n`ci install` also exists as the `ci-workflow` target inside `svelte-vitals install`, so it can be\nset up in the same pass as everything else. Both support `--dry-run` and `--force`.\n\n## What the generated workflow does\n\nOn every `pull_request` it checks out with `fetch-depth: 0`, then calls `@svelte-vitals/action`,\nwhich runs the analysis **in-process** scoped to the PR (`diff`/`baseline` at `origin/<base>`).\nFrom that one analysis it produces:\n\n- inline annotations on the diff,\n- a job summary,\n- a sticky PR comment (a hidden `<!-- svelte-vitals-report -->` marker updates the same comment\n instead of piling up new ones).\n\nIt fails the job **after** writing those, so a failing run still leaves the feedback behind.\n\nInputs: `path` (default `.`), `diff`, `baseline`, `github-token`. No `reporter` input \u2014 the\nfan-out is fixed. It reads your committed `svelte-vitals.config.*` and\n`svelte-vitals-suppressions.json`, so rule policy stays in those files.\n\nPermissions: `contents: read`, `pull-requests: write`. On fork PRs GitHub downgrades the token\nregardless, so the action skips the comment (never failing the job); annotations and summary\nstill work.\n\n## Without the Action\n\nAny CI can run the CLI directly. On GitHub, `GITHUB_ACTIONS=true` auto-selects the `github`\nreporter, so annotations come for free \u2014 but a detected AI-agent environment outranks it, so a\njob driven by an agent gets `agent` instead. Pass `--reporter github` when you need the\nannotations regardless of who is running the job:\n\n```bash\npnpm build\nnpx svelte-vitals@latest --reporter github --fail-on warning\n```\n\nFor a PR gate that ignores a legacy backlog, pair the two scoping flags:\n\n```bash\nnpx svelte-vitals@latest --diff origin/main --baseline origin/main --fail-on warning\n```\n\nGate on the score instead of, or as well as, individual findings with `--min-health <0-100>`.\n\nExit `1` means findings gated the run; exit `2` means the run did not happen \u2014 fail the job\nloudly on `2` rather than treating it as a pass.\n\n## Related\n\n- `svelte-vitals docs show scoping` \u2014 what `--diff` / `--baseline` / suppressions each do\n- `svelte-vitals docs show output` \u2014 reporters and exit codes"
28
+ body: "# Running in CI\n\n## Scaffold the GitHub Actions gate\n\n```bash\nnpx svelte-vitals@latest ci install # writes .github/workflows/svelte-vitals.yml\nnpx svelte-vitals@latest ci upgrade # bump only the pinned action ref in an existing file\n```\n\n`ci install` also exists as the `ci-workflow` target inside `svelte-vitals install`, so it can be\nset up in the same pass as everything else. Both support `--dry-run` and `--force`.\n\n## What the generated workflow does\n\nOn every `pull_request` it checks out with `fetch-depth: 0`, then calls `@svelte-vitals/action`,\nwhich runs the analysis **in-process** scoped to the PR (`diff`/`baseline` at `origin/<base>`).\nFrom that one analysis it produces:\n\n- inline annotations on the diff,\n- a job summary,\n- a sticky PR comment (a hidden `<!-- svelte-vitals-report -->` marker updates the same comment\n instead of piling up new ones).\n\nIt fails the job **after** writing those, so a failing run still leaves the feedback behind.\n\nInputs: `path` (default `.`), `diff`, `baseline`, `github-token`. No `reporter` input \u2014 the\nfan-out is fixed. It reads your committed `svelte-vitals.config.*` and\n`svelte-vitals-suppressions.json`, so rule policy stays in those files.\n\nPermissions: `contents: read`, `pull-requests: write`. On fork PRs GitHub downgrades the token\nregardless, so the action skips the comment (never failing the job); annotations and summary\nstill work.\n\n## Without the Action\n\nAny CI can run the CLI directly. On GitHub, `GITHUB_ACTIONS=true` auto-selects the `github`\nreporter, so annotations come for free \u2014 but a detected AI-agent environment outranks it, so a\njob driven by an agent gets `agent` instead. Pass `--reporter github` when you need the\nannotations regardless of who is running the job:\n\n```bash\nnpx svelte-vitals@latest --reporter github --fail-on warning\n```\n\nFor a PR gate that ignores a legacy backlog, pair the two scoping flags:\n\n```bash\nnpx svelte-vitals@latest --diff origin/main --baseline origin/main --fail-on warning\n```\n\nGate on the score instead of, or as well as, individual findings with `--min-health <0-100>`.\n\nExit `1` means findings gated the run; exit `2` means the run did not happen \u2014 fail the job\nloudly on `2` rather than treating it as a pass.\n\n## Related\n\n- `svelte-vitals docs show scoping` \u2014 what `--diff` / `--baseline` / suppressions each do\n- `svelte-vitals docs show output` \u2014 reporters and exit codes"
29
29
  },
30
30
  {
31
31
  name: "config",
32
32
  title: "The config file",
33
33
  description: "Where svelte-vitals.config lives, every top-level option, how to disable or re-grade a rule, and how to scope rules to routes or files.",
34
- body: "# The config file\n\n## Where it lives\n\nIn the **analyzed directory only** \u2014 no upward search. First match wins:\n\n1. `svelte-vitals.config.mjs`\n2. `svelte-vitals.config.js`\n3. `svelte-vitals.config.ts`\n\nNo file means built-in defaults. `svelte-vitals install --client config-file` scaffolds one with\nevery option commented out.\n\n```js\n// svelte-vitals.config.mjs\nexport default {\n treatDynamicAs: 'warn',\n metaComponents: ['Seo'],\n rules: { 'seo/json-ld': 'off' },\n failOn: 'warning',\n weights: { seo: 2 }\n};\n```\n\nA `.ts` config can `import { defineConfig } from 'svelte-vitals'` for type-checking, but that is a\n**runtime** import: it needs svelte-vitals as a declared dependency and Node 22.18+ (or 23.6+).\nA plain `export default {}` in `.mjs` behaves identically and always works.\n\n## Options\n\n| Option | Type | Default |\n| ---------------- | -------------------------------------------------------------- | ------------------ |\n| `treatDynamicAs` | `'pass' \\| 'warn' \\| 'fail'` | `'pass'` |\n| `metaComponents` | `string[]` | `[]` |\n| `rules` | `Record<ruleId, 'off' \\| Severity \\| { severity?, options? }>` | `{}` |\n| `failOn` | `'critical' \\| 'warning' \\| 'info'` | `'critical'` |\n| `weights` | `Partial<Record<Category, number>>` | every category `1` |\n| `overrides` | `RuleOverride[]` | (none) |\n\n`Severity` is `'critical' | 'warning' | 'info'`. `Category` is `'seo' | 'performance' |\n'correctness' | 'security' | 'architecture' | 'a11y'`. A weight of `0` drops a category from the Health\naverage; setting every category to `0` is an error (exit `2`).\n\n## Turning a rule off or down\n\n```js\nexport default {\n rules: {\n 'seo/json-ld': 'off', // remove its findings entirely\n 'architecture/prop-count': 'info' // keep it, stop it failing the build\n }\n};\n```\n\nMany rules take options, so check whether the finding is a **threshold disagreement** rather than\na defect first. `svelte-vitals explain <rule-id>` prints each option's name, default, bounds, and\nmerge semantics (`integer` replaces, `string-list` appends, `string-map` is spread over).\n\n```js\nexport default {\n rules: {\n 'architecture/prop-count': { options: { max: 12 } }\n }\n};\n```\n\n## Scoping to routes or files (`overrides`)\n\n`rules` applies everywhere; `overrides` applies only where it matches \u2014 typically routes that\nare deliberately not public.\n\n```js\nexport default {\n overrides: [\n { files: 'src/routes/(app)/**', rules: { seo: 'off' } },\n { route: '/admin/**', rules: { 'seo/title-presence': 'info' } }\n ]\n};\n```\n\nEach entry needs `rules` (keys are rule ids **or** category names) plus at least one of:\n\n- **`route`** \u2014 glob(s) against the route id as reported (`/blog/[slug]`). SvelteKit `(group)`\n segments are **not** in the route id, so use `files` to target a group.\n- **`files`** \u2014 glob(s) against the source path.\n\nGlobs are deliberately small: `*` within a segment, `**` across segments, a trailing `/**` also\nmatches the bare prefix. Everything else \u2014 including `(`, `)`, `[`, `]` \u2014 is literal. Later entries win.\n\n## Precedence\n\nPer field: **CLI flag > config file > built-in default**. One exception \u2014 `--rules` and `--ignore`\nare selection, not configuration: `--rules` narrows the run to the ids it names and overrides a\nconfig-file `off` for them, but keeps their declared severity and options; `--ignore` adds `off`\nentries for the ids it names, layered on top of whatever `rules` resolved to, and beats `--rules`\nwhen both name the same rule.\n\n`overrides` has no CLI flag; route policy belongs in a committed file.\n\n## Validation\n\nAn unknown rule id or category, a negative weight, a malformed `overrides` entry, or an invalid\nrule setting is a **hard error (exit `2`)** \u2014 a typo must not silently un-gate CI. An unrecognized\n`treatDynamicAs`/`failOn` value, or an unknown top-level key, only warns.\n\n## Related\n\n- `svelte-vitals explain --list` \u2014 every rule id\n- `svelte-vitals docs show scoping` \u2014 accepting an existing backlog instead of disabling rules"
34
+ body: "# The config file\n\n## Where it lives\n\nIn the **analyzed directory only** \u2014 no upward search. First match wins:\n\n1. `svelte-vitals.config.js`\n2. `svelte-vitals.config.ts`\n\nNo file means built-in defaults. `svelte-vitals install --client config-file` scaffolds one with\nevery option commented out.\n\n```js\n// svelte-vitals.config.js\nexport default {\n treatDynamicAs: 'warn',\n metaComponents: ['Seo'],\n rules: { 'seo/json-ld': 'off' },\n failOn: 'warning',\n weights: { seo: 2 }\n};\n```\n\nA `.ts` config can `import { defineConfig } from 'svelte-vitals'` for type-checking, but that is a\n**runtime** import: it needs svelte-vitals as a declared dependency. A plain `export default {}`\nin `.js` behaves identically and needs no dependency. Both are ESM \u2014 the project must be\n`\"type\": \"module\"` (SvelteKit's default).\n\n## Options\n\n| Option | Type | Default |\n| ---------------- | -------------------------------------------------------------- | ------------------ |\n| `treatDynamicAs` | `'pass' \\| 'warn' \\| 'fail'` | `'pass'` |\n| `metaComponents` | `string[]` | `[]` |\n| `rules` | `Record<ruleId, 'off' \\| Severity \\| { severity?, options? }>` | `{}` |\n| `failOn` | `'critical' \\| 'warning' \\| 'info'` | `'critical'` |\n| `weights` | `Partial<Record<Category, number>>` | every category `1` |\n| `overrides` | `RuleOverride[]` | (none) |\n\n`Severity` is `'critical' | 'warning' | 'info'`. `Category` is `'seo' | 'performance' |\n'correctness' | 'security' | 'architecture' | 'a11y'`. A weight of `0` drops a category from the Health\naverage; setting every category to `0` is an error (exit `2`).\n\n## Turning a rule off or down\n\n```js\nexport default {\n rules: {\n 'seo/json-ld': 'off', // remove its findings entirely\n 'architecture/prop-count': 'info' // keep it, stop it failing the build\n }\n};\n```\n\nMany rules take options, so check whether the finding is a **threshold disagreement** rather than\na defect first. `svelte-vitals explain <rule-id>` prints each option's name, default, bounds, and\nmerge semantics (`integer` replaces, `string-list` appends, `string-map` is spread over).\n\n```js\nexport default {\n rules: {\n 'architecture/prop-count': { options: { max: 12 } }\n }\n};\n```\n\n## Scoping to routes or files (`overrides`)\n\n`rules` applies everywhere; `overrides` applies only where it matches \u2014 typically routes that\nare deliberately not public.\n\n```js\nexport default {\n overrides: [\n { files: 'src/routes/(app)/**', rules: { seo: 'off' } },\n { route: '/admin/**', rules: { 'seo/title-presence': 'info' } }\n ]\n};\n```\n\nEach entry needs `rules` (keys are rule ids **or** category names) plus at least one of:\n\n- **`route`** \u2014 glob(s) against the route id as reported (`/blog/[slug]`). SvelteKit `(group)`\n segments are **not** in the route id, so use `files` to target a group.\n- **`files`** \u2014 glob(s) against the source path.\n\nGlobs are deliberately small: `*` within a segment, `**` across segments, a trailing `/**` also\nmatches the bare prefix. Everything else \u2014 including `(`, `)`, `[`, `]` \u2014 is literal. Later entries win.\n\n## Precedence\n\nPer field: **CLI flag > config file > built-in default**. One exception \u2014 `--rules` and `--ignore`\nare selection, not configuration: `--rules` narrows the run to the ids it names and overrides a\nconfig-file `off` for them, but keeps their declared severity and options; `--ignore` adds `off`\nentries for the ids it names, layered on top of whatever `rules` resolved to, and beats `--rules`\nwhen both name the same rule.\n\n`overrides` has no CLI flag; route policy belongs in a committed file.\n\n## Validation\n\nAn unknown rule id or category, a negative weight, a malformed `overrides` entry, or an invalid\nrule setting is a **hard error (exit `2`)** \u2014 a typo must not silently un-gate CI. An unrecognized\n`treatDynamicAs`/`failOn` value, or an unknown top-level key, only warns.\n\n## Related\n\n- `svelte-vitals explain --list` \u2014 every rule id\n- `svelte-vitals docs show scoping` \u2014 accepting an existing backlog instead of disabling rules"
35
35
  },
36
36
  {
37
37
  name: "monorepo",
38
38
  title: "Monorepos",
39
39
  description: "How svelte-vitals picks which SvelteKit app to analyze, why it exits 2 instead of prompting in a non-interactive shell, and how to name the app explicitly.",
40
- body: '# Monorepos\n\n## Naming the app is always safest\n\n```bash\nnpx svelte-vitals@latest apps/web\n```\n\nAn explicit `path` \u2014 or running from inside the app directory \u2014 skips detection entirely. Prefer\nit in a script, a hook, or an agent\'s shell.\n\n## What happens without a path\n\nWhen no `path` is given and the current directory is not itself a SvelteKit app, svelte-vitals\nlooks for nearby apps \u2014 a directory with `src/routes` **and** either a\n`svelte.config.{js,ts}` or a `package.json` declaring `@sveltejs/kit` (current `sv create`\noutput folds the SvelteKit config into `vite.config.ts` and emits no `svelte.config` file):\n\n| Found | Interactive terminal | Non-interactive (CI, agents, piped output) |\n| ----------- | ----------------------------------- | ---------------------------------------------------------- |\n| exactly one | analyzed, notice on stderr | same \u2014 analyzed, notice on stderr |\n| several | single-select prompt | **exit `2`** listing the apps, asking for an explicit path |\n| none | exit `2`, "not a SvelteKit project" | same |\n\n**svelte-vitals never prompts when stdout is not a TTY** \u2014 it fails fast with the list instead of\nhanging or guessing. Re-run with the path it printed. Cancelling the interactive prompt exits `0`.\n\n## `install` in a monorepo\n\n`svelte-vitals install` splits its targets by where they belong:\n\n- `vite-plugin`, `vite-hooks`, `config-file` write into the **app** directory \u2014 they resolve it\n the same way the analyzer does, and `--app <app>` names it explicitly.\n- the agent skills and `ci-workflow` always write at the **current** directory, because the repo\n root is their correct home.\n\n```bash\nnpx svelte-vitals@latest install --client vite-plugin,config-file --app apps/web --yes\n```\n\n`--app` pointing at a directory that is not a SvelteKit app is an error (exit `2`).\n\n## Related\n\n- `svelte-vitals docs show output` \u2014 what exit `2` means versus exit `1`'
40
+ body: '# Monorepos\n\n## Naming the app is always safest\n\n```bash\nnpx svelte-vitals@latest apps/web\n```\n\nAn explicit `path` \u2014 or running from inside the app directory \u2014 skips detection entirely. Prefer\nit in a script, a hook, or an agent\'s shell.\n\n## What happens without a path\n\nWhen no `path` is given and the current directory is not itself a SvelteKit app, svelte-vitals\nlooks for nearby apps \u2014 a directory with `src/routes` **and** either a\n`svelte.config.{js,ts}` or a `package.json` declaring `@sveltejs/kit` (current `sv create`\noutput folds the SvelteKit config into `vite.config.ts` and emits no `svelte.config` file):\n\n| Found | Interactive terminal | Non-interactive (CI, agents, piped output) |\n| ----------- | ----------------------------------- | ---------------------------------------------------------- |\n| exactly one | analyzed, notice on stderr | same \u2014 analyzed, notice on stderr |\n| several | single-select prompt | **exit `2`** listing the apps, asking for an explicit path |\n| none | exit `2`, "not a SvelteKit project" | same |\n\n**svelte-vitals never prompts when stdout is not a TTY** \u2014 it fails fast with the list instead of\nhanging or guessing. Re-run with the path it printed. Cancelling the interactive prompt exits `0`.\n\n## `install` in a monorepo\n\n`svelte-vitals install` splits its targets by where they belong:\n\n- `vite-plugin`, `vite-hooks`, `config-file` write into the **app** directory \u2014 they resolve it\n the same way the analyzer does, and `--app <app>` names it explicitly.\n- `cursor-rules` and `ci-workflow` always write at the **current** directory, because the repo\n root is their correct home.\n\n```bash\nnpx svelte-vitals@latest install --client vite-plugin,config-file --app apps/web --yes\n```\n\n`--app` pointing at a directory that is not a SvelteKit app is an error (exit `2`).\n\n## Related\n\n- `svelte-vitals docs show output` \u2014 what exit `2` means versus exit `1`'
41
41
  },
42
42
  {
43
43
  name: "output",
@@ -96,7 +96,7 @@ var DOCS_SHOW_ARGS = {
96
96
  ...HELP_ARG
97
97
  };
98
98
  async function buildDocsHelpText(rootCommand, locale) {
99
- const ja = locale === "ja" ? await import("./ja-GAQSBSXF.js") : void 0;
99
+ const ja = locale === "ja" ? await import("./ja-YYZQ62AJ.js") : void 0;
100
100
  const optionsSection = stripAutoVersionLine(
101
101
  await localizedOptionsSection(rootCommand, "svelte-vitals docs", locale, ja?.JA_ARG_DESCRIPTIONS.docs ?? {})
102
102
  );
@@ -1,5 +1,5 @@
1
1
  // src/rules-config.ts
2
- import { allRules } from "@svelte-vitals/core";
2
+ import { allRules } from "@svelte-vitals/core/internal";
3
3
  var KNOWN_IDS = new Set(allRules.map((r) => r.id));
4
4
  var RULE_BY_ID = new Map(allRules.map((r) => [r.id, r]));
5
5
  function findUnknownRuleIds(ids) {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isReporterName
3
- } from "./chunk-M5KM5SV7.js";
3
+ } from "./chunk-WGFXFKBB.js";
4
4
  import {
5
5
  findUnknownRuleIds,
6
6
  knownRuleIds
7
- } from "./chunk-TFBLQUAC.js";
7
+ } from "./chunk-AI24FJ5Q.js";
8
8
 
9
9
  // src/resolve-args.ts
10
10
  import { parseArgs } from "util";