@reddoorla/maintenance 0.14.0 → 0.15.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.
@@ -348,6 +348,7 @@ var init_write_audits_to_airtable = __esm({
348
348
 
349
349
  // src/cli/commands/audit.ts
350
350
  import { resolve as resolve2 } from "path";
351
+ import { Listr } from "listr2";
351
352
 
352
353
  // src/audits/util/spawn.ts
353
354
  import { spawn } from "child_process";
@@ -1104,29 +1105,20 @@ var DEFAULT_AUDIT_TIMEOUT_MS = 3e4;
1104
1105
  function timedSpawn(timeoutMs) {
1105
1106
  return (cmd, args, opts = {}) => defaultSpawn(cmd, args, { ...opts, timeoutMs: opts.timeoutMs ?? timeoutMs });
1106
1107
  }
1107
- async function runAudits(site, which) {
1108
- const names = which ?? ALL_AUDIT_NAMES;
1109
- for (const n of names) {
1110
- if (!(n in REGISTRY)) throw new Error(`unknown audit: ${n}`);
1111
- }
1108
+ async function runOneAudit(site, name) {
1109
+ if (!(name in REGISTRY)) throw new Error(`unknown audit: ${name}`);
1112
1110
  const spawn2 = timedSpawn(DEFAULT_AUDIT_TIMEOUT_MS);
1113
1111
  const label = site.name ?? site.path;
1114
- return Promise.all(
1115
- names.map(
1116
- (n) => REGISTRY[n]({ site, spawn: spawn2 }).catch(
1117
- (err) => ({
1118
- audit: n,
1119
- site: label,
1120
- status: "fail",
1121
- summary: `${n}: unexpected error \u2014 ${String(err)}`
1122
- })
1123
- )
1124
- )
1125
- );
1126
- }
1127
- async function runAuditsAcross(sites, which) {
1128
- const all = await Promise.all(sites.map((s) => runAudits(s, which)));
1129
- return all.flat();
1112
+ try {
1113
+ return await REGISTRY[name]({ site, spawn: spawn2 });
1114
+ } catch (err) {
1115
+ return {
1116
+ audit: name,
1117
+ site: label,
1118
+ status: "fail",
1119
+ summary: `${name}: unexpected error \u2014 ${String(err)}`
1120
+ };
1121
+ }
1130
1122
  }
1131
1123
 
1132
1124
  // src/cli/fleet/resolve-sites.ts
@@ -1292,8 +1284,87 @@ function formatTable(results) {
1292
1284
  function exitCode(results) {
1293
1285
  return results.some((r) => r.status === "fail") ? 1 : 0;
1294
1286
  }
1287
+ function formatDuration(ms) {
1288
+ if (ms < 1e3) return `${ms}ms`;
1289
+ const totalSeconds = Math.round(ms / 1e3);
1290
+ if (totalSeconds < 60) return `${totalSeconds}s`;
1291
+ const m = Math.floor(totalSeconds / 60);
1292
+ const s = totalSeconds % 60;
1293
+ return `${m}m${s.toString().padStart(2, "0")}s`;
1294
+ }
1295
+ function buildAuditTasks(sites, which, results, renderer) {
1296
+ const singleSite = sites.length === 1;
1297
+ if (singleSite) {
1298
+ const site = sites[0];
1299
+ return new Listr(
1300
+ which.map((name) => ({
1301
+ title: name,
1302
+ task: async (_ctx, task) => {
1303
+ const start = Date.now();
1304
+ const result = await runOneAudit(site, name);
1305
+ results.push(result);
1306
+ const elapsed = formatDuration(Date.now() - start);
1307
+ task.title = `${name}: ${result.summary} (${elapsed})`;
1308
+ if (result.status === "fail") throw new Error(result.summary);
1309
+ }
1310
+ })),
1311
+ { concurrent: true, exitOnError: false, renderer }
1312
+ );
1313
+ }
1314
+ return new Listr(
1315
+ sites.map((site) => {
1316
+ const label = site.name ?? site.path;
1317
+ return {
1318
+ title: label,
1319
+ task: async (_ctx, task) => {
1320
+ const start = Date.now();
1321
+ let done = 0;
1322
+ task.output = `0/${which.length} audits`;
1323
+ const settled = await Promise.all(
1324
+ which.map(async (name) => {
1325
+ const r = await runOneAudit(site, name);
1326
+ results.push(r);
1327
+ done += 1;
1328
+ task.output = `${done}/${which.length} audits`;
1329
+ return r;
1330
+ })
1331
+ );
1332
+ const elapsed = formatDuration(Date.now() - start);
1333
+ const failed = settled.filter((r) => r.status === "fail").length;
1334
+ const warned = settled.filter((r) => r.status === "warn").length;
1335
+ const note = failed > 0 ? `${failed} failed` : warned > 0 ? `${warned} warning${warned === 1 ? "" : "s"}` : "all green";
1336
+ task.title = `${label}: ${note} (${elapsed})`;
1337
+ if (failed > 0) throw new Error(`${label}: ${failed} audit(s) failed`);
1338
+ }
1339
+ };
1340
+ }),
1341
+ { concurrent: true, exitOnError: false, renderer }
1342
+ );
1343
+ }
1344
+ function formatWriteSummary(summary) {
1345
+ const lines = summary.writes.map((w) => {
1346
+ if (w.audit === "lighthouse") {
1347
+ const s = w.counts;
1348
+ return ` lighthouse: P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo}`;
1349
+ }
1350
+ if (w.audit === "a11y") {
1351
+ return ` a11y: ${w.counts.violations} violations`;
1352
+ }
1353
+ if (w.audit === "deps") {
1354
+ const c2 = w.counts;
1355
+ return ` deps: ${c2.drifted} drifted (${c2.majorBehind} major)`;
1356
+ }
1357
+ const c = w.counts;
1358
+ return ` security: ${c.critical}C/${c.high}H/${c.moderate}M/${c.low}L`;
1359
+ });
1360
+ return `\u2192 wrote to Websites[${summary.siteName}]:
1361
+ ${lines.join("\n")}`;
1362
+ }
1363
+ function rendererFor(json) {
1364
+ return json ? "silent" : "default";
1365
+ }
1295
1366
  async function runAuditCommand(site, opts) {
1296
- const which = parseOnly(opts.only);
1367
+ const which = parseOnly(opts.only) ?? ALL_AUDIT_NAMES;
1297
1368
  const cwd = opts.cwd ? resolve2(opts.cwd) : process.cwd();
1298
1369
  let sites = await resolveSites({
1299
1370
  ...site !== void 0 ? { site } : {},
@@ -1305,7 +1376,9 @@ async function runAuditCommand(site, opts) {
1305
1376
  const workdir = opts.workdir ?? `${process.env.HOME ?? ""}/.reddoor-maint/sites`;
1306
1377
  sites = await Promise.all(sites.map((s) => cloneIfNeeded(s, { workdir })));
1307
1378
  }
1308
- const results = await runAuditsAcross(sites, which);
1379
+ const results = [];
1380
+ const renderer = rendererFor(opts.json);
1381
+ await buildAuditTasks(sites, which, results, renderer).run();
1309
1382
  let output = opts.json ? JSON.stringify(results, null, 2) : formatTable(results);
1310
1383
  if (opts.writeAirtable !== void 0) {
1311
1384
  const { openBase: openBase2, readAirtableConfig: readAirtableConfig2 } = await Promise.resolve().then(() => (init_client(), client_exports));
@@ -1313,28 +1386,26 @@ async function runAuditCommand(site, opts) {
1313
1386
  const { resolveSlugFromCwd: resolveSlugFromCwd2 } = await Promise.resolve().then(() => (init_lighthouse_airtable(), lighthouse_airtable_exports));
1314
1387
  const { writeAuditsToAirtable: writeAuditsToAirtable2 } = await Promise.resolve().then(() => (init_write_audits_to_airtable(), write_audits_to_airtable_exports));
1315
1388
  const slug = typeof opts.writeAirtable === "string" && opts.writeAirtable.length > 0 ? opts.writeAirtable : await resolveSlugFromCwd2(cwd);
1316
- const base = openBase2(readAirtableConfig2());
1317
- const websites = await listWebsites2(base);
1318
- const summary = await writeAuditsToAirtable2({ base, websites, slug, results });
1319
- const lines = summary.writes.map((w) => {
1320
- if (w.audit === "lighthouse") {
1321
- const s = w.counts;
1322
- return ` lighthouse: P=${s.performance} A=${s.accessibility} BP=${s.bestPractices} SEO=${s.seo}`;
1323
- }
1324
- if (w.audit === "a11y") {
1325
- return ` a11y: ${w.counts.violations} violations`;
1326
- }
1327
- if (w.audit === "deps") {
1328
- const c2 = w.counts;
1329
- return ` deps: ${c2.drifted} drifted (${c2.majorBehind} major)`;
1330
- }
1331
- const c = w.counts;
1332
- return ` security: ${c.critical}C/${c.high}H/${c.moderate}M/${c.low}L`;
1333
- });
1334
- output += `
1389
+ let writeSummary = null;
1390
+ await new Listr(
1391
+ [
1392
+ {
1393
+ title: `Write to Airtable[${slug}]`,
1394
+ task: async (_ctx, task) => {
1395
+ const base = openBase2(readAirtableConfig2());
1396
+ task.output = "loading Websites\u2026";
1397
+ const websites = await listWebsites2(base);
1398
+ task.output = "writing scores\u2026";
1399
+ writeSummary = await writeAuditsToAirtable2({ base, websites, slug, results });
1400
+ task.title = `Wrote to Websites[${writeSummary.siteName}] (${writeSummary.writes.length} audit type${writeSummary.writes.length === 1 ? "" : "s"})`;
1401
+ }
1402
+ }
1403
+ ],
1404
+ { renderer }
1405
+ ).run();
1406
+ if (writeSummary) output += `
1335
1407
 
1336
- \u2192 wrote to Websites[${summary.siteName}]:
1337
- ${lines.join("\n")}`;
1408
+ ${formatWriteSummary(writeSummary)}`;
1338
1409
  }
1339
1410
  return { output, code: exitCode(results) };
1340
1411
  }