vibe-checking 1.0.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 (41) hide show
  1. package/README.md +53 -0
  2. package/dist/claude/correlator.d.ts +2 -0
  3. package/dist/claude/correlator.js +179 -0
  4. package/dist/claude/correlator.js.map +1 -0
  5. package/dist/claude/reader.d.ts +5 -0
  6. package/dist/claude/reader.js +191 -0
  7. package/dist/claude/reader.js.map +1 -0
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +102 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/repl/display.d.ts +16 -0
  12. package/dist/repl/display.js +153 -0
  13. package/dist/repl/display.js.map +1 -0
  14. package/dist/repl/repl.d.ts +9 -0
  15. package/dist/repl/repl.js +110 -0
  16. package/dist/repl/repl.js.map +1 -0
  17. package/dist/report/html.d.ts +9 -0
  18. package/dist/report/html.js +174 -0
  19. package/dist/report/html.js.map +1 -0
  20. package/dist/scanners/aggregator.d.ts +12 -0
  21. package/dist/scanners/aggregator.js +126 -0
  22. package/dist/scanners/aggregator.js.map +1 -0
  23. package/dist/scanners/deps.d.ts +6 -0
  24. package/dist/scanners/deps.js +73 -0
  25. package/dist/scanners/deps.js.map +1 -0
  26. package/dist/scanners/gitleaks.d.ts +7 -0
  27. package/dist/scanners/gitleaks.js +103 -0
  28. package/dist/scanners/gitleaks.js.map +1 -0
  29. package/dist/scanners/installer.d.ts +3 -0
  30. package/dist/scanners/installer.js +121 -0
  31. package/dist/scanners/installer.js.map +1 -0
  32. package/dist/scanners/rls.d.ts +6 -0
  33. package/dist/scanners/rls.js +177 -0
  34. package/dist/scanners/rls.js.map +1 -0
  35. package/dist/scanners/semgrep.d.ts +7 -0
  36. package/dist/scanners/semgrep.js +121 -0
  37. package/dist/scanners/semgrep.js.map +1 -0
  38. package/dist/types.d.ts +45 -0
  39. package/dist/types.js +2 -0
  40. package/dist/types.js.map +1 -0
  41. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # vibecheck
2
+
3
+ Audit AI-generated codebases — trace security findings back to the prompts that caused them.
4
+
5
+ ## Quick start
6
+
7
+ ```bash
8
+ npx vibecheck --with-claude-history
9
+ ```
10
+
11
+ No account. No upload. Everything stays local.
12
+
13
+ ## What it does
14
+
15
+ 1. **Scans** your repo for secrets (gitleaks), SAST issues (semgrep), missing Supabase RLS, and vulnerable dependencies (npm audit)
16
+ 2. **Reads** your Claude Code session history and **correlates** each finding to the prompt that generated it
17
+ 3. **Shows** rewritten prompts that would have produced secure code the first time
18
+ 4. **Generates** a shareable HTML report
19
+
20
+ ## Requirements
21
+
22
+ - Node.js ≥ 18
23
+ - For full scanning: [gitleaks](https://github.com/gitleaks/gitleaks) and [semgrep](https://semgrep.dev) installed
24
+ - Degrades gracefully if scanners are missing
25
+
26
+ ## Usage
27
+
28
+ ```bash
29
+ npx vibecheck # scan current directory
30
+ npx vibecheck --with-claude-history # scan + trace prompt origins
31
+ npx vibecheck --db-url postgres://... # include live RLS check
32
+ npx vibecheck ~/projects/my-app # scan a specific directory
33
+ ```
34
+
35
+ ## Interactive commands
36
+
37
+ | Command | Action |
38
+ |---------|--------|
39
+ | `1-N` | Inspect a finding |
40
+ | `fix` / `f` | Show the secure prompt rewrite |
41
+ | `ignore` / `i` | Dismiss the current finding |
42
+ | `next` / `n` | Jump to the next open finding |
43
+ | `list` / `l` | Reprint findings |
44
+ | `help` / `?` | Show commands |
45
+ | `q` | Finish and write report |
46
+
47
+ ## Privacy
48
+
49
+ No code, prompts, or secrets leave this machine. Ever.
50
+
51
+ ---
52
+
53
+ *vibecheck looked back at what happened. It can't stop the next insecure prompt — [Symbiotic](https://www.symbioticsec.ai) does that at generation time, continuously.*
@@ -0,0 +1,2 @@
1
+ import type { Finding, ClaudeSession } from "../types.js";
2
+ export declare function correlateFindings(findings: Finding[], sessions: ClaudeSession[], repoPath: string): void;
@@ -0,0 +1,179 @@
1
+ import { basename, resolve } from "node:path";
2
+ export function correlateFindings(findings, sessions, repoPath) {
3
+ for (const finding of findings) {
4
+ if (finding.trace || finding.manual)
5
+ continue;
6
+ const correlation = findCorrelation(finding, sessions, repoPath);
7
+ if (correlation) {
8
+ finding.trace = correlation.trace;
9
+ finding.fix = correlation.fix;
10
+ }
11
+ else if (!finding.manual) {
12
+ finding.manual = guessManualNote(finding);
13
+ }
14
+ }
15
+ }
16
+ function findCorrelation(finding, sessions, repoPath) {
17
+ const findingPath = extractFilePath(finding.path);
18
+ if (!findingPath)
19
+ return null;
20
+ for (const session of sessions) {
21
+ for (const prompt of session.prompts) {
22
+ const matchedFile = prompt.filesGenerated.find((f) => {
23
+ const resolved = f.startsWith("/") ? f : resolve(repoPath, f);
24
+ return (resolved.endsWith(findingPath) ||
25
+ basename(resolved) === basename(findingPath) ||
26
+ f === findingPath ||
27
+ f.endsWith(findingPath));
28
+ });
29
+ if (matchedFile) {
30
+ const trace = buildTrace(finding, prompt, session, matchedFile);
31
+ const fix = generateFix(finding, prompt);
32
+ return { trace, fix };
33
+ }
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+ function extractFilePath(path) {
39
+ // "git history · commit abc1234" → no file path for correlation
40
+ if (path.startsWith("git history"))
41
+ return null;
42
+ if (path.startsWith("database ·"))
43
+ return null;
44
+ if (path.startsWith("package.json"))
45
+ return null;
46
+ // "supabase/migrations/0007_orgs.sql" or "app/api/upload/route.ts"
47
+ return path;
48
+ }
49
+ function buildTrace(finding, prompt, session, matchedFile) {
50
+ const ts = formatTimestamp(prompt.timestamp || session.timestamp);
51
+ const lineCount = estimateLineCount(prompt, matchedFile);
52
+ return {
53
+ prompt: `"${truncate(prompt.text, 120)}"`,
54
+ session: `${ts} · claude code`,
55
+ file: `${matchedFile}${lineCount ? ` (+${lineCount} lines)` : ""}`,
56
+ result: inferResult(finding),
57
+ };
58
+ }
59
+ function inferResult(finding) {
60
+ const title = finding.title.toLowerCase();
61
+ const meta = finding.meta.toLowerCase();
62
+ if (title.includes("rls") || title.includes("row level security")) {
63
+ return "RLS was never enabled — the prompt asked for the schema, not the access rules.";
64
+ }
65
+ if (title.includes("validation") || title.includes("upload")) {
66
+ return "No validation generated. The prompt never mentioned constraints, so none were added.";
67
+ }
68
+ if (title.includes("injection") || title.includes("interpolat")) {
69
+ return "Raw query params concatenated into the query. No parameterization requested.";
70
+ }
71
+ if (title.includes("webhook") || title.includes("signature")) {
72
+ return "Handler trusts the payload directly. Signature verification was never requested.";
73
+ }
74
+ if (title.includes("xss") || title.includes("cross-site")) {
75
+ return "User input rendered without sanitization. The prompt didn't mention output encoding.";
76
+ }
77
+ if (meta.includes("auth") || title.includes("auth")) {
78
+ return "No authentication check generated. The prompt didn't specify access control.";
79
+ }
80
+ if (title.includes("service-role") || title.includes("service_role")) {
81
+ return "The service-role client was placed in a client-accessible module. The prompt didn't specify server-only.";
82
+ }
83
+ return `The prompt produced this code without the security constraint. The omission led to ${finding.title.toLowerCase()}.`;
84
+ }
85
+ function generateFix(finding, prompt) {
86
+ const originalPrompt = prompt.text.toLowerCase();
87
+ const title = finding.title.toLowerCase();
88
+ if (title.includes("rls") || title.includes("row level security")) {
89
+ return [
90
+ `"${truncate(prompt.text, 80)}.`,
91
+ `Enable row level security and add a policy so a user can only select rows`,
92
+ `for their own records. Deny anon access by default."`,
93
+ ];
94
+ }
95
+ if (title.includes("upload") || title.includes("validation")) {
96
+ return [
97
+ `"${truncate(prompt.text, 80)}.`,
98
+ `Validate MIME type (images only), cap size at 5MB, sanitize the filename`,
99
+ `against path traversal, require an authenticated session, and enforce an`,
100
+ `RLS policy so a user can only write to their own folder."`,
101
+ ];
102
+ }
103
+ if (title.includes("injection") || title.includes("interpolat")) {
104
+ return [
105
+ `"${truncate(prompt.text, 80)}.`,
106
+ `Validate the params as ISO dates and use parameterized Supabase filters —`,
107
+ `never string-concatenate user input into the query."`,
108
+ ];
109
+ }
110
+ if (title.includes("webhook") || title.includes("signature")) {
111
+ return [
112
+ `"${truncate(prompt.text, 80)}.`,
113
+ `Verify the Stripe-Signature header against the webhook secret and reject`,
114
+ `any event that fails verification."`,
115
+ ];
116
+ }
117
+ if (title.includes("xss") || title.includes("cross-site")) {
118
+ return [
119
+ `"${truncate(prompt.text, 80)}.`,
120
+ `Sanitize all user-provided content before rendering. Use proper encoding`,
121
+ `and never set innerHTML with unescaped user data."`,
122
+ ];
123
+ }
124
+ if (title.includes("auth") && !title.includes("webhook")) {
125
+ return [
126
+ `"${truncate(prompt.text, 80)}.`,
127
+ `Add authentication middleware that verifies the session token before`,
128
+ `processing the request. Reject unauthenticated requests with 401."`,
129
+ ];
130
+ }
131
+ // Generic fallback fix
132
+ return [
133
+ `"${truncate(prompt.text, 80)}.`,
134
+ `Add security constraints: validate inputs, enforce authentication,`,
135
+ `and follow least-privilege defaults."`,
136
+ ];
137
+ }
138
+ function formatTimestamp(ts) {
139
+ if (!ts)
140
+ return "unknown date";
141
+ try {
142
+ const d = new Date(ts);
143
+ if (isNaN(d.getTime()))
144
+ return ts;
145
+ return d.toISOString().replace("T", " ").slice(0, 16);
146
+ }
147
+ catch {
148
+ return ts;
149
+ }
150
+ }
151
+ function truncate(s, max) {
152
+ const clean = s.replace(/\n/g, " ").trim();
153
+ if (clean.length <= max)
154
+ return clean;
155
+ return clean.slice(0, max - 1) + "…";
156
+ }
157
+ function estimateLineCount(prompt, matchedFile) {
158
+ for (const tc of prompt.toolCalls) {
159
+ if (tc.filePath && tc.filePath.endsWith(basename(matchedFile))) {
160
+ if (tc.content) {
161
+ return tc.content.split("\n").length;
162
+ }
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+ function guessManualNote(finding) {
168
+ if (finding.source === "gitleaks") {
169
+ return "Not a generation issue — a leaked credential. Rotate the key in the relevant service, then purge it from git history. No prompt rewrite applies.";
170
+ }
171
+ if (finding.source === "deps") {
172
+ return "Not a generation issue — a vulnerable dependency. Update or replace the package. No prompt rewrite applies.";
173
+ }
174
+ if (finding.title.toLowerCase().includes("service-role")) {
175
+ return "Move the service-role client to a server-only module. Architectural fix, not a prompt rewrite.";
176
+ }
177
+ return null;
178
+ }
179
+ //# sourceMappingURL=correlator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/claude/correlator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ClaudeSession } from "../types.js";
2
+ export declare function readClaudeHistory(repoPath: string): Promise<{
3
+ sessions: ClaudeSession[];
4
+ sessionCount: number;
5
+ }>;
@@ -0,0 +1,191 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { join, resolve, basename } from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { homedir } from "node:os";
5
+ const CLAUDE_DIRS = [
6
+ join(homedir(), ".claude", "projects"),
7
+ join(homedir(), ".claude"),
8
+ ];
9
+ export async function readClaudeHistory(repoPath) {
10
+ const resolvedRepo = resolve(repoPath);
11
+ const allSessions = [];
12
+ for (const dir of CLAUDE_DIRS) {
13
+ if (!existsSync(dir))
14
+ continue;
15
+ const sessions = await findSessionFiles(dir, resolvedRepo);
16
+ allSessions.push(...sessions);
17
+ }
18
+ // Sort by timestamp, newest first
19
+ allSessions.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
20
+ return { sessions: allSessions, sessionCount: allSessions.length };
21
+ }
22
+ async function findSessionFiles(baseDir, repoPath) {
23
+ const sessions = [];
24
+ async function walk(dir) {
25
+ let entries;
26
+ try {
27
+ entries = await readdir(dir, { withFileTypes: true });
28
+ }
29
+ catch {
30
+ return;
31
+ }
32
+ for (const entry of entries) {
33
+ const fullPath = join(dir, entry.name);
34
+ if (entry.isDirectory()) {
35
+ // Look inside project-specific directories
36
+ await walk(fullPath);
37
+ }
38
+ else if (entry.name.endsWith(".jsonl") || entry.name.endsWith(".json")) {
39
+ try {
40
+ const session = await parseSessionFile(fullPath, repoPath);
41
+ if (session && session.prompts.length > 0) {
42
+ sessions.push(session);
43
+ }
44
+ }
45
+ catch {
46
+ // Skip unparseable files
47
+ }
48
+ }
49
+ }
50
+ }
51
+ await walk(baseDir);
52
+ return sessions;
53
+ }
54
+ async function parseSessionFile(filePath, repoPath) {
55
+ const content = await readFile(filePath, "utf-8");
56
+ const lines = content.split("\n").filter(Boolean);
57
+ let sessionTimestamp = "";
58
+ const prompts = [];
59
+ // Check if this session is related to the repo
60
+ let isRelevant = false;
61
+ for (const line of lines) {
62
+ let entry;
63
+ try {
64
+ entry = JSON.parse(line);
65
+ }
66
+ catch {
67
+ continue;
68
+ }
69
+ // Detect relevance from the session's working directory or file paths
70
+ if (!isRelevant) {
71
+ const cwd = (entry.cwd || entry.workingDirectory || "");
72
+ if (cwd && resolve(cwd).startsWith(repoPath)) {
73
+ isRelevant = true;
74
+ }
75
+ }
76
+ // Extract user messages as prompts
77
+ const role = entry.role || entry.type;
78
+ if (role === "human" || role === "user") {
79
+ const text = extractText(entry);
80
+ if (text) {
81
+ const ts = entry.timestamp ||
82
+ entry.createdAt ||
83
+ sessionTimestamp;
84
+ if (!sessionTimestamp)
85
+ sessionTimestamp = ts;
86
+ prompts.push({
87
+ text,
88
+ timestamp: ts,
89
+ filesGenerated: [],
90
+ toolCalls: [],
91
+ });
92
+ }
93
+ }
94
+ // Extract assistant responses with tool usage to find generated files
95
+ if (role === "assistant") {
96
+ const toolCalls = extractToolCalls(entry);
97
+ if (toolCalls.length > 0 && prompts.length > 0) {
98
+ const lastPrompt = prompts[prompts.length - 1];
99
+ lastPrompt.toolCalls.push(...toolCalls);
100
+ for (const tc of toolCalls) {
101
+ if (tc.filePath) {
102
+ lastPrompt.filesGenerated.push(tc.filePath);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ // If file path hints at the project
109
+ if (!isRelevant) {
110
+ const repoName = basename(repoPath).toLowerCase();
111
+ if (filePath.toLowerCase().includes(repoName)) {
112
+ isRelevant = true;
113
+ }
114
+ }
115
+ if (!isRelevant && prompts.length > 0) {
116
+ // Check if any generated files match repo files
117
+ for (const p of prompts) {
118
+ for (const f of p.filesGenerated) {
119
+ if (resolve(f).startsWith(repoPath) || !f.startsWith("/")) {
120
+ isRelevant = true;
121
+ break;
122
+ }
123
+ }
124
+ if (isRelevant)
125
+ break;
126
+ }
127
+ }
128
+ if (!isRelevant)
129
+ return null;
130
+ // Try to get session timestamp from file stat if not found in content
131
+ if (!sessionTimestamp) {
132
+ try {
133
+ const s = await stat(filePath);
134
+ sessionTimestamp = s.mtime.toISOString();
135
+ }
136
+ catch {
137
+ sessionTimestamp = new Date().toISOString();
138
+ }
139
+ }
140
+ return { timestamp: sessionTimestamp, prompts };
141
+ }
142
+ function extractText(entry) {
143
+ if (typeof entry.content === "string")
144
+ return entry.content;
145
+ if (typeof entry.message === "string")
146
+ return entry.message;
147
+ if (Array.isArray(entry.content)) {
148
+ const texts = entry.content
149
+ .filter((c) => c.type === "text" && typeof c.text === "string")
150
+ .map((c) => c.text);
151
+ return texts.join("\n");
152
+ }
153
+ if (entry.message &&
154
+ typeof entry.message === "object" &&
155
+ entry.message.content) {
156
+ return extractText(entry.message);
157
+ }
158
+ return "";
159
+ }
160
+ function extractToolCalls(entry) {
161
+ const calls = [];
162
+ const content = entry.content;
163
+ if (Array.isArray(content)) {
164
+ for (const block of content) {
165
+ if (block.type === "tool_use" || block.type === "tool_call") {
166
+ const tc = {
167
+ tool: (block.name || block.function?.name || "unknown"),
168
+ args: (block.input || block.function?.arguments || {}),
169
+ };
170
+ // Extract file paths from write/create tool calls
171
+ const toolName = tc.tool.toLowerCase();
172
+ if (toolName.includes("write") ||
173
+ toolName.includes("create") ||
174
+ toolName.includes("edit") ||
175
+ toolName.includes("file")) {
176
+ const path = tc.args.file_path ||
177
+ tc.args.path ||
178
+ tc.args.filePath ||
179
+ tc.args.file;
180
+ if (path) {
181
+ tc.filePath = path;
182
+ tc.content = tc.args.content || undefined;
183
+ }
184
+ }
185
+ calls.push(tc);
186
+ }
187
+ }
188
+ }
189
+ return calls;
190
+ }
191
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/claude/reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import pc from "picocolors";
4
+ import { runAllScanners } from "./scanners/aggregator.js";
5
+ import { readClaudeHistory } from "./claude/reader.js";
6
+ import { correlateFindings } from "./claude/correlator.js";
7
+ import { printBoot, printNoFindings } from "./repl/display.js";
8
+ import { startRepl } from "./repl/repl.js";
9
+ async function main() {
10
+ const args = process.argv.slice(2);
11
+ const withClaudeHistory = args.includes("--with-claude-history");
12
+ const dbUrlIdx = args.indexOf("--db-url");
13
+ const dbUrl = dbUrlIdx !== -1 ? args[dbUrlIdx + 1] : undefined;
14
+ const helpFlag = args.includes("--help") || args.includes("-h");
15
+ if (helpFlag) {
16
+ printUsage();
17
+ process.exit(0);
18
+ }
19
+ // Determine repo path: first non-flag arg, or cwd
20
+ let repoPath = process.cwd();
21
+ for (const arg of args) {
22
+ if (!arg.startsWith("-") && arg !== dbUrl) {
23
+ repoPath = resolve(arg);
24
+ break;
25
+ }
26
+ }
27
+ // Banner
28
+ console.log(`$ npx vibecheck ${withClaudeHistory ? pc.magenta("--with-claude-history") : ""}`);
29
+ console.log();
30
+ // Run scanners
31
+ const result = await runAllScanners({ repoPath, dbUrl, withClaudeHistory }, (msg) => console.log(pc.dim(msg)));
32
+ // Read Claude history if requested
33
+ if (withClaudeHistory) {
34
+ try {
35
+ const { sessions, sessionCount } = await readClaudeHistory(repoPath);
36
+ result.stats.claudeSessions = sessionCount;
37
+ if (sessions.length > 0 && result.findings.length > 0) {
38
+ correlateFindings(result.findings, sessions, repoPath);
39
+ }
40
+ }
41
+ catch (err) {
42
+ console.log(pc.dim(pc.yellow(` ⚠ could not read claude history: ${String(err)}`)));
43
+ }
44
+ }
45
+ // Fill in manual notes for findings that weren't correlated
46
+ for (const f of result.findings) {
47
+ if (!f.trace && !f.manual) {
48
+ if (f.source === "rls") {
49
+ f.manual =
50
+ "Enable row level security on this table and add appropriate policies. Without RLS, any client with the anon key can read and write all rows.";
51
+ }
52
+ else if (f.source === "semgrep") {
53
+ f.manual =
54
+ "This is a code-level issue found by static analysis. Review the flagged code and apply the recommended fix.";
55
+ }
56
+ }
57
+ }
58
+ // Boot line
59
+ printBoot(result.stats, withClaudeHistory);
60
+ if (result.findings.length === 0) {
61
+ printNoFindings();
62
+ return;
63
+ }
64
+ // Start interactive REPL
65
+ await startRepl(result.findings, result.stats, repoPath);
66
+ }
67
+ function printUsage() {
68
+ console.log(`
69
+ ${pc.bold("vibecheck")} — audit AI-generated codebases
70
+
71
+ ${pc.dim("USAGE")}
72
+ npx vibecheck [options] [path]
73
+
74
+ ${pc.dim("OPTIONS")}
75
+ --with-claude-history Read Claude Code session history and correlate
76
+ findings to the prompts that generated them
77
+ --db-url <url> Live Supabase RLS check via a postgres connection
78
+ -h, --help Show this help
79
+
80
+ ${pc.dim("EXAMPLES")}
81
+ npx vibecheck scan current directory
82
+ npx vibecheck --with-claude-history scan + trace prompt origins
83
+ npx vibecheck --db-url postgres://... include live RLS check
84
+ npx vibecheck ~/projects/my-app scan a specific directory
85
+
86
+ ${pc.dim("COMMANDS (interactive)")}
87
+ 1-N inspect a finding
88
+ fix / f show the secure prompt rewrite
89
+ ignore / i dismiss the current finding
90
+ next / n jump to the next open finding
91
+ list / l reprint findings
92
+ help / ? show commands
93
+ q finish and write report
94
+
95
+ ${pc.dim(pc.gray("local only — no code, prompts, or secrets leave this machine."))}
96
+ `);
97
+ }
98
+ main().catch((err) => {
99
+ console.error(pc.red(`fatal: ${err.message || err}`));
100
+ process.exit(1);
101
+ });
102
+ //# 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,16 @@
1
+ import type { Finding, FindingStatus } from "../types.js";
2
+ export declare function printBoot(stats: {
3
+ gitHistory: boolean;
4
+ sourceScanned: boolean;
5
+ supabaseMigrations: boolean;
6
+ claudeSessions: number;
7
+ stack: string[];
8
+ contributors: number;
9
+ }, withClaude: boolean): void;
10
+ export declare function printList(findings: Finding[], statuses: FindingStatus[]): void;
11
+ export declare function printInspect(finding: Finding, index: number): void;
12
+ export declare function printFix(finding: Finding): void;
13
+ export declare function printIgnore(index: number, ignored: boolean): void;
14
+ export declare function printHelp(findingCount: number): void;
15
+ export declare function printFinish(findings: Finding[], statuses: FindingStatus[], reportPath: string): void;
16
+ export declare function printNoFindings(): void;