@prism-d1/cli 1.1.2 → 1.2.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 (160) hide show
  1. package/dist/assets/github-workflows/prism-agent-eval.yml +2 -1
  2. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +11 -1
  3. package/dist/assets/gitlab-workflows/prism-eval-gate.yml +8 -0
  4. package/dist/assets/infra/lib/constructs/otel-collector-construct.ts +96 -0
  5. package/dist/assets/infra/lib/dashboard-stack.ts +27 -0
  6. package/dist/assets/infra/lib/lambda/otel-receiver.ts +278 -8
  7. package/dist/assets/infra/lib/lambda/pricing/litellm-snapshot.json +3769 -0
  8. package/dist/assets/infra/lib/lambda/pricing/price-source.ts +56 -0
  9. package/dist/assets/infra/lib/lambda/pricing/price-table.ts +240 -0
  10. package/dist/assets/infra/lib/lambda/pricing/prices-key.ts +6 -0
  11. package/dist/assets/infra/lib/lambda/pricing/reprice.ts +108 -0
  12. package/dist/assets/infra/lib/lambda/pricing-refresh.ts +352 -0
  13. package/dist/assets/infra/lib/lambda/velocity-widget.ts +124 -1
  14. package/dist/assets/infra/package.json +4 -1
  15. package/dist/assets/metric-hooks/prepare-commit-msg +3 -1
  16. package/dist/src/codewatch/config.d.ts +17 -0
  17. package/dist/src/codewatch/config.d.ts.map +1 -0
  18. package/dist/src/codewatch/config.js +40 -0
  19. package/dist/src/codewatch/config.js.map +1 -0
  20. package/dist/src/codewatch/gitleaks.d.ts +49 -0
  21. package/dist/src/codewatch/gitleaks.d.ts.map +1 -0
  22. package/dist/src/codewatch/gitleaks.js +160 -0
  23. package/dist/src/codewatch/gitleaks.js.map +1 -0
  24. package/dist/src/codewatch/globalHooks.d.ts +52 -0
  25. package/dist/src/codewatch/globalHooks.d.ts.map +1 -0
  26. package/dist/src/codewatch/globalHooks.js +235 -0
  27. package/dist/src/codewatch/globalHooks.js.map +1 -0
  28. package/dist/src/codewatch/hooks.d.ts +38 -0
  29. package/dist/src/codewatch/hooks.d.ts.map +1 -0
  30. package/dist/src/codewatch/hooks.js +176 -0
  31. package/dist/src/codewatch/hooks.js.map +1 -0
  32. package/dist/src/codewatch/prepush.d.ts +37 -0
  33. package/dist/src/codewatch/prepush.d.ts.map +1 -0
  34. package/dist/src/codewatch/prepush.js +231 -0
  35. package/dist/src/codewatch/prepush.js.map +1 -0
  36. package/dist/src/codewatch/results.d.ts +90 -0
  37. package/dist/src/codewatch/results.d.ts.map +1 -0
  38. package/dist/src/codewatch/results.js +121 -0
  39. package/dist/src/codewatch/results.js.map +1 -0
  40. package/dist/src/codewatch/reviewers/claude.d.ts +9 -0
  41. package/dist/src/codewatch/reviewers/claude.d.ts.map +1 -0
  42. package/dist/src/codewatch/reviewers/claude.js +48 -0
  43. package/dist/src/codewatch/reviewers/claude.js.map +1 -0
  44. package/dist/src/codewatch/reviewers/index.d.ts +39 -0
  45. package/dist/src/codewatch/reviewers/index.d.ts.map +1 -0
  46. package/dist/src/codewatch/reviewers/index.js +97 -0
  47. package/dist/src/codewatch/reviewers/index.js.map +1 -0
  48. package/dist/src/codewatch/reviewers/kiro.d.ts +14 -0
  49. package/dist/src/codewatch/reviewers/kiro.d.ts.map +1 -0
  50. package/dist/src/codewatch/reviewers/kiro.js +32 -0
  51. package/dist/src/codewatch/reviewers/kiro.js.map +1 -0
  52. package/dist/src/codewatch/reviewers/types.d.ts +56 -0
  53. package/dist/src/codewatch/reviewers/types.d.ts.map +1 -0
  54. package/dist/src/codewatch/reviewers/types.js +91 -0
  55. package/dist/src/codewatch/reviewers/types.js.map +1 -0
  56. package/dist/src/codewatch/rules.d.ts +12 -0
  57. package/dist/src/codewatch/rules.d.ts.map +1 -0
  58. package/dist/src/codewatch/rules.js +27 -0
  59. package/dist/src/codewatch/rules.js.map +1 -0
  60. package/dist/src/commands/_top/dashboard.d.ts +17 -0
  61. package/dist/src/commands/_top/dashboard.d.ts.map +1 -0
  62. package/dist/src/commands/_top/dashboard.js +76 -0
  63. package/dist/src/commands/_top/dashboard.js.map +1 -0
  64. package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -1
  65. package/dist/src/commands/bedrock-protection/scan-account.js +2 -1
  66. package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -1
  67. package/dist/src/commands/bedrock-protection/scan-org.d.ts.map +1 -1
  68. package/dist/src/commands/bedrock-protection/scan-org.js +16 -4
  69. package/dist/src/commands/bedrock-protection/scan-org.js.map +1 -1
  70. package/dist/src/commands/bootstrapper/install-eval-harness.d.ts.map +1 -1
  71. package/dist/src/commands/bootstrapper/install-eval-harness.js +15 -48
  72. package/dist/src/commands/bootstrapper/install-eval-harness.js.map +1 -1
  73. package/dist/src/commands/bootstrapper/install-git-hooks.d.ts +13 -0
  74. package/dist/src/commands/bootstrapper/install-git-hooks.d.ts.map +1 -1
  75. package/dist/src/commands/bootstrapper/install-git-hooks.js +28 -147
  76. package/dist/src/commands/bootstrapper/install-git-hooks.js.map +1 -1
  77. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
  78. package/dist/src/commands/bootstrapper/setup-otel-sync.js +5 -39
  79. package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
  80. package/dist/src/commands/codewatch/pre-commit.d.ts +7 -0
  81. package/dist/src/commands/codewatch/pre-commit.d.ts.map +1 -0
  82. package/dist/src/commands/codewatch/pre-commit.js +30 -0
  83. package/dist/src/commands/codewatch/pre-commit.js.map +1 -0
  84. package/dist/src/commands/codewatch/pre-push.d.ts +16 -0
  85. package/dist/src/commands/codewatch/pre-push.d.ts.map +1 -0
  86. package/dist/src/commands/codewatch/pre-push.js +32 -0
  87. package/dist/src/commands/codewatch/pre-push.js.map +1 -0
  88. package/dist/src/commands/codewatch/report.d.ts +22 -0
  89. package/dist/src/commands/codewatch/report.d.ts.map +1 -0
  90. package/dist/src/commands/codewatch/report.js +64 -0
  91. package/dist/src/commands/codewatch/report.js.map +1 -0
  92. package/dist/src/commands/enable/codewatch.d.ts +15 -0
  93. package/dist/src/commands/enable/codewatch.d.ts.map +1 -0
  94. package/dist/src/commands/enable/codewatch.js +186 -0
  95. package/dist/src/commands/enable/codewatch.js.map +1 -0
  96. package/dist/src/commands/git/claude-session-context.d.ts.map +1 -1
  97. package/dist/src/commands/git/claude-session-context.js +2 -1
  98. package/dist/src/commands/git/claude-session-context.js.map +1 -1
  99. package/dist/src/commands/git/commit-trailers.js +1 -1
  100. package/dist/src/commands/git/commit-trailers.js.map +1 -1
  101. package/dist/src/commands/workshop/verify-setup.d.ts.map +1 -1
  102. package/dist/src/commands/workshop/verify-setup.js +5 -3
  103. package/dist/src/commands/workshop/verify-setup.js.map +1 -1
  104. package/dist/src/dashboard/codewatch.d.ts +106 -0
  105. package/dist/src/dashboard/codewatch.d.ts.map +1 -0
  106. package/dist/src/dashboard/codewatch.js +119 -0
  107. package/dist/src/dashboard/codewatch.js.map +1 -0
  108. package/dist/src/dashboard/commits.d.ts +96 -0
  109. package/dist/src/dashboard/commits.d.ts.map +1 -0
  110. package/dist/src/dashboard/commits.js +207 -0
  111. package/dist/src/dashboard/commits.js.map +1 -0
  112. package/dist/src/dashboard/page.d.ts +10 -0
  113. package/dist/src/dashboard/page.d.ts.map +1 -0
  114. package/dist/src/dashboard/page.js +315 -0
  115. package/dist/src/dashboard/page.js.map +1 -0
  116. package/dist/src/dashboard/payload.d.ts +111 -0
  117. package/dist/src/dashboard/payload.d.ts.map +1 -0
  118. package/dist/src/dashboard/payload.js +93 -0
  119. package/dist/src/dashboard/payload.js.map +1 -0
  120. package/dist/src/dashboard/report.d.ts +99 -0
  121. package/dist/src/dashboard/report.d.ts.map +1 -0
  122. package/dist/src/dashboard/report.js +300 -0
  123. package/dist/src/dashboard/report.js.map +1 -0
  124. package/dist/src/dashboard/repos.d.ts +58 -0
  125. package/dist/src/dashboard/repos.d.ts.map +1 -0
  126. package/dist/src/dashboard/repos.js +111 -0
  127. package/dist/src/dashboard/repos.js.map +1 -0
  128. package/dist/src/dashboard/server.d.ts +52 -0
  129. package/dist/src/dashboard/server.d.ts.map +1 -0
  130. package/dist/src/dashboard/server.js +163 -0
  131. package/dist/src/dashboard/server.js.map +1 -0
  132. package/dist/src/dashboard/setup.d.ts +52 -0
  133. package/dist/src/dashboard/setup.d.ts.map +1 -0
  134. package/dist/src/dashboard/setup.js +129 -0
  135. package/dist/src/dashboard/setup.js.map +1 -0
  136. package/dist/src/dashboard/usage.d.ts +43 -0
  137. package/dist/src/dashboard/usage.d.ts.map +1 -0
  138. package/dist/src/dashboard/usage.js +88 -0
  139. package/dist/src/dashboard/usage.js.map +1 -0
  140. package/dist/src/index.d.ts +1 -0
  141. package/dist/src/index.d.ts.map +1 -1
  142. package/dist/src/index.js +40 -1
  143. package/dist/src/index.js.map +1 -1
  144. package/dist/src/utils/audit-bedrock.d.ts +1 -0
  145. package/dist/src/utils/audit-bedrock.d.ts.map +1 -1
  146. package/dist/src/utils/audit-bedrock.js +133 -0
  147. package/dist/src/utils/audit-bedrock.js.map +1 -1
  148. package/dist/src/utils/audit-org.d.ts +1 -0
  149. package/dist/src/utils/audit-org.d.ts.map +1 -1
  150. package/dist/src/utils/audit-org.js +155 -0
  151. package/dist/src/utils/audit-org.js.map +1 -1
  152. package/dist/src/utils/otel-sync-schedule.d.ts +22 -0
  153. package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -0
  154. package/dist/src/utils/otel-sync-schedule.js +68 -0
  155. package/dist/src/utils/otel-sync-schedule.js.map +1 -0
  156. package/dist/src/utils/tool-check.d.ts +14 -0
  157. package/dist/src/utils/tool-check.d.ts.map +1 -0
  158. package/dist/src/utils/tool-check.js +42 -0
  159. package/dist/src/utils/tool-check.js.map +1 -0
  160. package/package.json +3 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/dashboard/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Scan report: one pre-push review plus the pre-commit secret scans of the
3
+ * commits it covers. One module builds the data and renders it three ways,
4
+ * shared by GET /report/<id>, GET /report/<id>.md and `prism-cli codewatch report`.
5
+ *
6
+ * Ids are result file names without `.json`. They are only ever looked up in
7
+ * the directory listing of `.prism/results/`; no path is built from one.
8
+ * Secret values never appear: results do not store them, and the secret
9
+ * section projects rule id and location only.
10
+ */
11
+ import { basename } from 'node:path';
12
+ import { readResultEntries } from '../codewatch/results.js';
13
+ import { attributeFindings, Blamer, collectCommits, expandRange, readLog } from './commits.js';
14
+ /** Shape of a result id. Checked before the listing lookup, which is what actually decides. */
15
+ const ID_SHAPE = /^[A-Za-z0-9_-]{1,120}$/;
16
+ /** The listing entry whose id equals `id`, or null. Unknown, malformed and traversal ids all return null. */
17
+ export function findResultById(repoRoot, id, entries) {
18
+ if (typeof id !== 'string' || !ID_SHAPE.test(id))
19
+ return null;
20
+ return (entries ?? readResultEntries(repoRoot)).find((e) => e.id === id) ?? null;
21
+ }
22
+ const isReview = (r) => r.kind === 'review' && r.hook === 'pre-push';
23
+ const byTime = (a, b) => String(a.result.started_at).localeCompare(String(b.result.started_at));
24
+ /** Newest review entries, newest first. */
25
+ export function reviewEntries(entries) {
26
+ return entries.filter((e) => isReview(e.result) && e.result.commit).sort(byTime).reverse();
27
+ }
28
+ const SEV_ORDER = { high: 0, medium: 1, low: 2 };
29
+ /** Resolves `--commit <sha>`: the newest review whose range includes it (prefix match allowed). */
30
+ export function reviewForCommit(entries, sha, log) {
31
+ const want = sha.toLowerCase();
32
+ for (const e of reviewEntries(entries)) {
33
+ if (e.result.status === 'skipped')
34
+ continue;
35
+ const tip = e.result.commit;
36
+ if (tip.startsWith(want))
37
+ return e;
38
+ if (expandRange(log, e.result.base, tip).some((c) => c.startsWith(want)))
39
+ return e;
40
+ }
41
+ return null;
42
+ }
43
+ export function buildReport(repoRoot, entry, all, deps = {}) {
44
+ const rev = entry.result;
45
+ if (!isReview(rev) || !rev.commit)
46
+ throw new Error('not a pre-push review');
47
+ const log = deps.log ?? readLog(repoRoot);
48
+ const blamer = deps.blamer ?? new Blamer(repoRoot);
49
+ const pushed = rev.status !== 'skipped';
50
+ const { range, byCommit } = pushed ? attributeFindings(rev, log, blamer) : { range: [], byCommit: new Map() };
51
+ const subj = (sha) => (sha ? log.get(sha)?.subject ?? null : null);
52
+ // Findings with their commit, grouped by file, worst first.
53
+ const findings = [];
54
+ for (const [sha, fs] of byCommit)
55
+ for (const f of fs)
56
+ findings.push({ ...f, commit: sha, commitSubject: subj(sha) });
57
+ if (!pushed)
58
+ for (const f of rev.findings || [])
59
+ findings.push({ ...f, attributed: 'tip', inPushOf: null, commit: null, commitSubject: null });
60
+ const groups = new Map();
61
+ for (const f of findings) {
62
+ const k = f.file || '(no file)';
63
+ if (!groups.has(k))
64
+ groups.set(k, []);
65
+ groups.get(k).push(f);
66
+ }
67
+ const files = [...groups.entries()].map(([file, fs]) => ({
68
+ file,
69
+ findings: fs.sort((a, b) => SEV_ORDER[a.severity] - SEV_ORDER[b.severity] || (a.line ?? 0) - (b.line ?? 0)),
70
+ }));
71
+ const worst = (fs) => Math.min(...fs.map((f) => SEV_ORDER[f.severity]));
72
+ files.sort((a, b) => worst(a.findings) - worst(b.findings) || b.findings.length - a.findings.length || a.file.localeCompare(b.file));
73
+ const severity = { high: 0, medium: 0, low: 0 };
74
+ const category = { security: 0, quality: 0 };
75
+ for (const f of findings) {
76
+ severity[f.severity]++;
77
+ category[f.category]++;
78
+ }
79
+ // Secret scan state per commit, from the same matching the Commits table uses.
80
+ const rows = collectCommits(repoRoot, all.map((e) => e.result), { log, blamer, maxRows: Number.MAX_SAFE_INTEGER });
81
+ const rowBy = new Map(rows.rows.map((r) => [r.sha, r]));
82
+ const commits = range.map((sha) => {
83
+ const fs = byCommit.get(sha) || [];
84
+ const r = rowBy.get(sha);
85
+ return {
86
+ sha, short: sha.slice(0, 8), subject: subj(sha), authorDate: log.get(sha)?.authorDate ?? null,
87
+ secretScan: r?.secretScan.state ?? 'none', secretScanReason: r?.secretScan.reason ?? null,
88
+ high: fs.filter((f) => f.severity === 'high').length,
89
+ medium: fs.filter((f) => f.severity === 'medium').length,
90
+ low: fs.filter((f) => f.severity === 'low').length,
91
+ };
92
+ }).sort((a, b) => String(b.authorDate ?? '').localeCompare(String(a.authorDate ?? '')));
93
+ // Gitleaks blocks on this branch during the push window: after the previous
94
+ // review of this branch, up to this one.
95
+ const prev = reviewEntries(all).find((e) => e.result.branch === rev.branch && e.result.started_at < rev.started_at);
96
+ const from = prev ? prev.result.started_at : '';
97
+ const gitleaksBlocks = all.map((e) => e.result)
98
+ .filter((r) => r.kind === 'secrets' && r.hook === 'pre-commit' && r.status === 'findings' && r.branch === rev.branch && r.started_at > from && r.started_at <= rev.started_at)
99
+ .sort((a, b) => a.started_at.localeCompare(b.started_at))
100
+ .map((r) => ({ at: r.started_at, branch: r.branch, items: (r.findings || []).map((f) => ({ rule: f.rule, file: f.file, line: f.line })) }));
101
+ const started = Date.parse(rev.started_at);
102
+ const finished = Date.parse(rev.finished_at);
103
+ const state = rev.status === 'error' ? 'error' : rev.status === 'skipped' ? 'skipped' : findings.length ? 'findings' : 'clean';
104
+ return {
105
+ schema: 'prism.codewatch.report.v1',
106
+ id: entry.id,
107
+ repo: { name: basename(repoRoot), path: repoRoot },
108
+ branch: rev.branch, upstream: rev.upstream,
109
+ range: { base: rev.base, tip: rev.commit, commits: range.length },
110
+ reviewer: { tool: rev.tool, version: rev.tool_version, model: rev.model },
111
+ startedAt: rev.started_at, finishedAt: rev.finished_at,
112
+ durationSeconds: Number.isFinite(started) && Number.isFinite(finished) ? Math.max(0, Math.round((finished - started) / 1000)) : null,
113
+ status: rev.status, state, reason: rev.reason, score: rev.score,
114
+ truncated: /diff truncated/i.test(rev.reason || ''),
115
+ summary: rev.summary,
116
+ totals: { severity, category, findings: findings.length },
117
+ files,
118
+ secretScans: commits,
119
+ gitleaksBlocks,
120
+ commits,
121
+ };
122
+ }
123
+ // ---------------------------------------------------------------- renderers
124
+ const SCAN_TEXT = {
125
+ ok: 'ok', 'not-scanned': 'not scanned', 'no-verify': 'no-verify', flagged: 'secrets found', none: 'no record',
126
+ };
127
+ const short = (s) => (s ? s.slice(0, 8) : '-');
128
+ const oneLine = (s) => String(s ?? '').replace(/\s+/g, ' ').trim();
129
+ const loc = (f) => (f.line ? `line ${f.line}` : 'no line');
130
+ const counts = (c) => `${c.high} high, ${c.medium} medium, ${c.low} low`;
131
+ const dur = (s) => (s === null ? '-' : s < 60 ? `${s}s` : `${Math.floor(s / 60)}m ${s % 60}s`);
132
+ export function renderReportJson(r) {
133
+ return JSON.stringify(r, null, 2) + '\n';
134
+ }
135
+ /** Markdown: escapes the characters that would change structure inside list items and code spans. */
136
+ function md(s) {
137
+ return oneLine(s).replace(/([\\`*_[\]<>|#])/g, '\\$1');
138
+ }
139
+ export function renderReportMarkdown(r) {
140
+ const L = [];
141
+ L.push(`# Codewatch scan report: ${md(r.repo.name)}`, '');
142
+ if (r.truncated)
143
+ L.push(`> **Warning:** the diff was truncated before review, so later changes were not reviewed. (${md(r.reason)})`, '');
144
+ L.push(`- **Status:** ${r.state}${r.state === 'error' || r.state === 'skipped' ? ` (${md(r.reason)})` : ''}`);
145
+ L.push(`- **Branch:** ${md(r.branch ?? '-')}${r.upstream ? ` (against ${md(r.upstream)})` : ''}`);
146
+ L.push(`- **Pushed range:** ${short(r.range.base)}..${short(r.range.tip)} (${r.range.commits} commit${r.range.commits === 1 ? '' : 's'})`);
147
+ L.push(`- **Reviewer:** ${md(r.reviewer.tool)}${r.reviewer.model ? ` / ${md(r.reviewer.model)}` : ''}${r.reviewer.version ? ` (${md(r.reviewer.version)})` : ''}`);
148
+ L.push(`- **Started:** ${r.startedAt} · **Finished:** ${r.finishedAt} · **Duration:** ${dur(r.durationSeconds)}`);
149
+ if (r.score !== null)
150
+ L.push(`- **Score:** ${r.score}`);
151
+ L.push(`- **Report id:** ${md(r.id)}`, '');
152
+ L.push('## Summary', '', r.summary ? md(r.summary) : '_No summary._', '');
153
+ L.push('## Totals', '');
154
+ L.push(`- **By severity:** ${counts(r.totals.severity)}`);
155
+ L.push(`- **By category:** ${r.totals.category.security} security, ${r.totals.category.quality} quality`, '');
156
+ L.push('## Findings by file', '');
157
+ if (!r.files.length)
158
+ L.push('_No findings._', '');
159
+ for (const g of r.files) {
160
+ L.push(`### ${md(g.file)}`, '');
161
+ for (const f of g.findings) {
162
+ const who = f.commit ? `${short(f.commit)} "${md(f.commitSubject ?? '')}"${f.inPushOf ? ' (in push of tip; blame could not place this line)' : ''}` : 'not attributed';
163
+ L.push(`- **${f.severity}** · ${f.category} · ${loc(f)} · ${md(f.rule)} · commit ${who}`);
164
+ L.push(` ${md(f.message)}`);
165
+ }
166
+ L.push('');
167
+ }
168
+ L.push('## Secret scan', '');
169
+ if (!r.secretScans.length)
170
+ L.push('_No commits in range._');
171
+ for (const c of r.secretScans)
172
+ L.push(`- ${c.short} ${md(c.subject ?? '(no longer in history)')}: **${SCAN_TEXT[c.secretScan]}**${c.secretScanReason && c.secretScan !== 'ok' ? ` (${md(c.secretScanReason)})` : ''}`);
173
+ L.push('');
174
+ L.push('### Gitleaks blocks during this push', '');
175
+ if (!r.gitleaksBlocks.length)
176
+ L.push('_None._');
177
+ for (const b of r.gitleaksBlocks)
178
+ L.push(`- ${b.at}: ${b.items.map((i) => `${md(i.rule)} at ${md(i.file)}${i.line ? `:${i.line}` : ''}`).join('; ')}`);
179
+ L.push('');
180
+ L.push('## Commits', '');
181
+ if (!r.commits.length)
182
+ L.push('_No commits in range._');
183
+ for (const c of r.commits)
184
+ L.push(`- ${c.short} ${md(c.subject ?? '(no longer in history)')}${c.authorDate ? ` (${c.authorDate})` : ''}: ${counts(c)}`);
185
+ L.push('');
186
+ return L.join('\n');
187
+ }
188
+ export function escapeHtml(s) {
189
+ return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
190
+ }
191
+ const REPORT_CSS = `
192
+ :root { color-scheme: light dark; --bg:#f7f7f8; --card:#fff; --text:#1d1d1f; --muted:#6b6b73; --line:#e3e3e8; --high:#cf222e; --medium:#9a6700; --low:#57606a; --ok:#1a7f37; --warn:#9a6700; --accent:#0969da; }
193
+ @media (prefers-color-scheme: dark) { :root { --bg:#0d1117; --card:#161b22; --text:#e6edf3; --muted:#8b949e; --line:#30363d; --high:#f85149; --medium:#d29922; --low:#8b949e; --ok:#3fb950; --warn:#d29922; --accent:#58a6ff; } }
194
+ * { box-sizing: border-box; }
195
+ body { margin:0; background:var(--bg); color:var(--text); font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; }
196
+ main { max-width:1100px; margin:0 auto; padding:20px; }
197
+ nav { margin-bottom:12px; font-size:13px; } nav a { color:var(--accent); margin-right:14px; }
198
+ section { background:var(--card); border:1px solid var(--line); border-radius:10px; padding:14px 18px; margin-bottom:14px; }
199
+ h1 { font-size:20px; margin:0 0 8px; } h2 { font-size:15px; margin:0 0 10px; } h3 { font-size:13px; margin:14px 0 6px; } h3.file { font-family: ui-monospace, Menlo, monospace; }
200
+ dl { display:grid; grid-template-columns: max-content 1fr; gap:4px 16px; margin:0; } dt { color:var(--muted); } dd { margin:0; overflow-wrap:anywhere; }
201
+ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size:12px; }
202
+ table { width:100%; border-collapse:collapse; font-size:13px; } th, td { text-align:left; padding:5px 6px; border-bottom:1px solid var(--line); vertical-align:top; overflow-wrap:anywhere; } th { color:var(--muted); white-space:nowrap; }
203
+ .sev-high, .sev-medium, .sev-low { white-space:nowrap; } .sev-high { color:var(--high); font-weight:600; } .sev-medium { color:var(--medium); font-weight:600; } .sev-low { color:var(--low); }
204
+ .state { display:inline-block; padding:0 8px; border-radius:10px; border:1px solid currentColor; font-size:12px; font-weight:600; }
205
+ .s-findings, .s-error { color:var(--high); } .s-clean { color:var(--ok); } .s-skipped { color:var(--muted); }
206
+ .alert { border:1px solid var(--warn); border-left-width:4px; border-radius:6px; padding:10px 12px; margin:10px 0; font-weight:600; }
207
+ .muted { color:var(--muted); } .totals { display:flex; gap:24px; flex-wrap:wrap; } .totals b { font-size:20px; display:block; }
208
+ .summary { white-space:pre-wrap; }
209
+ @media print {
210
+ :root { --bg:#fff; --card:#fff; --text:#000; --muted:#444; --line:#bbb; }
211
+ body { font-size:11pt; } main { max-width:none; padding:0; } nav { display:none; }
212
+ section { border:none; border-radius:0; padding:0; margin:0 0 14pt; break-inside:avoid-page; }
213
+ table { page-break-inside:auto; } tr { break-inside:avoid; }
214
+ a { color:inherit; text-decoration:none; }
215
+ }
216
+ `;
217
+ /** Self-contained HTML: inline CSS, no script, every value escaped. */
218
+ export function renderReportHtml(r, opts = {}) {
219
+ const e = escapeHtml;
220
+ const nonce = opts.nonce ? ` nonce="${e(opts.nonce)}"` : '';
221
+ const rows = (cells) => cells.map((c) => `<tr>${c.map((x) => `<td>${x}</td>`).join('')}</tr>`).join('');
222
+ const sev = (s) => `<span class="sev-${s}">${s}</span>`;
223
+ const p = [];
224
+ p.push(`<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">`);
225
+ p.push(`<title>Codewatch report: ${e(r.repo.name)} ${e(short(r.range.tip))}</title><style${nonce}>${REPORT_CSS}</style></head><body><main>`);
226
+ if (opts.links)
227
+ p.push(`<nav><a href="${e(opts.links.back)}">&larr; Dashboard</a><a href="${e(opts.links.markdown)}" download>Download Markdown</a><span class="muted">Print to PDF from the browser's Print dialog.</span></nav>`);
228
+ p.push(`<section><h1>Codewatch scan report: ${e(r.repo.name)}</h1>`);
229
+ if (r.truncated)
230
+ p.push(`<div class="alert" role="alert">The diff was truncated before review, so later changes were not reviewed. ${e(r.reason)}</div>`);
231
+ p.push('<dl>');
232
+ const dd = (k, v) => p.push(`<dt>${k}</dt><dd>${v}</dd>`);
233
+ dd('Status', `<span class="state s-${e(r.state)}">${e(r.state)}</span>${r.state === 'error' || r.state === 'skipped' ? ` ${e(r.reason)}` : ''}`);
234
+ dd('Branch', `${e(r.branch ?? '-')}${r.upstream ? ` <span class="muted">against ${e(r.upstream)}</span>` : ''}`);
235
+ dd('Pushed range', `<code>${e(short(r.range.base))}..${e(short(r.range.tip))}</code> (${r.range.commits} commit${r.range.commits === 1 ? '' : 's'})`);
236
+ dd('Reviewer', `${e(r.reviewer.tool)}${r.reviewer.model ? ` / ${e(r.reviewer.model)}` : ''}${r.reviewer.version ? ` <span class="muted">${e(r.reviewer.version)}</span>` : ''}`);
237
+ dd('Started', e(r.startedAt));
238
+ dd('Finished', `${e(r.finishedAt)} <span class="muted">(${e(dur(r.durationSeconds))})</span>`);
239
+ if (r.score !== null)
240
+ dd('Score', e(r.score));
241
+ dd('Repository', `<code>${e(r.repo.path)}</code>`);
242
+ p.push('</dl></section>');
243
+ p.push(`<section><h2>Summary</h2><p class="summary">${r.summary ? e(r.summary) : '<span class="muted">No summary.</span>'}</p></section>`);
244
+ const t = r.totals;
245
+ p.push(`<section><h2>Totals</h2><div class="totals">`
246
+ + `<div><b class="sev-high">${t.severity.high}</b>high</div><div><b class="sev-medium">${t.severity.medium}</b>medium</div><div><b class="sev-low">${t.severity.low}</b>low</div>`
247
+ + `<div><b>${t.category.security}</b>security</div><div><b>${t.category.quality}</b>quality</div></div></section>`);
248
+ p.push('<section><h2>Findings by file</h2>');
249
+ if (!r.files.length)
250
+ p.push('<p class="muted">No findings.</p>');
251
+ for (const g of r.files) {
252
+ p.push(`<h3 class="file">${e(g.file)}</h3><table><thead><tr><th>Severity</th><th>Category</th><th>Line</th><th>Rule</th><th>Message</th><th>Commit</th></tr></thead><tbody>`);
253
+ p.push(rows(g.findings.map((f) => [
254
+ sev(f.severity), e(f.category), e(f.line ?? '-'), e(f.rule), e(f.message),
255
+ f.commit ? `<code>${e(short(f.commit))}</code> ${e(f.commitSubject ?? '')}${f.inPushOf ? '<br><span class="muted">in push of tip; blame could not place this line</span>' : ''}` : '<span class="muted">not attributed</span>',
256
+ ])));
257
+ p.push('</tbody></table>');
258
+ }
259
+ p.push('</section>');
260
+ p.push('<section><h2>Secret scan</h2>');
261
+ if (!r.secretScans.length)
262
+ p.push('<p class="muted">No commits in range.</p>');
263
+ else
264
+ p.push(`<table><thead><tr><th>Commit</th><th>Subject</th><th>Pre-commit scan</th></tr></thead><tbody>${rows(r.secretScans.map((c) => [
265
+ `<code>${e(c.short)}</code>`, e(c.subject ?? '(no longer in history)'),
266
+ `${e(SCAN_TEXT[c.secretScan])}${c.secretScanReason && c.secretScan !== 'ok' ? `<br><span class="muted">${e(c.secretScanReason)}</span>` : ''}`,
267
+ ]))}</tbody></table>`);
268
+ p.push('<h3>Gitleaks blocks during this push</h3>');
269
+ if (!r.gitleaksBlocks.length)
270
+ p.push('<p class="muted">None.</p>');
271
+ else
272
+ p.push(`<table><thead><tr><th>When</th><th>Rule</th><th>Location</th></tr></thead><tbody>${rows(r.gitleaksBlocks.flatMap((b) => b.items.map((i) => [
273
+ e(b.at), e(i.rule), `<code>${e(i.file)}${i.line ? `:${e(i.line)}` : ''}</code>`
274
+ ])))}</tbody></table>`);
275
+ p.push('</section>');
276
+ p.push('<section><h2>Commits</h2>');
277
+ if (!r.commits.length)
278
+ p.push('<p class="muted">No commits in range.</p>');
279
+ else
280
+ p.push(`<table><thead><tr><th>Commit</th><th>Subject</th><th>Date</th><th>High</th><th>Medium</th><th>Low</th></tr></thead><tbody>${rows(r.commits.map((c) => [
281
+ `<code>${e(c.short)}</code>`, e(c.subject ?? '(no longer in history)'), e(c.authorDate ?? '-'), e(c.high), e(c.medium), e(c.low)
282
+ ]))}</tbody></table>`);
283
+ p.push(`<p class="muted">Report id ${e(r.id)} · generated by prism-cli codewatch</p></section>`);
284
+ p.push('</main></body></html>');
285
+ return p.join('');
286
+ }
287
+ /** Finds `id` in any of `repos` and builds its report; null when unknown or not a review. */
288
+ export function reportFromRepos(repos, id) {
289
+ for (const repo of repos) {
290
+ const entries = readResultEntries(repo);
291
+ const hit = findResultById(repo, id, entries);
292
+ if (!hit)
293
+ continue;
294
+ if (!isReview(hit.result) || !hit.result.commit)
295
+ return null;
296
+ return buildReport(repo, hit, entries);
297
+ }
298
+ return null;
299
+ }
300
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/dashboard/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ export interface RepoRef {
2
+ name: string;
3
+ /** Real path (symlinks resolved), so the current repo and a scanned one compare equal. */
4
+ path: string;
5
+ /** Contains the working directory the dashboard was started in. */
6
+ current: boolean;
7
+ /** Has a `.prism/` directory (codewatch or another PRISM installer has run here). */
8
+ hasPrism: boolean;
9
+ }
10
+ /**
11
+ * Directory names never descended into. Hidden names (leading `.`) are skipped
12
+ * separately, which covers `.git`, `.cache`, `.venv` and the like.
13
+ */
14
+ export declare const SKIP_DIRS: Set<string>;
15
+ export declare const DEFAULT_SCAN_DEPTH = 3;
16
+ export declare const MAX_REPOS = 200;
17
+ /** Hard cap on directories listed, so an unusually wide home cannot stall the page. */
18
+ export declare const MAX_DIRS_VISITED = 20000;
19
+ export declare function gitToplevel(cwd: string): string | null;
20
+ export interface ScanResult {
21
+ repos: RepoRef[];
22
+ /** Directories listed. */
23
+ visited: number;
24
+ /** A cap (MAX_REPOS or MAX_DIRS_VISITED) stopped the scan early. */
25
+ truncated: boolean;
26
+ }
27
+ /**
28
+ * Git repos under `root`, at most `depth` levels below it. `.git` may be a
29
+ * directory or a file (a linked worktree's or submodule's pointer).
30
+ *
31
+ * - The walk stops at any git repo: nothing inside a repo is scanned, so
32
+ * nested repos and big working trees are skipped.
33
+ * - Hidden directories and SKIP_DIRS are never entered.
34
+ * - Symlinks are not followed (Dirent.isDirectory() is false for a link).
35
+ * - An unreadable directory is skipped, not an error.
36
+ * - `root` itself is never treated as a repo, so a home directory kept under
37
+ * git (dotfiles) does not end the scan before it starts.
38
+ */
39
+ export declare function scanForRepos(root: string, depth?: number): ScanResult;
40
+ export interface DiscoverOptions {
41
+ cwd: string;
42
+ /** Scan root; default the home directory. */
43
+ root?: string;
44
+ /** Injected in tests instead of os.homedir(). */
45
+ home?: string;
46
+ }
47
+ export interface Discovery {
48
+ repos: RepoRef[];
49
+ scannedRoot: string;
50
+ /** Path of the repo containing cwd, or null. */
51
+ currentRepo: string | null;
52
+ scanMs: number;
53
+ truncated: boolean;
54
+ /** Set when the scan root could not be used. */
55
+ error: string | null;
56
+ }
57
+ export declare function discoverRepos(opts: DiscoverOptions): Discovery;
58
+ //# sourceMappingURL=repos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repos.d.ts","sourceRoot":"","sources":["../../../src/dashboard/repos.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,aAAoG,CAAC;AAC3H,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,SAAS,MAAM,CAAC;AAC7B,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGtD;AAUD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAqB,GAAG,UAAU,CAuBjF;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,CAe9D"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Which repositories the dashboard shows.
3
+ *
4
+ * Default: every git repo under the user's home directory (3 levels deep),
5
+ * wherever the dashboard is started from, whether or not codewatch is set up
6
+ * in it -- a repo without codewatch is shown as missing. A repo is any
7
+ * directory with `.git`, as a directory or as a file (linked worktrees and
8
+ * submodules). The repo containing the working directory is listed first. `--root` moves the
9
+ * scan. Everything goes through discoverRepos() so a registry could be added
10
+ * later as one more source.
11
+ */
12
+ import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs';
13
+ import { homedir } from 'node:os';
14
+ import { basename, join, resolve } from 'node:path';
15
+ import { spawnSync } from 'node:child_process';
16
+ /**
17
+ * Directory names never descended into. Hidden names (leading `.`) are skipped
18
+ * separately, which covers `.git`, `.cache`, `.venv` and the like.
19
+ */
20
+ export const SKIP_DIRS = new Set(['node_modules', 'Library', 'build', 'dist', 'target', 'venv', '__pycache__', 'cdk.out']);
21
+ export const DEFAULT_SCAN_DEPTH = 3;
22
+ export const MAX_REPOS = 200;
23
+ /** Hard cap on directories listed, so an unusually wide home cannot stall the page. */
24
+ export const MAX_DIRS_VISITED = 20_000;
25
+ export function gitToplevel(cwd) {
26
+ const r = spawnSync('git', ['-C', cwd, 'rev-parse', '--show-toplevel'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
27
+ return r.status === 0 && r.stdout.trim() ? r.stdout.trim() : null;
28
+ }
29
+ function real(p) {
30
+ try {
31
+ return realpathSync(p);
32
+ }
33
+ catch {
34
+ return resolve(p);
35
+ }
36
+ }
37
+ function isDir(p) {
38
+ try {
39
+ return statSync(p).isDirectory();
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ /**
46
+ * Git repos under `root`, at most `depth` levels below it. `.git` may be a
47
+ * directory or a file (a linked worktree's or submodule's pointer).
48
+ *
49
+ * - The walk stops at any git repo: nothing inside a repo is scanned, so
50
+ * nested repos and big working trees are skipped.
51
+ * - Hidden directories and SKIP_DIRS are never entered.
52
+ * - Symlinks are not followed (Dirent.isDirectory() is false for a link).
53
+ * - An unreadable directory is skipped, not an error.
54
+ * - `root` itself is never treated as a repo, so a home directory kept under
55
+ * git (dotfiles) does not end the scan before it starts.
56
+ */
57
+ export function scanForRepos(root, depth = DEFAULT_SCAN_DEPTH) {
58
+ const repos = [];
59
+ let visited = 0;
60
+ let truncated = false;
61
+ const walk = (dir, level) => {
62
+ if (truncated)
63
+ return;
64
+ if (level > 0 && existsSync(join(dir, '.git'))) {
65
+ repos.push({ name: basename(dir), path: real(dir), current: false, hasPrism: isDir(join(dir, '.prism')) });
66
+ if (repos.length >= MAX_REPOS)
67
+ truncated = true;
68
+ return;
69
+ }
70
+ if (level >= depth)
71
+ return;
72
+ if (++visited > MAX_DIRS_VISITED) {
73
+ truncated = true;
74
+ return;
75
+ }
76
+ let entries;
77
+ try {
78
+ entries = readdirSync(dir, { withFileTypes: true });
79
+ }
80
+ catch {
81
+ return;
82
+ }
83
+ entries.sort((a, b) => a.name.localeCompare(b.name));
84
+ for (const e of entries) {
85
+ if (!e.isDirectory() || e.name.startsWith('.') || SKIP_DIRS.has(e.name))
86
+ continue;
87
+ walk(join(dir, e.name), level + 1);
88
+ }
89
+ };
90
+ walk(resolve(root), 0);
91
+ return { repos, visited, truncated };
92
+ }
93
+ export function discoverRepos(opts) {
94
+ const t0 = Date.now();
95
+ const top = gitToplevel(opts.cwd);
96
+ const currentRepo = top ? real(top) : null;
97
+ const scannedRoot = resolve(opts.root || opts.home || homedir());
98
+ const out = [];
99
+ if (currentRepo) {
100
+ out.push({ name: basename(currentRepo), path: currentRepo, current: true, hasPrism: isDir(join(currentRepo, '.prism')) });
101
+ }
102
+ if (!isDir(scannedRoot)) {
103
+ return { repos: out, scannedRoot, currentRepo, scanMs: Date.now() - t0, truncated: false, error: `scan root is not a directory: ${scannedRoot}` };
104
+ }
105
+ const scan = scanForRepos(scannedRoot);
106
+ for (const r of scan.repos)
107
+ if (r.path !== currentRepo)
108
+ out.push(r);
109
+ return { repos: out, scannedRoot, currentRepo, scanMs: Date.now() - t0, truncated: scan.truncated, error: null };
110
+ }
111
+ //# sourceMappingURL=repos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repos.js","sourceRoot":"","sources":["../../../src/dashboard/repos.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Loopback-only HTTP server for `prism-cli dashboard`.
3
+ *
4
+ * Access control, all enforced on every request:
5
+ * - bound to 127.0.0.1 only (the host is a constant, not an option);
6
+ * - a per-run 256-bit random token, accepted once from `/?token=` and
7
+ * exchanged for an HttpOnly, SameSite=Strict cookie, then required as that
8
+ * cookie on every request (compared in constant time);
9
+ * - the Host header must be 127.0.0.1:<port> or localhost:<port>, which
10
+ * defeats DNS rebinding (a rebound name arrives with its own Host);
11
+ * - GET only, read-only routes, no CORS headers, strict CSP.
12
+ *
13
+ * Why a minted token and not a platform auth mechanism: the server is
14
+ * reachable only from this machine, the audience is the developer running it,
15
+ * and the CLI ships as public sample code, so it uses the loopback-plus-token
16
+ * pattern native to local developer tools (Jupyter, VS Code server) rather
17
+ * than any hosted identity provider. It must never be bound beyond loopback.
18
+ */
19
+ import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
20
+ import { type ScanReport } from './report.js';
21
+ export declare const BIND_HOST = "127.0.0.1";
22
+ export declare function newToken(): string;
23
+ export declare function cookieName(port: number): string;
24
+ export interface HandlerOptions {
25
+ token: string;
26
+ /** Read at request time: the real port is known only after listen(). */
27
+ getPort: () => number;
28
+ getPayload: () => Promise<unknown>;
29
+ /**
30
+ * Looks a report up by result id among the dashboard's repos. The id is
31
+ * matched against directory listings only; it is never turned into a path.
32
+ */
33
+ getReport?: (id: string) => Promise<ScanReport | null>;
34
+ }
35
+ export declare function createHandler(opts: HandlerOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
36
+ export interface RunningServer {
37
+ server: Server;
38
+ port: number;
39
+ token: string;
40
+ url: string;
41
+ close: () => Promise<void>;
42
+ }
43
+ /** Starts the server on 127.0.0.1. `port` 0 (default) picks a free port. */
44
+ export declare function startServer(opts: {
45
+ port?: number;
46
+ token?: string;
47
+ getPayload: () => Promise<unknown>;
48
+ getReport?: (id: string) => Promise<ScanReport | null>;
49
+ }): Promise<RunningServer>;
50
+ /** Memoises the payload for `ttlMs` and shares one in-flight build between requests. */
51
+ export declare function cachedPayload(build: () => Promise<unknown>, ttlMs?: number): () => Promise<unknown>;
52
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/dashboard/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjG,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtF,eAAO,MAAM,SAAS,cAAc,CAAC;AAErC,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI/C;AAqCD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CACxD;AAKD,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,IAClC,KAAK,eAAe,EAAE,KAAK,cAAc,KAAG,OAAO,CAAC,IAAI,CAAC,CAwDxE;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAAC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAoBvL;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAWnG"}