@reddoorla/maintenance 0.57.0 → 0.59.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.
Files changed (70) hide show
  1. package/dist/airtable-YZ6VMSQZ.js +9 -0
  2. package/dist/{announce-JEVCDDKL.js → announce-Q2DXP5OO.js} +3 -3
  3. package/dist/{bump-deps-O3SOLQYY.js → bump-deps-RYHQIKW4.js} +2 -2
  4. package/dist/{chunk-4PY4I5OR.js → chunk-5PHCZ6L5.js} +11 -2
  5. package/dist/chunk-5PHCZ6L5.js.map +1 -0
  6. package/dist/{chunk-J3OPWFZE.js → chunk-6CSCLBAA.js} +2 -2
  7. package/dist/{chunk-XO2RUYVM.js → chunk-HB7QPECR.js} +2 -2
  8. package/dist/{chunk-IMIR7SC2.js → chunk-HPSGCDWY.js} +3 -3
  9. package/dist/chunk-HPSGCDWY.js.map +1 -0
  10. package/dist/{chunk-5L2QXUTU.js → chunk-KC4HU7BC.js} +2 -2
  11. package/dist/{chunk-CLVTVDOU.js → chunk-L4ULXHIN.js} +14 -2
  12. package/dist/chunk-L4ULXHIN.js.map +1 -0
  13. package/dist/{chunk-5WL3ET24.js → chunk-LMXIZITU.js} +3 -3
  14. package/dist/chunk-LMXIZITU.js.map +1 -0
  15. package/dist/{chunk-JQG222CI.js → chunk-TLZ4V2BE.js} +2 -2
  16. package/dist/{chunk-W3G7XFBZ.js → chunk-TZN2G6FD.js} +2 -2
  17. package/dist/cli/bin.js +13 -13
  18. package/dist/cli/commands/audit.js +6 -6
  19. package/dist/{convert-to-pnpm-UR64X3OX.js → convert-to-pnpm-KNCXU6FM.js} +2 -2
  20. package/dist/{digest-YTO73BEO.js → digest-RVIOHUXR.js} +10 -5
  21. package/dist/digest-RVIOHUXR.js.map +1 -0
  22. package/dist/{github-signals-XLQXXH6Q.js → github-signals-NCDBYSVV.js} +4 -4
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.js +114 -17
  25. package/dist/index.js.map +1 -1
  26. package/dist/{init-JITQXFVL.js → init-KD56UENX.js} +4 -4
  27. package/dist/{launch-XW6PEKUL.js → launch-35KSDHYO.js} +13 -7
  28. package/dist/launch-35KSDHYO.js.map +1 -0
  29. package/dist/{lighthouse-airtable-4FKYKFH6.js → lighthouse-airtable-N3KCBPVA.js} +3 -3
  30. package/dist/{onboard-TCQOP2W4.js → onboard-SCZ3UKZ2.js} +2 -2
  31. package/dist/{orchestrate-LHH3LQNP.js → orchestrate-D72PB6NG.js} +3 -3
  32. package/dist/{renovate-dispatch-YVBTBJJY.js → renovate-dispatch-P2FAJTQK.js} +42 -3
  33. package/dist/renovate-dispatch-P2FAJTQK.js.map +1 -0
  34. package/dist/{report-WK3SKWJI.js → report-CN56TGMK.js} +5 -5
  35. package/dist/{self-updating-BYUBUNO4.js → self-updating-HLMF7KEG.js} +2 -2
  36. package/dist/{svelte-codemods-BYRJAU7I.js → svelte-codemods-HNITLWQM.js} +2 -2
  37. package/dist/{sync-configs-JPRLAW5J.js → sync-configs-BZXBYKTI.js} +2 -2
  38. package/dist/{upgrade-ERA45EVR.js → upgrade-6YDUELFA.js} +2 -2
  39. package/dist/{websites-X5DLC2PC.js → websites-IYP7IGLU.js} +8 -4
  40. package/dist/{write-audits-to-airtable-CE4POBAF.js → write-audits-to-airtable-VDGHCZGQ.js} +4 -4
  41. package/package.json +1 -1
  42. package/dist/airtable-2BJX4ATJ.js +0 -9
  43. package/dist/chunk-4PY4I5OR.js.map +0 -1
  44. package/dist/chunk-5WL3ET24.js.map +0 -1
  45. package/dist/chunk-CLVTVDOU.js.map +0 -1
  46. package/dist/chunk-IMIR7SC2.js.map +0 -1
  47. package/dist/digest-YTO73BEO.js.map +0 -1
  48. package/dist/launch-XW6PEKUL.js.map +0 -1
  49. package/dist/renovate-dispatch-YVBTBJJY.js.map +0 -1
  50. /package/dist/{airtable-2BJX4ATJ.js.map → airtable-YZ6VMSQZ.js.map} +0 -0
  51. /package/dist/{announce-JEVCDDKL.js.map → announce-Q2DXP5OO.js.map} +0 -0
  52. /package/dist/{bump-deps-O3SOLQYY.js.map → bump-deps-RYHQIKW4.js.map} +0 -0
  53. /package/dist/{chunk-J3OPWFZE.js.map → chunk-6CSCLBAA.js.map} +0 -0
  54. /package/dist/{chunk-XO2RUYVM.js.map → chunk-HB7QPECR.js.map} +0 -0
  55. /package/dist/{chunk-5L2QXUTU.js.map → chunk-KC4HU7BC.js.map} +0 -0
  56. /package/dist/{chunk-JQG222CI.js.map → chunk-TLZ4V2BE.js.map} +0 -0
  57. /package/dist/{chunk-W3G7XFBZ.js.map → chunk-TZN2G6FD.js.map} +0 -0
  58. /package/dist/{convert-to-pnpm-UR64X3OX.js.map → convert-to-pnpm-KNCXU6FM.js.map} +0 -0
  59. /package/dist/{github-signals-XLQXXH6Q.js.map → github-signals-NCDBYSVV.js.map} +0 -0
  60. /package/dist/{init-JITQXFVL.js.map → init-KD56UENX.js.map} +0 -0
  61. /package/dist/{lighthouse-airtable-4FKYKFH6.js.map → lighthouse-airtable-N3KCBPVA.js.map} +0 -0
  62. /package/dist/{onboard-TCQOP2W4.js.map → onboard-SCZ3UKZ2.js.map} +0 -0
  63. /package/dist/{orchestrate-LHH3LQNP.js.map → orchestrate-D72PB6NG.js.map} +0 -0
  64. /package/dist/{report-WK3SKWJI.js.map → report-CN56TGMK.js.map} +0 -0
  65. /package/dist/{self-updating-BYUBUNO4.js.map → self-updating-HLMF7KEG.js.map} +0 -0
  66. /package/dist/{svelte-codemods-BYRJAU7I.js.map → svelte-codemods-HNITLWQM.js.map} +0 -0
  67. /package/dist/{sync-configs-JPRLAW5J.js.map → sync-configs-BZXBYKTI.js.map} +0 -0
  68. /package/dist/{upgrade-ERA45EVR.js.map → upgrade-6YDUELFA.js.map} +0 -0
  69. /package/dist/{websites-X5DLC2PC.js.map → websites-IYP7IGLU.js.map} +0 -0
  70. /package/dist/{write-audits-to-airtable-CE4POBAF.js.map → write-audits-to-airtable-VDGHCZGQ.js.map} +0 -0
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  DEFAULT_INIT_STEPS,
3
3
  a11yFixturesPage,
4
4
  init
5
- } from "./chunk-XO2RUYVM.js";
5
+ } from "./chunk-HB7QPECR.js";
6
6
  import {
7
7
  svelteCodemods
8
8
  } from "./chunk-FUD4I2ZW.js";
@@ -16,11 +16,11 @@ import {
16
16
  } from "./chunk-WVRPOXKH.js";
17
17
  import {
18
18
  draftReportForSite
19
- } from "./chunk-W3G7XFBZ.js";
19
+ } from "./chunk-TZN2G6FD.js";
20
20
  import "./chunk-6LIWDIXU.js";
21
21
  import {
22
22
  sendApprovedReports
23
- } from "./chunk-5L2QXUTU.js";
23
+ } from "./chunk-KC4HU7BC.js";
24
24
  import "./chunk-OGGRFBL4.js";
25
25
  import {
26
26
  BLURRED_CID,
@@ -60,7 +60,7 @@ import {
60
60
  runAudits,
61
61
  runAuditsAcross,
62
62
  securityAudit
63
- } from "./chunk-4PY4I5OR.js";
63
+ } from "./chunk-5PHCZ6L5.js";
64
64
  import "./chunk-LKGVSM2O.js";
65
65
  import {
66
66
  fromJsonFile,
@@ -71,12 +71,12 @@ import "./chunk-XXTZBPUY.js";
71
71
  import "./chunk-XTK5VIQB.js";
72
72
  import {
73
73
  fromAirtableBase
74
- } from "./chunk-JQG222CI.js";
74
+ } from "./chunk-TLZ4V2BE.js";
75
75
  import "./chunk-U5SZ4FOP.js";
76
76
  import {
77
77
  SEVERITY_RANK,
78
78
  siteSlug
79
- } from "./chunk-CLVTVDOU.js";
79
+ } from "./chunk-L4ULXHIN.js";
80
80
  import "./chunk-HN6I2XWI.js";
81
81
  import "./chunk-WEKL2HYJ.js";
82
82
  import "./chunk-6VAL7XJT.js";
@@ -232,6 +232,17 @@ var SUBMISSION_STATUS_SCRIPT = `document.querySelectorAll("button.subm-status").
232
232
  });
233
233
  });`;
234
234
 
235
+ // src/dashboard/site-details.ts
236
+ var SITE_STATUS_OPTIONS = [
237
+ "in development",
238
+ "launch period",
239
+ "maintenance",
240
+ "hosting",
241
+ "probably not our problem",
242
+ "deprecated"
243
+ ];
244
+ var FREQ_OPTIONS = ["None", "Monthly", "Quarterly", "Yearly"];
245
+
235
246
  // src/dashboard/render.ts
236
247
  var DASH = "\u2014";
237
248
  function scoreTile(label, value) {
@@ -380,21 +391,44 @@ function detailRow(label, value) {
380
391
  const display = typeof value === "string" && value.trim().length > 0 ? escapeHtml(value.trim()) : DASH;
381
392
  return `<div class="detail"><dt>${escapeHtml(label)}</dt><dd>${display}</dd></div>`;
382
393
  }
394
+ function savedSpan(field) {
395
+ return `<span class="detail-saved" data-for="${field}"></span>`;
396
+ }
397
+ function selectRow(label, field, options, current, url) {
398
+ const inList = current !== null && options.includes(current);
399
+ const opts = options.map(
400
+ (o) => `<option value="${escapeHtml(o)}"${o === current ? " selected" : ""}>${escapeHtml(o)}</option>`
401
+ ).join("");
402
+ const placeholder = inList ? "" : `<option value="" disabled selected hidden>\u2014 select \u2014</option>`;
403
+ return `<div class="detail"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><select id="detail-${field}" data-detail-field="${field}" data-details-url="${url}">${placeholder}${opts}</select>${savedSpan(field)}</dd></div>`;
404
+ }
405
+ function inputRow(label, field, value, url) {
406
+ return `<div class="detail"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><input type="text" id="detail-${field}" data-detail-field="${field}" data-details-url="${url}" value="${escapeHtml(value ?? "")}" />${savedSpan(field)}</dd></div>`;
407
+ }
408
+ function textareaRow(label, field, value, url) {
409
+ return `<div class="detail wide"><dt><label for="detail-${field}">${escapeHtml(label)}</label></dt><dd><textarea id="detail-${field}" data-detail-field="${field}" data-details-url="${url}">${escapeHtml(value ?? "")}</textarea>${savedSpan(field)}</dd></div>`;
410
+ }
383
411
  function siteDetailsSection(site) {
412
+ const url = `/api/sites/${escapeHtml(siteSlug(site.name))}/details`;
384
413
  const lastCommit = site.lastCommitAt ? `${relativeTimeFromNow(site.lastCommitAt)}` : null;
385
414
  const rows = [
386
- detailRow("Maintenance cadence", site.maintenanceFreq),
387
- detailRow("Testing cadence", site.testingFreq),
388
- detailRow("Report recipients (To)", site.reportRecipientsTo),
389
- detailRow("Report recipients (CC)", site.reportRecipientsCc),
390
- detailRow("Point of contact", site.pointOfContact),
391
- detailRow("GA4 property", site.ga4PropertyId),
392
- detailRow("Search query", site.searchQuery),
393
- detailRow("Git repo", site.gitRepo),
415
+ selectRow("Status", "status", SITE_STATUS_OPTIONS, site.status, url),
416
+ selectRow("Maintenance cadence", "maintenanceFreq", FREQ_OPTIONS, site.maintenanceFreq, url),
417
+ selectRow("Testing cadence", "testingFreq", FREQ_OPTIONS, site.testingFreq, url),
418
+ inputRow("Report recipients (To)", "reportRecipientsTo", site.reportRecipientsTo, url),
419
+ inputRow("Report recipients (CC)", "reportRecipientsCc", site.reportRecipientsCc, url),
420
+ inputRow("Point of contact", "pointOfContact", site.pointOfContact, url),
421
+ inputRow("GA4 property", "ga4PropertyId", site.ga4PropertyId, url),
422
+ inputRow("Search query", "searchQuery", site.searchQuery, url),
423
+ inputRow("Git repo", "gitRepo", site.gitRepo, url),
424
+ textareaRow("Copy \u2014 Intro", "copyIntro", site.copyIntro, url),
425
+ textareaRow("Copy \u2014 Contact", "copyContact", site.copyContact, url),
426
+ textareaRow("Copy \u2014 Footer", "copyFooter", site.copyFooter, url),
394
427
  detailRow("Last commit", lastCommit)
395
428
  ].join("");
429
+ const triggerBtn = site.gitRepo?.trim() ? `<button class="trigger-renovate" data-trigger-url="/api/sites/${escapeHtml(siteSlug(site.name))}/trigger-renovate">Trigger Renovate</button>` : "";
396
430
  return `<div class="section site-details">
397
- <h2>Site details</h2>
431
+ <h2>Site details ${triggerBtn}</h2>
398
432
  <dl class="details">${rows}</dl>
399
433
  </div>`;
400
434
  }
@@ -445,8 +479,13 @@ button.approve:disabled { opacity: 0.6; cursor: default; }
445
479
  .setup-missing { color: #a65a00; }
446
480
  .details { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0.5rem 1.5rem; margin: 0; }
447
481
  .detail { display: flex; flex-direction: column; }
482
+ .detail.wide { grid-column: 1 / -1; }
448
483
  .detail dt { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: #999; }
449
484
  .detail dd { margin: 0; }
485
+ .detail dd input, .detail dd select, .detail dd textarea { width: 100%; box-sizing: border-box; font: inherit; padding: 0.25rem 0.4rem; border: 1px solid #ccc; border-radius: 4px; background: transparent; color: inherit; }
486
+ .detail dd textarea { min-height: 3.5rem; resize: vertical; }
487
+ .detail-saved { font-size: 0.8rem; color: #2a8; }
488
+ button.trigger-renovate { font: inherit; font-size: 0.8rem; padding: 0.15rem 0.6rem; margin-left: 0.5rem; border: 1px solid #888; border-radius: 6px; background: transparent; color: inherit; cursor: pointer; }
450
489
  `;
451
490
  function renderSiteDashboardHtml(site, reports, submissions = [], spamTotals = null, now = /* @__PURE__ */ new Date()) {
452
491
  const name = escapeHtml(site.name);
@@ -524,6 +563,45 @@ function renderSiteDashboardHtml(site, reports, submissions = [], spamTotals = n
524
563
  }
525
564
  });
526
565
  });
566
+ // Trigger-renovate button: async on-demand dispatch (mirrors the cockpit).
567
+ document.querySelectorAll("button.trigger-renovate").forEach((b) => {
568
+ b.addEventListener("click", async () => {
569
+ b.disabled = true;
570
+ b.textContent = "Dispatching\u2026";
571
+ try {
572
+ const res = await fetch(b.dataset.triggerUrl, { method: "POST" });
573
+ b.textContent = res.ok ? "Dispatched \u2713" : "Failed";
574
+ if (!res.ok) b.disabled = false;
575
+ } catch {
576
+ b.textContent = "Failed";
577
+ b.disabled = false;
578
+ }
579
+ });
580
+ });
581
+ // Site-details editor: save on change (selects) / blur (inputs+textareas, only
582
+ // when the value actually changed). The per-field span shows \u2713 / \u2717.
583
+ function saveDetail(el) {
584
+ const span = document.querySelector('.detail-saved[data-for="' + el.dataset.detailField + '"]');
585
+ fetch(el.dataset.detailsUrl, {
586
+ method: "POST",
587
+ headers: { "content-type": "application/json" },
588
+ body: JSON.stringify({ field: el.dataset.detailField, value: el.value }),
589
+ })
590
+ .then((r) => {
591
+ if (span) span.textContent = r.ok ? " \u2713" : " \u2717";
592
+ })
593
+ .catch(() => {
594
+ if (span) span.textContent = " \u2717";
595
+ });
596
+ }
597
+ document.querySelectorAll("select[data-detail-field]").forEach((s) => {
598
+ s.addEventListener("change", () => saveDetail(s));
599
+ });
600
+ document.querySelectorAll("input[data-detail-field], textarea[data-detail-field]").forEach((i) => {
601
+ i.addEventListener("blur", () => {
602
+ if (i.value !== i.defaultValue) saveDetail(i);
603
+ });
604
+ });
527
605
  ${SUBMISSION_STATUS_SCRIPT}
528
606
  // Checklist gate: ticking a box POSTs the one field; the response { complete }
529
607
  // decides whether THIS report's Approve button is enabled. Scoped per report by
@@ -666,6 +744,7 @@ details.tier > summary { cursor:pointer; font-weight:700; font-size:1.05rem; pad
666
744
  .chip { font-size:0.8rem; padding:0.1rem 0.5rem; border-radius:6px; background:#f0f0f0; }
667
745
  @media (prefers-color-scheme: dark) { .chip { background:#222; } }
668
746
  .chip.critical { background:#fdecea; color:#b00; }
747
+ .chip.stuck { border:1px solid #b00; font-weight:600; }
669
748
  .badge { font-weight:700; color:#C00; font-size:0.72rem; margin-right:0.25rem; }
670
749
  .all-clear { background:#e8f5e9; color:#1b7a2f; padding:0.6rem 1rem; border-radius:8px; margin-bottom:1.25rem; font-weight:600; }
671
750
  @media (prefers-color-scheme: dark) { .all-clear { background:#10240f; color:#7fce85; } }
@@ -682,6 +761,7 @@ var FILTERS = [
682
761
  "delivery",
683
762
  "prs",
684
763
  "ci",
764
+ "auto-fix-failed",
685
765
  "stale",
686
766
  "no-domain",
687
767
  "pending",
@@ -695,6 +775,7 @@ function summaryBar(model) {
695
775
  `${s.deliveryFailures} delivery`,
696
776
  `${s.renovateFailing} PRs failing`,
697
777
  `${s.ciRed} CI red`,
778
+ `${s.autoFixStuck} auto-fix stuck`,
698
779
  `${s.pending} pending`,
699
780
  `${s.newSubmissions ?? 0} new`
700
781
  ].join(" \xB7 ");
@@ -771,7 +852,7 @@ function attentionBadge(status) {
771
852
  }
772
853
  function chips(c) {
773
854
  const items = c.items.map((it) => {
774
- const cls = it.severity === "critical" ? "chip critical" : "chip";
855
+ const cls = it.autoFixExhausted ? "chip critical stuck" : it.severity === "critical" ? "chip critical" : "chip";
775
856
  return `<span class="${cls}">${attentionBadge(it.status)}${escapeHtml(it.title)}</span>`;
776
857
  });
777
858
  for (const reason of c.watchReasons)
@@ -783,13 +864,19 @@ function signalsAttr(c) {
783
864
  for (const it of c.items) {
784
865
  kinds.add(it.kind === "vuln" ? "vulns" : it.kind === "renovate" ? "prs" : it.kind);
785
866
  }
867
+ if (c.items.some((it) => it.autoFixExhausted)) kinds.add("auto-fix-failed");
786
868
  for (const sig of c.watchSignals) kinds.add(sig);
787
869
  return [...kinds].join(" ");
788
870
  }
871
+ function triggerRenovateBtn(c) {
872
+ if (!c.site.gitRepo?.trim()) return "";
873
+ const url = `/api/sites/${escapeHtml(siteSlug(c.site.name))}/trigger-renovate`;
874
+ return `<button class="trigger-renovate" data-trigger-url="${url}">Trigger Renovate</button>`;
875
+ }
789
876
  function cockpitCard(c) {
790
877
  const base = card(c.site);
791
878
  const pill = `<span class="pill ${c.tier}">${PILL_LABEL[c.tier]}</span>`;
792
- const extra = `${pill}${chips(c)}${submBadge(c)}`;
879
+ const extra = `${pill}${chips(c)}${submBadge(c)}${triggerRenovateBtn(c)}`;
793
880
  const opening = `<article class="card" data-signals="${signalsAttr(c)}">`;
794
881
  return base.replace('<article class="card">', () => opening).replace("</article>", () => `${extra}</article>`);
795
882
  }
@@ -822,6 +909,16 @@ var FILTER_SCRIPT = `<script>
822
909
  catch(e){ b.textContent = 'Failed'; b.disabled = false; }
823
910
  });
824
911
  });
912
+ // trigger-renovate buttons: fire the on-demand dispatch (async, fire-and-forget).
913
+ document.querySelectorAll('button.trigger-renovate').forEach(function(b){
914
+ b.addEventListener('click', async function(){
915
+ b.disabled = true; b.textContent = 'Dispatching\u2026';
916
+ try { var res = await fetch(b.dataset.triggerUrl, { method: 'POST' });
917
+ b.textContent = res.ok ? 'Dispatched \u2713' : 'Failed';
918
+ if (!res.ok) b.disabled = false; }
919
+ catch(e){ b.textContent = 'Failed'; b.disabled = false; }
920
+ });
921
+ });
825
922
  })();
826
923
  </script>`;
827
924
  function renderCockpitHtml(model) {