@reddoorla/maintenance 0.15.0 → 0.17.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/cli/bin.js CHANGED
@@ -9,6 +9,54 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
+ // src/util/credentials.ts
13
+ import { readFileSync } from "fs";
14
+ import { homedir } from "os";
15
+ import { join } from "path";
16
+ function defaultCredentialsPath() {
17
+ const base = process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
18
+ return join(base, "reddoor-maint", "credentials.env");
19
+ }
20
+ function parseEnvFile(contents) {
21
+ const out = {};
22
+ for (const rawLine of contents.split(/\r?\n/)) {
23
+ const line = rawLine.trim();
24
+ if (!line || line.startsWith("#")) continue;
25
+ const eq = line.indexOf("=");
26
+ if (eq <= 0) continue;
27
+ const key = line.slice(0, eq).trim();
28
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;
29
+ let value = line.slice(eq + 1).trim();
30
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
31
+ value = value.slice(1, -1);
32
+ }
33
+ out[key] = value;
34
+ }
35
+ return out;
36
+ }
37
+ function loadCredentialsIntoEnv(path = defaultCredentialsPath()) {
38
+ let contents;
39
+ try {
40
+ contents = readFileSync(path, "utf-8");
41
+ } catch {
42
+ return [];
43
+ }
44
+ const parsed = parseEnvFile(contents);
45
+ const applied = [];
46
+ for (const [k, v] of Object.entries(parsed)) {
47
+ if (process.env[k] === void 0) {
48
+ process.env[k] = v;
49
+ applied.push(k);
50
+ }
51
+ }
52
+ return applied;
53
+ }
54
+ var init_credentials = __esm({
55
+ "src/util/credentials.ts"() {
56
+ "use strict";
57
+ }
58
+ });
59
+
12
60
  // src/reports/airtable/client.ts
13
61
  var client_exports = {};
14
62
  __export(client_exports, {
@@ -16,11 +64,19 @@ __export(client_exports, {
16
64
  readAirtableConfig: () => readAirtableConfig
17
65
  });
18
66
  import Airtable from "airtable";
67
+ function missing(name) {
68
+ return Object.assign(
69
+ new Error(
70
+ `${name} not set. Export it in your shell or put it in ${defaultCredentialsPath()} as ${name}=...`
71
+ ),
72
+ { exitCode: 2 }
73
+ );
74
+ }
19
75
  function readAirtableConfig() {
20
76
  const apiKey = process.env.AIRTABLE_PAT;
21
77
  const baseId = process.env.AIRTABLE_BASE_ID;
22
- if (!apiKey) throw Object.assign(new Error("AIRTABLE_PAT not set"), { exitCode: 2 });
23
- if (!baseId) throw Object.assign(new Error("AIRTABLE_BASE_ID not set"), { exitCode: 2 });
78
+ if (!apiKey) throw missing("AIRTABLE_PAT");
79
+ if (!baseId) throw missing("AIRTABLE_BASE_ID");
24
80
  return { apiKey, baseId };
25
81
  }
26
82
  function openBase(cfg) {
@@ -29,6 +85,7 @@ function openBase(cfg) {
29
85
  var init_client = __esm({
30
86
  "src/reports/airtable/client.ts"() {
31
87
  "use strict";
88
+ init_credentials();
32
89
  }
33
90
  });
34
91
 
@@ -179,7 +236,7 @@ __export(lighthouse_airtable_exports, {
179
236
  resolveSlugFromCwd: () => resolveSlugFromCwd
180
237
  });
181
238
  import { readFile as readFile7 } from "fs/promises";
182
- import { join as join7 } from "path";
239
+ import { join as join8 } from "path";
183
240
  function hasRealScores(result) {
184
241
  if (result.audit !== "lighthouse") return false;
185
242
  const details = result.details ?? {};
@@ -204,7 +261,7 @@ function lighthouseScoresFromResult(result) {
204
261
  }
205
262
  async function resolveSlugFromCwd(cwd) {
206
263
  try {
207
- const pkgPath = join7(cwd, "package.json");
264
+ const pkgPath = join8(cwd, "package.json");
208
265
  const raw = await readFile7(pkgPath, "utf-8");
209
266
  const pkg = JSON.parse(raw);
210
267
  if (!pkg.name) throw new Error("package.json has no 'name' field");
@@ -457,18 +514,18 @@ var init_reports = __esm({
457
514
  // src/reports/maintenance-email/assets/index.ts
458
515
  import { readFile as readFile13 } from "fs/promises";
459
516
  import { existsSync as existsSync3 } from "fs";
460
- import { dirname as dirname2, join as join21 } from "path";
517
+ import { dirname as dirname2, join as join22 } from "path";
461
518
  import { fileURLToPath as fileURLToPath2 } from "url";
462
519
  function resolveAssetsDir() {
463
520
  if (cachedAssetsDir) return cachedAssetsDir;
464
521
  let dir = dirname2(fileURLToPath2(import.meta.url));
465
522
  while (true) {
466
- const srcCandidate = join21(dir, "src", "reports", "maintenance-email", "assets", "check.png");
523
+ const srcCandidate = join22(dir, "src", "reports", "maintenance-email", "assets", "check.png");
467
524
  if (existsSync3(srcCandidate)) {
468
525
  cachedAssetsDir = dirname2(srcCandidate);
469
526
  return cachedAssetsDir;
470
527
  }
471
- const distCandidate = join21(dir, "dist", "reports", "maintenance-email", "assets", "check.png");
528
+ const distCandidate = join22(dir, "dist", "reports", "maintenance-email", "assets", "check.png");
472
529
  if (existsSync3(distCandidate)) {
473
530
  cachedAssetsDir = dirname2(distCandidate);
474
531
  return cachedAssetsDir;
@@ -485,8 +542,8 @@ function resolveAssetsDir() {
485
542
  async function loadBundledImages() {
486
543
  const assetsDir = resolveAssetsDir();
487
544
  const [check, blurred] = await Promise.all([
488
- readFile13(join21(assetsDir, "check.png")),
489
- readFile13(join21(assetsDir, "blurredTests.jpg"))
545
+ readFile13(join22(assetsDir, "check.png")),
546
+ readFile13(join22(assetsDir, "blurredTests.jpg"))
490
547
  ]);
491
548
  return {
492
549
  check: {
@@ -932,6 +989,7 @@ var init_orchestrate = __esm({
932
989
  });
933
990
 
934
991
  // src/cli/bin.ts
992
+ init_credentials();
935
993
  import { dirname as dirname6 } from "path";
936
994
  import { fileURLToPath as fileURLToPath3 } from "url";
937
995
  import { cac } from "cac";
@@ -971,7 +1029,7 @@ var defaultSpawn = (cmd, args, opts = {}) => new Promise((resolve10, reject) =>
971
1029
 
972
1030
  // src/audits/deps.ts
973
1031
  import { readFile } from "fs/promises";
974
- import { join } from "path";
1032
+ import { join as join2 } from "path";
975
1033
 
976
1034
  // src/util/site.ts
977
1035
  function siteLabel(site) {
@@ -1038,7 +1096,7 @@ function compareSemver(actual, baseline) {
1038
1096
  return "same";
1039
1097
  }
1040
1098
  async function depsAudit(ctx) {
1041
- const pkgPath = join(ctx.site.path, "package.json");
1099
+ const pkgPath = join2(ctx.site.path, "package.json");
1042
1100
  let pkgRaw;
1043
1101
  try {
1044
1102
  pkgRaw = await readFile(pkgPath, "utf-8");
@@ -1084,7 +1142,7 @@ async function depsAudit(ctx) {
1084
1142
  // src/audits/lint.ts
1085
1143
  import { existsSync } from "fs";
1086
1144
  import { readFile as readFile2 } from "fs/promises";
1087
- import { join as join2 } from "path";
1145
+ import { join as join3 } from "path";
1088
1146
  import { ESLint } from "eslint";
1089
1147
  import { check as prettierCheck, resolveConfig as prettierResolveConfig } from "prettier";
1090
1148
  import { glob } from "tinyglobby";
@@ -1095,7 +1153,7 @@ async function listFiles(cwd) {
1095
1153
  }
1096
1154
  async function lintAudit(ctx) {
1097
1155
  const { site } = ctx;
1098
- const configPath = join2(site.path, "eslint.config.js");
1156
+ const configPath = join3(site.path, "eslint.config.js");
1099
1157
  if (!existsSync(configPath)) {
1100
1158
  return {
1101
1159
  audit: "lint",
@@ -1115,7 +1173,7 @@ async function lintAudit(ctx) {
1115
1173
  const eslintWarnings = eslintResults.reduce((n, r) => n + r.warningCount, 0);
1116
1174
  const prettierUnformatted = [];
1117
1175
  for (const rel of relFiles) {
1118
- const absForResolve = join2(site.path, rel);
1176
+ const absForResolve = join3(site.path, rel);
1119
1177
  const source = await readFile2(absForResolve, "utf-8");
1120
1178
  const options = await prettierResolveConfig(absForResolve) ?? {};
1121
1179
  const ok = await prettierCheck(source, { ...options, filepath: absForResolve });
@@ -1279,7 +1337,7 @@ async function securityAudit(ctx) {
1279
1337
  // src/audits/lighthouse.ts
1280
1338
  import { readFile as readFile4, writeFile, mkdtemp, rm, readdir } from "fs/promises";
1281
1339
  import { tmpdir } from "os";
1282
- import { join as join4 } from "path";
1340
+ import { join as join5 } from "path";
1283
1341
 
1284
1342
  // src/configs/lighthouse.ts
1285
1343
  var lighthouseConfig = {
@@ -1314,11 +1372,11 @@ var lighthouseConfig = {
1314
1372
 
1315
1373
  // src/audits/util/site-config.ts
1316
1374
  import { readFile as readFile3 } from "fs/promises";
1317
- import { join as join3 } from "path";
1375
+ import { join as join4 } from "path";
1318
1376
  async function readSiteConfig(sitePath) {
1319
1377
  let raw;
1320
1378
  try {
1321
- raw = await readFile3(join3(sitePath, "package.json"), "utf-8");
1379
+ raw = await readFile3(join4(sitePath, "package.json"), "utf-8");
1322
1380
  } catch {
1323
1381
  return {};
1324
1382
  }
@@ -1379,7 +1437,7 @@ async function readLhrEntries(resultsDir) {
1379
1437
  const entries = [];
1380
1438
  for (const f of files) {
1381
1439
  if (!f.startsWith("lhr-") || !f.endsWith(".json")) continue;
1382
- const lhr = await readJsonMaybe(join4(resultsDir, f));
1440
+ const lhr = await readJsonMaybe(join5(resultsDir, f));
1383
1441
  if (!lhr || !lhr.categories) continue;
1384
1442
  const summary = {};
1385
1443
  for (const [k, v] of Object.entries(lhr.categories)) {
@@ -1433,10 +1491,10 @@ async function lighthouseAudit(ctx) {
1433
1491
  }
1434
1492
  }
1435
1493
  };
1436
- const configDir = await mkdtemp(join4(tmpdir(), "reddoor-lhci-"));
1437
- const configPath = join4(configDir, "lighthouserc.json");
1494
+ const configDir = await mkdtemp(join5(tmpdir(), "reddoor-lhci-"));
1495
+ const configPath = join5(configDir, "lighthouserc.json");
1438
1496
  await writeFile(configPath, JSON.stringify(resolvedConfig), "utf-8");
1439
- const resultsDir = join4(site.path, ".lighthouseci");
1497
+ const resultsDir = join5(site.path, ".lighthouseci");
1440
1498
  await rm(resultsDir, { recursive: true, force: true });
1441
1499
  let raw;
1442
1500
  try {
@@ -1471,7 +1529,7 @@ async function lighthouseAudit(ctx) {
1471
1529
  summary: `lighthouse: no lhr-*.json written (exit ${raw.code})${raw.stderr ? ` \u2014 ${raw.stderr.slice(0, 200)}` : ""}`
1472
1530
  };
1473
1531
  }
1474
- const assertionResults = await readJsonMaybe(join4(resultsDir, "assertion-results.json")) ?? [];
1532
+ const assertionResults = await readJsonMaybe(join5(resultsDir, "assertion-results.json")) ?? [];
1475
1533
  const failed = assertionResults.filter((a) => !a.passed);
1476
1534
  const assertions = failed.map((a) => ({
1477
1535
  category: categoryFromAssertion(a),
@@ -1498,7 +1556,7 @@ async function lighthouseAudit(ctx) {
1498
1556
 
1499
1557
  // src/audits/a11y.ts
1500
1558
  import { readFile as readFile5, writeFile as writeFile2, mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
1501
- import { join as join5 } from "path";
1559
+ import { join as join6 } from "path";
1502
1560
 
1503
1561
  // src/configs/playwright-a11y.ts
1504
1562
  import { defineConfig, devices } from "@playwright/test";
@@ -1623,14 +1681,14 @@ async function a11yAudit(ctx) {
1623
1681
  const spawn2 = ctx.spawn ?? defaultSpawn;
1624
1682
  const site = ctx.site;
1625
1683
  const label = siteLabel(site);
1626
- const specDir = await mkdtemp2(join5(site.path, ".reddoor-a11y-spec-"));
1627
- const specPath = join5(specDir, "a11y.spec.ts");
1684
+ const specDir = await mkdtemp2(join6(site.path, ".reddoor-a11y-spec-"));
1685
+ const specPath = join6(specDir, "a11y.spec.ts");
1628
1686
  await writeFile2(specPath, buildSpec(), "utf-8");
1629
1687
  const port = await findFreePort();
1630
- const configPath = join5(specDir, "playwright.config.ts");
1688
+ const configPath = join6(specDir, "playwright.config.ts");
1631
1689
  await writeFile2(configPath, buildPlaywrightConfig(port, site.path), "utf-8");
1632
- const resultsPath = join5(site.path, RESULTS_REL);
1633
- await rm2(join5(site.path, ".reddoor-a11y"), { recursive: true, force: true });
1690
+ const resultsPath = join6(site.path, RESULTS_REL);
1691
+ await rm2(join6(site.path, ".reddoor-a11y"), { recursive: true, force: true });
1634
1692
  let raw;
1635
1693
  try {
1636
1694
  raw = await spawn2(
@@ -1806,7 +1864,7 @@ async function resolveSites(input) {
1806
1864
 
1807
1865
  // src/cli/fleet/clone-if-needed.ts
1808
1866
  import { stat, readdir as readdir2, mkdir } from "fs/promises";
1809
- import { isAbsolute as isAbsolute2, join as join6 } from "path";
1867
+ import { isAbsolute as isAbsolute2, join as join7 } from "path";
1810
1868
  function deriveNameFromRepoUrl(repoUrl) {
1811
1869
  const slash = repoUrl.split("/").pop() ?? repoUrl;
1812
1870
  return slash.replace(/\.git$/, "");
@@ -1847,7 +1905,7 @@ async function cloneIfNeeded(site, opts) {
1847
1905
  const name = site.name ?? deriveNameFromRepoUrl(site.repoUrl);
1848
1906
  assertSafeName(name);
1849
1907
  assertSafeRepoUrl(site.repoUrl);
1850
- const target = join6(opts.workdir, name);
1908
+ const target = join7(opts.workdir, name);
1851
1909
  await mkdir(opts.workdir, { recursive: true });
1852
1910
  if (await isNonEmptyDir(target)) {
1853
1911
  return { ...site, name, path: target };
@@ -2009,11 +2067,11 @@ ${formatWriteSummary(writeSummary)}`;
2009
2067
 
2010
2068
  // src/cli/commands/sync-configs.ts
2011
2069
  import { readFile as readFile9 } from "fs/promises";
2012
- import { join as join9, resolve as resolve3 } from "path";
2070
+ import { join as join10, resolve as resolve3 } from "path";
2013
2071
 
2014
2072
  // src/recipes/sync-configs.ts
2015
2073
  import { readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
2016
- import { join as join8 } from "path";
2074
+ import { join as join9 } from "path";
2017
2075
 
2018
2076
  // src/recipes/sync-configs/templates.ts
2019
2077
  var eslint = {
@@ -2286,13 +2344,13 @@ async function readMaybe(path) {
2286
2344
  async function planTemplateDiffs(cwd, templates) {
2287
2345
  const diffs = [];
2288
2346
  for (const t of templates) {
2289
- const existing = await readMaybe(join8(cwd, t.path));
2347
+ const existing = await readMaybe(join9(cwd, t.path));
2290
2348
  if (existing !== t.contents) diffs.push(t);
2291
2349
  }
2292
2350
  return diffs;
2293
2351
  }
2294
2352
  async function planGitignore(cwd) {
2295
- const existing = await readMaybe(join8(cwd, ".gitignore"));
2353
+ const existing = await readMaybe(join9(cwd, ".gitignore"));
2296
2354
  const merge = mergeGitignore(existing, CANONICAL_GITIGNORE_ENTRIES);
2297
2355
  const tracked = await listTrackedFiles(cwd);
2298
2356
  const toUntrack = findTrackedArtifacts(tracked, CANONICAL_GITIGNORE_ENTRIES);
@@ -2300,7 +2358,7 @@ async function planGitignore(cwd) {
2300
2358
  return { kind: "apply", content: merge.content, toUntrack, added: merge.added };
2301
2359
  }
2302
2360
  async function applyGitignore(cwd, plan) {
2303
- await writeFile3(join8(cwd, ".gitignore"), plan.content, "utf-8");
2361
+ await writeFile3(join9(cwd, ".gitignore"), plan.content, "utf-8");
2304
2362
  if (plan.toUntrack.length > 0) {
2305
2363
  await removeFromIndex(cwd, plan.toUntrack);
2306
2364
  }
@@ -2323,7 +2381,7 @@ async function syncConfigs(site, opts = {}) {
2323
2381
  },
2324
2382
  apply: async ({ templateDiffs, gitignorePlan }, { commit: commit2 }) => {
2325
2383
  for (const t of templateDiffs) {
2326
- await writeFile3(join8(site.path, t.path), t.contents, "utf-8");
2384
+ await writeFile3(join9(site.path, t.path), t.contents, "utf-8");
2327
2385
  await commit2(`chore: sync ${t.config} config from @reddoorla/maintenance`);
2328
2386
  }
2329
2387
  if (gitignorePlan.kind === "apply") {
@@ -2352,7 +2410,7 @@ function parseOnly2(value) {
2352
2410
  async function dryPlanGitignore(cwd) {
2353
2411
  let existing;
2354
2412
  try {
2355
- existing = await readFile9(join9(cwd, ".gitignore"), "utf-8");
2413
+ existing = await readFile9(join10(cwd, ".gitignore"), "utf-8");
2356
2414
  } catch {
2357
2415
  return "would create .gitignore";
2358
2416
  }
@@ -2367,7 +2425,7 @@ async function dryPlan(cwd, which) {
2367
2425
  for (const t of templateTargets) {
2368
2426
  let existing = "";
2369
2427
  try {
2370
- existing = await readFile9(join9(cwd, t.path), "utf-8");
2428
+ existing = await readFile9(join10(cwd, t.path), "utf-8");
2371
2429
  } catch {
2372
2430
  }
2373
2431
  if (existing !== t.contents) lines.push(`would update ${t.path} (config: ${t.config})`);
@@ -2415,7 +2473,7 @@ import { resolve as resolve4 } from "path";
2415
2473
 
2416
2474
  // src/recipes/bump-deps.ts
2417
2475
  import { stat as stat2 } from "fs/promises";
2418
- import { join as join10 } from "path";
2476
+ import { join as join11 } from "path";
2419
2477
  async function exists(path) {
2420
2478
  try {
2421
2479
  await stat2(path);
@@ -2444,10 +2502,10 @@ async function bumpDeps(site, opts = {}) {
2444
2502
  // land on top of whatever else was in the tree.
2445
2503
  checkTreeFirst: true,
2446
2504
  plan: async () => {
2447
- const hasPnpmLock = await exists(join10(site.path, "pnpm-lock.yaml"));
2505
+ const hasPnpmLock = await exists(join11(site.path, "pnpm-lock.yaml"));
2448
2506
  if (!hasPnpmLock) {
2449
- const hasNpmLock = await exists(join10(site.path, "package-lock.json"));
2450
- const hasYarnLock = await exists(join10(site.path, "yarn.lock"));
2507
+ const hasNpmLock = await exists(join11(site.path, "package-lock.json"));
2508
+ const hasYarnLock = await exists(join11(site.path, "yarn.lock"));
2451
2509
  if (hasNpmLock || hasYarnLock) {
2452
2510
  const competing = hasNpmLock ? "package-lock.json" : "yarn.lock";
2453
2511
  return {
@@ -2517,7 +2575,7 @@ async function runBumpDepsCommand(site, opts) {
2517
2575
  import { resolve as resolve5 } from "path";
2518
2576
 
2519
2577
  // src/recipes/svelte-5/index.ts
2520
- import { join as join16 } from "path";
2578
+ import { join as join17 } from "path";
2521
2579
 
2522
2580
  // src/util/pkg.ts
2523
2581
  import { readFile as readFile10, writeFile as writeFile4 } from "fs/promises";
@@ -2566,7 +2624,7 @@ function bumpDep(pkg, name, version2, opts = {}) {
2566
2624
  }
2567
2625
 
2568
2626
  // src/recipes/svelte-5/step-bump-versions.ts
2569
- import { join as join11 } from "path";
2627
+ import { join as join12 } from "path";
2570
2628
  var SVELTE_5_VERSIONS = {
2571
2629
  svelte: "^5.55.5",
2572
2630
  "@sveltejs/kit": "^2.59.0",
@@ -2579,7 +2637,7 @@ var SVELTE_5_VERSIONS = {
2579
2637
  "typescript-svelte-plugin": "^0.3.52"
2580
2638
  };
2581
2639
  async function bumpToSvelte5Versions(cwd) {
2582
- const pkgPath = join11(cwd, "package.json");
2640
+ const pkgPath = join12(cwd, "package.json");
2583
2641
  const pkg = await readPackageJson(pkgPath);
2584
2642
  let next = pkg;
2585
2643
  for (const [name, version2] of Object.entries(SVELTE_5_VERSIONS)) {
@@ -2592,7 +2650,7 @@ async function bumpToSvelte5Versions(cwd) {
2592
2650
 
2593
2651
  // src/recipes/svelte-5/step-svelte-config.ts
2594
2652
  import { readFile as readFile11, writeFile as writeFile5 } from "fs/promises";
2595
- import { join as join12 } from "path";
2653
+ import { join as join13 } from "path";
2596
2654
  var VITE_PLUGIN_PKG = "@sveltejs/vite-plugin-svelte";
2597
2655
  var IMPORT_FROM_VITE_PLUGIN = new RegExp(
2598
2656
  String.raw`^import\s+\{\s*([^}]+?)\s*\}\s+from\s+["']` + VITE_PLUGIN_PKG.replace(/[/]/g, "\\/") + String.raw`["'];?[ \t]*\n`,
@@ -2633,7 +2691,7 @@ function dropPreprocessKey(source) {
2633
2691
  return source.slice(0, m.index) + source.slice(tailIdx).replace(new RegExp(`^${indent}\\n`), "");
2634
2692
  }
2635
2693
  async function migrateSvelteConfig(cwd) {
2636
- const path = join12(cwd, "svelte.config.js");
2694
+ const path = join13(cwd, "svelte.config.js");
2637
2695
  let src;
2638
2696
  try {
2639
2697
  src = await readFile11(path, "utf-8");
@@ -2670,9 +2728,9 @@ async function runSvelteMigrate(cwd, spawn2 = defaultSpawn) {
2670
2728
  }
2671
2729
 
2672
2730
  // src/recipes/svelte-5/step-tailwind-upgrade.ts
2673
- import { join as join13 } from "path";
2731
+ import { join as join14 } from "path";
2674
2732
  async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
2675
- const pkg = await readPackageJson(join13(cwd, "package.json"));
2733
+ const pkg = await readPackageJson(join14(cwd, "package.json"));
2676
2734
  const tailwindVersion = pkg.devDependencies?.tailwindcss ?? pkg.dependencies?.tailwindcss;
2677
2735
  if (!tailwindVersion) return { ran: false, reason: "tailwindcss not installed" };
2678
2736
  if (/^\^?4\./.test(tailwindVersion)) return { ran: false, reason: "already on tailwind 4.x" };
@@ -2694,7 +2752,7 @@ async function upgradeTailwind(cwd, spawn2 = defaultSpawn) {
2694
2752
 
2695
2753
  // src/recipes/svelte-5/step-gotchas.ts
2696
2754
  import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
2697
- import { join as join14 } from "path";
2755
+ import { join as join15 } from "path";
2698
2756
  import { glob as glob2 } from "tinyglobby";
2699
2757
 
2700
2758
  // src/recipes/svelte-5/codemods/on-event-to-handler.ts
@@ -3040,7 +3098,7 @@ async function planGotchaCodemods(cwd) {
3040
3098
  const changes = [];
3041
3099
  const relPaths = await glob2(SVELTE_GLOBS, { cwd, ignore: IGNORE2, absolute: false });
3042
3100
  for (const rel of relPaths) {
3043
- const path = join14(cwd, rel);
3101
+ const path = join15(cwd, rel);
3044
3102
  const before = await readFile12(path, "utf-8");
3045
3103
  const after = CODEMODS.reduce((s, fn) => fn(s), before);
3046
3104
  if (after !== before) changes.push({ rel, after });
@@ -3050,7 +3108,7 @@ async function planGotchaCodemods(cwd) {
3050
3108
  async function applyGotchaCodemods(cwd) {
3051
3109
  const changes = await planGotchaCodemods(cwd);
3052
3110
  for (const c of changes) {
3053
- await writeFile6(join14(cwd, c.rel), c.after, "utf-8");
3111
+ await writeFile6(join15(cwd, c.rel), c.after, "utf-8");
3054
3112
  }
3055
3113
  return { filesChanged: changes.length };
3056
3114
  }
@@ -3074,7 +3132,7 @@ async function verifyMigration(cwd, spawn2 = defaultSpawn) {
3074
3132
 
3075
3133
  // src/recipes/svelte-5/step-summary.ts
3076
3134
  import { writeFile as writeFile7 } from "fs/promises";
3077
- import { join as join15 } from "path";
3135
+ import { join as join16 } from "path";
3078
3136
  async function writeMigrationSummary(input) {
3079
3137
  const lines = [
3080
3138
  `# Svelte 4 \u2192 5 migration summary`,
@@ -3091,7 +3149,7 @@ async function writeMigrationSummary(input) {
3091
3149
  `- Verify Playwright a11y tests still pass.`
3092
3150
  ];
3093
3151
  const content = lines.join("\n") + "\n";
3094
- const path = join15(input.cwd, "MIGRATION_SVELTE_5.md");
3152
+ const path = join16(input.cwd, "MIGRATION_SVELTE_5.md");
3095
3153
  await writeFile7(path, content, "utf-8");
3096
3154
  return path;
3097
3155
  }
@@ -3099,7 +3157,7 @@ async function writeMigrationSummary(input) {
3099
3157
  // src/recipes/svelte-5/index.ts
3100
3158
  async function alreadyOnSvelte5(cwd) {
3101
3159
  try {
3102
- const pkg = await readPackageJson(join16(cwd, "package.json"));
3160
+ const pkg = await readPackageJson(join17(cwd, "package.json"));
3103
3161
  const v = pkg.devDependencies?.svelte ?? pkg.dependencies?.svelte;
3104
3162
  return !!v && /^\^?5\./.test(v);
3105
3163
  } catch {
@@ -3194,7 +3252,7 @@ import { resolve as resolve6 } from "path";
3194
3252
 
3195
3253
  // src/recipes/convert-to-pnpm.ts
3196
3254
  import { rm as rm3, stat as stat3 } from "fs/promises";
3197
- import { join as join17 } from "path";
3255
+ import { join as join18 } from "path";
3198
3256
 
3199
3257
  // src/recipes/convert-to-pnpm/script-rewrites.ts
3200
3258
  function rewriteScriptForPnpm(script) {
@@ -3227,9 +3285,9 @@ async function exists2(path) {
3227
3285
  async function convertToPnpm(site, opts = {}) {
3228
3286
  const spawn2 = opts.spawn ?? defaultSpawn;
3229
3287
  const pnpmVersion = opts.pnpmVersion ?? DEFAULT_PNPM_VERSION;
3230
- const pnpmLockPath = join17(site.path, "pnpm-lock.yaml");
3231
- const npmLockPath = join17(site.path, "package-lock.json");
3232
- const yarnLockPath = join17(site.path, "yarn.lock");
3288
+ const pnpmLockPath = join18(site.path, "pnpm-lock.yaml");
3289
+ const npmLockPath = join18(site.path, "package-lock.json");
3290
+ const yarnLockPath = join18(site.path, "yarn.lock");
3233
3291
  return withRecipe({
3234
3292
  name: "convert-to-pnpm",
3235
3293
  site,
@@ -3252,7 +3310,7 @@ async function convertToPnpm(site, opts = {}) {
3252
3310
  if (hasYarnLock) await rm3(yarnLockPath, { force: true });
3253
3311
  const sourceLock = hasNpmLock ? "package-lock.json" : "yarn.lock";
3254
3312
  await commit2(`chore(pnpm): remove ${sourceLock}`);
3255
- const pkgPath = join17(cwd, "package.json");
3313
+ const pkgPath = join18(cwd, "package.json");
3256
3314
  const pkg = await readPackageJson(pkgPath);
3257
3315
  const next = { ...pkg, packageManager: `pnpm@${pnpmVersion}` };
3258
3316
  if (pkg.scripts && typeof pkg.scripts === "object") {
@@ -3265,7 +3323,7 @@ async function convertToPnpm(site, opts = {}) {
3265
3323
  }
3266
3324
  await writePackageJson(pkgPath, next);
3267
3325
  await commit2("chore(pnpm): pin packageManager + rewrite npm scripts");
3268
- await rm3(join17(cwd, "node_modules"), { recursive: true, force: true });
3326
+ await rm3(join18(cwd, "node_modules"), { recursive: true, force: true });
3269
3327
  const installResult = await spawn2("pnpm", ["install"], { cwd, streaming: true });
3270
3328
  if (installResult.code !== 0) {
3271
3329
  return { kind: "failed", notes: `pnpm install failed (exit ${installResult.code})` };
@@ -3306,19 +3364,19 @@ import { resolve as resolve7 } from "path";
3306
3364
 
3307
3365
  // src/recipes/onboard.ts
3308
3366
  import { stat as stat4 } from "fs/promises";
3309
- import { join as join19 } from "path";
3367
+ import { join as join20 } from "path";
3310
3368
 
3311
3369
  // src/util/self-version.ts
3312
- import { readFileSync, existsSync as existsSync2 } from "fs";
3370
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
3313
3371
  import { fileURLToPath } from "url";
3314
- import { dirname, join as join18 } from "path";
3372
+ import { dirname, join as join19 } from "path";
3315
3373
  function selfPackageVersion(callerImportMetaUrl) {
3316
3374
  try {
3317
3375
  let dir = dirname(fileURLToPath(callerImportMetaUrl));
3318
3376
  while (true) {
3319
- const candidate = join18(dir, "package.json");
3377
+ const candidate = join19(dir, "package.json");
3320
3378
  if (existsSync2(candidate)) {
3321
- const raw = readFileSync(candidate, "utf-8");
3379
+ const raw = readFileSync2(candidate, "utf-8");
3322
3380
  const pkg = JSON.parse(raw);
3323
3381
  if (pkg.name === "@reddoorla/maintenance") {
3324
3382
  return pkg.version ?? "0.0.0";
@@ -3375,13 +3433,13 @@ async function onboard(site, opts = {}) {
3375
3433
  name: "onboard",
3376
3434
  site,
3377
3435
  plan: async () => {
3378
- if (!await exists3(join19(site.path, "pnpm-lock.yaml"))) {
3436
+ if (!await exists3(join20(site.path, "pnpm-lock.yaml"))) {
3379
3437
  return {
3380
3438
  kind: "failed",
3381
3439
  notes: "no pnpm-lock.yaml at site root \u2014 run convert-to-pnpm first"
3382
3440
  };
3383
3441
  }
3384
- const pkgPath = join19(site.path, "package.json");
3442
+ const pkgPath = join20(site.path, "package.json");
3385
3443
  const pkg = await readPackageJson(pkgPath);
3386
3444
  const toAdd = [];
3387
3445
  if (!isDeclared(pkg, PACKAGE_NAME)) {
@@ -3401,7 +3459,7 @@ async function onboard(site, opts = {}) {
3401
3459
  return { kind: "apply", plan: { pkg, toAdd } };
3402
3460
  },
3403
3461
  apply: async ({ pkg, toAdd }, { commit: commit2, cwd }) => {
3404
- const pkgPath = join19(cwd, "package.json");
3462
+ const pkgPath = join20(cwd, "package.json");
3405
3463
  let next = pkg;
3406
3464
  for (const dep of toAdd) {
3407
3465
  next = bumpDep(next, dep.name, dep.version);
@@ -3470,7 +3528,7 @@ import { resolve as resolve8 } from "path";
3470
3528
 
3471
3529
  // src/recipes/svelte-codemods.ts
3472
3530
  import { writeFile as writeFile8 } from "fs/promises";
3473
- import { join as join20 } from "path";
3531
+ import { join as join21 } from "path";
3474
3532
  async function svelteCodemods(site) {
3475
3533
  return withRecipe({
3476
3534
  name: "svelte-codemods",
@@ -3484,7 +3542,7 @@ async function svelteCodemods(site) {
3484
3542
  },
3485
3543
  apply: async (changes, { commit: commit2, cwd }) => {
3486
3544
  for (const c of changes) {
3487
- await writeFile8(join20(cwd, c.rel), c.after, "utf-8");
3545
+ await writeFile8(join21(cwd, c.rel), c.after, "utf-8");
3488
3546
  }
3489
3547
  await commit2(`refactor(svelte5): apply codemods (${changes.length} files)`);
3490
3548
  return { kind: "ok" };
@@ -3711,7 +3769,7 @@ import { resolve as resolve9 } from "path";
3711
3769
 
3712
3770
  // src/recipes/a11y-fixtures-page/index.ts
3713
3771
  import { access, mkdir as mkdir3, writeFile as writeFile10 } from "fs/promises";
3714
- import { dirname as dirname4, join as join22 } from "path";
3772
+ import { dirname as dirname4, join as join23 } from "path";
3715
3773
 
3716
3774
  // src/recipes/a11y-fixtures-page/template.ts
3717
3775
  var A11Y_FIXTURES_PAGE_RELATIVE = "src/routes/dev/a11y-fixtures/+page.svelte";
@@ -3762,7 +3820,7 @@ async function fileExists(path) {
3762
3820
  }
3763
3821
  }
3764
3822
  async function a11yFixturesPage(site) {
3765
- const target = join22(site.path, A11Y_FIXTURES_PAGE_RELATIVE);
3823
+ const target = join23(site.path, A11Y_FIXTURES_PAGE_RELATIVE);
3766
3824
  return withRecipe({
3767
3825
  name: "a11y-fixtures-page",
3768
3826
  site,
@@ -3869,15 +3927,15 @@ async function runInitCommand(site, opts) {
3869
3927
  }
3870
3928
 
3871
3929
  // src/cli/version.ts
3872
- import { readFileSync as readFileSync2, existsSync as existsSync4 } from "fs";
3873
- import { dirname as dirname5, join as join23 } from "path";
3930
+ import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
3931
+ import { dirname as dirname5, join as join24 } from "path";
3874
3932
  function resolvePackageVersion(fromDir) {
3875
3933
  try {
3876
3934
  let dir = fromDir;
3877
3935
  while (true) {
3878
- const candidate = join23(dir, "package.json");
3936
+ const candidate = join24(dir, "package.json");
3879
3937
  if (existsSync4(candidate)) {
3880
- const raw = readFileSync2(candidate, "utf-8");
3938
+ const raw = readFileSync3(candidate, "utf-8");
3881
3939
  const pkg = JSON.parse(raw);
3882
3940
  if (pkg.name === "@reddoorla/maintenance") {
3883
3941
  return pkg.version ?? "unknown";
@@ -3893,6 +3951,7 @@ function resolvePackageVersion(fromDir) {
3893
3951
  }
3894
3952
 
3895
3953
  // src/cli/bin.ts
3954
+ loadCredentialsIntoEnv();
3896
3955
  var here = dirname6(fileURLToPath3(import.meta.url));
3897
3956
  var version = resolvePackageVersion(here);
3898
3957
  var AUDIT_DESCRIPTIONS = {