@vibecheckai/cli 3.4.0 → 3.5.1
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/registry.js +154 -338
- package/bin/runners/context/generators/mcp.js +13 -15
- package/bin/runners/context/proof-context.js +1 -248
- package/bin/runners/lib/analysis-core.js +180 -198
- package/bin/runners/lib/analyzers.js +223 -1669
- package/bin/runners/lib/cli-output.js +210 -242
- package/bin/runners/lib/detectors-v2.js +785 -547
- package/bin/runners/lib/entitlements-v2.js +458 -96
- package/bin/runners/lib/error-handler.js +9 -16
- package/bin/runners/lib/global-flags.js +0 -37
- package/bin/runners/lib/route-truth.js +322 -1167
- package/bin/runners/lib/scan-output.js +469 -448
- package/bin/runners/lib/ship-output.js +27 -280
- package/bin/runners/lib/terminal-ui.js +733 -231
- package/bin/runners/lib/truth.js +321 -1004
- package/bin/runners/lib/unified-output.js +158 -162
- package/bin/runners/lib/upsell.js +204 -104
- package/bin/runners/runAllowlist.js +324 -0
- package/bin/runners/runAuth.js +95 -324
- package/bin/runners/runCheckpoint.js +21 -39
- package/bin/runners/runContext.js +24 -136
- package/bin/runners/runDoctor.js +67 -115
- package/bin/runners/runEvidencePack.js +219 -0
- package/bin/runners/runFix.js +5 -6
- package/bin/runners/runGuard.js +118 -212
- package/bin/runners/runInit.js +2 -14
- package/bin/runners/runInstall.js +281 -0
- package/bin/runners/runLabs.js +341 -0
- package/bin/runners/runMcp.js +52 -130
- package/bin/runners/runPolish.js +20 -43
- package/bin/runners/runProve.js +3 -13
- package/bin/runners/runReality.js +0 -14
- package/bin/runners/runReport.js +2 -3
- package/bin/runners/runScan.js +44 -511
- package/bin/runners/runShip.js +14 -28
- package/bin/runners/runValidate.js +2 -19
- package/bin/runners/runWatch.js +54 -118
- package/bin/vibecheck.js +41 -148
- package/mcp-server/ARCHITECTURE.md +339 -0
- package/mcp-server/__tests__/cache.test.ts +313 -0
- package/mcp-server/__tests__/executor.test.ts +239 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +1 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/package.json +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +4 -0
- package/mcp-server/__tests__/ids.test.ts +345 -0
- package/mcp-server/__tests__/integration/tools.test.ts +410 -0
- package/mcp-server/__tests__/registry.test.ts +365 -0
- package/mcp-server/__tests__/sandbox.test.ts +323 -0
- package/mcp-server/__tests__/schemas.test.ts +372 -0
- package/mcp-server/benchmarks/run-benchmarks.ts +304 -0
- package/mcp-server/examples/doctor.request.json +14 -0
- package/mcp-server/examples/doctor.response.json +53 -0
- package/mcp-server/examples/error.response.json +15 -0
- package/mcp-server/examples/scan.request.json +14 -0
- package/mcp-server/examples/scan.response.json +108 -0
- package/mcp-server/handlers/tool-handler.ts +671 -0
- package/mcp-server/index-v3.ts +293 -0
- package/mcp-server/index.js +1072 -1573
- package/mcp-server/index.old.js +4137 -0
- package/mcp-server/lib/cache.ts +341 -0
- package/mcp-server/lib/errors.ts +346 -0
- package/mcp-server/lib/executor.ts +792 -0
- package/mcp-server/lib/ids.ts +238 -0
- package/mcp-server/lib/logger.ts +368 -0
- package/mcp-server/lib/metrics.ts +365 -0
- package/mcp-server/lib/sandbox.ts +337 -0
- package/mcp-server/lib/validator.ts +229 -0
- package/mcp-server/package-lock.json +165 -0
- package/mcp-server/package.json +32 -7
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/registry/tools.json +476 -0
- package/mcp-server/schemas/error-envelope.schema.json +125 -0
- package/mcp-server/schemas/finding.schema.json +167 -0
- package/mcp-server/schemas/report-artifact.schema.json +88 -0
- package/mcp-server/schemas/run-request.schema.json +75 -0
- package/mcp-server/schemas/verdict.schema.json +168 -0
- package/mcp-server/tier-auth.d.ts +71 -0
- package/mcp-server/tier-auth.js +371 -183
- package/mcp-server/truth-context.js +90 -131
- package/mcp-server/truth-firewall-tools.js +1000 -1611
- package/mcp-server/tsconfig.json +34 -0
- package/mcp-server/vibecheck-tools.js +2 -2
- package/mcp-server/vitest.config.ts +16 -0
- package/package.json +3 -4
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +0 -474
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +0 -488
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +0 -228
- package/bin/runners/lib/agent-firewall/change-packet/store.js +0 -200
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +0 -21
- package/bin/runners/lib/agent-firewall/claims/extractor.js +0 -303
- package/bin/runners/lib/agent-firewall/claims/patterns.js +0 -24
- package/bin/runners/lib/agent-firewall/critic/index.js +0 -151
- package/bin/runners/lib/agent-firewall/critic/judge.js +0 -432
- package/bin/runners/lib/agent-firewall/critic/prompts.js +0 -305
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +0 -88
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +0 -75
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +0 -127
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +0 -102
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +0 -213
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +0 -145
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +0 -19
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +0 -87
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +0 -184
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +0 -163
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +0 -107
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +0 -68
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +0 -66
- package/bin/runners/lib/agent-firewall/interceptor/base.js +0 -304
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +0 -34
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +0 -465
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +0 -604
- package/bin/runners/lib/agent-firewall/lawbook/index.js +0 -304
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +0 -514
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +0 -420
- package/bin/runners/lib/agent-firewall/logger.js +0 -141
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +0 -90
- package/bin/runners/lib/agent-firewall/policy/engine.js +0 -103
- package/bin/runners/lib/agent-firewall/policy/loader.js +0 -451
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +0 -86
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +0 -162
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +0 -189
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +0 -93
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +0 -57
- package/bin/runners/lib/agent-firewall/policy/schema.json +0 -183
- package/bin/runners/lib/agent-firewall/policy/verdict.js +0 -54
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +0 -394
- package/bin/runners/lib/agent-firewall/proposal/index.js +0 -212
- package/bin/runners/lib/agent-firewall/proposal/schema.js +0 -251
- package/bin/runners/lib/agent-firewall/proposal/validator.js +0 -386
- package/bin/runners/lib/agent-firewall/reality/index.js +0 -332
- package/bin/runners/lib/agent-firewall/reality/state.js +0 -625
- package/bin/runners/lib/agent-firewall/reality/watcher.js +0 -322
- package/bin/runners/lib/agent-firewall/risk/index.js +0 -173
- package/bin/runners/lib/agent-firewall/risk/scorer.js +0 -328
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +0 -321
- package/bin/runners/lib/agent-firewall/risk/vectors.js +0 -421
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +0 -472
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +0 -346
- package/bin/runners/lib/agent-firewall/simulator/index.js +0 -181
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +0 -380
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +0 -661
- package/bin/runners/lib/agent-firewall/time-machine/index.js +0 -267
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +0 -436
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +0 -490
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +0 -530
- package/bin/runners/lib/agent-firewall/truthpack/index.js +0 -67
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +0 -137
- package/bin/runners/lib/agent-firewall/unblock/planner.js +0 -337
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +0 -118
- package/bin/runners/lib/api-client.js +0 -269
- package/bin/runners/lib/authority-badge.js +0 -425
- package/bin/runners/lib/engines/accessibility-engine.js +0 -190
- package/bin/runners/lib/engines/api-consistency-engine.js +0 -162
- package/bin/runners/lib/engines/ast-cache.js +0 -99
- package/bin/runners/lib/engines/code-quality-engine.js +0 -255
- package/bin/runners/lib/engines/console-logs-engine.js +0 -115
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +0 -268
- package/bin/runners/lib/engines/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/deprecated-api-engine.js +0 -226
- package/bin/runners/lib/engines/empty-catch-engine.js +0 -150
- package/bin/runners/lib/engines/file-filter.js +0 -131
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +0 -251
- package/bin/runners/lib/engines/mock-data-engine.js +0 -272
- package/bin/runners/lib/engines/parallel-processor.js +0 -71
- package/bin/runners/lib/engines/performance-issues-engine.js +0 -265
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +0 -243
- package/bin/runners/lib/engines/todo-fixme-engine.js +0 -115
- package/bin/runners/lib/engines/type-aware-engine.js +0 -152
- package/bin/runners/lib/engines/unsafe-regex-engine.js +0 -225
- package/bin/runners/lib/engines/vibecheck-engines/README.md +0 -53
- package/bin/runners/lib/engines/vibecheck-engines/index.js +0 -15
- package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
- package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
- package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
- package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
- package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +0 -139
- package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
- package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
- package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
- package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
- package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
- package/bin/runners/lib/engines/vibecheck-engines/package.json +0 -13
- package/bin/runners/lib/exit-codes.js +0 -275
- package/bin/runners/lib/fingerprint.js +0 -377
- package/bin/runners/lib/help-formatter.js +0 -413
- package/bin/runners/lib/logger.js +0 -38
- package/bin/runners/lib/ship-output-enterprise.js +0 -239
- package/bin/runners/lib/unified-cli-output.js +0 -604
- package/bin/runners/runAgent.d.ts +0 -5
- package/bin/runners/runAgent.js +0 -161
- package/bin/runners/runApprove.js +0 -1200
- package/bin/runners/runClassify.js +0 -859
- package/bin/runners/runContext.d.ts +0 -4
- package/bin/runners/runFirewall.d.ts +0 -5
- package/bin/runners/runFirewall.js +0 -134
- package/bin/runners/runFirewallHook.d.ts +0 -5
- package/bin/runners/runFirewallHook.js +0 -56
- package/bin/runners/runPolish.d.ts +0 -4
- package/bin/runners/runProof.zip +0 -0
- package/bin/runners/runTruth.d.ts +0 -5
- package/bin/runners/runTruth.js +0 -101
- package/mcp-server/HARDENING_SUMMARY.md +0 -299
- package/mcp-server/agent-firewall-interceptor.js +0 -500
- package/mcp-server/authority-tools.js +0 -569
- package/mcp-server/conductor/conflict-resolver.js +0 -588
- package/mcp-server/conductor/execution-planner.js +0 -544
- package/mcp-server/conductor/index.js +0 -377
- package/mcp-server/conductor/lock-manager.js +0 -615
- package/mcp-server/conductor/request-queue.js +0 -550
- package/mcp-server/conductor/session-manager.js +0 -500
- package/mcp-server/conductor/tools.js +0 -510
- package/mcp-server/lib/api-client.cjs +0 -13
- package/mcp-server/lib/logger.cjs +0 -30
- package/mcp-server/logger.js +0 -173
- package/mcp-server/tools-v3.js +0 -706
- package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caching Layer for MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Provides deterministic caching with:
|
|
5
|
+
* - Project fingerprinting for cache invalidation
|
|
6
|
+
* - Incremental run detection
|
|
7
|
+
* - TTL-based expiration
|
|
8
|
+
* - Memory + disk caching
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createHash } from 'crypto';
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, statSync, mkdirSync } from 'fs';
|
|
13
|
+
import { join, dirname } from 'path';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Cache entry structure
|
|
17
|
+
*/
|
|
18
|
+
export interface CacheEntry<T> {
|
|
19
|
+
data: T;
|
|
20
|
+
fingerprint: string;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
ttl: number;
|
|
23
|
+
hits: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Cache configuration
|
|
28
|
+
*/
|
|
29
|
+
export interface CacheConfig {
|
|
30
|
+
maxMemoryEntries?: number;
|
|
31
|
+
defaultTtl?: number;
|
|
32
|
+
diskCacheDir?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Project fingerprint - used for cache invalidation
|
|
37
|
+
*/
|
|
38
|
+
export interface ProjectFingerprint {
|
|
39
|
+
hash: string;
|
|
40
|
+
fileCount: number;
|
|
41
|
+
lastModified: number;
|
|
42
|
+
packageJsonHash?: string;
|
|
43
|
+
lockfileHash?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* In-memory LRU cache
|
|
48
|
+
*/
|
|
49
|
+
class MemoryCache<T> {
|
|
50
|
+
private cache = new Map<string, CacheEntry<T>>();
|
|
51
|
+
private maxEntries: number;
|
|
52
|
+
|
|
53
|
+
constructor(maxEntries = 100) {
|
|
54
|
+
this.maxEntries = maxEntries;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get(key: string): CacheEntry<T> | undefined {
|
|
58
|
+
const entry = this.cache.get(key);
|
|
59
|
+
if (entry) {
|
|
60
|
+
// Move to end (most recently used)
|
|
61
|
+
this.cache.delete(key);
|
|
62
|
+
entry.hits++;
|
|
63
|
+
this.cache.set(key, entry);
|
|
64
|
+
}
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
set(key: string, entry: CacheEntry<T>): void {
|
|
69
|
+
// Evict oldest if at capacity
|
|
70
|
+
if (this.cache.size >= this.maxEntries) {
|
|
71
|
+
const firstKey = this.cache.keys().next().value;
|
|
72
|
+
if (firstKey) this.cache.delete(firstKey);
|
|
73
|
+
}
|
|
74
|
+
this.cache.set(key, entry);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
delete(key: string): boolean {
|
|
78
|
+
return this.cache.delete(key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
clear(): void {
|
|
82
|
+
this.cache.clear();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
size(): number {
|
|
86
|
+
return this.cache.size;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Main cache class
|
|
92
|
+
*/
|
|
93
|
+
export class VibecheckCache {
|
|
94
|
+
private memoryCache: MemoryCache<unknown>;
|
|
95
|
+
private diskCacheDir?: string;
|
|
96
|
+
private defaultTtl: number;
|
|
97
|
+
private fingerprintCache = new Map<string, ProjectFingerprint>();
|
|
98
|
+
|
|
99
|
+
constructor(config: CacheConfig = {}) {
|
|
100
|
+
this.memoryCache = new MemoryCache(config.maxMemoryEntries ?? 100);
|
|
101
|
+
this.diskCacheDir = config.diskCacheDir;
|
|
102
|
+
this.defaultTtl = config.defaultTtl ?? 300; // 5 minutes
|
|
103
|
+
|
|
104
|
+
// Create disk cache dir if specified
|
|
105
|
+
if (this.diskCacheDir && !existsSync(this.diskCacheDir)) {
|
|
106
|
+
mkdirSync(this.diskCacheDir, { recursive: true });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Generate cache key
|
|
112
|
+
*/
|
|
113
|
+
generateKey(tool: string, projectPath: string, options?: Record<string, unknown>): string {
|
|
114
|
+
const fingerprint = this.getProjectFingerprint(projectPath);
|
|
115
|
+
const optionsHash = options ? createHash('md5').update(JSON.stringify(options)).digest('hex').substring(0, 8) : '';
|
|
116
|
+
return `${tool}:${fingerprint.hash}:${optionsHash}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get from cache
|
|
121
|
+
*/
|
|
122
|
+
get<T>(key: string): { data: T; cached: true; age: number } | { cached: false } {
|
|
123
|
+
// Try memory cache first
|
|
124
|
+
const memEntry = this.memoryCache.get(key) as CacheEntry<T> | undefined;
|
|
125
|
+
if (memEntry) {
|
|
126
|
+
const age = Date.now() - memEntry.timestamp;
|
|
127
|
+
if (age < memEntry.ttl * 1000) {
|
|
128
|
+
return { data: memEntry.data, cached: true, age };
|
|
129
|
+
}
|
|
130
|
+
// Expired - remove
|
|
131
|
+
this.memoryCache.delete(key);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Try disk cache
|
|
135
|
+
if (this.diskCacheDir) {
|
|
136
|
+
const diskEntry = this.getDiskCache<T>(key);
|
|
137
|
+
if (diskEntry) {
|
|
138
|
+
const age = Date.now() - diskEntry.timestamp;
|
|
139
|
+
if (age < diskEntry.ttl * 1000) {
|
|
140
|
+
// Promote to memory cache
|
|
141
|
+
this.memoryCache.set(key, diskEntry);
|
|
142
|
+
return { data: diskEntry.data, cached: true, age };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return { cached: false };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Set cache entry
|
|
152
|
+
*/
|
|
153
|
+
set<T>(
|
|
154
|
+
key: string,
|
|
155
|
+
data: T,
|
|
156
|
+
options?: { ttl?: number; fingerprint?: string }
|
|
157
|
+
): void {
|
|
158
|
+
const entry: CacheEntry<T> = {
|
|
159
|
+
data,
|
|
160
|
+
fingerprint: options?.fingerprint ?? '',
|
|
161
|
+
timestamp: Date.now(),
|
|
162
|
+
ttl: options?.ttl ?? this.defaultTtl,
|
|
163
|
+
hits: 0,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Set in memory cache
|
|
167
|
+
this.memoryCache.set(key, entry as CacheEntry<unknown>);
|
|
168
|
+
|
|
169
|
+
// Persist to disk if configured
|
|
170
|
+
if (this.diskCacheDir) {
|
|
171
|
+
this.setDiskCache(key, entry);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Invalidate cache for a project
|
|
177
|
+
*/
|
|
178
|
+
invalidate(projectPath: string): void {
|
|
179
|
+
// Clear fingerprint cache
|
|
180
|
+
this.fingerprintCache.delete(projectPath);
|
|
181
|
+
|
|
182
|
+
// We can't easily clear memory cache by project, so we rely on fingerprint mismatches
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get project fingerprint for cache invalidation
|
|
187
|
+
*/
|
|
188
|
+
getProjectFingerprint(projectPath: string): ProjectFingerprint {
|
|
189
|
+
// Check cache first
|
|
190
|
+
const cached = this.fingerprintCache.get(projectPath);
|
|
191
|
+
if (cached) {
|
|
192
|
+
return cached;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const fingerprint = this.computeProjectFingerprint(projectPath);
|
|
196
|
+
this.fingerprintCache.set(projectPath, fingerprint);
|
|
197
|
+
return fingerprint;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Compute project fingerprint
|
|
202
|
+
*/
|
|
203
|
+
private computeProjectFingerprint(projectPath: string): ProjectFingerprint {
|
|
204
|
+
const hash = createHash('md5');
|
|
205
|
+
let fileCount = 0;
|
|
206
|
+
let lastModified = 0;
|
|
207
|
+
|
|
208
|
+
// Hash key files that indicate project changes
|
|
209
|
+
const keyFiles = [
|
|
210
|
+
'package.json',
|
|
211
|
+
'package-lock.json',
|
|
212
|
+
'pnpm-lock.yaml',
|
|
213
|
+
'yarn.lock',
|
|
214
|
+
'tsconfig.json',
|
|
215
|
+
'.vibecheckrc',
|
|
216
|
+
'vibecheck.config.json',
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
let packageJsonHash: string | undefined;
|
|
220
|
+
let lockfileHash: string | undefined;
|
|
221
|
+
|
|
222
|
+
for (const file of keyFiles) {
|
|
223
|
+
const filePath = join(projectPath, file);
|
|
224
|
+
if (existsSync(filePath)) {
|
|
225
|
+
try {
|
|
226
|
+
const stat = statSync(filePath);
|
|
227
|
+
const content = readFileSync(filePath);
|
|
228
|
+
hash.update(content);
|
|
229
|
+
lastModified = Math.max(lastModified, stat.mtimeMs);
|
|
230
|
+
fileCount++;
|
|
231
|
+
|
|
232
|
+
if (file === 'package.json') {
|
|
233
|
+
packageJsonHash = createHash('md5').update(content).digest('hex').substring(0, 8);
|
|
234
|
+
}
|
|
235
|
+
if (file.includes('lock')) {
|
|
236
|
+
lockfileHash = createHash('md5').update(content).digest('hex').substring(0, 8);
|
|
237
|
+
}
|
|
238
|
+
} catch {
|
|
239
|
+
// Skip inaccessible files
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Also check .vibecheck directory
|
|
245
|
+
const vibecheckDir = join(projectPath, '.vibecheck');
|
|
246
|
+
if (existsSync(vibecheckDir)) {
|
|
247
|
+
try {
|
|
248
|
+
const stat = statSync(vibecheckDir);
|
|
249
|
+
lastModified = Math.max(lastModified, stat.mtimeMs);
|
|
250
|
+
} catch {
|
|
251
|
+
// Skip
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
hash: hash.digest('hex').substring(0, 16),
|
|
257
|
+
fileCount,
|
|
258
|
+
lastModified,
|
|
259
|
+
packageJsonHash,
|
|
260
|
+
lockfileHash,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Disk cache operations
|
|
266
|
+
*/
|
|
267
|
+
private getDiskCache<T>(key: string): CacheEntry<T> | null {
|
|
268
|
+
if (!this.diskCacheDir) return null;
|
|
269
|
+
|
|
270
|
+
const filePath = join(this.diskCacheDir, `${this.sanitizeKey(key)}.json`);
|
|
271
|
+
if (!existsSync(filePath)) return null;
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
275
|
+
return JSON.parse(content) as CacheEntry<T>;
|
|
276
|
+
} catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private setDiskCache<T>(key: string, entry: CacheEntry<T>): void {
|
|
282
|
+
if (!this.diskCacheDir) return;
|
|
283
|
+
|
|
284
|
+
const filePath = join(this.diskCacheDir, `${this.sanitizeKey(key)}.json`);
|
|
285
|
+
try {
|
|
286
|
+
writeFileSync(filePath, JSON.stringify(entry), 'utf-8');
|
|
287
|
+
} catch {
|
|
288
|
+
// Ignore disk write errors
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private sanitizeKey(key: string): string {
|
|
293
|
+
return key.replace(/[^a-zA-Z0-9_-]/g, '_').substring(0, 100);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Check if an incremental run is possible
|
|
298
|
+
*/
|
|
299
|
+
canRunIncremental(projectPath: string, lastRunFingerprint: string): boolean {
|
|
300
|
+
const currentFingerprint = this.getProjectFingerprint(projectPath);
|
|
301
|
+
return currentFingerprint.hash !== lastRunFingerprint;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Clear all caches
|
|
306
|
+
*/
|
|
307
|
+
clear(): void {
|
|
308
|
+
this.memoryCache.clear();
|
|
309
|
+
this.fingerprintCache.clear();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Get cache stats
|
|
314
|
+
*/
|
|
315
|
+
getStats(): { memoryEntries: number; fingerprintEntries: number } {
|
|
316
|
+
return {
|
|
317
|
+
memoryEntries: this.memoryCache.size(),
|
|
318
|
+
fingerprintEntries: this.fingerprintCache.size,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Singleton instance
|
|
324
|
+
let globalCache: VibecheckCache | null = null;
|
|
325
|
+
|
|
326
|
+
export function getGlobalCache(): VibecheckCache {
|
|
327
|
+
if (!globalCache) {
|
|
328
|
+
globalCache = new VibecheckCache();
|
|
329
|
+
}
|
|
330
|
+
return globalCache;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function initGlobalCache(config: CacheConfig): void {
|
|
334
|
+
globalCache = new VibecheckCache(config);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export default {
|
|
338
|
+
VibecheckCache,
|
|
339
|
+
getGlobalCache,
|
|
340
|
+
initGlobalCache,
|
|
341
|
+
};
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Handling & Normalization
|
|
3
|
+
*
|
|
4
|
+
* All errors are normalized to ErrorEnvelope format.
|
|
5
|
+
* No mystery errors - every failure has a code, message, and userAction.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { randomUUID } from 'crypto';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Error codes enum
|
|
12
|
+
*/
|
|
13
|
+
export enum ErrorCode {
|
|
14
|
+
INVALID_INPUT = 'INVALID_INPUT',
|
|
15
|
+
VALIDATION_ERROR = 'VALIDATION_ERROR',
|
|
16
|
+
PATH_NOT_FOUND = 'PATH_NOT_FOUND',
|
|
17
|
+
PATH_OUTSIDE_SANDBOX = 'PATH_OUTSIDE_SANDBOX',
|
|
18
|
+
PERMISSION_DENIED = 'PERMISSION_DENIED',
|
|
19
|
+
TIER_REQUIRED = 'TIER_REQUIRED',
|
|
20
|
+
RATE_LIMITED = 'RATE_LIMITED',
|
|
21
|
+
TIMEOUT = 'TIMEOUT',
|
|
22
|
+
CANCELLED = 'CANCELLED',
|
|
23
|
+
CLI_ERROR = 'CLI_ERROR',
|
|
24
|
+
INTERNAL_ERROR = 'INTERNAL_ERROR',
|
|
25
|
+
NOT_FOUND = 'NOT_FOUND',
|
|
26
|
+
ALREADY_EXISTS = 'ALREADY_EXISTS',
|
|
27
|
+
DEPENDENCY_MISSING = 'DEPENDENCY_MISSING',
|
|
28
|
+
CONFIG_ERROR = 'CONFIG_ERROR',
|
|
29
|
+
NETWORK_ERROR = 'NETWORK_ERROR',
|
|
30
|
+
TRUTH_FIREWALL_REQUIRED = 'TRUTH_FIREWALL_REQUIRED',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Error envelope structure
|
|
35
|
+
*/
|
|
36
|
+
export interface ErrorEnvelope {
|
|
37
|
+
ok: false;
|
|
38
|
+
error: {
|
|
39
|
+
code: ErrorCode;
|
|
40
|
+
message: string;
|
|
41
|
+
details?: Record<string, unknown>;
|
|
42
|
+
retryable: boolean;
|
|
43
|
+
retryAfterMs?: number;
|
|
44
|
+
userAction?: string;
|
|
45
|
+
docsUrl?: string;
|
|
46
|
+
};
|
|
47
|
+
requestId: string;
|
|
48
|
+
timestamp: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Success envelope structure
|
|
53
|
+
*/
|
|
54
|
+
export interface SuccessEnvelope<T> {
|
|
55
|
+
ok: true;
|
|
56
|
+
data: T;
|
|
57
|
+
meta?: {
|
|
58
|
+
cached?: boolean;
|
|
59
|
+
cacheAge?: number;
|
|
60
|
+
durationMs?: number;
|
|
61
|
+
requestId?: string;
|
|
62
|
+
};
|
|
63
|
+
timestamp: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Custom error class
|
|
68
|
+
*/
|
|
69
|
+
export class VibecheckError extends Error {
|
|
70
|
+
code: ErrorCode;
|
|
71
|
+
details?: Record<string, unknown>;
|
|
72
|
+
retryable: boolean;
|
|
73
|
+
retryAfterMs?: number;
|
|
74
|
+
userAction?: string;
|
|
75
|
+
docsUrl?: string;
|
|
76
|
+
|
|
77
|
+
constructor(
|
|
78
|
+
code: ErrorCode,
|
|
79
|
+
message: string,
|
|
80
|
+
options?: {
|
|
81
|
+
details?: Record<string, unknown>;
|
|
82
|
+
retryable?: boolean;
|
|
83
|
+
retryAfterMs?: number;
|
|
84
|
+
userAction?: string;
|
|
85
|
+
docsUrl?: string;
|
|
86
|
+
}
|
|
87
|
+
) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.name = 'VibecheckError';
|
|
90
|
+
this.code = code;
|
|
91
|
+
this.details = options?.details;
|
|
92
|
+
this.retryable = options?.retryable ?? false;
|
|
93
|
+
this.retryAfterMs = options?.retryAfterMs;
|
|
94
|
+
this.userAction = options?.userAction;
|
|
95
|
+
this.docsUrl = options?.docsUrl;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Create error envelope from error
|
|
101
|
+
*/
|
|
102
|
+
export function createErrorEnvelope(
|
|
103
|
+
error: unknown,
|
|
104
|
+
requestId?: string
|
|
105
|
+
): ErrorEnvelope {
|
|
106
|
+
const id = requestId || randomUUID();
|
|
107
|
+
const timestamp = new Date().toISOString();
|
|
108
|
+
|
|
109
|
+
if (error instanceof VibecheckError) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
error: {
|
|
113
|
+
code: error.code,
|
|
114
|
+
message: error.message,
|
|
115
|
+
details: error.details,
|
|
116
|
+
retryable: error.retryable,
|
|
117
|
+
retryAfterMs: error.retryAfterMs,
|
|
118
|
+
userAction: error.userAction,
|
|
119
|
+
docsUrl: error.docsUrl,
|
|
120
|
+
},
|
|
121
|
+
requestId: id,
|
|
122
|
+
timestamp,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Normalize unknown errors
|
|
127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
128
|
+
|
|
129
|
+
// Try to infer error type
|
|
130
|
+
const inferredCode = inferErrorCode(message);
|
|
131
|
+
const inferredAction = inferUserAction(inferredCode, message);
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
error: {
|
|
136
|
+
code: inferredCode,
|
|
137
|
+
message,
|
|
138
|
+
retryable: isRetryable(inferredCode),
|
|
139
|
+
userAction: inferredAction,
|
|
140
|
+
},
|
|
141
|
+
requestId: id,
|
|
142
|
+
timestamp,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create success envelope
|
|
148
|
+
*/
|
|
149
|
+
export function createSuccessEnvelope<T>(
|
|
150
|
+
data: T,
|
|
151
|
+
options?: {
|
|
152
|
+
cached?: boolean;
|
|
153
|
+
cacheAge?: number;
|
|
154
|
+
durationMs?: number;
|
|
155
|
+
requestId?: string;
|
|
156
|
+
}
|
|
157
|
+
): SuccessEnvelope<T> {
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
data,
|
|
161
|
+
meta: options ? {
|
|
162
|
+
cached: options.cached,
|
|
163
|
+
cacheAge: options.cacheAge,
|
|
164
|
+
durationMs: options.durationMs,
|
|
165
|
+
requestId: options.requestId,
|
|
166
|
+
} : undefined,
|
|
167
|
+
timestamp: new Date().toISOString(),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Infer error code from message
|
|
173
|
+
*/
|
|
174
|
+
function inferErrorCode(message: string): ErrorCode {
|
|
175
|
+
const lower = message.toLowerCase();
|
|
176
|
+
|
|
177
|
+
if (lower.includes('timeout') || lower.includes('timed out')) {
|
|
178
|
+
return ErrorCode.TIMEOUT;
|
|
179
|
+
}
|
|
180
|
+
if (lower.includes('enoent') || lower.includes('not found') || lower.includes('does not exist')) {
|
|
181
|
+
return ErrorCode.PATH_NOT_FOUND;
|
|
182
|
+
}
|
|
183
|
+
if (lower.includes('eperm') || lower.includes('eacces') || lower.includes('permission')) {
|
|
184
|
+
return ErrorCode.PERMISSION_DENIED;
|
|
185
|
+
}
|
|
186
|
+
if (lower.includes('rate limit') || lower.includes('too many requests')) {
|
|
187
|
+
return ErrorCode.RATE_LIMITED;
|
|
188
|
+
}
|
|
189
|
+
if (lower.includes('cancelled') || lower.includes('aborted')) {
|
|
190
|
+
return ErrorCode.CANCELLED;
|
|
191
|
+
}
|
|
192
|
+
if (lower.includes('validation') || lower.includes('invalid')) {
|
|
193
|
+
return ErrorCode.VALIDATION_ERROR;
|
|
194
|
+
}
|
|
195
|
+
if (lower.includes('tier') || lower.includes('upgrade') || lower.includes('subscription')) {
|
|
196
|
+
return ErrorCode.TIER_REQUIRED;
|
|
197
|
+
}
|
|
198
|
+
if (lower.includes('network') || lower.includes('econnrefused') || lower.includes('enotfound')) {
|
|
199
|
+
return ErrorCode.NETWORK_ERROR;
|
|
200
|
+
}
|
|
201
|
+
if (lower.includes('missing') && lower.includes('depend')) {
|
|
202
|
+
return ErrorCode.DEPENDENCY_MISSING;
|
|
203
|
+
}
|
|
204
|
+
if (lower.includes('config')) {
|
|
205
|
+
return ErrorCode.CONFIG_ERROR;
|
|
206
|
+
}
|
|
207
|
+
if (lower.includes('truth') && lower.includes('firewall')) {
|
|
208
|
+
return ErrorCode.TRUTH_FIREWALL_REQUIRED;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return ErrorCode.INTERNAL_ERROR;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Infer user action from error
|
|
216
|
+
*/
|
|
217
|
+
function inferUserAction(code: ErrorCode, message: string): string {
|
|
218
|
+
switch (code) {
|
|
219
|
+
case ErrorCode.PATH_NOT_FOUND:
|
|
220
|
+
return 'Check that the path exists and is spelled correctly';
|
|
221
|
+
case ErrorCode.PATH_OUTSIDE_SANDBOX:
|
|
222
|
+
return 'Provide a path within your project workspace';
|
|
223
|
+
case ErrorCode.PERMISSION_DENIED:
|
|
224
|
+
return 'Check file permissions or run with appropriate access';
|
|
225
|
+
case ErrorCode.TIER_REQUIRED:
|
|
226
|
+
return 'Upgrade your plan at https://vibecheck.dev/pricing';
|
|
227
|
+
case ErrorCode.RATE_LIMITED:
|
|
228
|
+
return 'Wait a moment and try again';
|
|
229
|
+
case ErrorCode.TIMEOUT:
|
|
230
|
+
return 'Try again with a smaller scope or increase timeout';
|
|
231
|
+
case ErrorCode.DEPENDENCY_MISSING:
|
|
232
|
+
return 'Run npm install or check your package.json';
|
|
233
|
+
case ErrorCode.CONFIG_ERROR:
|
|
234
|
+
return 'Check your vibecheck configuration file';
|
|
235
|
+
case ErrorCode.NETWORK_ERROR:
|
|
236
|
+
return 'Check your network connection and try again';
|
|
237
|
+
case ErrorCode.TRUTH_FIREWALL_REQUIRED:
|
|
238
|
+
return 'Call vibecheck.get_truthpack or vibecheck.validate_claim first';
|
|
239
|
+
case ErrorCode.VALIDATION_ERROR:
|
|
240
|
+
return 'Check your input parameters against the tool schema';
|
|
241
|
+
default:
|
|
242
|
+
return 'If this persists, please report at https://github.com/vibecheckai/vibecheck/issues';
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Check if error is retryable
|
|
248
|
+
*/
|
|
249
|
+
function isRetryable(code: ErrorCode): boolean {
|
|
250
|
+
switch (code) {
|
|
251
|
+
case ErrorCode.TIMEOUT:
|
|
252
|
+
case ErrorCode.RATE_LIMITED:
|
|
253
|
+
case ErrorCode.NETWORK_ERROR:
|
|
254
|
+
return true;
|
|
255
|
+
default:
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Error factory functions for common cases
|
|
262
|
+
*/
|
|
263
|
+
export const Errors = {
|
|
264
|
+
invalidInput(message: string, details?: Record<string, unknown>) {
|
|
265
|
+
return new VibecheckError(ErrorCode.INVALID_INPUT, message, {
|
|
266
|
+
details,
|
|
267
|
+
userAction: 'Check your input parameters',
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
pathNotFound(path: string) {
|
|
272
|
+
return new VibecheckError(ErrorCode.PATH_NOT_FOUND, `Path not found: ${path}`, {
|
|
273
|
+
details: { path },
|
|
274
|
+
userAction: 'Check that the path exists',
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
pathOutsideSandbox(path: string, workspace: string) {
|
|
279
|
+
return new VibecheckError(
|
|
280
|
+
ErrorCode.PATH_OUTSIDE_SANDBOX,
|
|
281
|
+
`Path '${path}' is outside the allowed workspace`,
|
|
282
|
+
{
|
|
283
|
+
details: { path, workspace },
|
|
284
|
+
userAction: 'Provide a path within your project workspace',
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
tierRequired(feature: string, requiredTier: string, currentTier: string) {
|
|
290
|
+
return new VibecheckError(
|
|
291
|
+
ErrorCode.TIER_REQUIRED,
|
|
292
|
+
`${feature} requires ${requiredTier} tier`,
|
|
293
|
+
{
|
|
294
|
+
details: { feature, requiredTier, currentTier },
|
|
295
|
+
userAction: `Upgrade to ${requiredTier} at https://vibecheck.dev/pricing`,
|
|
296
|
+
docsUrl: 'https://vibecheck.dev/pricing',
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
timeout(timeoutMs: number) {
|
|
302
|
+
return new VibecheckError(
|
|
303
|
+
ErrorCode.TIMEOUT,
|
|
304
|
+
`Operation timed out after ${timeoutMs}ms`,
|
|
305
|
+
{
|
|
306
|
+
retryable: true,
|
|
307
|
+
retryAfterMs: 5000,
|
|
308
|
+
userAction: 'Try with a smaller scope or increase timeout',
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
},
|
|
312
|
+
|
|
313
|
+
rateLimited(retryAfterMs: number) {
|
|
314
|
+
return new VibecheckError(ErrorCode.RATE_LIMITED, 'Rate limit exceeded', {
|
|
315
|
+
retryable: true,
|
|
316
|
+
retryAfterMs,
|
|
317
|
+
userAction: `Wait ${Math.ceil(retryAfterMs / 1000)} seconds and try again`,
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
cliError(message: string, exitCode?: number) {
|
|
322
|
+
return new VibecheckError(ErrorCode.CLI_ERROR, message, {
|
|
323
|
+
details: { exitCode },
|
|
324
|
+
userAction: 'Check the CLI output for details',
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
truthFirewallRequired() {
|
|
329
|
+
return new VibecheckError(
|
|
330
|
+
ErrorCode.TRUTH_FIREWALL_REQUIRED,
|
|
331
|
+
'Truth firewall requires claim validation before high-impact tools',
|
|
332
|
+
{
|
|
333
|
+
userAction: 'Call vibecheck.get_truthpack or vibecheck.validate_claim first',
|
|
334
|
+
docsUrl: 'https://vibecheck.dev/docs/truth-firewall',
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
export default {
|
|
341
|
+
ErrorCode,
|
|
342
|
+
VibecheckError,
|
|
343
|
+
Errors,
|
|
344
|
+
createErrorEnvelope,
|
|
345
|
+
createSuccessEnvelope,
|
|
346
|
+
};
|