vibe-checking 1.0.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.
- package/README.md +72 -25
- package/dist/analysis/behavior.d.ts +11 -0
- package/dist/analysis/behavior.js +105 -0
- package/dist/analysis/behavior.js.map +1 -0
- package/dist/claude/correlator.js +88 -56
- package/dist/claude/correlator.js.map +1 -1
- package/dist/claude/reader.js +20 -8
- package/dist/claude/reader.js.map +1 -1
- package/dist/cursor/reader.js +16 -4
- package/dist/cursor/reader.js.map +1 -1
- package/dist/hooks/installer.d.ts +3 -0
- package/dist/hooks/installer.js +79 -0
- package/dist/hooks/installer.js.map +1 -0
- package/dist/index.js +46 -4
- package/dist/index.js.map +1 -1
- package/dist/repl/display.d.ts +3 -2
- package/dist/repl/display.js +56 -26
- package/dist/repl/display.js.map +1 -1
- package/dist/repl/repl.d.ts +4 -3
- package/dist/repl/repl.js +23 -10
- package/dist/repl/repl.js.map +1 -1
- package/dist/report/html.js +13 -23
- package/dist/report/html.js.map +1 -1
- package/dist/scanners/aggregator.d.ts +1 -1
- package/dist/scanners/aggregator.js.map +1 -1
- package/dist/scanners/deps.js +0 -1
- package/dist/scanners/deps.js.map +1 -1
- package/dist/scanners/gitleaks.js +0 -1
- package/dist/scanners/gitleaks.js.map +1 -1
- package/dist/scanners/rls.js +0 -3
- package/dist/scanners/rls.js.map +1 -1
- package/dist/scanners/semgrep.js +13 -6
- package/dist/scanners/semgrep.js.map +1 -1
- package/dist/state/store.d.ts +5 -0
- package/dist/state/store.js +48 -0
- package/dist/state/store.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,52 +1,99 @@
|
|
|
1
1
|
# vibecheck
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Security audit for AI-generated codebases.
|
|
4
|
+
|
|
5
|
+
vibecheck finds security vulnerabilities in your code and traces each one back to the AI prompt that introduced it.
|
|
6
|
+
|
|
7
|
+
Run it before you deploy, or whenever you want to check what your AI sessions left behind.
|
|
8
|
+
|
|
9
|
+
No account. No API key. Nothing leaves your machine.
|
|
4
10
|
|
|
5
11
|
## Quick start
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
|
-
npx
|
|
14
|
+
npx vibe-checking --with-cursor-history --with-claude-history
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run this from your project directory. To scan automatically on every push:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx vibe-checking hook install
|
|
9
21
|
```
|
|
10
22
|
|
|
11
|
-
|
|
23
|
+
## What it checks
|
|
24
|
+
|
|
25
|
+
- **Secrets** — leaked API keys, tokens, credentials in git history (via gitleaks)
|
|
26
|
+
- **Code vulnerabilities** — injection, XSS, crypto issues, auth gaps (via semgrep)
|
|
27
|
+
- **Supabase RLS** — tables missing Row Level Security in your migrations
|
|
28
|
+
- **Dependencies** — known CVEs in your packages (via npm audit)
|
|
29
|
+
|
|
30
|
+
gitleaks and semgrep are auto-installed if missing.
|
|
31
|
+
|
|
32
|
+
## Vibe coding analysis
|
|
12
33
|
|
|
13
|
-
|
|
34
|
+
When you add `--with-cursor-history` or `--with-claude-history`, vibecheck reads the session files that Cursor and Claude Code store locally on your machine. It performs two analyses:
|
|
14
35
|
|
|
15
|
-
|
|
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
|
|
36
|
+
**Prompt tracing** — matches each security finding to the AI prompt that generated the vulnerable code. Shows what the prompt asked for, what file was generated, and what security constraints were missing.
|
|
19
37
|
|
|
20
|
-
|
|
38
|
+
**Behavior analysis** — looks at how you interacted with the AI across all sessions:
|
|
39
|
+
- **Blind approval chains** — sequences of 3+ "ok/continue/oui" where code was accepted without review
|
|
40
|
+
- **High-delegation prompts** — short prompts that generated large amounts of code
|
|
41
|
+
- **Files without review** — generated files never mentioned again in the conversation
|
|
42
|
+
- **Security-blind sessions** — sessions where security was never mentioned in any prompt
|
|
21
43
|
|
|
22
|
-
|
|
23
|
-
- For full scanning: [gitleaks](https://github.com/gitleaks/gitleaks) and [semgrep](https://semgrep.dev) installed
|
|
24
|
-
- Degrades gracefully if scanners are missing
|
|
44
|
+
Without these flags, you still get the full security scan — just without the prompt tracing and behavior analysis.
|
|
25
45
|
|
|
26
46
|
## Usage
|
|
27
47
|
|
|
28
48
|
```bash
|
|
29
|
-
npx
|
|
30
|
-
npx
|
|
31
|
-
npx
|
|
32
|
-
npx
|
|
49
|
+
npx vibe-checking # security scan only
|
|
50
|
+
npx vibe-checking --with-cursor-history # scan + vibe analysis (Cursor)
|
|
51
|
+
npx vibe-checking --with-claude-history # scan + vibe analysis (Claude)
|
|
52
|
+
npx vibe-checking --with-cursor-history --with-claude-history # scan + vibe analysis (both)
|
|
53
|
+
npx vibe-checking hook install # add pre-push hook
|
|
54
|
+
npx vibe-checking hook remove # remove pre-push hook
|
|
33
55
|
```
|
|
34
56
|
|
|
35
57
|
## Interactive commands
|
|
36
58
|
|
|
59
|
+
Once the scan completes, you get an interactive prompt:
|
|
60
|
+
|
|
37
61
|
| Command | Action |
|
|
38
62
|
|---------|--------|
|
|
39
|
-
| `1
|
|
40
|
-
| `
|
|
41
|
-
| `ignore`
|
|
42
|
-
| `next`
|
|
43
|
-
| `list`
|
|
44
|
-
| `
|
|
45
|
-
| `q` |
|
|
63
|
+
| `1`, `2`, `3`... | Inspect a finding (shows prompt trace + missing constraints) |
|
|
64
|
+
| `solved` | Mark finding as fixed in code |
|
|
65
|
+
| `ignore` | Dismiss the current finding |
|
|
66
|
+
| `next` | Jump to the next open finding |
|
|
67
|
+
| `list` | Reprint the list with updated score |
|
|
68
|
+
| `vibe` | Show vibe coding behavior analysis |
|
|
69
|
+
| `q` | Save statuses and write report |
|
|
70
|
+
|
|
71
|
+
## Persistent statuses
|
|
72
|
+
|
|
73
|
+
Findings you mark as `solved` or `ignore` are saved in a `.vibecheck` file at the root of your repo. On the next scan, vibecheck loads these statuses:
|
|
74
|
+
|
|
75
|
+
- **ignored** findings stay dismissed
|
|
76
|
+
- **solved** findings are re-checked — if the vulnerability is still there, it goes back to open
|
|
77
|
+
|
|
78
|
+
Commit `.vibecheck` to share decisions with your team. If all findings are handled, the scan passes silently.
|
|
79
|
+
|
|
80
|
+
## Git hook
|
|
81
|
+
|
|
82
|
+
`npx vibe-checking hook install` adds a pre-push hook to your repo. Every time you `git push`, vibecheck runs a full scan. If there are open findings, the REPL opens and you need to handle them before the push goes through. If everything is already solved or ignored, the push passes immediately.
|
|
83
|
+
|
|
84
|
+
To skip the hook once: `git push --no-verify`.
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
46
87
|
|
|
47
|
-
|
|
88
|
+
Everything runs locally:
|
|
89
|
+
- **gitleaks** and **semgrep** are local binaries that scan your code and git history
|
|
90
|
+
- **RLS analysis** parses your SQL migration files directly
|
|
91
|
+
- **npm audit** checks your lock file against the npm vulnerability database
|
|
92
|
+
- **Prompt history** is read from local files (`~/.claude/projects/` and `~/.cursor/projects/`)
|
|
93
|
+
- **Behavior analysis** is pattern matching on your prompt text and session structure
|
|
94
|
+
- **Statuses** are saved in `.vibecheck` at the root of your repo
|
|
48
95
|
|
|
49
|
-
No
|
|
96
|
+
No API keys needed. No code uploaded.
|
|
50
97
|
|
|
51
98
|
---
|
|
52
99
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ClaudeSession, Finding } from "../types.js";
|
|
2
|
+
export interface VibeAnalysis {
|
|
3
|
+
blindChains: number;
|
|
4
|
+
highDelegationPrompts: number;
|
|
5
|
+
filesWithoutReview: number;
|
|
6
|
+
sessionsWithoutSecurityMention: number;
|
|
7
|
+
totalSessions: number;
|
|
8
|
+
totalPrompts: number;
|
|
9
|
+
findingsFromBlindChains: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function analyzeVibePatterns(sessions: ClaudeSession[], findings: Finding[]): VibeAnalysis;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const GENERIC_PROMPT_RE = /^(ok|oui|yes|yep|go|continue|next|sure|d'accord|parfait|merci|thanks|good|bien|c'est bon|les autres|et les autres|la suite)/i;
|
|
2
|
+
const SECURITY_KEYWORDS = [
|
|
3
|
+
"security", "auth", "validation", "rls", "sanitize", "encrypt",
|
|
4
|
+
"permission", "policy", "access control", "xss", "injection",
|
|
5
|
+
"csrf", "cors", "secret", "credential", "token verification",
|
|
6
|
+
"signature", "webhook secret", "row level",
|
|
7
|
+
];
|
|
8
|
+
const BLIND_CHAIN_THRESHOLD = 3;
|
|
9
|
+
const HIGH_DELEGATION_RATIO = 20;
|
|
10
|
+
function isGeneric(text) {
|
|
11
|
+
const clean = text.replace(/\s+/g, " ").trim();
|
|
12
|
+
return clean.length < 25 || GENERIC_PROMPT_RE.test(clean);
|
|
13
|
+
}
|
|
14
|
+
function wordCount(text) {
|
|
15
|
+
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
16
|
+
}
|
|
17
|
+
export function analyzeVibePatterns(sessions, findings) {
|
|
18
|
+
let blindChains = 0;
|
|
19
|
+
let highDelegationPrompts = 0;
|
|
20
|
+
let filesWithoutReview = 0;
|
|
21
|
+
let sessionsWithoutSecurityMention = 0;
|
|
22
|
+
let totalPrompts = 0;
|
|
23
|
+
const blindChainFiles = new Set();
|
|
24
|
+
for (const session of sessions) {
|
|
25
|
+
const prompts = session.prompts;
|
|
26
|
+
totalPrompts += prompts.length;
|
|
27
|
+
// Signal 1: blind approval chains
|
|
28
|
+
let consecutiveGeneric = 0;
|
|
29
|
+
for (const prompt of prompts) {
|
|
30
|
+
if (isGeneric(prompt.text)) {
|
|
31
|
+
consecutiveGeneric++;
|
|
32
|
+
if (consecutiveGeneric >= BLIND_CHAIN_THRESHOLD) {
|
|
33
|
+
if (consecutiveGeneric === BLIND_CHAIN_THRESHOLD)
|
|
34
|
+
blindChains++;
|
|
35
|
+
for (const f of prompt.filesGenerated) {
|
|
36
|
+
blindChainFiles.add(f);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
consecutiveGeneric = 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Signal 2: high delegation ratio
|
|
45
|
+
for (const prompt of prompts) {
|
|
46
|
+
if (prompt.toolCalls.length === 0)
|
|
47
|
+
continue;
|
|
48
|
+
const words = wordCount(prompt.text);
|
|
49
|
+
if (words < 3)
|
|
50
|
+
continue;
|
|
51
|
+
let linesGenerated = 0;
|
|
52
|
+
for (const tc of prompt.toolCalls) {
|
|
53
|
+
if (tc.content) {
|
|
54
|
+
linesGenerated += tc.content.split("\n").length;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (linesGenerated > 0 && linesGenerated / words > HIGH_DELEGATION_RATIO) {
|
|
58
|
+
highDelegationPrompts++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Signal 3: files accepted without review
|
|
62
|
+
const allGeneratedFiles = new Set();
|
|
63
|
+
const mentionedInFollowUp = new Set();
|
|
64
|
+
for (let i = 0; i < prompts.length; i++) {
|
|
65
|
+
for (const f of prompts[i].filesGenerated) {
|
|
66
|
+
allGeneratedFiles.add(f);
|
|
67
|
+
}
|
|
68
|
+
// Check if later prompts mention any previously generated files
|
|
69
|
+
if (i > 0) {
|
|
70
|
+
const promptLower = prompts[i].text.toLowerCase();
|
|
71
|
+
for (const f of allGeneratedFiles) {
|
|
72
|
+
const basename = f.split("/").pop() || f;
|
|
73
|
+
if (promptLower.includes(basename.toLowerCase())) {
|
|
74
|
+
mentionedInFollowUp.add(f);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
filesWithoutReview += allGeneratedFiles.size - mentionedInFollowUp.size;
|
|
80
|
+
// Signal 4: no security mention
|
|
81
|
+
const hasSecurityMention = prompts.some((p) => {
|
|
82
|
+
const lower = p.text.toLowerCase();
|
|
83
|
+
return SECURITY_KEYWORDS.some((kw) => lower.includes(kw));
|
|
84
|
+
});
|
|
85
|
+
if (!hasSecurityMention) {
|
|
86
|
+
sessionsWithoutSecurityMention++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Cross-reference: how many findings come from blind chain files
|
|
90
|
+
const findingsFromBlindChains = findings.filter((f) => {
|
|
91
|
+
if (!f.trace)
|
|
92
|
+
return false;
|
|
93
|
+
return Array.from(blindChainFiles).some((bcf) => bcf.endsWith(f.path) || f.path.endsWith(bcf.split("/").pop() || ""));
|
|
94
|
+
}).length;
|
|
95
|
+
return {
|
|
96
|
+
blindChains,
|
|
97
|
+
highDelegationPrompts,
|
|
98
|
+
filesWithoutReview,
|
|
99
|
+
sessionsWithoutSecurityMention,
|
|
100
|
+
totalSessions: sessions.length,
|
|
101
|
+
totalPrompts,
|
|
102
|
+
findingsFromBlindChains,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=behavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavior.js","sourceRoot":"","sources":["../../src/analysis/behavior.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,6 @@ export function correlateFindings(findings, sessions, repoPath) {
|
|
|
6
6
|
const correlation = findCorrelation(finding, sessions, repoPath);
|
|
7
7
|
if (correlation) {
|
|
8
8
|
finding.trace = correlation.trace;
|
|
9
|
-
finding.fix = correlation.fix;
|
|
10
9
|
}
|
|
11
10
|
else if (!finding.manual) {
|
|
12
11
|
finding.manual = guessManualNote(finding);
|
|
@@ -52,9 +51,8 @@ function findCorrelation(finding, sessions, repoPath) {
|
|
|
52
51
|
return false;
|
|
53
52
|
});
|
|
54
53
|
if (matchedFile) {
|
|
55
|
-
const trace = buildTrace(finding, prompt, session, matchedFile);
|
|
56
|
-
|
|
57
|
-
return { trace, fix };
|
|
54
|
+
const trace = buildTrace(finding, prompt, session, matchedFile, repoPath);
|
|
55
|
+
return { trace };
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
}
|
|
@@ -71,14 +69,22 @@ function extractFilePath(path) {
|
|
|
71
69
|
// "supabase/migrations/0007_orgs.sql" or "app/api/upload/route.ts"
|
|
72
70
|
return path;
|
|
73
71
|
}
|
|
74
|
-
function
|
|
72
|
+
function relativize(filePath, repoPath) {
|
|
73
|
+
const prefix = repoPath.endsWith("/") ? repoPath : repoPath + "/";
|
|
74
|
+
if (filePath.startsWith(prefix))
|
|
75
|
+
return filePath.slice(prefix.length);
|
|
76
|
+
return filePath;
|
|
77
|
+
}
|
|
78
|
+
function buildTrace(finding, prompt, session, matchedFile, repoPath) {
|
|
75
79
|
const ts = formatTimestamp(prompt.timestamp || session.timestamp);
|
|
76
80
|
const lineCount = estimateLineCount(prompt, matchedFile);
|
|
81
|
+
const relFile = relativize(matchedFile, repoPath);
|
|
77
82
|
return {
|
|
78
83
|
prompt: `"${truncate(prompt.text, 120)}"`,
|
|
79
84
|
session: `${ts} · claude code`,
|
|
80
|
-
file: `${
|
|
85
|
+
file: `${relFile}${lineCount ? ` (+${lineCount} lines)` : ""}`,
|
|
81
86
|
result: inferResult(finding),
|
|
87
|
+
missingConstraints: detectMissingConstraints(finding, prompt),
|
|
82
88
|
};
|
|
83
89
|
}
|
|
84
90
|
function inferResult(finding) {
|
|
@@ -99,6 +105,11 @@ function inferResult(finding) {
|
|
|
99
105
|
if (title.includes("xss") || title.includes("cross-site")) {
|
|
100
106
|
return "User input rendered without sanitization. The prompt didn't mention output encoding.";
|
|
101
107
|
}
|
|
108
|
+
if (title.includes("cipher") || title.includes("crypto") ||
|
|
109
|
+
title.includes("gcm") || title.includes("decipher") ||
|
|
110
|
+
title.includes("hash") || title.includes("hmac")) {
|
|
111
|
+
return "The cryptographic operation is missing a required security parameter. The prompt didn't specify the full crypto requirements.";
|
|
112
|
+
}
|
|
102
113
|
if (meta.includes("auth") || title.includes("auth")) {
|
|
103
114
|
return "No authentication check generated. The prompt didn't specify access control.";
|
|
104
115
|
}
|
|
@@ -107,58 +118,79 @@ function inferResult(finding) {
|
|
|
107
118
|
}
|
|
108
119
|
return `The prompt produced this code without the security constraint. The omission led to ${finding.title.toLowerCase()}.`;
|
|
109
120
|
}
|
|
110
|
-
|
|
111
|
-
|
|
121
|
+
const CONCERN_MAP = {
|
|
122
|
+
crypto: [
|
|
123
|
+
{ keywords: ["auth tag", "authentication tag", "gcm tag", "tag verification", "verify tag"], label: "No mention of auth tag verification for GCM mode" },
|
|
124
|
+
{ keywords: ["key derivation", "kdf", "pbkdf", "scrypt", "argon"], label: "No mention of key derivation function" },
|
|
125
|
+
{ keywords: ["tamper", "integrity", "reject ciphertext", "verify integrity"], label: "No mention of tampered ciphertext rejection" },
|
|
126
|
+
{ keywords: ["iv", "nonce", "initialization vector", "random iv"], label: "No mention of IV/nonce management" },
|
|
127
|
+
],
|
|
128
|
+
rls: [
|
|
129
|
+
{ keywords: ["rls", "row level security", "enable rls"], label: "No mention of Row Level Security" },
|
|
130
|
+
{ keywords: ["policy", "policies", "access policy"], label: "No mention of access policy definition" },
|
|
131
|
+
{ keywords: ["anon", "anonymous", "deny anon", "block anon"], label: "No mention of denying anonymous access" },
|
|
132
|
+
],
|
|
133
|
+
injection: [
|
|
134
|
+
{ keywords: ["parameterized", "prepared statement", "bind param", "placeholder"], label: "No mention of parameterized queries" },
|
|
135
|
+
{ keywords: ["validate input", "input validation", "sanitize input"], label: "No mention of input validation" },
|
|
136
|
+
],
|
|
137
|
+
webhook: [
|
|
138
|
+
{ keywords: ["signature", "verify signature", "stripe-signature", "webhook secret"], label: "No mention of signature verification" },
|
|
139
|
+
{ keywords: ["replay", "idempotency", "idempotent"], label: "No mention of replay protection" },
|
|
140
|
+
],
|
|
141
|
+
xss: [
|
|
142
|
+
{ keywords: ["sanitize", "sanitization", "escape", "encoding", "encode"], label: "No mention of output sanitization/encoding" },
|
|
143
|
+
{ keywords: ["csp", "content-security-policy", "content security"], label: "No mention of Content Security Policy" },
|
|
144
|
+
{ keywords: ["innerhtml", "dangerouslysetinnerhtml", "raw html"], label: "No mention of avoiding raw HTML insertion" },
|
|
145
|
+
],
|
|
146
|
+
auth: [
|
|
147
|
+
{ keywords: ["session", "token", "jwt", "verify token", "check session"], label: "No mention of session/token verification" },
|
|
148
|
+
{ keywords: ["access control", "authorization", "permission", "role"], label: "No mention of access control" },
|
|
149
|
+
{ keywords: ["401", "unauthorized", "reject unauthenticated"], label: "No mention of rejecting unauthenticated requests" },
|
|
150
|
+
],
|
|
151
|
+
upload: [
|
|
152
|
+
{ keywords: ["mime", "file type", "content-type", "allowed types"], label: "No mention of MIME type validation" },
|
|
153
|
+
{ keywords: ["size limit", "max size", "file size", "cap size"], label: "No mention of file size limit" },
|
|
154
|
+
{ keywords: ["filename", "sanitize name", "path traversal"], label: "No mention of filename sanitization" },
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
function categorizeFinding(finding) {
|
|
112
158
|
const title = finding.title.toLowerCase();
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (title.includes("
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
return
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
159
|
+
const meta = finding.meta.toLowerCase();
|
|
160
|
+
if (title.includes("rls") || title.includes("row level security"))
|
|
161
|
+
return "rls";
|
|
162
|
+
if (title.includes("upload") || title.includes("validation"))
|
|
163
|
+
return "upload";
|
|
164
|
+
if (title.includes("injection") || title.includes("interpolat"))
|
|
165
|
+
return "injection";
|
|
166
|
+
if (title.includes("webhook") || title.includes("signature"))
|
|
167
|
+
return "webhook";
|
|
168
|
+
if (title.includes("xss") || title.includes("cross-site"))
|
|
169
|
+
return "xss";
|
|
170
|
+
if (title.includes("cipher") || title.includes("crypto") ||
|
|
171
|
+
title.includes("gcm") || title.includes("decipher") ||
|
|
172
|
+
title.includes("hash") || title.includes("hmac"))
|
|
173
|
+
return "crypto";
|
|
174
|
+
if (meta.includes("auth") || title.includes("auth"))
|
|
175
|
+
return "auth";
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
function detectMissingConstraints(finding, prompt) {
|
|
179
|
+
const category = categorizeFinding(finding);
|
|
180
|
+
if (!category)
|
|
181
|
+
return [];
|
|
182
|
+
const concerns = CONCERN_MAP[category];
|
|
183
|
+
if (!concerns)
|
|
184
|
+
return [];
|
|
185
|
+
const promptText = prompt.text.toLowerCase();
|
|
186
|
+
const missing = [];
|
|
187
|
+
for (const concern of concerns) {
|
|
188
|
+
const mentioned = concern.keywords.some((kw) => promptText.includes(kw));
|
|
189
|
+
if (!mentioned) {
|
|
190
|
+
missing.push(concern.label);
|
|
191
|
+
}
|
|
141
192
|
}
|
|
142
|
-
|
|
143
|
-
return [
|
|
144
|
-
`"${truncate(prompt.text, 80)}.`,
|
|
145
|
-
`Sanitize all user-provided content before rendering. Use proper encoding`,
|
|
146
|
-
`and never set innerHTML with unescaped user data."`,
|
|
147
|
-
];
|
|
148
|
-
}
|
|
149
|
-
if (title.includes("auth") && !title.includes("webhook")) {
|
|
150
|
-
return [
|
|
151
|
-
`"${truncate(prompt.text, 80)}.`,
|
|
152
|
-
`Add authentication middleware that verifies the session token before`,
|
|
153
|
-
`processing the request. Reject unauthenticated requests with 401."`,
|
|
154
|
-
];
|
|
155
|
-
}
|
|
156
|
-
// Generic fallback fix
|
|
157
|
-
return [
|
|
158
|
-
`"${truncate(prompt.text, 80)}.`,
|
|
159
|
-
`Add security constraints: validate inputs, enforce authentication,`,
|
|
160
|
-
`and follow least-privilege defaults."`,
|
|
161
|
-
];
|
|
193
|
+
return missing;
|
|
162
194
|
}
|
|
163
195
|
function formatTimestamp(ts) {
|
|
164
196
|
if (!ts)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/claude/correlator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/claude/correlator.ts"],"names":[],"mappings":"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"}
|
package/dist/claude/reader.js
CHANGED
|
@@ -6,6 +6,18 @@ const CLAUDE_DIRS = [
|
|
|
6
6
|
join(homedir(), ".claude", "projects"),
|
|
7
7
|
join(homedir(), ".claude"),
|
|
8
8
|
];
|
|
9
|
+
const GENERIC_PROMPT_RE = /^(ok|oui|yes|yep|go|continue|next|sure|d'accord|parfait|merci|thanks|good|bien|c'est bon|les autres|et les autres|la suite)/i;
|
|
10
|
+
function isGenericPrompt(text) {
|
|
11
|
+
const clean = text.replace(/\s+/g, " ").trim();
|
|
12
|
+
return clean.length < 25 || GENERIC_PROMPT_RE.test(clean);
|
|
13
|
+
}
|
|
14
|
+
function findSubstantivePrompt(prompts) {
|
|
15
|
+
for (let i = prompts.length - 1; i >= 0; i--) {
|
|
16
|
+
if (!isGenericPrompt(prompts[i].text))
|
|
17
|
+
return prompts[i];
|
|
18
|
+
}
|
|
19
|
+
return prompts[prompts.length - 1] ?? null;
|
|
20
|
+
}
|
|
9
21
|
export async function readClaudeHistory(repoPath) {
|
|
10
22
|
const resolvedRepo = resolve(repoPath);
|
|
11
23
|
const allSessions = [];
|
|
@@ -79,15 +91,15 @@ async function parseSessionFile(filePath, repoPath) {
|
|
|
79
91
|
if (role === "human" || role === "user") {
|
|
80
92
|
// Skip pure tool_result lines (they are user-type but contain tool output, not prompts)
|
|
81
93
|
if (entry.toolUseResult !== undefined) {
|
|
82
|
-
//
|
|
94
|
+
// Harvest file paths from toolUseResult, attach to the best prompt
|
|
83
95
|
const tur = entry.toolUseResult;
|
|
84
96
|
if (tur && typeof tur === "object") {
|
|
85
97
|
const turObj = tur;
|
|
86
98
|
const fp = turObj.filePath;
|
|
87
99
|
if (fp && prompts.length > 0) {
|
|
88
|
-
const
|
|
89
|
-
if (!
|
|
90
|
-
|
|
100
|
+
const target = findSubstantivePrompt(prompts);
|
|
101
|
+
if (!target.filesGenerated.includes(fp)) {
|
|
102
|
+
target.filesGenerated.push(fp);
|
|
91
103
|
}
|
|
92
104
|
}
|
|
93
105
|
}
|
|
@@ -112,11 +124,11 @@ async function parseSessionFile(filePath, repoPath) {
|
|
|
112
124
|
if (role === "assistant") {
|
|
113
125
|
const toolCalls = extractToolCalls(msg);
|
|
114
126
|
if (toolCalls.length > 0 && prompts.length > 0) {
|
|
115
|
-
const
|
|
116
|
-
|
|
127
|
+
const target = findSubstantivePrompt(prompts);
|
|
128
|
+
target.toolCalls.push(...toolCalls);
|
|
117
129
|
for (const tc of toolCalls) {
|
|
118
|
-
if (tc.filePath && !
|
|
119
|
-
|
|
130
|
+
if (tc.filePath && !target.filesGenerated.includes(tc.filePath)) {
|
|
131
|
+
target.filesGenerated.push(tc.filePath);
|
|
120
132
|
}
|
|
121
133
|
}
|
|
122
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/claude/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,WAAW,GAAG;IAClB,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC;IACtC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB;IAEhB,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,WAAW,GAAoB,EAAE,CAAC;IAExC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC/B,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAC3D,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,WAAW,CAAC,IAAI,CACd,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAC5E,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;AACrE,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAe,EACf,QAAgB;IAEhB,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,UAAU,IAAI,CAAC,GAAW;QAC7B,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAEvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;oBAC3D,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAC1C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,yBAAyB;gBAC3B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,QAAgB,EAChB,QAAgB;IAEhB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElD,IAAI,gBAAgB,GAAG,EAAE,CAAC;IAC1B,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAA8B,CAAC;QACnC,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,kCAAkC;QAClC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAAW,CAAC;YAClE,IAAI,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7C,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;QACH,CAAC;QAED,2DAA2D;QAC3D,MAAM,GAAG,GAAG,CACV,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;YAChD,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC,KAAK,CACiB,CAAC;QAC7B,MAAM,IAAI,GACP,GAAG,CAAC,IAAe,IAAK,KAAK,CAAC,IAAe,IAAK,KAAK,CAAC,IAAe,IAAI,EAAE,CAAC;QAEjF,uBAAuB;QACvB,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACxC,wFAAwF;YACxF,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;gBACtC,
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/claude/reader.ts"],"names":[],"mappings":"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"}
|
package/dist/cursor/reader.js
CHANGED
|
@@ -3,6 +3,18 @@ import { join, resolve } from "node:path";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
const CURSOR_PROJECTS_DIR = join(homedir(), ".cursor", "projects");
|
|
6
|
+
const GENERIC_PROMPT_RE = /^(ok|oui|yes|yep|go|continue|next|sure|d'accord|parfait|merci|thanks|good|bien|c'est bon|les autres|et les autres|la suite)/i;
|
|
7
|
+
function isGenericPrompt(text) {
|
|
8
|
+
const clean = text.replace(/\s+/g, " ").trim();
|
|
9
|
+
return clean.length < 25 || GENERIC_PROMPT_RE.test(clean);
|
|
10
|
+
}
|
|
11
|
+
function findSubstantivePrompt(prompts) {
|
|
12
|
+
for (let i = prompts.length - 1; i >= 0; i--) {
|
|
13
|
+
if (!isGenericPrompt(prompts[i].text))
|
|
14
|
+
return prompts[i];
|
|
15
|
+
}
|
|
16
|
+
return prompts[prompts.length - 1] ?? null;
|
|
17
|
+
}
|
|
6
18
|
/**
|
|
7
19
|
* Build the Cursor project slug from an absolute repo path.
|
|
8
20
|
* /Users/foo/Documents/github/titane → Users-foo-Documents-github-titane
|
|
@@ -77,11 +89,11 @@ async function parseTranscript(filePath) {
|
|
|
77
89
|
if (role === "assistant" && Array.isArray(msgContent)) {
|
|
78
90
|
const toolCalls = extractToolCalls(msgContent);
|
|
79
91
|
if (toolCalls.length > 0 && prompts.length > 0) {
|
|
80
|
-
const
|
|
81
|
-
|
|
92
|
+
const target = findSubstantivePrompt(prompts);
|
|
93
|
+
target.toolCalls.push(...toolCalls);
|
|
82
94
|
for (const tc of toolCalls) {
|
|
83
|
-
if (tc.filePath && !
|
|
84
|
-
|
|
95
|
+
if (tc.filePath && !target.filesGenerated.includes(tc.filePath)) {
|
|
96
|
+
target.filesGenerated.push(tc.filePath);
|
|
85
97
|
}
|
|
86
98
|
}
|
|
87
99
|
}
|