depstein 0.1.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 (65) hide show
  1. package/README.md +438 -0
  2. package/dist/core/cache.d.ts +15 -0
  3. package/dist/core/cache.js +75 -0
  4. package/dist/core/cache.js.map +1 -0
  5. package/dist/core/fetcher.d.ts +7 -0
  6. package/dist/core/fetcher.js +59 -0
  7. package/dist/core/fetcher.js.map +1 -0
  8. package/dist/core/replacements.d.ts +32 -0
  9. package/dist/core/replacements.js +419 -0
  10. package/dist/core/replacements.js.map +1 -0
  11. package/dist/core/scanner.d.ts +7 -0
  12. package/dist/core/scanner.js +298 -0
  13. package/dist/core/scanner.js.map +1 -0
  14. package/dist/core/scorer.d.ts +5 -0
  15. package/dist/core/scorer.js +289 -0
  16. package/dist/core/scorer.js.map +1 -0
  17. package/dist/core/types.d.ts +99 -0
  18. package/dist/core/types.js +2 -0
  19. package/dist/core/types.js.map +1 -0
  20. package/dist/core/vulnerabilities.d.ts +5 -0
  21. package/dist/core/vulnerabilities.js +93 -0
  22. package/dist/core/vulnerabilities.js.map +1 -0
  23. package/dist/ecosystems/cargo.d.ts +2 -0
  24. package/dist/ecosystems/cargo.js +74 -0
  25. package/dist/ecosystems/cargo.js.map +1 -0
  26. package/dist/ecosystems/golang.d.ts +2 -0
  27. package/dist/ecosystems/golang.js +90 -0
  28. package/dist/ecosystems/golang.js.map +1 -0
  29. package/dist/ecosystems/npm.d.ts +2 -0
  30. package/dist/ecosystems/npm.js +92 -0
  31. package/dist/ecosystems/npm.js.map +1 -0
  32. package/dist/ecosystems/pypi.d.ts +2 -0
  33. package/dist/ecosystems/pypi.js +80 -0
  34. package/dist/ecosystems/pypi.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +303 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/tui/colors.d.ts +17 -0
  39. package/dist/tui/colors.js +86 -0
  40. package/dist/tui/colors.js.map +1 -0
  41. package/dist/tui/dashboard.d.ts +7 -0
  42. package/dist/tui/dashboard.js +236 -0
  43. package/dist/tui/dashboard.js.map +1 -0
  44. package/dist/tui/detail.d.ts +6 -0
  45. package/dist/tui/detail.js +68 -0
  46. package/dist/tui/detail.js.map +1 -0
  47. package/dist/tui/picker.d.ts +7 -0
  48. package/dist/tui/picker.js +62 -0
  49. package/dist/tui/picker.js.map +1 -0
  50. package/dist/tui/summary.d.ts +6 -0
  51. package/dist/tui/summary.js +13 -0
  52. package/dist/tui/summary.js.map +1 -0
  53. package/dist/tui/table.d.ts +9 -0
  54. package/dist/tui/table.js +50 -0
  55. package/dist/tui/table.js.map +1 -0
  56. package/dist/utils/format.d.ts +9 -0
  57. package/dist/utils/format.js +72 -0
  58. package/dist/utils/format.js.map +1 -0
  59. package/dist/utils/http.d.ts +2 -0
  60. package/dist/utils/http.js +53 -0
  61. package/dist/utils/http.js.map +1 -0
  62. package/dist/utils/spinner.d.ts +11 -0
  63. package/dist/utils/spinner.js +40 -0
  64. package/dist/utils/spinner.js.map +1 -0
  65. package/package.json +50 -0
package/dist/index.js ADDED
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ import React from 'react';
3
+ import { render } from 'ink';
4
+ import { Command } from 'commander';
5
+ import { readFileSync, writeFileSync } from 'fs';
6
+ import { fileURLToPath } from 'url';
7
+ import { dirname, join, resolve } from 'path';
8
+ import { scan, findWorkspaceRoots } from './core/scanner.js';
9
+ import { fetchAll } from './core/fetcher.js';
10
+ import { score as scoreOne, getGrade, getReplacementPackage } from './core/scorer.js';
11
+ import { Dashboard } from './tui/dashboard.js';
12
+ import { PickerApp } from './tui/picker.js';
13
+ import { Spinner } from './utils/spinner.js';
14
+ // ── Version ────────────────────────────────────────────────────────────────────
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ function readVersion() {
17
+ try {
18
+ const pkgPath = join(__dirname, '..', 'package.json');
19
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
20
+ return pkg.version;
21
+ }
22
+ catch {
23
+ return '0.1.0';
24
+ }
25
+ }
26
+ // ── Build AuditResult ──────────────────────────────────────────────────────────
27
+ function buildResult(projectPath, ecosystem, scored) {
28
+ const avg = scored.length > 0
29
+ ? scored.reduce((s, d) => s + d.totalScore, 0) / scored.length
30
+ : 0;
31
+ return {
32
+ projectPath,
33
+ ecosystem,
34
+ scoredDependencies: scored,
35
+ averageScore: avg,
36
+ grade: getGrade(Math.round(avg)),
37
+ totalCount: scored.length,
38
+ criticalCount: scored.filter(d => d.grade === 'F').length,
39
+ poorCount: scored.filter(d => d.grade === 'D').length,
40
+ fairCount: scored.filter(d => d.grade === 'C').length,
41
+ goodCount: scored.filter(d => d.grade === 'B').length,
42
+ excellentCount: scored.filter(d => d.grade === 'A').length,
43
+ timestamp: new Date().toISOString(),
44
+ };
45
+ }
46
+ // ── JSON mode ─────────────────────────────────────────────────────────────────
47
+ async function runJsonMode(scanResult, options) {
48
+ const spinner = new Spinner();
49
+ const { dependencies } = scanResult;
50
+ spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
51
+ let lastDone = 0;
52
+ const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
53
+ if (done !== lastDone) {
54
+ spinner.update(`[${done}/${total}] ${current}`);
55
+ lastDone = done;
56
+ }
57
+ });
58
+ spinner.succeed(`Fetched ${metadata.length} packages`);
59
+ const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
60
+ const result = buildResult(scanResult.projectPath, scanResult.ecosystem, scored);
61
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
62
+ // CI threshold check
63
+ if (options.minScore != null && result.averageScore < options.minScore) {
64
+ process.stderr.write(`\n✗ Average score ${Math.round(result.averageScore)}/100 is below ` +
65
+ `the required threshold of ${options.minScore}/100\n`);
66
+ process.exit(1);
67
+ }
68
+ }
69
+ // ── CI mode ─────────────────────────────────────────────────────────────────
70
+ //
71
+ // Plain-text output + GitHub Actions ::error:: annotations for poor packages.
72
+ // Exits with code 1 if average score is below the threshold (default 70).
73
+ async function runCiMode(scanResult, options) {
74
+ const spinner = new Spinner();
75
+ const { dependencies } = scanResult;
76
+ spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
77
+ let lastDone = 0;
78
+ const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
79
+ if (done !== lastDone) {
80
+ spinner.update(`[${done}/${total}] ${current}`);
81
+ lastDone = done;
82
+ }
83
+ });
84
+ spinner.succeed(`Fetched ${metadata.length} packages`);
85
+ const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
86
+ const result = buildResult(scanResult.projectPath, scanResult.ecosystem, scored);
87
+ const threshold = options.minScore ?? 70;
88
+ const isGHA = process.env['GITHUB_ACTIONS'] === 'true';
89
+ // Table header
90
+ process.stdout.write(`\ndepstein CI — ${result.totalCount} packages, avg ${Math.round(result.averageScore)}/100 (${result.grade})\n`);
91
+ process.stdout.write(`threshold: ${threshold}/100\n\n`);
92
+ // Per-package lines
93
+ const sorted = [...scored].sort((a, b) => a.totalScore - b.totalScore);
94
+ for (const dep of sorted) {
95
+ const icon = dep.grade === 'F' ? '✗' : dep.grade === 'D' ? '!' : dep.grade === 'C' ? '~' : '✓';
96
+ const issueStr = dep.issues.length > 0 ? dep.issues.join(', ') : 'ok';
97
+ process.stdout.write(` ${icon} ${dep.raw.name.padEnd(30)} ${String(dep.totalScore).padStart(3)}/100 ${dep.grade} ${issueStr}\n`);
98
+ if (dep.suggestion) {
99
+ process.stdout.write(` → ${dep.suggestion}\n`);
100
+ }
101
+ // GitHub Actions annotation for F/D packages
102
+ if (isGHA && (dep.grade === 'F' || dep.grade === 'D')) {
103
+ const msg = `${dep.raw.name} scored ${dep.totalScore}/100 (${dep.grade}) — ${issueStr}`;
104
+ process.stdout.write(`::error title=${dep.raw.name}::${msg}\n`);
105
+ }
106
+ }
107
+ process.stdout.write('\n');
108
+ const failed = result.averageScore < threshold;
109
+ if (failed) {
110
+ const msg = `Average score ${Math.round(result.averageScore)}/100 is below threshold ${threshold}/100`;
111
+ process.stderr.write(`✗ ${msg}\n`);
112
+ if (isGHA) {
113
+ process.stdout.write(`::error title=depstein::${msg}\n`);
114
+ }
115
+ process.exit(1);
116
+ }
117
+ else {
118
+ process.stdout.write(`✓ Average score ${Math.round(result.averageScore)}/100 meets threshold ${threshold}/100\n`);
119
+ }
120
+ }
121
+ // ── --fix mode ────────────────────────────────────────────────────────────────
122
+ //
123
+ // Reads package.json, replaces known deprecated packages with their recommended
124
+ // alternatives, writes the modified file, and prints what changed.
125
+ // The user must run `npm install` afterward to apply the changes.
126
+ async function runFixMode(scanResult, options) {
127
+ const spinner = new Spinner();
128
+ const { dependencies } = scanResult;
129
+ if (scanResult.ecosystem !== 'npm') {
130
+ process.stderr.write('--fix currently only supports npm projects (package.json)\n');
131
+ process.exit(1);
132
+ }
133
+ const pkgJsonPath = join(scanResult.projectPath, 'package.json');
134
+ let pkgJson;
135
+ try {
136
+ pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
137
+ }
138
+ catch {
139
+ process.stderr.write(`Cannot read ${pkgJsonPath}\n`);
140
+ process.exit(1);
141
+ }
142
+ spinner.start(`Fetching metadata for ${dependencies.length} packages…`);
143
+ let lastDone = 0;
144
+ const metadata = await fetchAll(dependencies, options.noCache, (done, total, current) => {
145
+ if (done !== lastDone) {
146
+ spinner.update(`[${done}/${total}] ${current}`);
147
+ lastDone = done;
148
+ }
149
+ });
150
+ spinner.succeed(`Fetched ${metadata.length} packages`);
151
+ const scored = metadata.map((meta, i) => scoreOne(dependencies[i], meta));
152
+ // Collect packages with a real npm package replacement
153
+ const replacements = [];
154
+ for (const dep of scored) {
155
+ const replacement = getReplacementPackage(dep.raw.name);
156
+ if (replacement) {
157
+ replacements.push({ from: dep.raw.name, to: replacement, reason: dep.suggestion ?? '' });
158
+ }
159
+ }
160
+ if (replacements.length === 0) {
161
+ process.stdout.write('✓ No replacements found — all packages look fine!\n');
162
+ return;
163
+ }
164
+ const deps = (pkgJson.dependencies ?? {});
165
+ const devDeps = (pkgJson.devDependencies ?? {});
166
+ const applied = [];
167
+ for (const { from, to, reason } of replacements) {
168
+ if (from in deps) {
169
+ delete deps[from];
170
+ deps[to] = '*';
171
+ applied.push({ from, to, reason });
172
+ }
173
+ else if (from in devDeps) {
174
+ delete devDeps[from];
175
+ devDeps[to] = '*';
176
+ applied.push({ from, to, reason });
177
+ }
178
+ }
179
+ if (applied.length === 0) {
180
+ process.stdout.write('✓ No matching packages found in package.json to replace.\n');
181
+ return;
182
+ }
183
+ if (Object.keys(deps).length > 0)
184
+ pkgJson.dependencies = deps;
185
+ if (Object.keys(devDeps).length > 0)
186
+ pkgJson.devDependencies = devDeps;
187
+ writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8');
188
+ process.stdout.write('\n✓ package.json updated:\n\n');
189
+ for (const { from, to, reason } of applied) {
190
+ process.stdout.write(` ${from} → ${to}\n`);
191
+ if (reason)
192
+ process.stdout.write(` ${reason}\n`);
193
+ }
194
+ process.stdout.write('\nRun npm install to apply changes.\n\n');
195
+ }
196
+ // ── Main ───────────────────────────────────────────────────────────────────────
197
+ async function main() {
198
+ const program = new Command();
199
+ program
200
+ .name('depstein')
201
+ .description('Dependency health scorer for npm, PyPI, Cargo, and Go projects')
202
+ .version(readVersion(), '-v, --version')
203
+ .argument('[path]', 'Path to project directory', '.')
204
+ .option('--ecosystem <type>', 'Force ecosystem: npm | pypi | cargo | golang')
205
+ .option('--filter <mode>', 'Filter: all | critical | poor | dev | prod', 'all')
206
+ .option('--sort <by>', 'Sort by: score | name | size | updated', 'score')
207
+ .option('--no-cache', 'Bypass disk cache')
208
+ .option('--json', 'Output raw JSON instead of TUI')
209
+ .option('--top <n>', 'Show only the N worst packages')
210
+ .option('--fix', 'Replace deprecated packages in package.json with better alternatives')
211
+ .option('--min-score <n>', 'Exit with code 1 if average score drops below N (CI mode)')
212
+ .option('--ci', 'CI mode: plain text + GitHub Actions ::error:: annotations (default threshold 70)')
213
+ .addHelpText('after', `
214
+ Examples:
215
+ $ depstein Analyze current directory
216
+ $ depstein ~/my-project Analyze specific project
217
+ $ depstein --filter critical Show only failing deps
218
+ $ depstein --json > report.json Export full report
219
+ $ depstein --top 10 Show 10 worst packages
220
+ $ depstein --no-cache Bypass cache for fresh data
221
+ $ depstein --fix Replace deprecated packages in package.json
222
+ $ depstein --min-score 75 Fail CI if avg score < 75
223
+ $ depstein --json --min-score 75 Combined: JSON output + CI threshold
224
+ $ depstein --ci CI mode with GitHub Actions annotations
225
+ $ depstein --ci --min-score 80 CI mode with custom threshold
226
+ `);
227
+ program.parse(process.argv);
228
+ const projectArg = program.args[0] ?? '.';
229
+ const opts = program.opts();
230
+ // commander uses --no-cache → opts.cache = false
231
+ const noCache = opts.cache === false || opts.noCache === true;
232
+ const options = {
233
+ path: resolve(projectArg),
234
+ ecosystem: opts.ecosystem,
235
+ filter: opts.filter ?? 'all',
236
+ sort: opts.sort ?? 'score',
237
+ noCache,
238
+ json: opts.json ?? false,
239
+ top: opts.top ? parseInt(opts.top, 10) : undefined,
240
+ fix: opts.fix ?? false,
241
+ minScore: opts.minScore ? parseInt(opts.minScore, 10) : undefined,
242
+ ci: opts.ci ?? false,
243
+ };
244
+ // Validate flags
245
+ const validFilters = ['all', 'critical', 'poor', 'dev', 'prod'];
246
+ if (!validFilters.includes(options.filter)) {
247
+ process.stderr.write(`Invalid --filter value "${options.filter}". Use: ${validFilters.join(' | ')}\n`);
248
+ process.exit(1);
249
+ }
250
+ const validSorts = ['score', 'name', 'size', 'updated'];
251
+ if (!validSorts.includes(options.sort)) {
252
+ process.stderr.write(`Invalid --sort value "${options.sort}". Use: ${validSorts.join(' | ')}\n`);
253
+ process.exit(1);
254
+ }
255
+ // Scan project
256
+ const scanResult = scan(options.path, options.ecosystem);
257
+ if (!scanResult) {
258
+ // No project at the given path — open the interactive path-picker TUI
259
+ // instead of dumping a plain-text error. --json / --ci / --fix still
260
+ // need a real project, so keep the error path for those modes.
261
+ if (options.json || options.ci || options.fix) {
262
+ const workspaceRoots = findWorkspaceRoots(options.path);
263
+ if (workspaceRoots.length > 0) {
264
+ process.stderr.write(`Monorepo detected with ${workspaceRoots.length} workspace packages.\n` +
265
+ `Run depstein with a specific workspace path:\n` +
266
+ workspaceRoots.slice(0, 5).map(r => ` depstein ${r}`).join('\n') + '\n');
267
+ }
268
+ else {
269
+ process.stderr.write(`No recognized project found in: ${options.path}\n` +
270
+ `Expected: package.json, requirements.txt, pyproject.toml, go.mod, or Cargo.toml\n`);
271
+ }
272
+ process.exit(1);
273
+ }
274
+ // Interactive TUI picker
275
+ const { waitUntilExit } = render(React.createElement(PickerApp, { initialPath: options.path, options }), { exitOnCtrlC: true });
276
+ await waitUntilExit();
277
+ return;
278
+ }
279
+ if (scanResult.dependencies.length === 0) {
280
+ process.stderr.write(`No dependencies found in ${options.path}\n`);
281
+ process.exit(0);
282
+ }
283
+ if (options.ci) {
284
+ await runCiMode(scanResult, options);
285
+ return;
286
+ }
287
+ if (options.fix) {
288
+ await runFixMode(scanResult, options);
289
+ return;
290
+ }
291
+ if (options.json) {
292
+ await runJsonMode(scanResult, options);
293
+ return;
294
+ }
295
+ // TUI mode
296
+ const { waitUntilExit } = render(React.createElement(Dashboard, { scanResult, options }), { exitOnCtrlC: true });
297
+ await waitUntilExit();
298
+ }
299
+ main().catch(err => {
300
+ process.stderr.write(`\nFatal error: ${err.message}\n`);
301
+ process.exit(1);
302
+ });
303
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Grade } from '../core/types.js';
2
+ export declare const ACCENT = "#e04a1a";
3
+ export declare function gradeColor(grade: Grade): string;
4
+ export declare function scoreColor(score: number, text?: string | number): string;
5
+ /**
6
+ * Color an issue label with an icon prefix.
7
+ * vulnerable / abandoned → red ⚠
8
+ * no types / huge size → yellow ◆
9
+ * outdated / license → orange ◆
10
+ */
11
+ export declare function issueColor(issue: string): string;
12
+ export declare function severityColor(severity: string): string;
13
+ export declare function barColor(score: number, bar: string): string;
14
+ /**
15
+ * Grade-distribution bar — each segment colored by its grade bucket.
16
+ */
17
+ export declare function gradeDistBar(excellent: number, good: number, fair: number, poor: number, critical: number, width?: number): string;
@@ -0,0 +1,86 @@
1
+ import chalk from 'chalk';
2
+ export const ACCENT = '#e04a1a';
3
+ export function gradeColor(grade) {
4
+ switch (grade) {
5
+ case 'A': return chalk.greenBright(grade);
6
+ case 'B': return chalk.hex('#9ACD32')(grade); // yellow-green
7
+ case 'C': return chalk.yellow(grade);
8
+ case 'D': return chalk.hex('#FF8C00')(grade); // orange
9
+ case 'F': return chalk.redBright(grade);
10
+ }
11
+ }
12
+ export function scoreColor(score, text) {
13
+ const t = String(text ?? score);
14
+ if (score >= 90)
15
+ return chalk.greenBright(t);
16
+ if (score >= 75)
17
+ return chalk.green(t);
18
+ if (score >= 60)
19
+ return chalk.yellow(t);
20
+ return chalk.red(t);
21
+ }
22
+ /**
23
+ * Color an issue label with an icon prefix.
24
+ * vulnerable / abandoned → red ⚠
25
+ * no types / huge size → yellow ◆
26
+ * outdated / license → orange ◆
27
+ */
28
+ export function issueColor(issue) {
29
+ const lower = issue.toLowerCase();
30
+ if (lower.includes('vuln') || lower.includes('critical'))
31
+ return chalk.redBright(`⚠ ${issue}`);
32
+ if (lower.includes('abandoned'))
33
+ return chalk.redBright(`⚠ ${issue}`);
34
+ if (lower.includes('no types'))
35
+ return chalk.yellow(`◆ ${issue}`);
36
+ if (lower.includes('huge size'))
37
+ return chalk.yellow(`◆ ${issue}`);
38
+ if (lower.includes('outdated'))
39
+ return chalk.hex('#FF8C00')(`◆ ${issue}`);
40
+ if (lower.includes('license'))
41
+ return chalk.hex('#FF8C00')(`◆ ${issue}`);
42
+ return chalk.dim(issue);
43
+ }
44
+ export function severityColor(severity) {
45
+ switch (severity.toUpperCase()) {
46
+ case 'CRITICAL': return chalk.bgRed.white(' CRITICAL ');
47
+ case 'HIGH': return chalk.redBright('HIGH');
48
+ case 'MEDIUM': return chalk.yellow('MEDIUM');
49
+ default: return chalk.dim('LOW');
50
+ }
51
+ }
52
+ export function barColor(score, bar) {
53
+ if (score >= 90)
54
+ return chalk.greenBright(bar);
55
+ if (score >= 75)
56
+ return chalk.green(bar);
57
+ if (score >= 60)
58
+ return chalk.yellow(bar);
59
+ if (score >= 30)
60
+ return chalk.hex('#FF8C00')(bar);
61
+ return chalk.red(bar);
62
+ }
63
+ /**
64
+ * Grade-distribution bar — each segment colored by its grade bucket.
65
+ */
66
+ export function gradeDistBar(excellent, good, fair, poor, critical, width = 30) {
67
+ const total = excellent + good + fair + poor + critical;
68
+ if (total === 0)
69
+ return chalk.dim('░'.repeat(width));
70
+ const seg = (count, colorFn) => {
71
+ const len = Math.max(0, Math.round((count / total) * width));
72
+ return colorFn('█'.repeat(len));
73
+ };
74
+ const raw = seg(excellent, chalk.greenBright) +
75
+ seg(good, chalk.hex('#9ACD32')) +
76
+ seg(fair, chalk.yellow) +
77
+ seg(poor, chalk.hex('#FF8C00')) +
78
+ seg(critical, chalk.redBright);
79
+ // Pad to exactly `width` visible cells if segments don't fill due to rounding
80
+ const bare = raw.replace(/\x1B\[[0-9;]*m/g, '');
81
+ const diff = width - bare.length;
82
+ if (diff > 0)
83
+ return raw + chalk.dim('░'.repeat(diff));
84
+ return raw;
85
+ }
86
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/tui/colors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ScanResult, CLIOptions } from '../core/types.js';
2
+ interface DashboardProps {
3
+ scanResult: ScanResult;
4
+ options: CLIOptions;
5
+ }
6
+ export declare function Dashboard({ scanResult, options }: DashboardProps): import("react/jsx-runtime").JSX.Element | null;
7
+ export {};