svelte-vitals 0.43.0 → 0.44.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/dist/bin.js +216 -229
- package/dist/chunk-5Q2PT47V.js +27 -0
- package/dist/{chunk-6Y2E7QCQ.js → chunk-WD5TSADH.js} +244 -230
- package/dist/{cli-J5V65YIN.js → cli-LGD6NDAO.js} +4 -6
- package/dist/index.d.ts +30 -32
- package/dist/index.js +1 -3
- package/package.json +2 -3
- package/dist/chunk-SLUMRYUD.js +0 -9
package/dist/bin.js
CHANGED
|
@@ -3,19 +3,19 @@ import {
|
|
|
3
3
|
CONFIG_FILENAMES,
|
|
4
4
|
discoverApps,
|
|
5
5
|
findUnknownRuleIds,
|
|
6
|
+
hasDep,
|
|
6
7
|
isReporterName,
|
|
7
8
|
knownRuleIds,
|
|
8
9
|
readCoreVersion,
|
|
9
10
|
readPackageVersion,
|
|
11
|
+
readPkg,
|
|
10
12
|
run
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WD5TSADH.js";
|
|
12
14
|
import {
|
|
13
|
-
consoleIO
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import mri4 from "mri";
|
|
18
|
-
import * as p2 from "@clack/prompts";
|
|
15
|
+
consoleIO,
|
|
16
|
+
parseCliArgs,
|
|
17
|
+
toList
|
|
18
|
+
} from "./chunk-5Q2PT47V.js";
|
|
19
19
|
|
|
20
20
|
// src/resolve-args.ts
|
|
21
21
|
var CATEGORIES = ["seo", "performance", "correctness", "security", "architecture"];
|
|
@@ -24,7 +24,7 @@ function parseWeights(raw, errors) {
|
|
|
24
24
|
const weights = {};
|
|
25
25
|
const unknownCategories = [];
|
|
26
26
|
const invalidValues = [];
|
|
27
|
-
for (const pair of raw
|
|
27
|
+
for (const pair of toList(raw)) {
|
|
28
28
|
const eq = pair.indexOf("=");
|
|
29
29
|
if (eq === -1) {
|
|
30
30
|
invalidValues.push(pair);
|
|
@@ -65,7 +65,7 @@ function parseCategories(raw, errors) {
|
|
|
65
65
|
if (typeof raw !== "string" || raw.trim() === "") return void 0;
|
|
66
66
|
const categories = [];
|
|
67
67
|
const unknownCategories = [];
|
|
68
|
-
for (const entry of raw
|
|
68
|
+
for (const entry of toList(raw).map((s) => s.toLowerCase())) {
|
|
69
69
|
if (!CATEGORIES.includes(entry)) {
|
|
70
70
|
unknownCategories.push(entry);
|
|
71
71
|
continue;
|
|
@@ -81,12 +81,73 @@ function parseCategories(raw, errors) {
|
|
|
81
81
|
}
|
|
82
82
|
return categories;
|
|
83
83
|
}
|
|
84
|
-
var
|
|
84
|
+
var VALUE_FLAGS = [
|
|
85
|
+
"meta-components",
|
|
86
|
+
"treat-dynamic-as",
|
|
87
|
+
"route",
|
|
88
|
+
"fail-on",
|
|
89
|
+
"reporter",
|
|
90
|
+
"rules",
|
|
91
|
+
"ignore",
|
|
92
|
+
"min-health",
|
|
93
|
+
"out-file",
|
|
94
|
+
"weights",
|
|
95
|
+
"category"
|
|
96
|
+
];
|
|
97
|
+
function parseRunArgs(args) {
|
|
98
|
+
const patched = args.map((a, i) => a === "--diff" && (args[i + 1] ?? "--").startsWith("-") ? "--diff=HEAD" : a);
|
|
99
|
+
return parseCliArgs(patched, {
|
|
100
|
+
boolean: [
|
|
101
|
+
"by-route",
|
|
102
|
+
"staged",
|
|
103
|
+
"score",
|
|
104
|
+
"verbose",
|
|
105
|
+
"update-suppressions",
|
|
106
|
+
"no-suppressions",
|
|
107
|
+
"no-color",
|
|
108
|
+
"no-animation",
|
|
109
|
+
"help",
|
|
110
|
+
"version"
|
|
111
|
+
],
|
|
112
|
+
string: [
|
|
113
|
+
"meta-components",
|
|
114
|
+
"treat-dynamic-as",
|
|
115
|
+
"route",
|
|
116
|
+
"fail-on",
|
|
117
|
+
"reporter",
|
|
118
|
+
"rules",
|
|
119
|
+
"ignore",
|
|
120
|
+
"min-health",
|
|
121
|
+
"out-file",
|
|
122
|
+
"diff",
|
|
123
|
+
"baseline",
|
|
124
|
+
"weights",
|
|
125
|
+
"category"
|
|
126
|
+
],
|
|
127
|
+
short: { h: "help", v: "version" }
|
|
128
|
+
});
|
|
129
|
+
}
|
|
85
130
|
function resolveArgs(argv) {
|
|
86
131
|
const warnings = [];
|
|
87
132
|
const errors = [];
|
|
133
|
+
for (const flag of VALUE_FLAGS) {
|
|
134
|
+
const v = argv[flag];
|
|
135
|
+
if (v !== void 0 && (typeof v !== "string" || v.trim() === "" || v.startsWith("-"))) {
|
|
136
|
+
errors.push(`svelte-vitals: --${flag} requires a value.`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
let minHealth;
|
|
140
|
+
const minHealthRaw = argv["min-health"];
|
|
141
|
+
if (minHealthRaw !== void 0) {
|
|
142
|
+
const n = Number(minHealthRaw);
|
|
143
|
+
if (!Number.isFinite(n) || n < 0 || n > 100) {
|
|
144
|
+
errors.push(`svelte-vitals: invalid --min-health '${minHealthRaw}'; expected a number 0-100.`);
|
|
145
|
+
} else {
|
|
146
|
+
minHealth = n;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
88
149
|
const positional = argv._[0];
|
|
89
|
-
const metaComponents = typeof argv["meta-components"] === "string" ? argv["meta-components"]
|
|
150
|
+
const metaComponents = typeof argv["meta-components"] === "string" ? toList(argv["meta-components"]) : void 0;
|
|
90
151
|
const treatRaw = argv["treat-dynamic-as"];
|
|
91
152
|
const treatDynamicAs = treatRaw === "warn" || treatRaw === "fail" || treatRaw === "pass" ? treatRaw : void 0;
|
|
92
153
|
if (typeof treatRaw === "string" && treatDynamicAs === void 0) {
|
|
@@ -98,8 +159,8 @@ function resolveArgs(argv) {
|
|
|
98
159
|
const diffBase = typeof argv.diff === "string" ? argv.diff || "HEAD" : void 0;
|
|
99
160
|
const staged = Boolean(argv.staged);
|
|
100
161
|
let baselineRef;
|
|
101
|
-
if (
|
|
102
|
-
if (argv.baseline.trim() === "") {
|
|
162
|
+
if (argv.baseline !== void 0) {
|
|
163
|
+
if (typeof argv.baseline !== "string" || argv.baseline.trim() === "" || argv.baseline.startsWith("-")) {
|
|
103
164
|
errors.push("svelte-vitals: --baseline requires a git ref (e.g. --baseline origin/main).");
|
|
104
165
|
} else {
|
|
105
166
|
baselineRef = argv.baseline;
|
|
@@ -137,9 +198,9 @@ function resolveArgs(argv) {
|
|
|
137
198
|
warnings.push("svelte-vitals: --score overrides --reporter; reporter output suppressed.");
|
|
138
199
|
}
|
|
139
200
|
const verbose = Boolean(argv["verbose"]);
|
|
140
|
-
const noColor = argv
|
|
141
|
-
const noAnimation = argv
|
|
142
|
-
const noSuppressions = argv
|
|
201
|
+
const noColor = Boolean(argv["no-color"]);
|
|
202
|
+
const noAnimation = Boolean(argv["no-animation"]);
|
|
203
|
+
const noSuppressions = Boolean(argv["no-suppressions"]);
|
|
143
204
|
const updateSuppressions = Boolean(argv["update-suppressions"]);
|
|
144
205
|
if (updateSuppressions && noSuppressions) {
|
|
145
206
|
errors.push("svelte-vitals: --update-suppressions and --no-suppressions cannot be used together.");
|
|
@@ -175,7 +236,8 @@ function resolveArgs(argv) {
|
|
|
175
236
|
...updateSuppressions ? { updateSuppressions } : {}
|
|
176
237
|
},
|
|
177
238
|
warnings,
|
|
178
|
-
errors
|
|
239
|
+
errors,
|
|
240
|
+
minHealth
|
|
179
241
|
};
|
|
180
242
|
}
|
|
181
243
|
|
|
@@ -183,83 +245,11 @@ function resolveArgs(argv) {
|
|
|
183
245
|
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
184
246
|
import { dirname } from "path";
|
|
185
247
|
import { spawnSync } from "child_process";
|
|
186
|
-
import mri from "mri";
|
|
187
248
|
import * as p from "@clack/prompts";
|
|
188
249
|
|
|
189
250
|
// src/install/index.ts
|
|
190
251
|
import { join as join3 } from "path";
|
|
191
252
|
|
|
192
|
-
// src/install/vite-targets.ts
|
|
193
|
-
var VITE_TARGETS = [
|
|
194
|
-
{
|
|
195
|
-
id: "vite-plugin",
|
|
196
|
-
label: "Vite plugin (build gate)",
|
|
197
|
-
hint: "Fails `vite build` when prerendered pages cross the SEO/Performance threshold"
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
id: "vite-hooks",
|
|
201
|
-
label: "Live dashboard accuracy",
|
|
202
|
-
hint: "Feeds real rendered results into the live dashboard as you browse \u2014 improves per-route accuracy, never fails a build"
|
|
203
|
-
}
|
|
204
|
-
];
|
|
205
|
-
function viteTargetById(id) {
|
|
206
|
-
return VITE_TARGETS.find((t) => t.id === id);
|
|
207
|
-
}
|
|
208
|
-
function isViteTargetId(id) {
|
|
209
|
-
return VITE_TARGETS.some((t) => t.id === id);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// src/install/agent-targets.ts
|
|
213
|
-
var AGENT_TARGETS = [
|
|
214
|
-
{
|
|
215
|
-
id: "claude-skill",
|
|
216
|
-
label: "Agent skill: svelte-vitals",
|
|
217
|
-
hint: "Teaches the agent svelte-vitals rules + when to run the scanner (Claude Code, Codex, Cursor)",
|
|
218
|
-
relPaths: [
|
|
219
|
-
".claude/skills/svelte-vitals/SKILL.md",
|
|
220
|
-
".agents/skills/svelte-vitals/SKILL.md",
|
|
221
|
-
".cursor/skills/svelte-vitals/SKILL.md"
|
|
222
|
-
]
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
id: "cursor-rules",
|
|
226
|
-
label: "Cursor rules",
|
|
227
|
-
hint: "Project rules file so Cursor avoids flagged patterns up front",
|
|
228
|
-
relPaths: [".cursor/rules/svelte-vitals.mdc"]
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
id: "claude-skill-improve",
|
|
232
|
-
label: "Agent skill: improve-svelte",
|
|
233
|
-
hint: "Senior-advisor audit \u2192 implementation plans (read-only), for a project-wide improvement roadmap (Claude Code, Codex, Cursor)",
|
|
234
|
-
relPaths: [
|
|
235
|
-
".claude/skills/improve-svelte/SKILL.md",
|
|
236
|
-
".agents/skills/improve-svelte/SKILL.md",
|
|
237
|
-
".cursor/skills/improve-svelte/SKILL.md"
|
|
238
|
-
]
|
|
239
|
-
}
|
|
240
|
-
];
|
|
241
|
-
function agentTargetById(id) {
|
|
242
|
-
return AGENT_TARGETS.find((t) => t.id === id);
|
|
243
|
-
}
|
|
244
|
-
function isAgentTargetId(id) {
|
|
245
|
-
return AGENT_TARGETS.some((t) => t.id === id);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// src/install/config-targets.ts
|
|
249
|
-
var CONFIG_TARGETS = [
|
|
250
|
-
{
|
|
251
|
-
id: "config-file",
|
|
252
|
-
label: "Config file",
|
|
253
|
-
hint: "Scaffolds svelte-vitals.config.{mjs,ts} (auto-picks the best one) with every option commented out"
|
|
254
|
-
}
|
|
255
|
-
];
|
|
256
|
-
function configTargetById(id) {
|
|
257
|
-
return CONFIG_TARGETS.find((t) => t.id === id);
|
|
258
|
-
}
|
|
259
|
-
function isConfigTargetId(id) {
|
|
260
|
-
return CONFIG_TARGETS.some((t) => t.id === id);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
253
|
// src/ci/workflow.ts
|
|
264
254
|
var WORKFLOW_PATH = ".github/workflows/svelte-vitals.yml";
|
|
265
255
|
var CHECKOUT_SHA = "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0";
|
|
@@ -298,20 +288,74 @@ function buildWorkflowYaml(opts) {
|
|
|
298
288
|
].join("\n");
|
|
299
289
|
}
|
|
300
290
|
|
|
301
|
-
// src/install/
|
|
302
|
-
var
|
|
291
|
+
// src/install/targets.ts
|
|
292
|
+
var INSTALL_TARGETS = [
|
|
293
|
+
{
|
|
294
|
+
id: "vite-plugin",
|
|
295
|
+
kind: "vite",
|
|
296
|
+
label: "Vite plugin (build gate)",
|
|
297
|
+
hint: "Fails `vite build` when prerendered pages cross the SEO/Performance threshold",
|
|
298
|
+
relPaths: []
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
id: "vite-hooks",
|
|
302
|
+
kind: "vite",
|
|
303
|
+
label: "Live dashboard accuracy",
|
|
304
|
+
hint: "Feeds real rendered results into the live dashboard as you browse \u2014 improves per-route accuracy, never fails a build",
|
|
305
|
+
relPaths: []
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
id: "claude-skill",
|
|
309
|
+
kind: "agent",
|
|
310
|
+
label: "Agent skill: svelte-vitals",
|
|
311
|
+
hint: "Teaches the agent svelte-vitals rules + when to run the scanner (Claude Code, Codex, Cursor)",
|
|
312
|
+
relPaths: [
|
|
313
|
+
".claude/skills/svelte-vitals/SKILL.md",
|
|
314
|
+
".agents/skills/svelte-vitals/SKILL.md",
|
|
315
|
+
".cursor/skills/svelte-vitals/SKILL.md"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
id: "cursor-rules",
|
|
320
|
+
kind: "agent",
|
|
321
|
+
label: "Cursor rules",
|
|
322
|
+
hint: "Project rules file so Cursor avoids flagged patterns up front",
|
|
323
|
+
relPaths: [".cursor/rules/svelte-vitals.mdc"]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: "claude-skill-improve",
|
|
327
|
+
kind: "agent",
|
|
328
|
+
label: "Agent skill: improve-svelte",
|
|
329
|
+
hint: "Senior-advisor audit \u2192 implementation plans (read-only), for a project-wide improvement roadmap (Claude Code, Codex, Cursor)",
|
|
330
|
+
relPaths: [
|
|
331
|
+
".claude/skills/improve-svelte/SKILL.md",
|
|
332
|
+
".agents/skills/improve-svelte/SKILL.md",
|
|
333
|
+
".cursor/skills/improve-svelte/SKILL.md"
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
id: "config-file",
|
|
338
|
+
kind: "config",
|
|
339
|
+
label: "Config file",
|
|
340
|
+
hint: "Scaffolds svelte-vitals.config.{mjs,ts} (auto-picks the best one) with every option commented out",
|
|
341
|
+
relPaths: []
|
|
342
|
+
},
|
|
303
343
|
{
|
|
304
344
|
id: "ci-workflow",
|
|
345
|
+
kind: "ci",
|
|
305
346
|
label: "GitHub Actions CI",
|
|
306
347
|
hint: "Scaffolds a workflow that runs @svelte-vitals/action on pull requests \u2014 inline annotations, job summary, sticky PR comment",
|
|
307
|
-
|
|
348
|
+
relPaths: [WORKFLOW_PATH]
|
|
308
349
|
}
|
|
309
350
|
];
|
|
310
|
-
function
|
|
311
|
-
return
|
|
351
|
+
function targetById(id) {
|
|
352
|
+
return INSTALL_TARGETS.find((t) => t.id === id);
|
|
312
353
|
}
|
|
313
|
-
function
|
|
314
|
-
return
|
|
354
|
+
function targetsOfKind(kind) {
|
|
355
|
+
return INSTALL_TARGETS.filter((t) => t.kind === kind);
|
|
356
|
+
}
|
|
357
|
+
function isKind(id, kind) {
|
|
358
|
+
return targetById(id)?.kind === kind;
|
|
315
359
|
}
|
|
316
360
|
|
|
317
361
|
// src/install/skill-content.ts
|
|
@@ -755,23 +799,10 @@ function findExistingConfigFile(readFile, cwd) {
|
|
|
755
799
|
return CONFIG_FILENAMES.find((rel) => readFile(join(cwd, rel)) !== void 0);
|
|
756
800
|
}
|
|
757
801
|
function hasSvelteVitalsDependency(readFile, cwd) {
|
|
758
|
-
|
|
759
|
-
if (raw === void 0) return false;
|
|
760
|
-
try {
|
|
761
|
-
const pkg = JSON.parse(raw);
|
|
762
|
-
return Boolean(pkg.dependencies?.["svelte-vitals"] ?? pkg.devDependencies?.["svelte-vitals"]);
|
|
763
|
-
} catch {
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
802
|
+
return hasDep(readPkg(readFile, cwd), "svelte-vitals");
|
|
766
803
|
}
|
|
767
804
|
function isEsmProject(readFile, cwd) {
|
|
768
|
-
|
|
769
|
-
if (raw === void 0) return false;
|
|
770
|
-
try {
|
|
771
|
-
return JSON.parse(raw).type === "module";
|
|
772
|
-
} catch {
|
|
773
|
-
return false;
|
|
774
|
-
}
|
|
805
|
+
return readPkg(readFile, cwd)?.type === "module";
|
|
775
806
|
}
|
|
776
807
|
function detectBestConfigExtension(opts) {
|
|
777
808
|
if (!nodeSupportsNativeTypeScript(opts.nodeVersion)) return "mjs";
|
|
@@ -796,7 +827,7 @@ function codemodViteConfig(existing) {
|
|
|
796
827
|
return { status: "manual", snippet: MANUAL_SNIPPET };
|
|
797
828
|
}
|
|
798
829
|
const already = configObj.plugins.find(
|
|
799
|
-
(
|
|
830
|
+
(p2) => p2?.$type === "function-call" && p2?.$callee === "svelteVitals"
|
|
800
831
|
);
|
|
801
832
|
if (already !== void 0) {
|
|
802
833
|
return { status: "exists" };
|
|
@@ -904,14 +935,10 @@ function detectPackageManager(io) {
|
|
|
904
935
|
return detectPackageManagerFromLockfile(io) ?? "npm";
|
|
905
936
|
}
|
|
906
937
|
function hasVitePackage(io) {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
return Boolean(pkg.dependencies?.["@svelte-vitals/vite"] || pkg.devDependencies?.["@svelte-vitals/vite"]);
|
|
912
|
-
} catch {
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
938
|
+
return hasDep(
|
|
939
|
+
readPkg((p2) => io.readFile(p2), io.cwd),
|
|
940
|
+
"@svelte-vitals/vite"
|
|
941
|
+
);
|
|
915
942
|
}
|
|
916
943
|
function installCommand(pm) {
|
|
917
944
|
const action = pm === "npm" ? "install" : "add";
|
|
@@ -946,12 +973,12 @@ function resolveCandidate(io, baseDir, candidates) {
|
|
|
946
973
|
function planForVitePlugin(io, appDir) {
|
|
947
974
|
const { path, content } = resolveCandidate(io, appDir, ["vite.config.ts", "vite.config.js", "vite.config.mjs"]);
|
|
948
975
|
const result = codemodViteConfig(content);
|
|
949
|
-
return { id: "vite-plugin", label:
|
|
976
|
+
return { id: "vite-plugin", label: targetById("vite-plugin").label, path, ...result };
|
|
950
977
|
}
|
|
951
978
|
function planForViteHooks(io, appDir) {
|
|
952
979
|
const { path, content } = resolveCandidate(io, appDir, ["src/hooks.server.ts", "src/hooks.server.js"]);
|
|
953
980
|
const result = codemodHooksServer(content);
|
|
954
|
-
return { id: "vite-hooks", label:
|
|
981
|
+
return { id: "vite-hooks", label: targetById("vite-hooks").label, path, ...result };
|
|
955
982
|
}
|
|
956
983
|
function agentTargetContent(id, version) {
|
|
957
984
|
switch (id) {
|
|
@@ -967,8 +994,9 @@ function agentTargetContent(id, version) {
|
|
|
967
994
|
}
|
|
968
995
|
}
|
|
969
996
|
}
|
|
970
|
-
function planForAgentTarget(
|
|
971
|
-
const
|
|
997
|
+
function planForAgentTarget(id, io, force, version) {
|
|
998
|
+
const target = targetById(id);
|
|
999
|
+
const content = agentTargetContent(id, version);
|
|
972
1000
|
return target.relPaths.map((relPath) => {
|
|
973
1001
|
const path = join3(io.cwd, relPath);
|
|
974
1002
|
const existing = io.readFile(path);
|
|
@@ -976,7 +1004,8 @@ function planForAgentTarget(target, io, force, version) {
|
|
|
976
1004
|
return { id: target.id, label: target.label, path, status, content };
|
|
977
1005
|
});
|
|
978
1006
|
}
|
|
979
|
-
function planForConfigTarget(
|
|
1007
|
+
function planForConfigTarget(io, force, appDir) {
|
|
1008
|
+
const target = targetById("config-file");
|
|
980
1009
|
const existingRel = findExistingConfigFile(io.readFile, appDir);
|
|
981
1010
|
if (existingRel !== void 0) {
|
|
982
1011
|
const path2 = join3(appDir, existingRel);
|
|
@@ -996,8 +1025,9 @@ function planForConfigTarget(target, io, force, appDir) {
|
|
|
996
1025
|
const content = buildConfigFileTemplate({ useDefineConfig: ext === "ts" });
|
|
997
1026
|
return { id: target.id, label: target.label, path, status: "created", content };
|
|
998
1027
|
}
|
|
999
|
-
function planForCiTarget(
|
|
1000
|
-
const
|
|
1028
|
+
function planForCiTarget(io, force) {
|
|
1029
|
+
const target = targetById("ci-workflow");
|
|
1030
|
+
const path = join3(io.cwd, target.relPaths[0]);
|
|
1001
1031
|
const existing = io.readFile(path);
|
|
1002
1032
|
const plan = planWorkflowWrite(existing, force);
|
|
1003
1033
|
const content = plan.status === "exists" ? void 0 : buildWorkflowYaml({ actionSha: ACTION_SHA, actionVersion: ACTION_VERSION });
|
|
@@ -1014,7 +1044,7 @@ ${indent(r.snippet)}` : head;
|
|
|
1014
1044
|
async function runRefresh(io, flags, version) {
|
|
1015
1045
|
let hadFailure = false;
|
|
1016
1046
|
const rows = [];
|
|
1017
|
-
for (const target of
|
|
1047
|
+
for (const target of targetsOfKind("agent")) {
|
|
1018
1048
|
const content = agentTargetContent(target.id, version);
|
|
1019
1049
|
for (const relPath of target.relPaths) {
|
|
1020
1050
|
const path = join3(io.cwd, relPath);
|
|
@@ -1079,25 +1109,26 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1079
1109
|
".cursor/environment.json",
|
|
1080
1110
|
".cursorrules",
|
|
1081
1111
|
".cursorignore",
|
|
1082
|
-
|
|
1112
|
+
targetById("cursor-rules").relPaths[0]
|
|
1083
1113
|
].some((rel) => configExists(join3(io.cwd, rel)));
|
|
1084
1114
|
const detectedAgents = [
|
|
1085
1115
|
...claudeSkillDetected ? ["claude-skill"] : [],
|
|
1086
1116
|
...cursorRulesDetected ? ["cursor-rules"] : []
|
|
1087
1117
|
];
|
|
1088
|
-
const ciWorkflowDetected = configExists(join3(io.cwd,
|
|
1089
|
-
const configFileDetected = findExistingConfigFile((
|
|
1118
|
+
const ciWorkflowDetected = configExists(join3(io.cwd, targetById("ci-workflow").relPaths[0]));
|
|
1119
|
+
const configFileDetected = findExistingConfigFile((p2) => configExists(p2) ? "" : void 0, io.cwd) !== void 0;
|
|
1090
1120
|
const detected = [
|
|
1091
|
-
...viteConfigExists ?
|
|
1121
|
+
...viteConfigExists ? targetsOfKind("vite").map((t) => t.id) : [],
|
|
1092
1122
|
...detectedAgents,
|
|
1093
|
-
...ciWorkflowDetected ?
|
|
1094
|
-
...configFileDetected ?
|
|
1123
|
+
...ciWorkflowDetected ? ["ci-workflow"] : [],
|
|
1124
|
+
...configFileDetected ? ["config-file"] : []
|
|
1095
1125
|
];
|
|
1126
|
+
const asOption = (t) => ({ id: t.id, label: t.label, hint: t.hint });
|
|
1096
1127
|
const groups = {
|
|
1097
|
-
"Vite integration":
|
|
1098
|
-
"Agent Skills & rules":
|
|
1099
|
-
"CI (GitHub Actions)":
|
|
1100
|
-
"Config file":
|
|
1128
|
+
"Vite integration": targetsOfKind("vite").map(asOption),
|
|
1129
|
+
"Agent Skills & rules": targetsOfKind("agent").map(asOption),
|
|
1130
|
+
"CI (GitHub Actions)": targetsOfKind("ci").map(asOption),
|
|
1131
|
+
"Config file": targetsOfKind("config").map(asOption)
|
|
1101
1132
|
};
|
|
1102
1133
|
const picked = await prompts.selectClients(groups, detected);
|
|
1103
1134
|
if (picked === null) {
|
|
@@ -1111,10 +1142,10 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1111
1142
|
);
|
|
1112
1143
|
return 2;
|
|
1113
1144
|
}
|
|
1114
|
-
const viteIds = ids.filter(
|
|
1115
|
-
const agentIds = ids.filter(
|
|
1116
|
-
const configIds = ids.filter(
|
|
1117
|
-
const ciIds = ids.filter(
|
|
1145
|
+
const viteIds = ids.filter((id) => isKind(id, "vite"));
|
|
1146
|
+
const agentIds = ids.filter((id) => isKind(id, "agent"));
|
|
1147
|
+
const configIds = ids.filter((id) => isKind(id, "config"));
|
|
1148
|
+
const ciIds = ids.filter((id) => isKind(id, "ci"));
|
|
1118
1149
|
if (viteIds.length === 0 && agentIds.length === 0 && configIds.length === 0 && ciIds.length === 0) {
|
|
1119
1150
|
io.errorLog("svelte-vitals: no valid targets selected.");
|
|
1120
1151
|
return 2;
|
|
@@ -1124,10 +1155,10 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1124
1155
|
if (io.readFile(join3(dir, "svelte.config.js")) !== void 0 || io.readFile(join3(dir, "svelte.config.ts")) !== void 0) {
|
|
1125
1156
|
return true;
|
|
1126
1157
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1158
|
+
return hasDep(
|
|
1159
|
+
readPkg((p2) => io.readFile(p2), dir),
|
|
1160
|
+
"@sveltejs/kit"
|
|
1161
|
+
);
|
|
1131
1162
|
} catch {
|
|
1132
1163
|
return false;
|
|
1133
1164
|
}
|
|
@@ -1177,20 +1208,18 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1177
1208
|
}
|
|
1178
1209
|
}
|
|
1179
1210
|
for (const agentId of agentIds) {
|
|
1180
|
-
const target = agentTargetById(agentId);
|
|
1181
1211
|
try {
|
|
1182
|
-
rows.push(...planForAgentTarget(
|
|
1212
|
+
rows.push(...planForAgentTarget(agentId, io, flags.force ?? false, version));
|
|
1183
1213
|
} catch (err) {
|
|
1184
1214
|
io.errorLog(
|
|
1185
|
-
`svelte-vitals: could not check existing agent target ${
|
|
1215
|
+
`svelte-vitals: could not check existing agent target ${agentId}: ${err instanceof Error ? err.message : String(err)}`
|
|
1186
1216
|
);
|
|
1187
1217
|
return 2;
|
|
1188
1218
|
}
|
|
1189
1219
|
}
|
|
1190
|
-
|
|
1191
|
-
const target = configTargetById(configId);
|
|
1220
|
+
if (configIds.length > 0) {
|
|
1192
1221
|
try {
|
|
1193
|
-
rows.push(planForConfigTarget(
|
|
1222
|
+
rows.push(planForConfigTarget(io, flags.force ?? false, appDir));
|
|
1194
1223
|
} catch (err) {
|
|
1195
1224
|
io.errorLog(
|
|
1196
1225
|
`svelte-vitals: could not check existing config file: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -1198,13 +1227,12 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1198
1227
|
return 2;
|
|
1199
1228
|
}
|
|
1200
1229
|
}
|
|
1201
|
-
|
|
1202
|
-
const target = ciTargetById(ciId);
|
|
1230
|
+
if (ciIds.length > 0) {
|
|
1203
1231
|
try {
|
|
1204
|
-
rows.push(planForCiTarget(
|
|
1232
|
+
rows.push(planForCiTarget(io, flags.force ?? false));
|
|
1205
1233
|
} catch (err) {
|
|
1206
1234
|
io.errorLog(
|
|
1207
|
-
`svelte-vitals: could not check existing workflow at ${join3(io.cwd,
|
|
1235
|
+
`svelte-vitals: could not check existing workflow at ${join3(io.cwd, targetById("ci-workflow").relPaths[0])}: ${err instanceof Error ? err.message : String(err)}`
|
|
1208
1236
|
);
|
|
1209
1237
|
return 2;
|
|
1210
1238
|
}
|
|
@@ -1227,7 +1255,7 @@ async function runInstall(flags, io, prompts, version = "0.0.0") {
|
|
|
1227
1255
|
let viteWasWritten = false;
|
|
1228
1256
|
for (const r of rows) {
|
|
1229
1257
|
if (r.status === "exists") {
|
|
1230
|
-
const hint =
|
|
1258
|
+
const hint = isKind(r.id, "vite") ? "" : " \u2014 use --force to overwrite";
|
|
1231
1259
|
io.log(`= ${r.label}: already configured (${r.path})${hint}.`);
|
|
1232
1260
|
continue;
|
|
1233
1261
|
}
|
|
@@ -1239,8 +1267,8 @@ ${indent(r.snippet ?? "")}`);
|
|
|
1239
1267
|
try {
|
|
1240
1268
|
io.writeFile(r.path, r.content ?? "");
|
|
1241
1269
|
io.log(`\u2713 ${r.label}: ${r.status} ${r.path}`);
|
|
1242
|
-
if (
|
|
1243
|
-
if (
|
|
1270
|
+
if (isKind(r.id, "vite")) viteWasWritten = true;
|
|
1271
|
+
if (isKind(r.id, "config") && r.path.endsWith(".ts")) {
|
|
1244
1272
|
io.log(
|
|
1245
1273
|
"svelte-vitals: note \u2014 a .ts config needs Node 22.18+ (or 23.6+) everywhere svelte-vitals runs, CI included; rename to .mjs if that is not guaranteed."
|
|
1246
1274
|
);
|
|
@@ -1276,17 +1304,21 @@ ${indent(r.snippet ?? "")}`);
|
|
|
1276
1304
|
}
|
|
1277
1305
|
|
|
1278
1306
|
// src/install/args.ts
|
|
1279
|
-
var VALID_TARGETS =
|
|
1280
|
-
...VITE_TARGETS.map((t) => t.id),
|
|
1281
|
-
...AGENT_TARGETS.map((t) => t.id),
|
|
1282
|
-
...CONFIG_TARGETS.map((t) => t.id),
|
|
1283
|
-
...CI_TARGETS.map((t) => t.id)
|
|
1284
|
-
];
|
|
1307
|
+
var VALID_TARGETS = INSTALL_TARGETS.map((t) => t.id);
|
|
1285
1308
|
var EXPECTED_TARGETS = VALID_TARGETS.join("|");
|
|
1309
|
+
function parseInstallArgs(args) {
|
|
1310
|
+
return parseCliArgs(args, {
|
|
1311
|
+
boolean: ["yes", "dry-run", "force", "refresh", "help"],
|
|
1312
|
+
// `scope` is still declared although the flag is gone: it keeps `--scope global` from
|
|
1313
|
+
// parsing its value as a positional, so resolveInstallArgs can warn and carry on.
|
|
1314
|
+
string: ["client", "scope", "app"],
|
|
1315
|
+
short: { y: "yes", h: "help" }
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1286
1318
|
function resolveInstallArgs(argv) {
|
|
1287
1319
|
const warnings = [];
|
|
1288
1320
|
const errors = [];
|
|
1289
|
-
const rawClients =
|
|
1321
|
+
const rawClients = toList(argv.client);
|
|
1290
1322
|
const client = [];
|
|
1291
1323
|
for (const c of rawClients) {
|
|
1292
1324
|
if (VALID_TARGETS.includes(c)) {
|
|
@@ -1408,6 +1440,14 @@ function realIO() {
|
|
|
1408
1440
|
}
|
|
1409
1441
|
};
|
|
1410
1442
|
}
|
|
1443
|
+
async function selectAppPrompt(apps, message) {
|
|
1444
|
+
const res = await p.select({
|
|
1445
|
+
message,
|
|
1446
|
+
options: apps.map((a) => ({ value: a, label: a })),
|
|
1447
|
+
initialValue: apps[0]
|
|
1448
|
+
});
|
|
1449
|
+
return p.isCancel(res) ? null : res;
|
|
1450
|
+
}
|
|
1411
1451
|
function clackPrompts() {
|
|
1412
1452
|
return {
|
|
1413
1453
|
selectClients: async (groups, defaults) => {
|
|
@@ -1424,14 +1464,7 @@ function clackPrompts() {
|
|
|
1424
1464
|
});
|
|
1425
1465
|
return p.isCancel(res) ? null : res;
|
|
1426
1466
|
},
|
|
1427
|
-
selectApp:
|
|
1428
|
-
const res = await p.select({
|
|
1429
|
-
message: "Multiple SvelteKit apps found \u2014 which one should the Vite/config targets go into?",
|
|
1430
|
-
options: apps.map((a) => ({ value: a, label: a })),
|
|
1431
|
-
initialValue: apps[0]
|
|
1432
|
-
});
|
|
1433
|
-
return p.isCancel(res) ? null : res;
|
|
1434
|
-
},
|
|
1467
|
+
selectApp: (apps) => selectAppPrompt(apps, "Multiple SvelteKit apps found \u2014 which one should the Vite/config targets go into?"),
|
|
1435
1468
|
confirm: async (planText) => {
|
|
1436
1469
|
const res = await p.confirm({ message: `Apply this plan?
|
|
1437
1470
|
${planText}` });
|
|
@@ -1440,13 +1473,7 @@ ${planText}` });
|
|
|
1440
1473
|
};
|
|
1441
1474
|
}
|
|
1442
1475
|
async function runInstallCli(args) {
|
|
1443
|
-
const argv =
|
|
1444
|
-
boolean: ["yes", "dry-run", "force", "refresh", "help"],
|
|
1445
|
-
// `scope` is still declared although the flag is gone: it keeps `--scope global` from
|
|
1446
|
-
// parsing its value as a positional, so resolveInstallArgs can warn and carry on.
|
|
1447
|
-
string: ["client", "scope", "app"],
|
|
1448
|
-
alias: { y: "yes", h: "help" }
|
|
1449
|
-
});
|
|
1476
|
+
const argv = parseInstallArgs(args);
|
|
1450
1477
|
if (argv.help) {
|
|
1451
1478
|
console.log(INSTALL_HELP);
|
|
1452
1479
|
return 0;
|
|
@@ -1460,7 +1487,6 @@ async function runInstallCli(args) {
|
|
|
1460
1487
|
|
|
1461
1488
|
// src/ci/cli.ts
|
|
1462
1489
|
import { join as join4 } from "path";
|
|
1463
|
-
import mri2 from "mri";
|
|
1464
1490
|
|
|
1465
1491
|
// src/ci/upgrade.ts
|
|
1466
1492
|
var CANONICAL_PATH = "oekazuma/svelte-vitals-action";
|
|
@@ -1529,10 +1555,7 @@ async function runCiCli(args, io = realIO()) {
|
|
|
1529
1555
|
io.log(CI_HELP);
|
|
1530
1556
|
return 2;
|
|
1531
1557
|
}
|
|
1532
|
-
const argv =
|
|
1533
|
-
boolean: ["force", "dry-run", "help"],
|
|
1534
|
-
alias: { h: "help" }
|
|
1535
|
-
});
|
|
1558
|
+
const argv = parseCliArgs(args.slice(1), { boolean: ["force", "dry-run", "help"], short: { h: "help" } });
|
|
1536
1559
|
if (argv.help) {
|
|
1537
1560
|
io.log(CI_HELP);
|
|
1538
1561
|
return 0;
|
|
@@ -1563,10 +1586,7 @@ async function runCiCli(args, io = realIO()) {
|
|
|
1563
1586
|
return 0;
|
|
1564
1587
|
}
|
|
1565
1588
|
async function runCiUpgrade(args, io) {
|
|
1566
|
-
const argv =
|
|
1567
|
-
boolean: ["dry-run", "help"],
|
|
1568
|
-
alias: { h: "help" }
|
|
1569
|
-
});
|
|
1589
|
+
const argv = parseCliArgs(args, { boolean: ["dry-run", "help"], short: { h: "help" } });
|
|
1570
1590
|
if (argv.help) {
|
|
1571
1591
|
io.log(CI_HELP);
|
|
1572
1592
|
return 0;
|
|
@@ -1602,7 +1622,6 @@ async function runCiUpgrade(args, io) {
|
|
|
1602
1622
|
}
|
|
1603
1623
|
|
|
1604
1624
|
// src/explain.ts
|
|
1605
|
-
import mri3 from "mri";
|
|
1606
1625
|
import { allRules as allRules2, CATEGORIES as CATEGORIES2, explainRule } from "@svelte-vitals/core";
|
|
1607
1626
|
var EXPLAIN_HELP = `svelte-vitals explain \u2014 print a rule's rationale, fix, and configurable options
|
|
1608
1627
|
|
|
@@ -1652,7 +1671,7 @@ function renderRuleList() {
|
|
|
1652
1671
|
);
|
|
1653
1672
|
}
|
|
1654
1673
|
function runExplainCli(args, io = consoleIO) {
|
|
1655
|
-
const argv =
|
|
1674
|
+
const argv = parseCliArgs(args, { boolean: ["json", "list", "help"], short: { h: "help" } });
|
|
1656
1675
|
if (argv.help) {
|
|
1657
1676
|
io.log(EXPLAIN_HELP);
|
|
1658
1677
|
return 0;
|
|
@@ -1750,17 +1769,13 @@ If you are an AI agent:
|
|
|
1750
1769
|
naming the flag to pass. \`install\` is the exception \u2014 non-interactively it skips its
|
|
1751
1770
|
confirmation and writes, so pass \`--dry-run\` first if you need to see the plan.`;
|
|
1752
1771
|
var VERSION = readPackageVersion();
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
message: "Multiple SvelteKit apps found \u2014 which one should svelte-vitals analyze?",
|
|
1756
|
-
options: apps.map((a) => ({ value: a, label: a }))
|
|
1757
|
-
});
|
|
1758
|
-
return p2.isCancel(res) ? null : res;
|
|
1772
|
+
function selectApp(apps) {
|
|
1773
|
+
return selectAppPrompt(apps, "Multiple SvelteKit apps found \u2014 which one should svelte-vitals analyze?");
|
|
1759
1774
|
}
|
|
1760
1775
|
async function main() {
|
|
1761
1776
|
const rawArgs = process.argv.slice(2);
|
|
1762
1777
|
if (rawArgs[0] === "docs") {
|
|
1763
|
-
const { runDocsCli } = await import("./cli-
|
|
1778
|
+
const { runDocsCli } = await import("./cli-LGD6NDAO.js");
|
|
1764
1779
|
process.exitCode = runDocsCli(rawArgs.slice(1));
|
|
1765
1780
|
return;
|
|
1766
1781
|
}
|
|
@@ -1776,25 +1791,7 @@ async function main() {
|
|
|
1776
1791
|
const code2 = await runCiCli(rawArgs.slice(1));
|
|
1777
1792
|
process.exit(code2);
|
|
1778
1793
|
}
|
|
1779
|
-
const argv =
|
|
1780
|
-
alias: { h: "help", v: "version" },
|
|
1781
|
-
boolean: ["by-route", "staged", "score", "verbose", "update-suppressions"],
|
|
1782
|
-
string: [
|
|
1783
|
-
"meta-components",
|
|
1784
|
-
"treat-dynamic-as",
|
|
1785
|
-
"route",
|
|
1786
|
-
"fail-on",
|
|
1787
|
-
"reporter",
|
|
1788
|
-
"rules",
|
|
1789
|
-
"ignore",
|
|
1790
|
-
"min-health",
|
|
1791
|
-
"out-file",
|
|
1792
|
-
"diff",
|
|
1793
|
-
"baseline",
|
|
1794
|
-
"weights",
|
|
1795
|
-
"category"
|
|
1796
|
-
]
|
|
1797
|
-
});
|
|
1794
|
+
const argv = parseRunArgs(rawArgs);
|
|
1798
1795
|
if (argv.help) {
|
|
1799
1796
|
console.log(HELP);
|
|
1800
1797
|
return;
|
|
@@ -1804,20 +1801,10 @@ async function main() {
|
|
|
1804
1801
|
console.error("svelte-vitals: run `svelte-vitals docs list` for the bundled guides.");
|
|
1805
1802
|
return;
|
|
1806
1803
|
}
|
|
1807
|
-
const { options, warnings, errors } = resolveArgs(argv);
|
|
1804
|
+
const { options, warnings, errors, minHealth } = resolveArgs(argv);
|
|
1808
1805
|
for (const w of warnings) console.error(w);
|
|
1809
1806
|
for (const e of errors) console.error(e);
|
|
1810
1807
|
if (!options) process.exit(2);
|
|
1811
|
-
const minHealthRaw = argv["min-health"];
|
|
1812
|
-
let minHealth;
|
|
1813
|
-
if (minHealthRaw !== void 0) {
|
|
1814
|
-
const n = Number(minHealthRaw);
|
|
1815
|
-
if (!Number.isFinite(n) || n < 0 || n > 100) {
|
|
1816
|
-
console.error(`svelte-vitals: invalid --min-health '${minHealthRaw}'; expected a number 0-100.`);
|
|
1817
|
-
process.exit(2);
|
|
1818
|
-
}
|
|
1819
|
-
minHealth = n;
|
|
1820
|
-
}
|
|
1821
1808
|
const code = await run({
|
|
1822
1809
|
...options,
|
|
1823
1810
|
minHealth,
|