verification-layer 0.16.0 → 0.19.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 (81) hide show
  1. package/README.md +174 -21
  2. package/dist/ai/cache.d.ts +15 -0
  3. package/dist/ai/cache.d.ts.map +1 -0
  4. package/dist/ai/cache.js +75 -0
  5. package/dist/ai/cache.js.map +1 -0
  6. package/dist/ai/client.d.ts +11 -0
  7. package/dist/ai/client.d.ts.map +1 -0
  8. package/dist/ai/client.js +27 -0
  9. package/dist/ai/client.js.map +1 -0
  10. package/dist/ai/config.d.ts +29 -0
  11. package/dist/ai/config.d.ts.map +1 -0
  12. package/dist/ai/config.js +29 -0
  13. package/dist/ai/config.js.map +1 -0
  14. package/dist/ai/cost-tracker.d.ts +23 -0
  15. package/dist/ai/cost-tracker.d.ts.map +1 -0
  16. package/dist/ai/cost-tracker.js +55 -0
  17. package/dist/ai/cost-tracker.js.map +1 -0
  18. package/dist/ai/index.d.ts +16 -0
  19. package/dist/ai/index.d.ts.map +1 -0
  20. package/dist/ai/index.js +13 -0
  21. package/dist/ai/index.js.map +1 -0
  22. package/dist/ai/rate-limiter.d.ts +16 -0
  23. package/dist/ai/rate-limiter.d.ts.map +1 -0
  24. package/dist/ai/rate-limiter.js +51 -0
  25. package/dist/ai/rate-limiter.js.map +1 -0
  26. package/dist/ai/rules/index.d.ts +11 -0
  27. package/dist/ai/rules/index.d.ts.map +1 -0
  28. package/dist/ai/rules/index.js +57 -0
  29. package/dist/ai/rules/index.js.map +1 -0
  30. package/dist/ai/rules/prompts/audit-logging.d.ts +7 -0
  31. package/dist/ai/rules/prompts/audit-logging.d.ts.map +1 -0
  32. package/dist/ai/rules/prompts/audit-logging.js +65 -0
  33. package/dist/ai/rules/prompts/audit-logging.js.map +1 -0
  34. package/dist/ai/rules/prompts/data-retention.d.ts +7 -0
  35. package/dist/ai/rules/prompts/data-retention.d.ts.map +1 -0
  36. package/dist/ai/rules/prompts/data-retention.js +60 -0
  37. package/dist/ai/rules/prompts/data-retention.js.map +1 -0
  38. package/dist/ai/rules/prompts/minimum-access.d.ts +7 -0
  39. package/dist/ai/rules/prompts/minimum-access.d.ts.map +1 -0
  40. package/dist/ai/rules/prompts/minimum-access.js +53 -0
  41. package/dist/ai/rules/prompts/minimum-access.js.map +1 -0
  42. package/dist/ai/rules/prompts/phi-encryption.d.ts +7 -0
  43. package/dist/ai/rules/prompts/phi-encryption.d.ts.map +1 -0
  44. package/dist/ai/rules/prompts/phi-encryption.js +60 -0
  45. package/dist/ai/rules/prompts/phi-encryption.js.map +1 -0
  46. package/dist/ai/rules/prompts/rbac-check.d.ts +7 -0
  47. package/dist/ai/rules/prompts/rbac-check.d.ts.map +1 -0
  48. package/dist/ai/rules/prompts/rbac-check.js +61 -0
  49. package/dist/ai/rules/prompts/rbac-check.js.map +1 -0
  50. package/dist/ai/rules/prompts/session-management.d.ts +7 -0
  51. package/dist/ai/rules/prompts/session-management.d.ts.map +1 -0
  52. package/dist/ai/rules/prompts/session-management.js +62 -0
  53. package/dist/ai/rules/prompts/session-management.js.map +1 -0
  54. package/dist/ai/rules/rule-runner.d.ts +36 -0
  55. package/dist/ai/rules/rule-runner.d.ts.map +1 -0
  56. package/dist/ai/rules/rule-runner.js +117 -0
  57. package/dist/ai/rules/rule-runner.js.map +1 -0
  58. package/dist/ai/rules/triage.d.ts +11 -0
  59. package/dist/ai/rules/triage.d.ts.map +1 -0
  60. package/dist/ai/rules/triage.js +107 -0
  61. package/dist/ai/rules/triage.js.map +1 -0
  62. package/dist/ai/rules/types.d.ts +33 -0
  63. package/dist/ai/rules/types.d.ts.map +1 -0
  64. package/dist/ai/rules/types.js +5 -0
  65. package/dist/ai/rules/types.js.map +1 -0
  66. package/dist/ai/sanitizer.d.ts +21 -0
  67. package/dist/ai/sanitizer.d.ts.map +1 -0
  68. package/dist/ai/sanitizer.js +81 -0
  69. package/dist/ai/sanitizer.js.map +1 -0
  70. package/dist/ai/scanner.d.ts +31 -0
  71. package/dist/ai/scanner.d.ts.map +1 -0
  72. package/dist/ai/scanner.js +93 -0
  73. package/dist/ai/scanner.js.map +1 -0
  74. package/dist/cli.js +97 -0
  75. package/dist/cli.js.map +1 -1
  76. package/dist/scan.d.ts.map +1 -1
  77. package/dist/scan.js +33 -0
  78. package/dist/scan.js.map +1 -1
  79. package/dist/types.d.ts +7 -0
  80. package/dist/types.d.ts.map +1 -1
  81. package/package.json +2 -1
package/README.md CHANGED
@@ -15,6 +15,7 @@ vlayer is a CLI tool that scans your codebase for HIPAA compliance issues. It's
15
15
 
16
16
  **Key capabilities:**
17
17
  - Scan for 50+ security vulnerabilities and PHI exposure patterns
18
+ - **AI-powered analysis** with Claude API for complex violations and false positive reduction
18
19
  - Auto-fix common issues with one command
19
20
  - Generate professional audit reports (HTML, PDF, JSON)
20
21
  - Detect your tech stack and provide tailored recommendations
@@ -50,30 +51,64 @@ node dist/cli.js report /path/to/project -o audit-report.html
50
51
 
51
52
  ---
52
53
 
53
- ## 🌐 Web Dashboard
54
+ ## 🌐 VLayer Ecosystem
54
55
 
55
- **Live Dashboard**: [https://dashboard-silk-zeta-55.vercel.app](https://dashboard-silk-zeta-55.vercel.app)
56
+ **Dashboard**: [https://app.vlayer.app](https://app.vlayer.app) - Compliance monitoring platform
57
+ **Playground**: [https://play.vlayer.app](https://play.vlayer.app) - Try vlayer in your browser
58
+ **Documentation**: [https://docs.vlayer.app](https://docs.vlayer.app) - Complete guides and API reference
59
+ **Landing Page**: [https://vlayer.app](https://vlayer.app) - Marketing site
56
60
 
57
- Monitor HIPAA compliance across all your projects with our web dashboard:
61
+ Enterprise-grade HIPAA compliance monitoring platform for tracking violations, compliance scores, and generating audit reports.
58
62
 
59
- **Features:**
60
- - 📊 **Visual Compliance Scores** - Animated gauges showing 0-100 scores
61
- - 📈 **Historical Tracking** - View compliance trends over time
62
- - 🗂️ **Multi-Project Management** - Monitor multiple codebases from one place
63
- - 🔍 **Detailed Findings** - Filter by severity and view recommendations
64
- - 📋 **Executive Reports** - Share compliance status with stakeholders
65
-
66
- **Quick Start:**
67
- 1. Visit the dashboard and create a project
68
- 2. Run a scan: `node dist/cli.js scan ./src --format json --output scan.json`
69
- 3. Upload results via API:
63
+ ### Design
64
+
65
+ **Professional Enterprise UI:**
66
+ - 🎨 **Dark Navy Theme** - Professional color palette (#0A1628, #0F172A) with emerald/teal accents
67
+ - 📐 **Fixed Sidebar Navigation** - Icon-based menu with VLayer branding and system status
68
+ - 💎 **Glassmorphism Effects** - Gradient cards with subtle shadows and transparency
69
+ - 🎯 **Circular Progress Gauges** - Animated SVG gauges for compliance scores (0-100)
70
+ - 🏷️ **Status Badges** - Color-coded indicators (Compliant/At Risk/Critical)
71
+ - **Smooth Transitions** - Hover effects and state changes with professional animations
72
+
73
+ ### Features
74
+
75
+ - 🔐 **Supabase Authentication** - Secure email/password authentication with session management
76
+ - 📊 **Visual Compliance Dashboard** - 4-metric overview with real-time scores and status distribution
77
+ - 📈 **Historical Score Tracking** - Interactive charts showing compliance trends over time
78
+ - 🗂️ **Multi-Project Management** - Monitor unlimited projects with inline progress indicators
79
+ - 🔍 **Detailed Findings View** - Filter by severity with comprehensive issue breakdowns
80
+ - 📋 **Executive Summaries** - Professional reports with grade assignments (A-F)
81
+ - 🎨 **Enterprise Tables** - Sortable project lists with circular scores and status badges
82
+ - 📱 **Responsive Design** - Optimized for desktop, tablet, and mobile devices
83
+ - 👤 **User Management** - User profiles with logout functionality in sidebar
84
+
85
+ ### Quick Start
86
+
87
+ 1. **Create Account**: Sign up at [app.vlayer.app/signup](https://app.vlayer.app/signup) with your email
88
+ 2. **Login**: Access the dashboard at [app.vlayer.app](https://app.vlayer.app)
89
+ 3. **Create Project**: Click "+ New Project" and enter your project details
90
+ 4. **Run Scan**: Execute a compliance scan on your codebase
70
91
  ```bash
71
- curl -X POST https://dashboard-silk-zeta-55.vercel.app/api/projects/{projectId}/scans \
92
+ node dist/cli.js scan ./src --format json --output scan.json
93
+ ```
94
+ 5. **Upload Results**: Send scan data to your project via API
95
+ ```bash
96
+ curl -X POST https://app.vlayer.app/api/projects/{projectId}/scans \
72
97
  -H "Content-Type: application/json" \
73
98
  -d @scan.json
74
99
  ```
75
100
 
76
- See [dashboard/README.md](dashboard/README.md) for API documentation and deployment instructions.
101
+ ### Demo Data
102
+
103
+ The dashboard includes 4 demo projects with realistic compliance data:
104
+ - **HealthCare Portal** - 92/100 (Grade A - Excellent)
105
+ - **Telemedicine API** - 78/100 (Grade C - Fair)
106
+ - **Insurance Claims System** - 56/100 (Grade F - Critical)
107
+ - **Mobile Health App** - 95/100 (Grade A - Excellent)
108
+
109
+ ### API & Documentation
110
+
111
+ See [dashboard/README.md](dashboard/README.md) for complete API documentation and deployment instructions.
77
112
 
78
113
  ---
79
114
 
@@ -371,6 +406,96 @@ node dist/cli.js audit ./my-app --generate-report --org "Healthcare Inc" --audit
371
406
 
372
407
  ---
373
408
 
409
+ ### 6. AI-Powered Scanning (Beta)
410
+
411
+ **Reduce false positives and catch complex violations with Claude AI.**
412
+
413
+ vlayer now includes optional AI-powered analysis using Anthropic's Claude API:
414
+
415
+ #### Features
416
+
417
+ - **🤖 LLM-Powered Rules**: 6 specialized AI rules for detecting complex HIPAA violations
418
+ - **🎯 AI Triage**: Automatically classify findings to reduce false positives by 50%+
419
+ - **🔒 PHI Scrubbing**: All code is sanitized before sending to the LLM (HIPAA-safe)
420
+ - **💰 Cost Control**: Budget limits, caching, and rate limiting built-in
421
+ - **📊 Confidence Scores**: AI provides reasoning and confidence for each finding
422
+
423
+ #### Quick Start
424
+
425
+ ```bash
426
+ # Set your API key
427
+ export ANTHROPIC_API_KEY="sk-ant-..."
428
+
429
+ # Run AI-powered scan (default: 50¢ budget)
430
+ node dist/cli.js ai-scan ./my-app
431
+
432
+ # Adjust budget
433
+ node dist/cli.js ai-scan ./my-app --budget 100
434
+
435
+ # Run LLM rules only (skip triage)
436
+ node dist/cli.js ai-scan ./my-app --rules-only
437
+
438
+ # Enable AI triage in regular scan
439
+ node dist/cli.js scan ./my-app # AI triage runs automatically if API key is set
440
+
441
+ # Disable AI features
442
+ node dist/cli.js scan ./my-app --no-ai
443
+ ```
444
+
445
+ #### AI Rules
446
+
447
+ The AI scanner includes 6 specialized rules:
448
+
449
+ | Rule ID | Name | Detects |
450
+ |---------|------|---------|
451
+ | **HIPAA-PHI-003** | Minimum Necessary Access | APIs returning more PHI than needed (SELECT * violations) |
452
+ | **HIPAA-SEC-001** | PHI Encryption | Unencrypted PHI in transit or at rest |
453
+ | **HIPAA-ACCESS-001** | Role-Based Access Control | Missing auth checks, hardcoded roles, IDOR vulnerabilities |
454
+ | **HIPAA-AUDIT-001** | Audit Logging | PHI operations without proper audit trails |
455
+ | **HIPAA-RETENTION-001** | Data Retention | Improper deletion, missing retention policies |
456
+ | **HIPAA-AUTH-001** | Session Management | Weak session configs, missing timeouts |
457
+
458
+ #### Configuration
459
+
460
+ Add AI settings to `.vlayerrc.json`:
461
+
462
+ ```json
463
+ {
464
+ "ai": {
465
+ "enabled": true,
466
+ "enableTriage": true,
467
+ "enableLLMRules": true,
468
+ "filterFalsePositives": true,
469
+ "budgetCents": 50
470
+ }
471
+ }
472
+ ```
473
+
474
+ #### Cost & Performance
475
+
476
+ - **Typical scan**: 5-20 API calls, $0.10-$0.50
477
+ - **Caching**: Results cached for 24 hours by file hash
478
+ - **Rate limiting**: Max 20 calls/minute, 50 calls/scan
479
+ - **PHI protection**: All sensitive data scrubbed before API call
480
+
481
+ **Example output:**
482
+ ```
483
+ 🤖 Starting AI-powered HIPAA scan...
484
+ 🔒 Scrubbed 3 PHI patterns from src/api/patients.ts
485
+ 📋 Running 6 LLM-powered rules...
486
+ ✅ AI scan complete: 12 findings, 48¢
487
+
488
+ AI Scan Summary:
489
+ Files scanned: 8
490
+ AI findings: 12
491
+ AI calls made: 18
492
+ Cost: 48¢
493
+ Critical: 2
494
+ High: 5
495
+ ```
496
+
497
+ ---
498
+
374
499
  ## Report Examples
375
500
 
376
501
  ### HTML Report
@@ -496,13 +621,41 @@ Each finding maps to specific HIPAA regulations:
496
621
  ## Roadmap
497
622
 
498
623
  ### Recently Completed ✅
499
- - [x] **Phase 4A: Web Dashboard**
624
+ - [x] **Phase 4E: Authentication & User Management**
625
+ - [x] Supabase Auth integration
626
+ - [x] Email/password authentication flow
627
+ - [x] Login and signup pages with dark theme
628
+ - [x] Protected routes via Next.js middleware
629
+ - [x] User session management
630
+ - [x] User profile display in sidebar
631
+ - [x] Logout functionality
632
+ - [x] Environment variables configured in Vercel
633
+ - [x] **Phase 4D: Custom Domain Configuration**
634
+ - [x] Configured custom domains on vlayer.app
635
+ - [x] Dashboard: app.vlayer.app
636
+ - [x] Playground: play.vlayer.app
637
+ - [x] Documentation: docs.vlayer.app
638
+ - [x] Landing page: vlayer.app
639
+ - [x] Automatic DNS configuration via Vercel
640
+ - [x] SSL/TLS certificates provisioned for all domains
641
+ - [x] Updated all cross-project links
642
+ - [x] **Phase 4C: Dashboard Consolidation**
643
+ - [x] Moved landing page to separate repo ([vlayer-website](https://github.com/Francosimon53/vlayer-website))
644
+ - [x] Dashboard now at root route (/) instead of /dashboard
645
+ - [x] Simplified route structure (/, /projects, /projects/[id])
646
+ - [x] Removed route groups for cleaner app organization
647
+ - [x] Dashboard-focused application architecture
648
+ - [x] **Phase 4A: Web Dashboard (Enterprise Redesign)**
500
649
  - [x] Next.js dashboard deployed to Vercel
650
+ - [x] Enterprise-grade dark navy theme with emerald accents
651
+ - [x] Fixed sidebar navigation with VLayer branding
652
+ - [x] Circular progress gauges with animations
501
653
  - [x] Multi-project management with REST API
502
- - [x] Visual compliance score gauges and charts
503
- - [x] Historical score tracking and trends
504
- - [x] Detailed findings viewer with filtering
505
- - [x] Live at: https://dashboard-silk-zeta-55.vercel.app
654
+ - [x] Status badges (Compliant/At Risk/Critical)
655
+ - [x] Historical score tracking with visual charts
656
+ - [x] Demo data with 4 realistic projects
657
+ - [x] Glassmorphism effects and professional shadows
658
+ - [x] Responsive design optimized for all devices
506
659
  - [x] **Phase 3B: Dashboard & Compliance Score**
507
660
  - [x] HIPAA Compliance Score (0-100) with severity weighting
508
661
  - [x] Enhanced HTML reports with visual gauge
@@ -0,0 +1,15 @@
1
+ /**
2
+ * AI Cache - Cache results by file hash
3
+ */
4
+ export declare class AICache {
5
+ private cacheDir;
6
+ private ttlMs;
7
+ constructor();
8
+ ensureCacheDir(): Promise<void>;
9
+ getFileHash(content: string): string;
10
+ getCacheKey(fileHash: string, ruleId: string): string;
11
+ get(fileContent: string, ruleId: string): Promise<any | null>;
12
+ set(fileContent: string, ruleId: string, result: any): Promise<void>;
13
+ clear(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;;IAOhB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIpC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAI/C,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IA2BhB,GAAG,CACP,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,IAAI,CAAC;IAqBV,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAO7B"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * AI Cache - Cache results by file hash
3
+ */
4
+ import * as crypto from 'crypto';
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import { AI_CONFIG } from './config.js';
8
+ export class AICache {
9
+ cacheDir;
10
+ ttlMs;
11
+ constructor() {
12
+ this.cacheDir = AI_CONFIG.cache.directory;
13
+ this.ttlMs = AI_CONFIG.cache.ttlHours * 60 * 60 * 1000;
14
+ }
15
+ async ensureCacheDir() {
16
+ try {
17
+ await fs.mkdir(this.cacheDir, { recursive: true });
18
+ }
19
+ catch (error) {
20
+ // Directory might already exist
21
+ }
22
+ }
23
+ getFileHash(content) {
24
+ return crypto.createHash('sha256').update(content).digest('hex');
25
+ }
26
+ getCacheKey(fileHash, ruleId) {
27
+ return `${fileHash}-${ruleId}.json`;
28
+ }
29
+ async get(fileContent, ruleId) {
30
+ if (!AI_CONFIG.cache.enabled) {
31
+ return null;
32
+ }
33
+ await this.ensureCacheDir();
34
+ const fileHash = this.getFileHash(fileContent);
35
+ const cacheKey = this.getCacheKey(fileHash, ruleId);
36
+ const cachePath = path.join(this.cacheDir, cacheKey);
37
+ try {
38
+ const data = await fs.readFile(cachePath, 'utf-8');
39
+ const entry = JSON.parse(data);
40
+ // Check if cache is expired
41
+ const age = Date.now() - entry.timestamp;
42
+ if (age > this.ttlMs) {
43
+ await fs.unlink(cachePath); // Delete expired cache
44
+ return null;
45
+ }
46
+ return entry.result;
47
+ }
48
+ catch (error) {
49
+ return null;
50
+ }
51
+ }
52
+ async set(fileContent, ruleId, result) {
53
+ if (!AI_CONFIG.cache.enabled) {
54
+ return;
55
+ }
56
+ await this.ensureCacheDir();
57
+ const fileHash = this.getFileHash(fileContent);
58
+ const cacheKey = this.getCacheKey(fileHash, ruleId);
59
+ const cachePath = path.join(this.cacheDir, cacheKey);
60
+ const entry = {
61
+ fileHash,
62
+ ruleId,
63
+ result,
64
+ timestamp: Date.now(),
65
+ ttl: this.ttlMs,
66
+ };
67
+ await fs.writeFile(cachePath, JSON.stringify(entry, null, 2), 'utf-8');
68
+ }
69
+ async clear() {
70
+ await this.ensureCacheDir();
71
+ const files = await fs.readdir(this.cacheDir);
72
+ await Promise.all(files.map((file) => fs.unlink(path.join(this.cacheDir, file))));
73
+ }
74
+ }
75
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/ai/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Anthropic AI Client (singleton)
3
+ */
4
+ import Anthropic from '@anthropic-ai/sdk';
5
+ export declare function getAIClient(): Anthropic;
6
+ export declare function isAIAvailable(): boolean;
7
+ /**
8
+ * Reset client (useful for testing)
9
+ */
10
+ export declare function resetAIClient(): void;
11
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAI1C,wBAAgB,WAAW,IAAI,SAAS,CAavC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Anthropic AI Client (singleton)
3
+ */
4
+ import Anthropic from '@anthropic-ai/sdk';
5
+ let client = null;
6
+ export function getAIClient() {
7
+ if (!client) {
8
+ const apiKey = process.env.ANTHROPIC_API_KEY || process.env.VLAYER_AI_KEY;
9
+ if (!apiKey) {
10
+ throw new Error('AI features require an Anthropic API key.\n' +
11
+ 'Set ANTHROPIC_API_KEY or VLAYER_AI_KEY environment variable.\n' +
12
+ 'Get your key at: https://console.anthropic.com/settings/keys');
13
+ }
14
+ client = new Anthropic({ apiKey });
15
+ }
16
+ return client;
17
+ }
18
+ export function isAIAvailable() {
19
+ return !!(process.env.ANTHROPIC_API_KEY || process.env.VLAYER_AI_KEY);
20
+ }
21
+ /**
22
+ * Reset client (useful for testing)
23
+ */
24
+ export function resetAIClient() {
25
+ client = null;
26
+ }
27
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,IAAI,MAAM,GAAqB,IAAI,CAAC;AAEpC,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,6CAA6C;gBAC3C,gEAAgE;gBAChE,8DAA8D,CACjE,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * AI Configuration
3
+ */
4
+ export declare const AI_CONFIG: {
5
+ readonly model: "claude-sonnet-4-20250514";
6
+ readonly maxTokens: 2048;
7
+ readonly temperature: 0.1;
8
+ readonly maxFileSizeBytes: 50000;
9
+ readonly maxConcurrentCalls: 3;
10
+ readonly rateLimit: {
11
+ readonly maxCallsPerMinute: 20;
12
+ readonly maxCallsPerScan: 50;
13
+ };
14
+ readonly budget: {
15
+ readonly defaultMaxCentsPerScan: 50;
16
+ readonly estimatedCostPerCall: 1.5;
17
+ };
18
+ readonly cache: {
19
+ readonly enabled: true;
20
+ readonly directory: ".vlayer/ai-cache";
21
+ readonly ttlHours: 24;
22
+ };
23
+ readonly pricing: {
24
+ readonly inputCostPerMillion: 3;
25
+ readonly outputCostPerMillion: 15;
26
+ };
27
+ };
28
+ export type AIModel = typeof AI_CONFIG.model;
29
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;CAwBZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,OAAO,SAAS,CAAC,KAAK,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * AI Configuration
3
+ */
4
+ export const AI_CONFIG = {
5
+ model: 'claude-sonnet-4-20250514',
6
+ maxTokens: 2048,
7
+ temperature: 0.1, // Deterministic for security
8
+ maxFileSizeBytes: 50_000, // Don't send files > 50KB
9
+ maxConcurrentCalls: 3,
10
+ rateLimit: {
11
+ maxCallsPerMinute: 20,
12
+ maxCallsPerScan: 50,
13
+ },
14
+ budget: {
15
+ defaultMaxCentsPerScan: 50, // $0.50 default
16
+ estimatedCostPerCall: 1.5, // ~$0.015 per call with Sonnet
17
+ },
18
+ cache: {
19
+ enabled: true,
20
+ directory: '.vlayer/ai-cache',
21
+ ttlHours: 24,
22
+ },
23
+ pricing: {
24
+ // Claude Sonnet 4 pricing (per million tokens)
25
+ inputCostPerMillion: 3.0,
26
+ outputCostPerMillion: 15.0,
27
+ },
28
+ };
29
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,KAAK,EAAE,0BAAmC;IAC1C,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG,EAAE,6BAA6B;IAC/C,gBAAgB,EAAE,MAAM,EAAE,0BAA0B;IACpD,kBAAkB,EAAE,CAAC;IACrB,SAAS,EAAE;QACT,iBAAiB,EAAE,EAAE;QACrB,eAAe,EAAE,EAAE;KACpB;IACD,MAAM,EAAE;QACN,sBAAsB,EAAE,EAAE,EAAE,gBAAgB;QAC5C,oBAAoB,EAAE,GAAG,EAAE,+BAA+B;KAC3D;IACD,KAAK,EAAE;QACL,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,kBAAkB;QAC7B,QAAQ,EAAE,EAAE;KACb;IACD,OAAO,EAAE;QACP,+CAA+C;QAC/C,mBAAmB,EAAE,GAAG;QACxB,oBAAoB,EAAE,IAAI;KAC3B;CACO,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Cost Tracker - Track AI API usage and costs
3
+ */
4
+ export declare class CostTracker {
5
+ private totalInputTokens;
6
+ private totalOutputTokens;
7
+ private totalCalls;
8
+ private budgetCents;
9
+ constructor(budgetCents?: number);
10
+ trackUsage(inputTokens: number, outputTokens: number): void;
11
+ getEstimatedCostCents(): number;
12
+ isOverBudget(): boolean;
13
+ getSummary(): string;
14
+ getEstimate(): string;
15
+ getStats(): {
16
+ totalCalls: number;
17
+ totalInputTokens: number;
18
+ totalOutputTokens: number;
19
+ estimatedCost: number;
20
+ };
21
+ reset(): void;
22
+ }
23
+ //# sourceMappingURL=cost-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,WAAW;IACtB,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,GAAE,MAAgD;IAIzE,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAM3D,qBAAqB,IAAI,MAAM;IAW/B,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,MAAM;IAUpB,WAAW,IAAI,MAAM;IAOrB,QAAQ;;;;;;IASR,KAAK,IAAI,IAAI;CAKd"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Cost Tracker - Track AI API usage and costs
3
+ */
4
+ import { AI_CONFIG } from './config.js';
5
+ export class CostTracker {
6
+ totalInputTokens = 0;
7
+ totalOutputTokens = 0;
8
+ totalCalls = 0;
9
+ budgetCents;
10
+ constructor(budgetCents = AI_CONFIG.budget.defaultMaxCentsPerScan) {
11
+ this.budgetCents = budgetCents;
12
+ }
13
+ trackUsage(inputTokens, outputTokens) {
14
+ this.totalInputTokens += inputTokens;
15
+ this.totalOutputTokens += outputTokens;
16
+ this.totalCalls++;
17
+ }
18
+ getEstimatedCostCents() {
19
+ // Sonnet pricing: $3/M input, $15/M output
20
+ const inputCost = (this.totalInputTokens * AI_CONFIG.pricing.inputCostPerMillion) /
21
+ 1_000_000;
22
+ const outputCost = (this.totalOutputTokens * AI_CONFIG.pricing.outputCostPerMillion) /
23
+ 1_000_000;
24
+ return (inputCost + outputCost) * 100; // Convert to cents
25
+ }
26
+ isOverBudget() {
27
+ return this.getEstimatedCostCents() >= this.budgetCents;
28
+ }
29
+ getSummary() {
30
+ const cost = this.getEstimatedCostCents() / 100;
31
+ return (`AI scan: ${this.totalCalls} calls, ` +
32
+ `${this.totalInputTokens} input tokens, ` +
33
+ `${this.totalOutputTokens} output tokens, ` +
34
+ `~$${cost.toFixed(3)}`);
35
+ }
36
+ getEstimate() {
37
+ const estimatedCalls = this.totalCalls || 1;
38
+ const estimatedCost = (estimatedCalls * AI_CONFIG.budget.estimatedCostPerCall) / 100;
39
+ return `Estimated cost: ~$${estimatedCost.toFixed(3)} (${estimatedCalls} calls)`;
40
+ }
41
+ getStats() {
42
+ return {
43
+ totalCalls: this.totalCalls,
44
+ totalInputTokens: this.totalInputTokens,
45
+ totalOutputTokens: this.totalOutputTokens,
46
+ estimatedCost: this.getEstimatedCostCents(),
47
+ };
48
+ }
49
+ reset() {
50
+ this.totalInputTokens = 0;
51
+ this.totalOutputTokens = 0;
52
+ this.totalCalls = 0;
53
+ }
54
+ }
55
+ //# sourceMappingURL=cost-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../../src/ai/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,OAAO,WAAW;IACd,gBAAgB,GAAG,CAAC,CAAC;IACrB,iBAAiB,GAAG,CAAC,CAAC;IACtB,UAAU,GAAG,CAAC,CAAC;IACf,WAAW,CAAS;IAE5B,YAAY,cAAsB,SAAS,CAAC,MAAM,CAAC,sBAAsB;QACvE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;IAED,UAAU,CAAC,WAAmB,EAAE,YAAoB;QAClD,IAAI,CAAC,gBAAgB,IAAI,WAAW,CAAC;QACrC,IAAI,CAAC,iBAAiB,IAAI,YAAY,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,qBAAqB;QACnB,2CAA2C;QAC3C,MAAM,SAAS,GACb,CAAC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;YAC/D,SAAS,CAAC;QACZ,MAAM,UAAU,GACd,CAAC,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC;YACjE,SAAS,CAAC;QACZ,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,mBAAmB;IAC5D,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,qBAAqB,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;IAC1D,CAAC;IAED,UAAU;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,EAAE,GAAG,GAAG,CAAC;QAChD,OAAO,CACL,YAAY,IAAI,CAAC,UAAU,UAAU;YACrC,GAAG,IAAI,CAAC,gBAAgB,iBAAiB;YACzC,GAAG,IAAI,CAAC,iBAAiB,kBAAkB;YAC3C,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CACvB,CAAC;IACJ,CAAC;IAED,WAAW;QACT,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QAC5C,MAAM,aAAa,GACjB,CAAC,cAAc,GAAG,SAAS,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,GAAG,CAAC;QACjE,OAAO,qBAAqB,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,cAAc,SAAS,CAAC;IACnF,CAAC;IAED,QAAQ;QACN,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,aAAa,EAAE,IAAI,CAAC,qBAAqB,EAAE;SAC5C,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * AI-Powered HIPAA Scanning
3
+ * Export all AI functionality
4
+ */
5
+ export { getAIClient, isAIAvailable } from './client.js';
6
+ export { AI_CONFIG } from './config.js';
7
+ export { sanitizeCodeForLLM } from './sanitizer.js';
8
+ export type { SanitizationResult } from './sanitizer.js';
9
+ export { CostTracker } from './cost-tracker.js';
10
+ export { AICache } from './cache.js';
11
+ export { RateLimiter } from './rate-limiter.js';
12
+ export { RuleRunner, triageFinding, triageFindings, AI_RULES, } from './rules/index.js';
13
+ export type { LLMRule, AIFinding, TriagedFinding, TriageClassification, LLMRuleResponse, TriageResponse, } from './rules/index.js';
14
+ export { runAIScan, triageExistingFindings } from './scanner.js';
15
+ export type { AIScanOptions, AIScanResult } from './scanner.js';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,OAAO,EACP,SAAS,EACT,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * AI-Powered HIPAA Scanning
3
+ * Export all AI functionality
4
+ */
5
+ export { getAIClient, isAIAvailable } from './client.js';
6
+ export { AI_CONFIG } from './config.js';
7
+ export { sanitizeCodeForLLM } from './sanitizer.js';
8
+ export { CostTracker } from './cost-tracker.js';
9
+ export { AICache } from './cache.js';
10
+ export { RateLimiter } from './rate-limiter.js';
11
+ export { RuleRunner, triageFinding, triageFindings, AI_RULES, } from './rules/index.js';
12
+ export { runAIScan, triageExistingFindings } from './scanner.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Rate Limiter - Prevent exceeding API rate limits
3
+ */
4
+ export declare class RateLimiter {
5
+ private callTimestamps;
6
+ private totalCalls;
7
+ canMakeCall(): boolean;
8
+ recordCall(): void;
9
+ waitIfNeeded(): Promise<void>;
10
+ reset(): void;
11
+ getStats(): {
12
+ callsThisMinute: number;
13
+ totalCalls: number;
14
+ };
15
+ }
16
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/ai/rate-limiter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,qBAAa,WAAW;IACtB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAK;IAEvB,WAAW,IAAI,OAAO;IAsBtB,UAAU,IAAI,IAAI;IAKZ,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAenC,KAAK,IAAI,IAAI;IAKb,QAAQ,IAAI;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAM5D"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Rate Limiter - Prevent exceeding API rate limits
3
+ */
4
+ import { AI_CONFIG } from './config.js';
5
+ export class RateLimiter {
6
+ callTimestamps = [];
7
+ totalCalls = 0;
8
+ canMakeCall() {
9
+ const now = Date.now();
10
+ const oneMinuteAgo = now - 60000;
11
+ // Remove timestamps older than 1 minute
12
+ this.callTimestamps = this.callTimestamps.filter((t) => t > oneMinuteAgo);
13
+ // Check per-minute limit
14
+ if (this.callTimestamps.length >= AI_CONFIG.rateLimit.maxCallsPerMinute) {
15
+ return false;
16
+ }
17
+ // Check per-scan limit
18
+ if (this.totalCalls >= AI_CONFIG.rateLimit.maxCallsPerScan) {
19
+ return false;
20
+ }
21
+ return true;
22
+ }
23
+ recordCall() {
24
+ this.callTimestamps.push(Date.now());
25
+ this.totalCalls++;
26
+ }
27
+ async waitIfNeeded() {
28
+ if (this.canMakeCall()) {
29
+ return;
30
+ }
31
+ // Wait for the oldest call to expire
32
+ const oldestCall = this.callTimestamps[0];
33
+ if (oldestCall) {
34
+ const waitTime = 60000 - (Date.now() - oldestCall) + 100; // +100ms buffer
35
+ if (waitTime > 0) {
36
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
37
+ }
38
+ }
39
+ }
40
+ reset() {
41
+ this.callTimestamps = [];
42
+ this.totalCalls = 0;
43
+ }
44
+ getStats() {
45
+ const now = Date.now();
46
+ const oneMinuteAgo = now - 60000;
47
+ const callsThisMinute = this.callTimestamps.filter((t) => t > oneMinuteAgo).length;
48
+ return { callsThisMinute, totalCalls: this.totalCalls };
49
+ }
50
+ }
51
+ //# sourceMappingURL=rate-limiter.js.map