@nanocollective/sentinel 0.1.0-alpha.0 → 0.1.0-alpha.2

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 (60) hide show
  1. package/dist/cli.js +58 -16
  2. package/dist/cli.js.map +1 -1
  3. package/dist/dedup/hash.d.ts +6 -3
  4. package/dist/dedup/hash.d.ts.map +1 -1
  5. package/dist/dedup/hash.js +7 -9
  6. package/dist/dedup/hash.js.map +1 -1
  7. package/dist/dedup/reconcile.d.ts +2 -0
  8. package/dist/dedup/reconcile.d.ts.map +1 -1
  9. package/dist/dedup/reconcile.js +57 -23
  10. package/dist/dedup/reconcile.js.map +1 -1
  11. package/dist/index.d.ts +8 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +6 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/init/templates.d.ts.map +1 -1
  16. package/dist/init/templates.js +14 -1
  17. package/dist/init/templates.js.map +1 -1
  18. package/dist/issues/gh-client.d.ts +2 -0
  19. package/dist/issues/gh-client.d.ts.map +1 -1
  20. package/dist/issues/gh-client.js +22 -0
  21. package/dist/issues/gh-client.js.map +1 -1
  22. package/dist/issues/types.d.ts +7 -0
  23. package/dist/issues/types.d.ts.map +1 -1
  24. package/dist/observe/dashboard.d.ts +9 -0
  25. package/dist/observe/dashboard.d.ts.map +1 -0
  26. package/dist/observe/dashboard.js +87 -0
  27. package/dist/observe/dashboard.js.map +1 -0
  28. package/dist/observe/record.d.ts +11 -0
  29. package/dist/observe/record.d.ts.map +1 -0
  30. package/dist/observe/record.js +66 -0
  31. package/dist/observe/record.js.map +1 -0
  32. package/dist/observe/types.d.ts +48 -0
  33. package/dist/observe/types.d.ts.map +1 -0
  34. package/dist/observe/types.js +8 -0
  35. package/dist/observe/types.js.map +1 -0
  36. package/dist/orchestrator/extract.d.ts +2 -1
  37. package/dist/orchestrator/extract.d.ts.map +1 -1
  38. package/dist/orchestrator/extract.js +94 -2
  39. package/dist/orchestrator/extract.js.map +1 -1
  40. package/dist/run/clone.d.ts +9 -11
  41. package/dist/run/clone.d.ts.map +1 -1
  42. package/dist/run/clone.js +24 -32
  43. package/dist/run/clone.js.map +1 -1
  44. package/dist/run/expand.d.ts +26 -0
  45. package/dist/run/expand.d.ts.map +1 -0
  46. package/dist/run/expand.js +62 -0
  47. package/dist/run/expand.js.map +1 -0
  48. package/dist/run/preview.d.ts +11 -3
  49. package/dist/run/preview.d.ts.map +1 -1
  50. package/dist/run/preview.js +14 -1
  51. package/dist/run/preview.js.map +1 -1
  52. package/dist/run/repo-lister.d.ts +16 -0
  53. package/dist/run/repo-lister.d.ts.map +1 -0
  54. package/dist/run/repo-lister.js +46 -0
  55. package/dist/run/repo-lister.js.map +1 -0
  56. package/dist/run/run.d.ts +10 -5
  57. package/dist/run/run.d.ts.map +1 -1
  58. package/dist/run/run.js +24 -8
  59. package/dist/run/run.js.map +1 -1
  60. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/issues/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAC;AAElD,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACtD,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACb;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC5B,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9D;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAChC,UAAU,CAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAC5E,WAAW,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,UAAU,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAE9D,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC7B,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACpB;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC5B,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,MAAM,EAAE,WAAW,EAAE,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/issues/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,sBAAsB,CAAC;AAElD,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACtD,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACb;AAED,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,gDAAgD;AAChD,MAAM,WAAW,YAAY;IAC5B,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9D;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAChC;;0CAEsC;IACtC,YAAY,CAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,UAAU,CAAC,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAC5E,WAAW,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,UAAU,CAAC,MAAM,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,gBAAgB,CAAC;AAE9D,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC7B,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACpB;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC5B,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,wDAAwD;IACxD,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,MAAM,EAAE,WAAW,EAAE,CAAC;CACtB"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Render a self-contained static HTML dashboard from the committed run records.
3
+ * No database, no build step, no external assets — a single page suitable for
4
+ * the config repo's GitHub Pages. Pure and tested.
5
+ */
6
+ import type { RunRecord } from './types.js';
7
+ /** Render the dashboard HTML for a set of run records (newest first). */
8
+ export declare function renderDashboard(records: RunRecord[]): string;
9
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../source/observe/dashboard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAmC1C,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAsD5D"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Render a self-contained static HTML dashboard from the committed run records.
3
+ * No database, no build step, no external assets — a single page suitable for
4
+ * the config repo's GitHub Pages. Pure and tested.
5
+ */
6
+ const MAX_ROWS = 60;
7
+ function escapeHtml(text) {
8
+ return text
9
+ .replace(/&/g, '&')
10
+ .replace(/</g, '&lt;')
11
+ .replace(/>/g, '&gt;')
12
+ .replace(/"/g, '&quot;');
13
+ }
14
+ function severityCell(count, className) {
15
+ const shown = count > 0 ? String(count) : '·';
16
+ return `<td class="sev ${className}">${shown}</td>`;
17
+ }
18
+ function row(record) {
19
+ const { bySeverity } = record.totals;
20
+ const filed = record.filing ? String(record.filing.filed) : '—';
21
+ return [
22
+ '<tr>',
23
+ `<td class="ts">${escapeHtml(record.timestamp)}</td>`,
24
+ `<td><span class="mode ${record.mode}">${record.mode}</span></td>`,
25
+ `<td class="num">${record.totals.repos}</td>`,
26
+ `<td class="num">${record.totals.findings}</td>`,
27
+ severityCell(bySeverity.critical, 'critical'),
28
+ severityCell(bySeverity.high, 'high'),
29
+ severityCell(bySeverity.medium, 'medium'),
30
+ severityCell(bySeverity.low, 'low'),
31
+ `<td class="num">${filed}</td>`,
32
+ '</tr>',
33
+ ].join('');
34
+ }
35
+ /** Render the dashboard HTML for a set of run records (newest first). */
36
+ export function renderDashboard(records) {
37
+ const sorted = [...records].sort((a, b) => b.timestamp.localeCompare(a.timestamp));
38
+ const latest = sorted[0];
39
+ const rows = sorted.slice(0, MAX_ROWS).map(row).join('\n');
40
+ const summary = latest
41
+ ? `Latest run ${escapeHtml(latest.timestamp)} — ${latest.totals.findings} finding(s) across ${latest.totals.repos} repo(s).`
42
+ : 'No runs recorded yet.';
43
+ return `<!doctype html>
44
+ <html lang="en">
45
+ <head>
46
+ <meta charset="utf-8">
47
+ <meta name="viewport" content="width=device-width, initial-scale=1">
48
+ <title>Sentinel</title>
49
+ <style>
50
+ :root { color-scheme: dark; }
51
+ body { font-family: system-ui, sans-serif; background: #1a1b26; color: #a9b1d6; margin: 0; padding: 2rem; }
52
+ h1 { color: #7aa2f7; margin: 0 0 .25rem; font-size: 1.4rem; }
53
+ p.summary { color: #c0caf5; margin: 0 0 1.5rem; }
54
+ table { border-collapse: collapse; width: 100%; font-size: .9rem; }
55
+ th, td { padding: .5rem .6rem; text-align: left; border-bottom: 1px solid #292e42; }
56
+ th { color: #565f89; font-weight: 600; text-transform: uppercase; font-size: .72rem; letter-spacing: .04em; }
57
+ td.num, td.sev { text-align: right; font-variant-numeric: tabular-nums; }
58
+ .ts { color: #9aa5ce; font-variant-numeric: tabular-nums; }
59
+ .mode { padding: .1rem .45rem; border-radius: 999px; font-size: .72rem; }
60
+ .mode.live { background: #2d3b2d; color: #9ece6a; }
61
+ .mode.dry-run { background: #3b352d; color: #e0af68; }
62
+ .mode.audit-only { background: #2d3242; color: #7dcfff; }
63
+ .sev.critical { color: #f7768e; }
64
+ .sev.high { color: #ff9e64; }
65
+ .sev.medium { color: #e0af68; }
66
+ .sev.low { color: #565f89; }
67
+ footer { margin-top: 1.5rem; color: #565f89; font-size: .8rem; }
68
+ </style>
69
+ </head>
70
+ <body>
71
+ <h1>🛡️ Sentinel</h1>
72
+ <p class="summary">${summary}</p>
73
+ <table>
74
+ <thead><tr>
75
+ <th>Run</th><th>Mode</th><th>Repos</th><th>Findings</th>
76
+ <th>Crit</th><th>High</th><th>Med</th><th>Low</th><th>Filed</th>
77
+ </tr></thead>
78
+ <tbody>
79
+ ${rows}
80
+ </tbody>
81
+ </table>
82
+ <footer>Generated by <a href="https://docs.nanocollective.org/sentinel/docs" style="color:#7aa2f7">Sentinel</a> from committed run records.</footer>
83
+ </body>
84
+ </html>
85
+ `;
86
+ }
87
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../source/observe/dashboard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,IAAI;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,SAAiB;IACrD,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9C,OAAO,kBAAkB,SAAS,KAAK,KAAK,OAAO,CAAC;AACrD,CAAC;AAED,SAAS,GAAG,CAAC,MAAiB;IAC7B,MAAM,EAAC,UAAU,EAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,OAAO;QACN,MAAM;QACN,kBAAkB,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO;QACrD,yBAAyB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,cAAc;QAClE,mBAAmB,MAAM,CAAC,MAAM,CAAC,KAAK,OAAO;QAC7C,mBAAmB,MAAM,CAAC,MAAM,CAAC,QAAQ,OAAO;QAChD,YAAY,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC;QAC7C,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC;QACrC,YAAY,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC;QACzC,YAAY,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC;QACnC,mBAAmB,KAAK,OAAO;QAC/B,OAAO;KACP,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACZ,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,OAAoB;IACnD,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACzC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CACtC,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3D,MAAM,OAAO,GAAG,MAAM;QACrB,CAAC,CAAC,cAAc,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,sBAAsB,MAAM,CAAC,MAAM,CAAC,KAAK,WAAW;QAC5H,CAAC,CAAC,uBAAuB,CAAC;IAE3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6Ba,OAAO;;;;;;;EAO1B,IAAI;;;;;;CAML,CAAC;AACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Build a durable {@link RunRecord} from a run's {@link RunReport}. Pure — the
3
+ * CLI stamps the timestamp and mode and writes the JSON.
4
+ */
5
+ import type { RunReport } from '../run/run.js';
6
+ import type { RunMode, RunRecord } from './types.js';
7
+ /** Build a run record from a report, a timestamp, and the run mode. */
8
+ export declare function buildRunRecord(report: RunReport, timestamp: string, mode: RunMode): RunRecord;
9
+ /** A filesystem-safe filename for a run record from its timestamp. */
10
+ export declare function recordFilename(timestamp: string): string;
11
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../source/observe/record.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAGX,OAAO,EACP,SAAS,EAET,MAAM,YAAY,CAAC;AA8BpB,uEAAuE;AACvE,wBAAgB,cAAc,CAC7B,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,GACX,SAAS,CAiCX;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Build a durable {@link RunRecord} from a run's {@link RunReport}. Pure — the
3
+ * CLI stamps the timestamp and mode and writes the JSON.
4
+ */
5
+ import { SEVERITIES } from '../findings/types.js';
6
+ function emptyCounts() {
7
+ return { low: 0, medium: 0, high: 0, critical: 0 };
8
+ }
9
+ function addCounts(into, from) {
10
+ for (const severity of SEVERITIES) {
11
+ into[severity] += from[severity];
12
+ }
13
+ }
14
+ function repoRecord(outcome) {
15
+ const bySeverity = emptyCounts();
16
+ let findings = 0;
17
+ const packs = outcome.packs.map(pack => {
18
+ for (const finding of pack.findings) {
19
+ bySeverity[finding.severity] += 1;
20
+ }
21
+ findings += pack.findings.length;
22
+ return {
23
+ pack: pack.pack,
24
+ version: pack.version,
25
+ findings: pack.findings.length,
26
+ ok: pack.ok,
27
+ };
28
+ });
29
+ return { repo: outcome.repo, findings, bySeverity, packs };
30
+ }
31
+ /** Build a run record from a report, a timestamp, and the run mode. */
32
+ export function buildRunRecord(report, timestamp, mode) {
33
+ const repos = report.outcome.repos.map(repoRecord);
34
+ const totalsBySeverity = emptyCounts();
35
+ let totalFindings = 0;
36
+ for (const repo of repos) {
37
+ addCounts(totalsBySeverity, repo.bySeverity);
38
+ totalFindings += repo.findings;
39
+ }
40
+ const record = {
41
+ timestamp,
42
+ mode,
43
+ repos,
44
+ totals: {
45
+ repos: repos.length,
46
+ findings: totalFindings,
47
+ bySeverity: totalsBySeverity,
48
+ },
49
+ targetErrors: report.targetErrors,
50
+ };
51
+ if (report.filed) {
52
+ const filing = { filed: 0, touched: 0, resolved: 0 };
53
+ for (const { result } of report.reconciled) {
54
+ filing.filed += result.created.length;
55
+ filing.touched += result.touched;
56
+ filing.resolved += result.resolved;
57
+ }
58
+ record.filing = filing;
59
+ }
60
+ return record;
61
+ }
62
+ /** A filesystem-safe filename for a run record from its timestamp. */
63
+ export function recordFilename(timestamp) {
64
+ return `${timestamp.replace(/[:.]/g, '-')}.json`;
65
+ }
66
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../source/observe/record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The durable per-run record and the shapes the dashboard renders from. One
3
+ * record is committed to the config repo per run (the durable store); the
4
+ * dashboard is the read-side surface generated from the records
5
+ * (see docs/workflow/index.md#observability-and-run-history).
6
+ */
7
+ import type { Severity } from '../findings/types.js';
8
+ /** Finding counts broken down by severity. */
9
+ export type SeverityCounts = Record<Severity, number>;
10
+ /** One pack's contribution within a repo, for the record. */
11
+ export interface PackRunRecord {
12
+ pack: string;
13
+ version: string;
14
+ findings: number;
15
+ ok: boolean;
16
+ }
17
+ /** One repository's result within a run. */
18
+ export interface RepoRunRecord {
19
+ repo: string;
20
+ findings: number;
21
+ bySeverity: SeverityCounts;
22
+ packs: PackRunRecord[];
23
+ }
24
+ /** The mode a run executed in. */
25
+ export type RunMode = 'live' | 'dry-run' | 'audit-only';
26
+ /** Issue-filing totals for a live run. */
27
+ export interface FilingSummary {
28
+ filed: number;
29
+ touched: number;
30
+ resolved: number;
31
+ }
32
+ /** A committed record of one Sentinel run. */
33
+ export interface RunRecord {
34
+ /** ISO timestamp of the run. */
35
+ timestamp: string;
36
+ mode: RunMode;
37
+ repos: RepoRunRecord[];
38
+ totals: {
39
+ repos: number;
40
+ findings: number;
41
+ bySeverity: SeverityCounts;
42
+ };
43
+ /** Present on a live run. */
44
+ filing?: FilingSummary;
45
+ /** Target-expansion / clone failures, carried for visibility. */
46
+ targetErrors: string[];
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/observe/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAEnD,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAEtD,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,OAAO,CAAC;CACZ;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,cAAc,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;CACvB;AAED,kCAAkC;AAClC,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;AAExD,0CAA0C;AAC1C,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,8CAA8C;AAC9C,MAAM,WAAW,SAAS;IACzB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,MAAM,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,cAAc,CAAC;KAC3B,CAAC;IACF,6BAA6B;IAC7B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,iEAAiE;IACjE,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The durable per-run record and the shapes the dashboard renders from. One
3
+ * record is committed to the config repo per run (the durable store); the
4
+ * dashboard is the read-side surface generated from the records
5
+ * (see docs/workflow/index.md#observability-and-run-history).
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../source/observe/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -8,7 +8,8 @@
8
8
  */
9
9
  /**
10
10
  * Return the last top-level JSON array in the output that parses to an array,
11
- * as a string, or null if there is none.
11
+ * as a string, or null if there is none. Falls back to salvaging a truncated
12
+ * array of objects.
12
13
  */
13
14
  export declare function extractJsonArray(output: string): string | null;
14
15
  //# sourceMappingURL=extract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../source/orchestrator/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6CH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa9D"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../source/orchestrator/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkIH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa9D"}
@@ -48,9 +48,101 @@ function topLevelArraySpans(text) {
48
48
  }
49
49
  return spans;
50
50
  }
51
+ /**
52
+ * Recover complete objects from a truncated array-of-objects. Models
53
+ * occasionally cut off mid-array (max tokens), leaving `[{...},{...},{incomp`
54
+ * which parses as nothing. This finds the last `[` that opens an object array
55
+ * and keeps the leading complete `{...}` objects. Returns null if nothing
56
+ * recoverable. Only used as a fallback when a clean array was not found.
57
+ */
58
+ function salvageTruncatedArray(output) {
59
+ // Find the last top-level `[` immediately followed by `{` (an object array),
60
+ // tracking string state so brackets inside strings are ignored.
61
+ let inString = false;
62
+ let escaped = false;
63
+ let start = -1;
64
+ for (let i = 0; i < output.length; i++) {
65
+ const char = output[i];
66
+ if (inString) {
67
+ if (escaped) {
68
+ escaped = false;
69
+ }
70
+ else if (char === '\\') {
71
+ escaped = true;
72
+ }
73
+ else if (char === '"') {
74
+ inString = false;
75
+ }
76
+ continue;
77
+ }
78
+ if (char === '"') {
79
+ inString = true;
80
+ }
81
+ else if (char === '[') {
82
+ const next = output.slice(i + 1).match(/^\s*\{/);
83
+ if (next) {
84
+ start = i;
85
+ }
86
+ }
87
+ }
88
+ if (start === -1) {
89
+ return null;
90
+ }
91
+ // Collect balanced top-level {...} objects from just after the `[`.
92
+ const objects = [];
93
+ let depth = 0;
94
+ let objectStart = -1;
95
+ inString = false;
96
+ escaped = false;
97
+ for (let i = start + 1; i < output.length; i++) {
98
+ const char = output[i];
99
+ if (inString) {
100
+ if (escaped) {
101
+ escaped = false;
102
+ }
103
+ else if (char === '\\') {
104
+ escaped = true;
105
+ }
106
+ else if (char === '"') {
107
+ inString = false;
108
+ }
109
+ continue;
110
+ }
111
+ if (char === '"') {
112
+ inString = true;
113
+ }
114
+ else if (char === '{') {
115
+ if (depth === 0) {
116
+ objectStart = i;
117
+ }
118
+ depth++;
119
+ }
120
+ else if (char === '}') {
121
+ depth--;
122
+ if (depth === 0 && objectStart !== -1) {
123
+ objects.push(output.slice(objectStart, i + 1));
124
+ objectStart = -1;
125
+ }
126
+ }
127
+ else if (char === ']' && depth === 0) {
128
+ break;
129
+ }
130
+ }
131
+ if (objects.length === 0) {
132
+ return null;
133
+ }
134
+ const salvaged = `[${objects.join(',')}]`;
135
+ try {
136
+ return Array.isArray(JSON.parse(salvaged)) ? salvaged : null;
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ }
51
142
  /**
52
143
  * Return the last top-level JSON array in the output that parses to an array,
53
- * as a string, or null if there is none.
144
+ * as a string, or null if there is none. Falls back to salvaging a truncated
145
+ * array of objects.
54
146
  */
55
147
  export function extractJsonArray(output) {
56
148
  const spans = topLevelArraySpans(output);
@@ -65,6 +157,6 @@ export function extractJsonArray(output) {
65
157
  // Not valid JSON on its own; try the next candidate.
66
158
  }
67
159
  }
68
- return null;
160
+ return salvageTruncatedArray(output);
69
161
  }
70
162
  //# sourceMappingURL=extract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../source/orchestrator/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qEAAqE;AACrE,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACzB,QAAQ,GAAG,KAAK,CAAC;YAClB,CAAC;YACD,SAAS;QACV,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACjB,KAAK,GAAG,CAAC,CAAC;YACX,CAAC;YACD,KAAK,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACf,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACrC,KAAK,GAAG,CAAC,CAAC,CAAC;gBACZ,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAChC,IAAI,CAAC;YACJ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,qDAAqD;QACtD,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../source/orchestrator/extract.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qEAAqE;AACrE,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAErB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACzB,QAAQ,GAAG,KAAK,CAAC;YAClB,CAAC;YACD,SAAS;QACV,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACjB,KAAK,GAAG,CAAC,CAAC;YACX,CAAC;YACD,KAAK,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACf,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACrC,KAAK,GAAG,CAAC,CAAC,CAAC;gBACZ,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC5C,6EAA6E;IAC7E,gEAAgE;IAChE,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACzB,QAAQ,GAAG,KAAK,CAAC;YAClB,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACjD,IAAI,IAAI,EAAE,CAAC;gBACV,KAAK,GAAG,CAAC,CAAC;YACX,CAAC;QACF,CAAC;IACF,CAAC;IACD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,oEAAoE;IACpE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;IACrB,QAAQ,GAAG,KAAK,CAAC;IACjB,OAAO,GAAG,KAAK,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,KAAK,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACzB,QAAQ,GAAG,KAAK,CAAC;YAClB,CAAC;YACD,SAAS;QACV,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAClB,QAAQ,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBACjB,WAAW,GAAG,CAAC,CAAC;YACjB,CAAC;YACD,KAAK,EAAE,CAAC;QACT,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACzB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,IAAI,WAAW,KAAK,CAAC,CAAC,EAAE,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC/C,WAAW,GAAG,CAAC,CAAC,CAAC;YAClB,CAAC;QACF,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM;QACP,CAAC;IACF,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,IAAI,CAAC;QACJ,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC9C,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QAChC,IAAI,CAAC;YACJ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACb,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,qDAAqD;QACtD,CAAC;IACF,CAAC;IACD,OAAO,qBAAqB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC"}
@@ -6,18 +6,16 @@
6
6
  */
7
7
  /** Build the `gh repo clone` argv for a shallow single-branch clone. */
8
8
  export declare function buildCloneArgs(repo: string, dir: string): string[];
9
- /** The outcome of ensuring the target repos are present in the workspace. */
10
- export interface EnsureTargetsResult {
11
- cloned: string[];
12
- skipped: string[];
13
- errors: {
14
- repo: string;
15
- error: string;
16
- }[];
9
+ /** The outcome of ensuring one repo is present in the workspace. */
10
+ export interface PrepareResult {
11
+ ok: boolean;
12
+ /** True if the repo was already present and no clone was attempted. */
13
+ skipped: boolean;
14
+ error?: string;
17
15
  }
18
16
  /**
19
- * Ensure each repo is checked out under `workspaceDir/<owner>/<name>`, cloning
20
- * any that are missing. Repos already present are left untouched.
17
+ * Ensure a single repo is checked out at `dir`, cloning it if missing. Returns
18
+ * a result rather than throwing so one failure does not abort a run.
21
19
  */
22
- export declare function ensureTargets(repos: string[], workspaceDir: string): EnsureTargetsResult;
20
+ export declare function prepareRepo(repo: string, dir: string): Promise<PrepareResult>;
23
21
  //# sourceMappingURL=clone.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../source/run/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAElE;AAED,6EAA6E;AAC7E,MAAM,WAAW,mBAAmB;IACnC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;CACxC;AAGD;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,YAAY,EAAE,MAAM,GAClB,mBAAmB,CA+BrB"}
1
+ {"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../source/run/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAElE;AAED,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAGD;;;GAGG;AACH,wBAAsB,WAAW,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,aAAa,CAAC,CAwBxB"}
package/dist/run/clone.js CHANGED
@@ -6,46 +6,38 @@
6
6
  */
7
7
  import { spawnSync } from 'node:child_process';
8
8
  import { existsSync } from 'node:fs';
9
- import { join } from 'node:path';
10
9
  /** Build the `gh repo clone` argv for a shallow single-branch clone. */
11
10
  export function buildCloneArgs(repo, dir) {
12
11
  return ['repo', 'clone', repo, dir, '--', '--depth', '1', '--single-branch'];
13
12
  }
14
13
  /* c8 ignore start -- spawns gh and touches the filesystem. */
15
14
  /**
16
- * Ensure each repo is checked out under `workspaceDir/<owner>/<name>`, cloning
17
- * any that are missing. Repos already present are left untouched.
15
+ * Ensure a single repo is checked out at `dir`, cloning it if missing. Returns
16
+ * a result rather than throwing so one failure does not abort a run.
18
17
  */
19
- export function ensureTargets(repos, workspaceDir) {
20
- const result = { cloned: [], skipped: [], errors: [] };
21
- for (const repo of repos) {
22
- const dir = join(workspaceDir, repo);
23
- if (existsSync(dir)) {
24
- result.skipped.push(repo);
25
- continue;
26
- }
27
- const run = spawnSync('gh', buildCloneArgs(repo, dir), {
28
- encoding: 'utf8',
29
- stdio: ['ignore', 'pipe', 'pipe'],
30
- env: process.env,
31
- });
32
- if (run.error) {
33
- const code = run.error.code;
34
- result.errors.push({
35
- repo,
36
- error: code === 'ENOENT'
37
- ? '`gh` is not on PATH. Install the GitHub CLI.'
38
- : String(run.error),
39
- });
40
- }
41
- else if (run.status !== 0) {
42
- result.errors.push({ repo, error: (run.stderr ?? '').trim() });
43
- }
44
- else {
45
- result.cloned.push(repo);
46
- }
18
+ export async function prepareRepo(repo, dir) {
19
+ if (existsSync(dir)) {
20
+ return { ok: true, skipped: true };
47
21
  }
48
- return result;
22
+ const run = spawnSync('gh', buildCloneArgs(repo, dir), {
23
+ encoding: 'utf8',
24
+ stdio: ['ignore', 'pipe', 'pipe'],
25
+ env: process.env,
26
+ });
27
+ if (run.error) {
28
+ const code = run.error.code;
29
+ return {
30
+ ok: false,
31
+ skipped: false,
32
+ error: code === 'ENOENT'
33
+ ? '`gh` is not on PATH. Install the GitHub CLI.'
34
+ : String(run.error),
35
+ };
36
+ }
37
+ if (run.status !== 0) {
38
+ return { ok: false, skipped: false, error: (run.stderr ?? '').trim() };
39
+ }
40
+ return { ok: true, skipped: false };
49
41
  }
50
42
  /* c8 ignore stop */
51
43
  //# sourceMappingURL=clone.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clone.js","sourceRoot":"","sources":["../../source/run/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAC,UAAU,EAAC,MAAM,SAAS,CAAC;AACnC,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAE/B,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,GAAW;IACvD,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;AAC9E,CAAC;AASD,8DAA8D;AAC9D;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAe,EACf,YAAoB;IAEpB,MAAM,MAAM,GAAwB,EAAC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAC,CAAC;IAE1E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,SAAS;QACV,CAAC;QACD,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;YACtD,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,OAAO,CAAC,GAAG;SAChB,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAI,GAAG,CAAC,KAA+B,CAAC,IAAI,CAAC;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;gBAClB,IAAI;gBACJ,KAAK,EACJ,IAAI,KAAK,QAAQ;oBAChB,CAAC,CAAC,8CAA8C;oBAChD,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;aACrB,CAAC,CAAC;QACJ,CAAC;aAAM,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAC,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AACD,oBAAoB"}
1
+ {"version":3,"file":"clone.js","sourceRoot":"","sources":["../../source/run/clone.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAC,UAAU,EAAC,MAAM,SAAS,CAAC;AAEnC,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,GAAW;IACvD,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;AAC9E,CAAC;AAUD,8DAA8D;AAC9D;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,IAAY,EACZ,GAAW;IAEX,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC;IAClC,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;QACtD,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,GAAG,EAAE,OAAO,CAAC,GAAG;KAChB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAI,GAAG,CAAC,KAA+B,CAAC,IAAI,CAAC;QACvD,OAAO;YACN,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,KAAK;YACd,KAAK,EACJ,IAAI,KAAK,QAAQ;gBAChB,CAAC,CAAC,8CAA8C;gBAChD,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;SACrB,CAAC;IACH,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAC,CAAC;IACtE,CAAC;IACD,OAAO,EAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;AACnC,CAAC;AACD,oBAAoB"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Expand a config's targets into concrete repositories. Explicit `repo:`
3
+ * targets pass through; `pattern:` targets are matched against the owner's
4
+ * repositories (listed via an injected {@link RepoLister}). A repo that matches
5
+ * several targets is audited once, with the union of their rule packs.
6
+ */
7
+ import type { Target } from '../config/types.js';
8
+ import type { RepoLister } from './repo-lister.js';
9
+ /** A concrete repository to audit, with its assigned rule packs. */
10
+ export interface ResolvedRepoTarget {
11
+ repo: string;
12
+ rulePacks: string[];
13
+ }
14
+ /** The outcome of expanding targets. */
15
+ export interface ExpandResult {
16
+ targets: ResolvedRepoTarget[];
17
+ /** Reasons a target could not be expanded (missing lister, list failure). */
18
+ errors: string[];
19
+ }
20
+ /**
21
+ * Expand `config.targets`. Pattern targets need a lister; without one they are
22
+ * recorded as errors and skipped. The owner is the segment before the first
23
+ * `/` in the pattern (e.g. `my-org` for `my-org/web-*`).
24
+ */
25
+ export declare function expandTargets(targets: Target[], lister?: RepoLister): Promise<ExpandResult>;
26
+ //# sourceMappingURL=expand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.d.ts","sourceRoot":"","sources":["../../source/run/expand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAE/C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,oEAAoE;AACpE,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wCAAwC;AACxC,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAcD;;;;GAIG;AACH,wBAAsB,aAAa,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,CAAC,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAkDvB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Expand a config's targets into concrete repositories. Explicit `repo:`
3
+ * targets pass through; `pattern:` targets are matched against the owner's
4
+ * repositories (listed via an injected {@link RepoLister}). A repo that matches
5
+ * several targets is audited once, with the union of their rule packs.
6
+ */
7
+ import { matchesGlob } from '../rule-packs/glob.js';
8
+ function addRepo(byRepo, repo, rulePacks) {
9
+ const packs = byRepo.get(repo) ?? new Set();
10
+ for (const pack of rulePacks) {
11
+ packs.add(pack);
12
+ }
13
+ byRepo.set(repo, packs);
14
+ }
15
+ /**
16
+ * Expand `config.targets`. Pattern targets need a lister; without one they are
17
+ * recorded as errors and skipped. The owner is the segment before the first
18
+ * `/` in the pattern (e.g. `my-org` for `my-org/web-*`).
19
+ */
20
+ export async function expandTargets(targets, lister) {
21
+ const byRepo = new Map();
22
+ const errors = [];
23
+ const listed = new Map();
24
+ for (const target of targets) {
25
+ if (target.repo) {
26
+ addRepo(byRepo, target.repo, target.rulePacks);
27
+ continue;
28
+ }
29
+ if (!target.pattern) {
30
+ continue;
31
+ }
32
+ const pattern = target.pattern;
33
+ if (!lister) {
34
+ errors.push(`cannot expand pattern "${pattern}" — no repo lister available (needs a GitHub token)`);
35
+ continue;
36
+ }
37
+ const owner = pattern.split('/')[0];
38
+ if (!owner) {
39
+ errors.push(`invalid pattern "${pattern}" — expected owner/glob`);
40
+ continue;
41
+ }
42
+ let repos = listed.get(owner);
43
+ if (!repos) {
44
+ try {
45
+ repos = await lister.list(owner);
46
+ listed.set(owner, repos);
47
+ }
48
+ catch (error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ errors.push(`failed to list repos for "${owner}": ${message}`);
51
+ continue;
52
+ }
53
+ }
54
+ const matched = repos.filter(repo => matchesGlob(pattern, repo));
55
+ for (const repo of matched) {
56
+ addRepo(byRepo, repo, target.rulePacks);
57
+ }
58
+ }
59
+ const resolved = [...byRepo.entries()].map(([repo, packs]) => ({ repo, rulePacks: [...packs] }));
60
+ return { targets: resolved, errors };
61
+ }
62
+ //# sourceMappingURL=expand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expand.js","sourceRoot":"","sources":["../../source/run/expand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAgBlD,SAAS,OAAO,CACf,MAAgC,EAChC,IAAY,EACZ,SAAmB;IAEnB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;IACpD,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,OAAiB,EACjB,MAAmB;IAEnB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE3C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAC/C,SAAS;QACV,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACrB,SAAS;QACV,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CACV,0BAA0B,OAAO,qDAAqD,CACtF,CAAC;YACF,SAAS;QACV,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,oBAAoB,OAAO,yBAAyB,CAAC,CAAC;YAClE,SAAS;QACV,CAAC;QAED,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,IAAI,CAAC;gBACJ,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACjC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,CAAC,IAAI,CAAC,6BAA6B,KAAK,MAAM,OAAO,EAAE,CAAC,CAAC;gBAC/D,SAAS;YACV,CAAC;QACF,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACjE,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;IAED,MAAM,QAAQ,GAAyB,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAC/D,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,CAAC,EAAC,CAAC,CAClD,CAAC;IACF,OAAO,EAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAC,CAAC;AACpC,CAAC"}