svelte-vitals 0.2.0 → 0.3.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
@@ -50,6 +50,12 @@ Passed (3)
50
50
 
51
51
  Useful as a CI gate.
52
52
 
53
+ ### Agent-native output
54
+
55
+ `svelte-vitals --reporter agent` emits a Markdown remediation document an AI coding agent can act on directly: each failing finding lists its location, a concrete fix (with a code snippet), and an acceptance check.
56
+
57
+ It is selected **automatically** when run inside a known AI-agent harness (e.g. Claude Code sets `CLAUDECODE`). Force it anywhere with `SVELTE_VITALS_REPORTER=agent`, or override with `--reporter console|json`. When auto-selected (not requested explicitly), a one-line hint is printed to stderr explaining how to override, so a human running it in an agent terminal isn't surprised by the Markdown output.
58
+
53
59
  ## How it works
54
60
 
55
61
  svelte-vitals resolves the effective `<head>` of every route by walking the layout chain (`+layout.svelte` → … → `+page.svelte`) and parsing `<svelte:head>` with `svelte/compiler`.
package/dist/bin.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ isReporterName,
3
4
  readPackageVersion,
4
5
  run
5
- } from "./chunk-LF3INKYM.js";
6
+ } from "./chunk-LYX2RVRM.js";
6
7
 
7
8
  // src/bin.ts
8
9
  import mri from "mri";
@@ -36,7 +37,7 @@ Options:
36
37
  --treat-dynamic-as <mode> pass | warn | fail (default: pass)
37
38
  --route <glob> Only analyze routes matching this glob
38
39
  --by-route Show per-route score breakdown in console output
39
- --reporter <mode> console | json (default: console)
40
+ --reporter <fmt> console | json | agent (auto: agent under AI-agent envs)
40
41
  --json Alias for --reporter=json
41
42
  --fail-on <severity> Fail (exit 1) when any finding reaches this severity: critical | warning | info
42
43
  --fail-on-warning Alias for --fail-on=warning
@@ -78,7 +79,16 @@ async function main() {
78
79
  console.error(`Known rule ids: ${knownRuleIds().join(", ")}`);
79
80
  process.exit(2);
80
81
  }
81
- const reporter = argv.json || argv.reporter === "json" ? "json" : "console";
82
+ let reporter;
83
+ if (argv.json) {
84
+ reporter = "json";
85
+ } else if (typeof argv.reporter === "string") {
86
+ if (!isReporterName(argv.reporter)) {
87
+ console.error(`svelte-vitals: unknown reporter '${argv.reporter}'. Valid values: console, json, agent.`);
88
+ process.exit(2);
89
+ }
90
+ reporter = argv.reporter;
91
+ }
82
92
  const failOnRaw = argv["fail-on"];
83
93
  const failOn = argv["fail-on-warning"] ? "warning" : failOnRaw === "warning" || failOnRaw === "info" || failOnRaw === "critical" ? failOnRaw : void 0;
84
94
  const code = await run({
@@ -4,6 +4,7 @@ import {
4
4
  runRules,
5
5
  formatConsoleReport,
6
6
  formatJsonReport,
7
+ formatAgentReport,
7
8
  summarize,
8
9
  hasFailureAtOrAbove,
9
10
  defineConfig,
@@ -41,6 +42,10 @@ function createNodeRuntime() {
41
42
  import { defaultConfig } from "@svelte-vitals/core";
42
43
 
43
44
  // src/providers/source/project.ts
45
+ import {
46
+ ROBOTS_SOURCE_PATHS,
47
+ SITEMAP_SOURCE_PATHS
48
+ } from "@svelte-vitals/core";
44
49
  var ProjectError = class extends Error {
45
50
  constructor(message) {
46
51
  super(message);
@@ -86,12 +91,8 @@ async function detectAppHtmlLang(rt, cwd) {
86
91
  }
87
92
  async function collectProjectFacts(rt, cwd) {
88
93
  const [hasRobotsTxt, hasSitemap, htmlLang] = await Promise.all([
89
- existsAny(rt, cwd, ["static/robots.txt", "src/routes/robots.txt/+server.ts", "src/routes/robots.txt/+server.js"]),
90
- existsAny(rt, cwd, [
91
- "static/sitemap.xml",
92
- "src/routes/sitemap.xml/+server.ts",
93
- "src/routes/sitemap.xml/+server.js"
94
- ]),
94
+ existsAny(rt, cwd, ROBOTS_SOURCE_PATHS),
95
+ existsAny(rt, cwd, SITEMAP_SOURCE_PATHS),
95
96
  detectAppHtmlLang(rt, cwd)
96
97
  ]);
97
98
  return { hasRobotsTxt, hasSitemap, htmlLang };
@@ -445,6 +446,28 @@ function readPackageVersion() {
445
446
  }
446
447
  }
447
448
 
449
+ // src/reporter-resolve.ts
450
+ var AGENT_ENV_VARS = ["CLAUDECODE", "SVELTE_VITALS_AGENT"];
451
+ function isReporterName(value) {
452
+ return value === "console" || value === "json" || value === "agent";
453
+ }
454
+ function isAgentEnv(env = process.env) {
455
+ return AGENT_ENV_VARS.some((key) => {
456
+ const v = env[key];
457
+ return v !== void 0 && v !== "";
458
+ });
459
+ }
460
+ function resolveReporter(explicit, env = process.env) {
461
+ if (explicit) return explicit;
462
+ const fromEnv = env.SVELTE_VITALS_REPORTER;
463
+ if (isReporterName(fromEnv)) return fromEnv;
464
+ if (isAgentEnv(env)) return "agent";
465
+ return "console";
466
+ }
467
+ function isAutoDetectedAgent(explicit, env = process.env) {
468
+ return !explicit && !isReporterName(env.SVELTE_VITALS_REPORTER) && isAgentEnv(env);
469
+ }
470
+
448
471
  // src/index.ts
449
472
  function routeMatcher(glob) {
450
473
  if (!glob) return () => true;
@@ -478,8 +501,17 @@ async function run(opts = {}) {
478
501
  const project = await collectProjectFacts(rt, cwd);
479
502
  const rules = selectRules(allRules, config);
480
503
  const results = applyRuleSeverities(await runRules(rules, { heads, project, config }), config);
481
- if (opts.reporter === "json") {
504
+ const env = opts.env ?? process.env;
505
+ const reporter = resolveReporter(opts.reporter, env);
506
+ if (reporter === "agent" && isAutoDetectedAgent(opts.reporter, env)) {
507
+ errorLog(
508
+ "svelte-vitals: agent reporter auto-selected (AI-agent env detected); override with --reporter console|json."
509
+ );
510
+ }
511
+ if (reporter === "json") {
482
512
  log(formatJsonReport(results, config, { version: readPackageVersion() }));
513
+ } else if (reporter === "agent") {
514
+ log(formatAgentReport(results, config));
483
515
  } else {
484
516
  log(formatConsoleReport(results, config, { byRoute: opts.byRoute ?? false }));
485
517
  }
@@ -493,6 +525,7 @@ async function run(opts = {}) {
493
525
 
494
526
  export {
495
527
  readPackageVersion,
528
+ isReporterName,
496
529
  routeMatcher,
497
530
  run
498
531
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Severity, RuleSetting } from '@svelte-vitals/core';
2
2
 
3
+ type ReporterName = 'console' | 'json' | 'agent';
4
+
3
5
  interface RunOptions {
4
6
  cwd?: string;
5
7
  log?: (line: string) => void;
@@ -8,10 +10,12 @@ interface RunOptions {
8
10
  treatDynamicAs?: 'pass' | 'warn' | 'fail';
9
11
  /** Restrict analysis to routes whose path matches this glob (matched against the route path without leading slash). */
10
12
  route?: string;
11
- reporter?: 'console' | 'json';
13
+ reporter?: ReporterName;
12
14
  byRoute?: boolean;
13
15
  failOn?: Severity;
14
16
  rules?: Record<string, RuleSetting>;
17
+ /** Override process.env for reporter auto-detection (mainly useful in tests). */
18
+ env?: NodeJS.ProcessEnv;
15
19
  }
16
20
  declare function routeMatcher(glob: string | undefined): (route: string) => boolean;
17
21
  /**
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  routeMatcher,
3
3
  run
4
- } from "./chunk-LF3INKYM.js";
4
+ } from "./chunk-LYX2RVRM.js";
5
5
  export {
6
6
  routeMatcher,
7
7
  run
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-vitals",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A SvelteKit SEO checker — not a runtime Web Vitals reporter. Static analysis of your routes' head metadata.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "mri": "^1.2.0",
39
39
  "svelte": "^5.56.3",
40
40
  "tinyglobby": "^0.2.17",
41
- "@svelte-vitals/core": "0.2.0"
41
+ "@svelte-vitals/core": "0.4.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^24.7.0"