@vibecheckai/cli 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +214 -0
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +228 -0
- package/bin/runners/lib/agent-firewall/change-packet/store.js +200 -0
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +21 -0
- package/bin/runners/lib/agent-firewall/claims/extractor.js +214 -0
- package/bin/runners/lib/agent-firewall/claims/patterns.js +24 -0
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +88 -0
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +75 -0
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +118 -0
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +102 -0
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +142 -0
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +145 -0
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +19 -0
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +87 -0
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +184 -0
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +163 -0
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +107 -0
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +68 -0
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +66 -0
- package/bin/runners/lib/agent-firewall/interceptor/base.js +304 -0
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +35 -0
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +34 -0
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +84 -0
- package/bin/runners/lib/agent-firewall/policy/engine.js +72 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +143 -0
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +61 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +50 -0
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +93 -0
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +57 -0
- package/bin/runners/lib/agent-firewall/policy/schema.json +183 -0
- package/bin/runners/lib/agent-firewall/policy/verdict.js +54 -0
- package/bin/runners/lib/agent-firewall/truthpack/index.js +67 -0
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +116 -0
- package/bin/runners/lib/agent-firewall/unblock/planner.js +337 -0
- package/bin/runners/lib/analysis-core.js +198 -180
- package/bin/runners/lib/analyzers.js +1119 -536
- package/bin/runners/lib/cli-output.js +236 -210
- package/bin/runners/lib/detectors-v2.js +547 -785
- package/bin/runners/lib/fingerprint.js +377 -0
- package/bin/runners/lib/route-truth.js +1167 -322
- package/bin/runners/lib/scan-output.js +144 -738
- package/bin/runners/lib/ship-output-enterprise.js +239 -0
- package/bin/runners/lib/terminal-ui.js +188 -770
- package/bin/runners/lib/truth.js +1004 -321
- package/bin/runners/lib/unified-output.js +162 -158
- package/bin/runners/runAgent.js +161 -0
- package/bin/runners/runFirewall.js +134 -0
- package/bin/runners/runFirewallHook.js +56 -0
- package/bin/runners/runScan.js +113 -10
- package/bin/runners/runShip.js +7 -8
- package/bin/runners/runTruth.js +89 -0
- package/mcp-server/agent-firewall-interceptor.js +164 -0
- package/mcp-server/index.js +347 -313
- package/mcp-server/truth-context.js +131 -90
- package/mcp-server/truth-firewall-tools.js +1412 -1045
- package/package.json +1 -1
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Truth Context
|
|
3
|
-
*
|
|
4
|
-
* Core
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* Truth Context – MCP Tools for Evidence‑Backed AI
|
|
3
|
+
*
|
|
4
|
+
* Core context-engine tools that surface **truth-backed** context for AI agents.
|
|
5
|
+
* Every response is grounded in concrete evidence with file/line citations
|
|
6
|
+
* and explicit confidence scores.
|
|
7
|
+
*
|
|
8
|
+
* This is the "Truth Firewall", exposed to agents as an "Evidence Pack" / "Truth Pack". [web:3]
|
|
9
|
+
*
|
|
9
10
|
* Tools:
|
|
10
|
-
* vibecheck.ctx
|
|
11
|
-
* vibecheck.verify_claim
|
|
12
|
-
* vibecheck.evidence
|
|
11
|
+
* - vibecheck.ctx – Build a repo-level Truth Pack (routes, auth, billing, env, schema)
|
|
12
|
+
* - vibecheck.verify_claim – Check whether a claim is backed by real evidence
|
|
13
|
+
* - vibecheck.evidence – Pull code-level evidence for a specific file/function
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
import fs from "fs/promises";
|
|
@@ -23,60 +24,72 @@ import { execSync } from "child_process";
|
|
|
23
24
|
export const TRUTH_CONTEXT_TOOLS = [
|
|
24
25
|
{
|
|
25
26
|
name: "vibecheck.ctx",
|
|
26
|
-
description: `📋
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Use this before
|
|
27
|
+
description: `📋 Build a repo Truth Pack: routes, auth, billing, env vars, schema.
|
|
28
|
+
|
|
29
|
+
Generates an evidence-backed context bundle with file/line citations.
|
|
30
|
+
Use this before the agent makes any architectural or behavioral claims
|
|
31
|
+
about the codebase.
|
|
30
32
|
|
|
31
33
|
Returns:
|
|
32
|
-
- routes: All
|
|
33
|
-
- auth: Auth guards, protected routes, auth flow
|
|
34
|
-
- billing: Payment gates, subscription checks, paid
|
|
35
|
-
- env: Environment variables (declared vs used)
|
|
36
|
-
- schema: Database schema
|
|
37
|
-
- confidence:
|
|
34
|
+
- routes: All detected routes with handlers and middleware
|
|
35
|
+
- auth: Auth guards, protected routes, auth flow indicators
|
|
36
|
+
- billing: Payment gates, subscription checks, paid feature indicators
|
|
37
|
+
- env: Environment variables (declared vs used, mismatches)
|
|
38
|
+
- schema: Database schema and TypeScript contracts
|
|
39
|
+
- confidence: Aggregate confidence score (0–1) for the extracted view`,
|
|
38
40
|
inputSchema: {
|
|
39
41
|
type: "object",
|
|
40
42
|
properties: {
|
|
41
43
|
scope: {
|
|
42
44
|
type: "string",
|
|
43
45
|
enum: ["all", "routes", "auth", "billing", "env", "schema"],
|
|
44
|
-
description: "
|
|
46
|
+
description: "Which slice of context to extract (default: all)",
|
|
45
47
|
default: "all",
|
|
46
48
|
},
|
|
47
49
|
path: {
|
|
48
50
|
type: "string",
|
|
49
|
-
description: "Project path (default: current directory)",
|
|
51
|
+
description: "Project root path (default: current working directory)",
|
|
50
52
|
},
|
|
51
53
|
},
|
|
52
54
|
},
|
|
53
55
|
},
|
|
54
56
|
{
|
|
55
57
|
name: "vibecheck.verify_claim",
|
|
56
|
-
description: `🔍
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Returns evidence (file/line)
|
|
58
|
+
description: `🔍 Truth Firewall check – verify that a claim is backed by code.
|
|
59
|
+
|
|
60
|
+
Run this before asserting that something exists, is configured, or is enforced.
|
|
61
|
+
Returns concrete evidence (file/line) when the claim is supported,
|
|
62
|
+
or a structured rejection with an explanation when it is not.
|
|
60
63
|
|
|
61
64
|
Examples:
|
|
62
|
-
- "Route /api/users exists"
|
|
63
|
-
- "Auth is required for /admin"
|
|
64
|
-
- "Stripe is configured"
|
|
65
|
+
- "Route /api/users exists" → VERIFIED with handler at src/routes/users.ts:45
|
|
66
|
+
- "Auth is required for /admin" → VERIFIED via middleware at src/middleware/auth.ts:12
|
|
67
|
+
- "Stripe is configured" → REJECTED: No evidence of Stripe integration found`,
|
|
65
68
|
inputSchema: {
|
|
66
69
|
type: "object",
|
|
67
70
|
properties: {
|
|
68
71
|
claim_type: {
|
|
69
72
|
type: "string",
|
|
70
|
-
enum: [
|
|
71
|
-
|
|
73
|
+
enum: [
|
|
74
|
+
"route",
|
|
75
|
+
"endpoint",
|
|
76
|
+
"env_var",
|
|
77
|
+
"middleware",
|
|
78
|
+
"auth_guard",
|
|
79
|
+
"billing_gate",
|
|
80
|
+
"file",
|
|
81
|
+
"function",
|
|
82
|
+
],
|
|
83
|
+
description: "Category of claim to verify",
|
|
72
84
|
},
|
|
73
85
|
claim: {
|
|
74
86
|
type: "string",
|
|
75
|
-
description:
|
|
87
|
+
description:
|
|
88
|
+
"The claim subject (e.g. '/api/users', 'AUTH_SECRET', 'authMiddleware')",
|
|
76
89
|
},
|
|
77
90
|
path: {
|
|
78
91
|
type: "string",
|
|
79
|
-
description: "Project path (default: current directory)",
|
|
92
|
+
description: "Project root path (default: current working directory)",
|
|
80
93
|
},
|
|
81
94
|
},
|
|
82
95
|
required: ["claim_type", "claim"],
|
|
@@ -84,33 +97,35 @@ Examples:
|
|
|
84
97
|
},
|
|
85
98
|
{
|
|
86
99
|
name: "vibecheck.evidence",
|
|
87
|
-
description: `📎
|
|
88
|
-
|
|
89
|
-
Returns
|
|
90
|
-
Use this when
|
|
100
|
+
description: `📎 Retrieve code evidence for a file or symbol.
|
|
101
|
+
|
|
102
|
+
Returns an annotated code snippet with line numbers for precise citation.
|
|
103
|
+
Use this when the agent needs to quote or reason about specific code blocks
|
|
104
|
+
in its response.`,
|
|
91
105
|
inputSchema: {
|
|
92
106
|
type: "object",
|
|
93
107
|
properties: {
|
|
94
108
|
file: {
|
|
95
109
|
type: "string",
|
|
96
|
-
description: "File path relative to project root",
|
|
110
|
+
description: "File path relative to the project root",
|
|
97
111
|
},
|
|
98
112
|
function_name: {
|
|
99
113
|
type: "string",
|
|
100
|
-
description: "Optional function/class name to
|
|
114
|
+
description: "Optional function/class name to locate within the file",
|
|
101
115
|
},
|
|
102
116
|
line: {
|
|
103
117
|
type: "number",
|
|
104
|
-
description: "Optional
|
|
118
|
+
description: "Optional 1-based line number to center the snippet on",
|
|
105
119
|
},
|
|
106
120
|
context_lines: {
|
|
107
121
|
type: "number",
|
|
108
|
-
description:
|
|
122
|
+
description:
|
|
123
|
+
"Number of lines of context before/after the target (default: 10)",
|
|
109
124
|
default: 10,
|
|
110
125
|
},
|
|
111
126
|
path: {
|
|
112
127
|
type: "string",
|
|
113
|
-
description: "Project path (default: current directory)",
|
|
128
|
+
description: "Project root path (default: current working directory)",
|
|
114
129
|
},
|
|
115
130
|
},
|
|
116
131
|
required: ["file"],
|
|
@@ -119,7 +134,7 @@ Use this when you need to reference specific code in your response.`,
|
|
|
119
134
|
];
|
|
120
135
|
|
|
121
136
|
// ============================================================================
|
|
122
|
-
// TOOL
|
|
137
|
+
// TOOL DISPATCH
|
|
123
138
|
// ============================================================================
|
|
124
139
|
|
|
125
140
|
export async function handleTruthContextTool(toolName, args) {
|
|
@@ -168,10 +183,11 @@ async function getTruthPack(projectPath, scope) {
|
|
|
168
183
|
truthPack.sections.schema = await extractSchema(projectPath);
|
|
169
184
|
}
|
|
170
185
|
|
|
171
|
-
// Calculate overall confidence
|
|
172
186
|
const sections = Object.values(truthPack.sections);
|
|
173
187
|
if (sections.length > 0) {
|
|
174
|
-
truthPack.confidence =
|
|
188
|
+
truthPack.confidence =
|
|
189
|
+
sections.reduce((sum, section) => sum + (section.confidence || 0), 0) /
|
|
190
|
+
sections.length;
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
return truthPack;
|
|
@@ -179,7 +195,7 @@ async function getTruthPack(projectPath, scope) {
|
|
|
179
195
|
return {
|
|
180
196
|
error: error.message,
|
|
181
197
|
projectPath,
|
|
182
|
-
suggestion: "Run
|
|
198
|
+
suggestion: "Run `vibecheck init` to set up the project",
|
|
183
199
|
};
|
|
184
200
|
}
|
|
185
201
|
}
|
|
@@ -193,12 +209,12 @@ async function extractRoutes(projectPath) {
|
|
|
193
209
|
];
|
|
194
210
|
|
|
195
211
|
const files = await findSourceFiles(projectPath, [".ts", ".js", ".tsx", ".jsx"]);
|
|
196
|
-
|
|
197
|
-
for (const file of files.slice(0, 50)) {
|
|
212
|
+
|
|
213
|
+
for (const file of files.slice(0, 50)) {
|
|
198
214
|
try {
|
|
199
215
|
const content = await fs.readFile(file, "utf8");
|
|
200
216
|
const relPath = path.relative(projectPath, file);
|
|
201
|
-
|
|
217
|
+
|
|
202
218
|
for (const pattern of routePatterns) {
|
|
203
219
|
let match;
|
|
204
220
|
pattern.lastIndex = 0;
|
|
@@ -223,7 +239,7 @@ async function extractRoutes(projectPath) {
|
|
|
223
239
|
|
|
224
240
|
return {
|
|
225
241
|
count: routes.length,
|
|
226
|
-
routes: routes.slice(0, 100),
|
|
242
|
+
routes: routes.slice(0, 100),
|
|
227
243
|
confidence: routes.length > 0 ? 0.8 : 0.2,
|
|
228
244
|
};
|
|
229
245
|
}
|
|
@@ -238,12 +254,12 @@ async function extractAuth(projectPath) {
|
|
|
238
254
|
];
|
|
239
255
|
|
|
240
256
|
const files = await findSourceFiles(projectPath, [".ts", ".js"]);
|
|
241
|
-
|
|
257
|
+
|
|
242
258
|
for (const file of files.slice(0, 50)) {
|
|
243
259
|
try {
|
|
244
260
|
const content = await fs.readFile(file, "utf8");
|
|
245
261
|
const relPath = path.relative(projectPath, file);
|
|
246
|
-
|
|
262
|
+
|
|
247
263
|
for (const pattern of authPatterns) {
|
|
248
264
|
let match;
|
|
249
265
|
pattern.lastIndex = 0;
|
|
@@ -265,7 +281,12 @@ async function extractAuth(projectPath) {
|
|
|
265
281
|
return {
|
|
266
282
|
count: authIndicators.length,
|
|
267
283
|
indicators: authIndicators.slice(0, 50),
|
|
268
|
-
confidence:
|
|
284
|
+
confidence:
|
|
285
|
+
authIndicators.length > 5
|
|
286
|
+
? 0.8
|
|
287
|
+
: authIndicators.length > 0
|
|
288
|
+
? 0.5
|
|
289
|
+
: 0.1,
|
|
269
290
|
};
|
|
270
291
|
}
|
|
271
292
|
|
|
@@ -279,12 +300,12 @@ async function extractBilling(projectPath) {
|
|
|
279
300
|
];
|
|
280
301
|
|
|
281
302
|
const files = await findSourceFiles(projectPath, [".ts", ".js"]);
|
|
282
|
-
|
|
303
|
+
|
|
283
304
|
for (const file of files.slice(0, 30)) {
|
|
284
305
|
try {
|
|
285
306
|
const content = await fs.readFile(file, "utf8");
|
|
286
307
|
const relPath = path.relative(projectPath, file);
|
|
287
|
-
|
|
308
|
+
|
|
288
309
|
for (const pattern of billingPatterns) {
|
|
289
310
|
let match;
|
|
290
311
|
pattern.lastIndex = 0;
|
|
@@ -306,7 +327,12 @@ async function extractBilling(projectPath) {
|
|
|
306
327
|
return {
|
|
307
328
|
count: billingIndicators.length,
|
|
308
329
|
indicators: billingIndicators.slice(0, 30),
|
|
309
|
-
confidence:
|
|
330
|
+
confidence:
|
|
331
|
+
billingIndicators.length > 3
|
|
332
|
+
? 0.7
|
|
333
|
+
: billingIndicators.length > 0
|
|
334
|
+
? 0.4
|
|
335
|
+
: 0.1,
|
|
310
336
|
};
|
|
311
337
|
}
|
|
312
338
|
|
|
@@ -314,7 +340,6 @@ async function extractEnvVars(projectPath) {
|
|
|
314
340
|
const declared = [];
|
|
315
341
|
const used = [];
|
|
316
342
|
|
|
317
|
-
// Check .env.example, .env.local.example, etc.
|
|
318
343
|
const envFiles = [".env.example", ".env.local.example", ".env.sample"];
|
|
319
344
|
for (const envFile of envFiles) {
|
|
320
345
|
try {
|
|
@@ -331,11 +356,10 @@ async function extractEnvVars(projectPath) {
|
|
|
331
356
|
}
|
|
332
357
|
}
|
|
333
358
|
} catch {
|
|
334
|
-
// File
|
|
359
|
+
// File does not exist
|
|
335
360
|
}
|
|
336
361
|
}
|
|
337
362
|
|
|
338
|
-
// Find process.env usage in code
|
|
339
363
|
const files = await findSourceFiles(projectPath, [".ts", ".js"]);
|
|
340
364
|
for (const file of files.slice(0, 30)) {
|
|
341
365
|
try {
|
|
@@ -356,11 +380,10 @@ async function extractEnvVars(projectPath) {
|
|
|
356
380
|
}
|
|
357
381
|
}
|
|
358
382
|
|
|
359
|
-
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
const unused = [...declaredNames].filter(n => !usedNames.has(n));
|
|
383
|
+
const declaredNames = new Set(declared.map((d) => d.name));
|
|
384
|
+
const usedNames = new Set(used.map((u) => u.name));
|
|
385
|
+
const undeclared = [...usedNames].filter((name) => !declaredNames.has(name));
|
|
386
|
+
const unused = [...declaredNames].filter((name) => !usedNames.has(name));
|
|
364
387
|
|
|
365
388
|
return {
|
|
366
389
|
declared: declared.slice(0, 50),
|
|
@@ -376,7 +399,6 @@ async function extractEnvVars(projectPath) {
|
|
|
376
399
|
async function extractSchema(projectPath) {
|
|
377
400
|
const schemas = [];
|
|
378
401
|
|
|
379
|
-
// Check for Prisma schema
|
|
380
402
|
try {
|
|
381
403
|
const prismaPath = path.join(projectPath, "prisma", "schema.prisma");
|
|
382
404
|
const content = await fs.readFile(prismaPath, "utf8");
|
|
@@ -389,16 +411,15 @@ async function extractSchema(projectPath) {
|
|
|
389
411
|
});
|
|
390
412
|
}
|
|
391
413
|
} catch {
|
|
392
|
-
// No Prisma
|
|
414
|
+
// No Prisma schema
|
|
393
415
|
}
|
|
394
416
|
|
|
395
|
-
// Check for TypeScript types/interfaces
|
|
396
417
|
const files = await findSourceFiles(projectPath, [".ts", ".tsx"]);
|
|
397
418
|
for (const file of files.slice(0, 20)) {
|
|
398
419
|
try {
|
|
399
420
|
const content = await fs.readFile(file, "utf8");
|
|
400
421
|
const relPath = path.relative(projectPath, file);
|
|
401
|
-
|
|
422
|
+
|
|
402
423
|
const typeMatches = content.matchAll(/(?:interface|type)\s+(\w+)/g);
|
|
403
424
|
for (const match of typeMatches) {
|
|
404
425
|
const line = content.substring(0, match.index).split("\n").length;
|
|
@@ -417,7 +438,8 @@ async function extractSchema(projectPath) {
|
|
|
417
438
|
return {
|
|
418
439
|
count: schemas.length,
|
|
419
440
|
schemas: schemas.slice(0, 50),
|
|
420
|
-
confidence:
|
|
441
|
+
confidence:
|
|
442
|
+
schemas.length > 5 ? 0.7 : schemas.length > 0 ? 0.4 : 0.2,
|
|
421
443
|
};
|
|
422
444
|
}
|
|
423
445
|
|
|
@@ -436,7 +458,7 @@ async function verifyClaim(projectPath, claimType, claim) {
|
|
|
436
458
|
|
|
437
459
|
try {
|
|
438
460
|
switch (claimType) {
|
|
439
|
-
case "file":
|
|
461
|
+
case "file": {
|
|
440
462
|
const filePath = path.join(projectPath, claim);
|
|
441
463
|
try {
|
|
442
464
|
await fs.access(filePath);
|
|
@@ -453,11 +475,14 @@ async function verifyClaim(projectPath, claimType, claim) {
|
|
|
453
475
|
result.rejection = `File does not exist: ${claim}`;
|
|
454
476
|
}
|
|
455
477
|
break;
|
|
478
|
+
}
|
|
456
479
|
|
|
457
480
|
case "route":
|
|
458
|
-
case "endpoint":
|
|
481
|
+
case "endpoint": {
|
|
459
482
|
const routes = await extractRoutes(projectPath);
|
|
460
|
-
const matchingRoute = routes.routes.find(
|
|
483
|
+
const matchingRoute = routes.routes.find(
|
|
484
|
+
(route) => route.path === claim || route.path.includes(claim),
|
|
485
|
+
);
|
|
461
486
|
if (matchingRoute) {
|
|
462
487
|
result.verified = true;
|
|
463
488
|
result.confidence = 0.9;
|
|
@@ -466,26 +491,31 @@ async function verifyClaim(projectPath, claimType, claim) {
|
|
|
466
491
|
result.rejection = `No route matching "${claim}" found in codebase`;
|
|
467
492
|
}
|
|
468
493
|
break;
|
|
494
|
+
}
|
|
469
495
|
|
|
470
|
-
case "env_var":
|
|
496
|
+
case "env_var": {
|
|
471
497
|
const envData = await extractEnvVars(projectPath);
|
|
472
|
-
const isDeclared = envData.declared.some(
|
|
473
|
-
const isUsed = envData.used.some(
|
|
498
|
+
const isDeclared = envData.declared.some((env) => env.name === claim);
|
|
499
|
+
const isUsed = envData.used.some((env) => env.name === claim);
|
|
474
500
|
if (isDeclared || isUsed) {
|
|
475
501
|
result.verified = true;
|
|
476
502
|
result.confidence = isDeclared && isUsed ? 1.0 : 0.7;
|
|
477
503
|
result.evidence = {
|
|
478
504
|
declared: isDeclared,
|
|
479
505
|
used: isUsed,
|
|
480
|
-
locations: [
|
|
506
|
+
locations: [
|
|
507
|
+
...envData.declared.filter((env) => env.name === claim),
|
|
508
|
+
...envData.used.filter((env) => env.name === claim),
|
|
509
|
+
],
|
|
481
510
|
};
|
|
482
511
|
} else {
|
|
483
512
|
result.rejection = `Environment variable "${claim}" not found`;
|
|
484
513
|
}
|
|
485
514
|
break;
|
|
515
|
+
}
|
|
486
516
|
|
|
487
517
|
default:
|
|
488
|
-
result.rejection = `Claim type "${claimType}" verification not yet
|
|
518
|
+
result.rejection = `Claim type "${claimType}" verification is not implemented yet`;
|
|
489
519
|
}
|
|
490
520
|
} catch (error) {
|
|
491
521
|
result.rejection = `Verification error: ${error.message}`;
|
|
@@ -500,17 +530,19 @@ async function verifyClaim(projectPath, claimType, claim) {
|
|
|
500
530
|
|
|
501
531
|
async function getEvidence(projectPath, file, options) {
|
|
502
532
|
const filePath = path.join(projectPath, file);
|
|
503
|
-
|
|
533
|
+
|
|
504
534
|
try {
|
|
505
535
|
const content = await fs.readFile(filePath, "utf8");
|
|
506
536
|
const lines = content.split("\n");
|
|
507
|
-
|
|
537
|
+
|
|
508
538
|
let targetLine = options.line || 1;
|
|
509
539
|
const contextLines = options.context_lines || 10;
|
|
510
|
-
|
|
511
|
-
// If function_name provided, find it
|
|
540
|
+
|
|
512
541
|
if (options.function_name) {
|
|
513
|
-
const pattern = new RegExp(
|
|
542
|
+
const pattern = new RegExp(
|
|
543
|
+
`(function|const|let|var|class)\\s+${options.function_name}`,
|
|
544
|
+
"i",
|
|
545
|
+
);
|
|
514
546
|
for (let i = 0; i < lines.length; i++) {
|
|
515
547
|
if (pattern.test(lines[i])) {
|
|
516
548
|
targetLine = i + 1;
|
|
@@ -518,14 +550,18 @@ async function getEvidence(projectPath, file, options) {
|
|
|
518
550
|
}
|
|
519
551
|
}
|
|
520
552
|
}
|
|
521
|
-
|
|
553
|
+
|
|
522
554
|
const startLine = Math.max(1, targetLine - contextLines);
|
|
523
555
|
const endLine = Math.min(lines.length, targetLine + contextLines);
|
|
524
|
-
|
|
525
|
-
const snippet = lines
|
|
526
|
-
.
|
|
556
|
+
|
|
557
|
+
const snippet = lines
|
|
558
|
+
.slice(startLine - 1, endLine)
|
|
559
|
+
.map(
|
|
560
|
+
(line, index) =>
|
|
561
|
+
`${String(startLine + index).padStart(4, " ")} | ${line}`,
|
|
562
|
+
)
|
|
527
563
|
.join("\n");
|
|
528
|
-
|
|
564
|
+
|
|
529
565
|
return {
|
|
530
566
|
file,
|
|
531
567
|
targetLine,
|
|
@@ -549,14 +585,19 @@ async function getEvidence(projectPath, file, options) {
|
|
|
549
585
|
|
|
550
586
|
async function findSourceFiles(projectPath, extensions) {
|
|
551
587
|
const files = [];
|
|
552
|
-
|
|
588
|
+
|
|
553
589
|
async function walk(dir) {
|
|
554
590
|
try {
|
|
555
591
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
556
592
|
for (const entry of entries) {
|
|
557
593
|
const fullPath = path.join(dir, entry.name);
|
|
558
594
|
if (entry.isDirectory()) {
|
|
559
|
-
if (
|
|
595
|
+
if (
|
|
596
|
+
!entry.name.startsWith(".") &&
|
|
597
|
+
entry.name !== "node_modules" &&
|
|
598
|
+
entry.name !== "dist" &&
|
|
599
|
+
entry.name !== "build"
|
|
600
|
+
) {
|
|
560
601
|
await walk(fullPath);
|
|
561
602
|
}
|
|
562
603
|
} else if (entry.isFile()) {
|
|
@@ -570,7 +611,7 @@ async function findSourceFiles(projectPath, extensions) {
|
|
|
570
611
|
// Skip inaccessible directories
|
|
571
612
|
}
|
|
572
613
|
}
|
|
573
|
-
|
|
614
|
+
|
|
574
615
|
await walk(projectPath);
|
|
575
616
|
return files;
|
|
576
617
|
}
|