@vibecheckai/cli 3.7.0 → 3.9.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 (118) hide show
  1. package/README.md +135 -63
  2. package/bin/_deprecations.js +447 -19
  3. package/bin/_router.js +1 -1
  4. package/bin/registry.js +347 -280
  5. package/bin/runners/context/generators/cursor-enhanced.js +2439 -0
  6. package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
  7. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
  8. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
  9. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
  10. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
  11. package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
  12. package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
  13. package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
  14. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
  15. package/bin/runners/lib/agent-firewall/index.js +200 -0
  16. package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
  17. package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
  18. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
  19. package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
  20. package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
  21. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
  22. package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
  23. package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
  24. package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
  25. package/bin/runners/lib/agent-firewall/interceptor/base.js +7 -3
  26. package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
  27. package/bin/runners/lib/agent-firewall/session/index.js +26 -0
  28. package/bin/runners/lib/artifact-envelope.js +540 -0
  29. package/bin/runners/lib/auth-shared.js +977 -0
  30. package/bin/runners/lib/checkpoint.js +941 -0
  31. package/bin/runners/lib/cleanup/engine.js +571 -0
  32. package/bin/runners/lib/cleanup/index.js +53 -0
  33. package/bin/runners/lib/cleanup/output.js +375 -0
  34. package/bin/runners/lib/cleanup/rules.js +1060 -0
  35. package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
  36. package/bin/runners/lib/doctor/failure-signatures.js +526 -0
  37. package/bin/runners/lib/doctor/fix-script.js +336 -0
  38. package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
  39. package/bin/runners/lib/doctor/modules/index.js +62 -3
  40. package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
  41. package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
  42. package/bin/runners/lib/doctor/safe-repair.js +384 -0
  43. package/bin/runners/lib/engine/ast-cache.js +210 -210
  44. package/bin/runners/lib/engine/auth-extractor.js +211 -211
  45. package/bin/runners/lib/engine/billing-extractor.js +112 -112
  46. package/bin/runners/lib/engine/enforcement-extractor.js +100 -100
  47. package/bin/runners/lib/engine/env-extractor.js +207 -207
  48. package/bin/runners/lib/engine/express-extractor.js +208 -208
  49. package/bin/runners/lib/engine/extractors.js +849 -849
  50. package/bin/runners/lib/engine/index.js +207 -207
  51. package/bin/runners/lib/engine/repo-index.js +514 -514
  52. package/bin/runners/lib/engine/types.js +124 -124
  53. package/bin/runners/lib/engines/attack-detector.js +1192 -0
  54. package/bin/runners/lib/entitlements-v2.js +2 -2
  55. package/bin/runners/lib/missions/briefing.js +427 -0
  56. package/bin/runners/lib/missions/checkpoint.js +753 -0
  57. package/bin/runners/lib/missions/hardening.js +851 -0
  58. package/bin/runners/lib/missions/plan.js +421 -32
  59. package/bin/runners/lib/missions/safety-gates.js +645 -0
  60. package/bin/runners/lib/missions/schema.js +478 -0
  61. package/bin/runners/lib/packs/bundle.js +675 -0
  62. package/bin/runners/lib/packs/evidence-pack.js +671 -0
  63. package/bin/runners/lib/packs/pack-factory.js +837 -0
  64. package/bin/runners/lib/packs/permissions-pack.js +686 -0
  65. package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
  66. package/bin/runners/lib/safelist/index.js +96 -0
  67. package/bin/runners/lib/safelist/integration.js +334 -0
  68. package/bin/runners/lib/safelist/matcher.js +696 -0
  69. package/bin/runners/lib/safelist/schema.js +948 -0
  70. package/bin/runners/lib/safelist/store.js +438 -0
  71. package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
  72. package/bin/runners/lib/ship-gate.js +832 -0
  73. package/bin/runners/lib/ship-manifest.js +1153 -0
  74. package/bin/runners/lib/ship-output.js +1 -1
  75. package/bin/runners/lib/unified-cli-output.js +710 -383
  76. package/bin/runners/lib/upsell.js +3 -3
  77. package/bin/runners/lib/why-tree.js +650 -0
  78. package/bin/runners/runAllowlist.js +33 -4
  79. package/bin/runners/runApprove.js +240 -1122
  80. package/bin/runners/runAudit.js +692 -0
  81. package/bin/runners/runAuth.js +325 -29
  82. package/bin/runners/runCheckpoint.js +442 -494
  83. package/bin/runners/runCleanup.js +343 -0
  84. package/bin/runners/runDoctor.js +269 -19
  85. package/bin/runners/runFix.js +411 -32
  86. package/bin/runners/runForge.js +411 -0
  87. package/bin/runners/runIntent.js +906 -0
  88. package/bin/runners/runKickoff.js +878 -0
  89. package/bin/runners/runLaunch.js +2000 -0
  90. package/bin/runners/runLink.js +785 -0
  91. package/bin/runners/runMcp.js +1741 -837
  92. package/bin/runners/runPacks.js +2089 -0
  93. package/bin/runners/runPolish.js +41 -0
  94. package/bin/runners/runReality.js +178 -1
  95. package/bin/runners/runSafelist.js +1190 -0
  96. package/bin/runners/runScan.js +21 -9
  97. package/bin/runners/runShield.js +1282 -0
  98. package/bin/runners/runShip.js +395 -16
  99. package/bin/vibecheck.js +34 -6
  100. package/mcp-server/README.md +117 -158
  101. package/mcp-server/handlers/index.ts +2 -2
  102. package/mcp-server/handlers/tool-handler.ts +50 -11
  103. package/mcp-server/index.js +16 -0
  104. package/mcp-server/intent-firewall-interceptor.js +529 -0
  105. package/mcp-server/lib/executor.ts +5 -5
  106. package/mcp-server/lib/index.ts +14 -4
  107. package/mcp-server/lib/sandbox.test.ts +4 -4
  108. package/mcp-server/lib/sandbox.ts +2 -2
  109. package/mcp-server/manifest.json +473 -0
  110. package/mcp-server/package.json +1 -1
  111. package/mcp-server/registry/tool-registry.js +315 -523
  112. package/mcp-server/registry/tools.json +442 -428
  113. package/mcp-server/registry.test.ts +18 -12
  114. package/mcp-server/tier-auth.js +68 -11
  115. package/mcp-server/tools-v3.js +70 -16
  116. package/mcp-server/tsconfig.json +1 -0
  117. package/package.json +2 -1
  118. package/bin/runners/runProof.zip +0 -0
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 🔥 FORGE - AI Brain Generator Runner
4
+ *
5
+ * Generates the smallest set of rules that produce the biggest accuracy lift.
6
+ * "Minimal but lethal" - 5-10 rules max by default, expandable tiers.
7
+ */
8
+
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ const crypto = require("crypto");
12
+
13
+ // Import CLI utilities for professional styling
14
+ const {
15
+ colors: c,
16
+ printBanner,
17
+ printCommandHeader,
18
+ printSectionHeader,
19
+ printTable,
20
+ highlight,
21
+ highlightPath,
22
+ highlightCode,
23
+ printSuccess,
24
+ printError,
25
+ printWarning,
26
+ formatNumber,
27
+ gradientText,
28
+ } = require("./cli-utils");
29
+
30
+ // Default configuration
31
+ const DEFAULT_CONFIG = {
32
+ maxRules: 10,
33
+ tier: "standard",
34
+ platforms: ["cursor", "windsurf"],
35
+ incremental: true,
36
+ generateContract: true,
37
+ generateTruthpack: true,
38
+ verbose: false,
39
+ };
40
+
41
+ // Rule tier configurations
42
+ const TIER_CONFIGS = {
43
+ minimal: {
44
+ maxRules: 5,
45
+ features: ["architecture", "avoid", "types", "components", "testing"],
46
+ },
47
+ standard: {
48
+ maxRules: 10,
49
+ features: ["architecture", "avoid", "types", "components", "testing", "state", "data-flow", "environment", "hooks", "api-patterns"],
50
+ },
51
+ extended: {
52
+ maxRules: 20,
53
+ features: ["architecture", "avoid", "types", "components", "testing", "state", "data-flow", "environment", "hooks", "api-patterns", "security", "performance", "accessibility", "i18n", "error-handling", "logging", "caching", "database", "authentication", "authorization"],
54
+ },
55
+ comprehensive: {
56
+ maxRules: 50,
57
+ features: ["*"],
58
+ },
59
+ };
60
+
61
+ /**
62
+ * Parse command line arguments
63
+ */
64
+ function parseArgs(args) {
65
+ const opts = {
66
+ ...DEFAULT_CONFIG,
67
+ help: false,
68
+ path: ".",
69
+ };
70
+
71
+ for (let i = 0; i < args.length; i++) {
72
+ const arg = args[i];
73
+ if (arg === "--help" || arg === "-h") opts.help = true;
74
+ if (arg === "--path" || arg === "-p") opts.path = args[++i];
75
+ if (arg.startsWith("--path=")) opts.path = arg.split("=")[1];
76
+ if (arg === "--tier" || arg === "-t") opts.tier = args[++i];
77
+ if (arg.startsWith("--tier=")) opts.tier = arg.split("=")[1];
78
+ if (arg === "--max-rules") opts.maxRules = parseInt(args[++i]);
79
+ if (arg.startsWith("--max-rules=")) opts.maxRules = parseInt(arg.split("=")[1]);
80
+ if (arg === "--no-incremental") opts.incremental = false;
81
+ if (arg === "--no-contract") opts.generateContract = false;
82
+ if (arg === "--no-truthpack") opts.generateTruthpack = false;
83
+ if (arg === "--verbose" || arg === "-v") opts.verbose = true;
84
+ if (arg === "--cursor-only") opts.platforms = ["cursor"];
85
+ if (arg === "--windsurf-only") opts.platforms = ["windsurf"];
86
+ if (arg === "minimal") opts.tier = "minimal";
87
+ if (arg === "standard") opts.tier = "standard";
88
+ if (arg === "extended") opts.tier = "extended";
89
+ if (arg === "comprehensive") opts.tier = "comprehensive";
90
+ }
91
+
92
+ return opts;
93
+ }
94
+
95
+ /**
96
+ * Print help message
97
+ */
98
+ function printHelp() {
99
+ console.log();
100
+ printBanner();
101
+ printCommandHeader("FORGE", "AI Brain Generator v1.0");
102
+
103
+ console.log(`${gradientText("Minimal but lethal", [c.red, c.yellow, c.green])} - Generate the smallest set of rules that produce the biggest accuracy lift.\n`);
104
+
105
+ console.log(`${c.yellow}USAGE${c.reset}`);
106
+ console.log(` ${c.cyan}vibecheck forge${c.reset} ${c.dim}[options] [tier]${c.reset}`);
107
+ console.log();
108
+
109
+ console.log(`${c.yellow}TIERS${c.reset}`);
110
+ const tiers = [
111
+ ["minimal", "5 rules max", "Core essentials only"],
112
+ ["standard", "10 rules max", "Balanced coverage (default)"],
113
+ ["extended", "20 rules max", "Comprehensive coverage"],
114
+ ["comprehensive", "50 rules max", "Everything included"],
115
+ ];
116
+ printTable(["Tier", "Rules", "Description"], tiers);
117
+ console.log();
118
+
119
+ console.log(`${c.yellow}OPTIONS${c.reset}`);
120
+ const options = [
121
+ ["--path, -p <dir>", "Project directory (default: current)"],
122
+ ["--tier, -t <tier>", "Rule tier (minimal|standard|extended|comprehensive)"],
123
+ ["--max-rules <n>", "Override max rules for tier"],
124
+ ["--no-incremental", "Regenerate all rules (don't diff)"],
125
+ ["--no-contract", "Skip AI contract generation"],
126
+ ["--no-truthpack", "Skip truthpack generation"],
127
+ ["--cursor-only", "Generate only Cursor rules"],
128
+ ["--windsurf-only", "Generate only Windsurf rules"],
129
+ ["--verbose, -v", "Show detailed output"],
130
+ ["--help, -h", "Show this help"],
131
+ ];
132
+ printTable(["Option", "Description"], options);
133
+ console.log();
134
+
135
+ console.log(`${c.yellow}OUTPUTS${c.reset}`);
136
+ const outputs = [
137
+ [".cursorrules", "Main Cursor rules file"],
138
+ [".cursor/rules/*.mdc", "MDC specification files"],
139
+ [".cursor/skills/", "Auto-generated skills"],
140
+ [".cursor/agents/", "Subagent definitions"],
141
+ [".cursor/hooks/", "Automation hooks"],
142
+ [".windsurf/rules/", "Windsurf rules"],
143
+ [".vibecheck/ai-contract.json", "AI Contract (JSON)"],
144
+ [".vibecheck/AI_CONTRACT.md", "Human-readable contract"],
145
+ [".vibecheck/truth/truthpack.json", "Truthpack"],
146
+ [".vibecheck/forge-manifest.json", "Manifest for incremental"],
147
+ ];
148
+ printTable(["File", "Description"], outputs);
149
+ console.log();
150
+
151
+ console.log(`${c.yellow}EXAMPLES${c.reset}`);
152
+ console.log(` ${c.cyan}vibecheck forge${c.reset} ${c.dim}# Standard tier, incremental${c.reset}`);
153
+ console.log(` ${c.cyan}vibecheck forge minimal${c.reset} ${c.dim}# Minimal tier (5 rules)${c.reset}`);
154
+ console.log(` ${c.cyan}vibecheck forge --max-rules=7${c.reset} ${c.dim}# Custom rule count${c.reset}`);
155
+ console.log(` ${c.cyan}vibecheck forge --no-incremental${c.reset} ${c.dim}# Force full regeneration${c.reset}`);
156
+ console.log();
157
+ }
158
+
159
+ /**
160
+ * Main forge runner
161
+ */
162
+ async function runForge(args) {
163
+ const opts = parseArgs(args);
164
+
165
+ if (opts.help) {
166
+ printHelp();
167
+ return 0;
168
+ }
169
+
170
+ const startTime = Date.now();
171
+ const projectPath = path.resolve(opts.path);
172
+
173
+ // Display header
174
+ console.log();
175
+ printBanner();
176
+ printCommandHeader("FORGE", "AI Brain Generator v1.0");
177
+
178
+ console.log(`${c.dim}Project:${c.reset} ${highlightPath(projectPath)}`);
179
+ console.log(`${c.dim}Tier:${c.reset} ${highlight(opts.tier)} (max ${opts.maxRules} rules)`);
180
+ console.log(`${c.dim}Mode:${c.reset} ${opts.incremental ? "Incremental" : "Full regeneration"}`);
181
+ console.log();
182
+
183
+ try {
184
+ // Try to import TypeScript forge module
185
+ let forgeModule;
186
+ try {
187
+ forgeModule = require("../../packages/cli/src/forge");
188
+ } catch {
189
+ // Fall back to JavaScript implementation
190
+ forgeModule = null;
191
+ }
192
+
193
+ if (forgeModule) {
194
+ // Use TypeScript implementation
195
+ const result = await forgeModule.forge(projectPath, opts);
196
+
197
+ printForgeResults(result, opts, startTime);
198
+ return 0;
199
+ }
200
+
201
+ // Fallback: use existing context generator with forge wrapper
202
+ console.log(`${c.yellow}⚡ Using context generator with Forge enhancements...${c.reset}\n`);
203
+
204
+ const { runContext } = require("../../packages/cli/src/context");
205
+ const contextArgs = ["--path", projectPath, "--enhanced"];
206
+
207
+ if (opts.verbose) contextArgs.push("--verbose");
208
+
209
+ const result = await runContext(contextArgs);
210
+
211
+ // Generate additional forge-specific outputs
212
+ if (opts.generateContract) {
213
+ generateSimpleContract(projectPath);
214
+ }
215
+
216
+ if (opts.generateTruthpack) {
217
+ generateSimpleTruthpack(projectPath);
218
+ }
219
+
220
+ const timeMs = Date.now() - startTime;
221
+ console.log(`\n${c.green}✓ Forge complete in ${timeMs}ms${c.reset}`);
222
+
223
+ return result;
224
+ } catch (error) {
225
+ printError(`Forge failed: ${error.message}`);
226
+ if (opts.verbose) {
227
+ console.error(error.stack);
228
+ }
229
+ return 1;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Print forge results
235
+ */
236
+ function printForgeResults(result, opts, startTime) {
237
+ const timeMs = Date.now() - startTime;
238
+
239
+ printSectionHeader("FORGE COMPLETE");
240
+
241
+ console.log(`${c.green}🔥 Generated ${result.stats.rulesGenerated} rules in ${timeMs}ms${c.reset}\n`);
242
+
243
+ // Stats
244
+ const statsTable = [
245
+ ["Rules Generated", formatNumber(result.stats.rulesGenerated)],
246
+ ["Files Written", formatNumber(result.stats.filesWritten)],
247
+ ["Rules Skipped", formatNumber(result.stats.rulesSkipped)],
248
+ ["Rules Pruned", formatNumber(result.stats.rulesPruned)],
249
+ ["Incremental", result.stats.incremental ? "Yes" : "No"],
250
+ ["Time", `${timeMs}ms`],
251
+ ];
252
+ printTable(["Metric", "Value"], statsTable);
253
+ console.log();
254
+
255
+ // Contract summary
256
+ if (result.contract) {
257
+ console.log(`${c.cyan}📜 AI Contract${c.reset}`);
258
+ console.log(` ${c.dim}Allowed actions:${c.reset} ${result.contract.allowed.length}`);
259
+ console.log(` ${c.dim}Forbidden actions:${c.reset} ${result.contract.forbidden.length}`);
260
+ console.log(` ${c.dim}Critical safety rules:${c.reset} ${result.contract.safetyRules.critical.length}`);
261
+ console.log();
262
+ }
263
+
264
+ // Truthpack summary
265
+ if (result.truthpack) {
266
+ console.log(`${c.cyan}📦 Truthpack${c.reset}`);
267
+ console.log(` ${c.dim}Sections:${c.reset} ${Object.keys(result.truthpack.sections).length}`);
268
+ console.log(` ${c.dim}Confidence:${c.reset} ${(result.truthpack.confidence * 100).toFixed(1)}%`);
269
+ console.log(` ${c.dim}Issues:${c.reset} ${result.truthpack.validationIssues.length}`);
270
+ console.log();
271
+ }
272
+
273
+ // Files list
274
+ console.log(`${c.cyan}Generated Files:${c.reset}`);
275
+ result.files.slice(0, 15).forEach((file, idx) => {
276
+ console.log(` ${c.dim}${idx + 1}.${c.reset} ${highlightPath(file)}`);
277
+ });
278
+ if (result.files.length > 15) {
279
+ console.log(` ${c.dim}... and ${result.files.length - 15} more${c.reset}`);
280
+ }
281
+ console.log();
282
+
283
+ // Summary banner
284
+ console.log(`${c.bgGreen}${c.black} 🔥 FORGE v1.0 - Minimal but lethal ${c.reset}\n`);
285
+ }
286
+
287
+ /**
288
+ * Generate a simple AI contract
289
+ */
290
+ function generateSimpleContract(projectPath) {
291
+ const contract = {
292
+ version: "1.0.0",
293
+ generatedAt: new Date().toISOString(),
294
+ projectId: path.basename(projectPath),
295
+ allowed: [
296
+ "Create new files in appropriate directories",
297
+ "Modify existing source code files",
298
+ "Add or update dependencies",
299
+ "Create and run tests",
300
+ ],
301
+ forbidden: [
302
+ "Commit secrets or credentials to code",
303
+ "Disable security checks",
304
+ "Use `any` type in TypeScript",
305
+ "Skip error handling",
306
+ ],
307
+ requiresConfirmation: [
308
+ "Delete any file",
309
+ "Modify database schema",
310
+ "Change authentication logic",
311
+ ],
312
+ fileBoundaries: {
313
+ mayCreate: ["src/**/*", "tests/**/*"],
314
+ mayNotModify: [".env", "*.lock", "node_modules/**"],
315
+ restrictedPatterns: ["**/auth/**", "**/config/**"],
316
+ },
317
+ codeStandards: {
318
+ mustFollow: ["Use TypeScript", "Follow existing patterns"],
319
+ mustAvoid: ["any type", "console.log in production"],
320
+ preferredPatterns: ["Functional components", "Custom hooks"],
321
+ },
322
+ safetyRules: {
323
+ critical: ["Never commit secrets", "Always validate input"],
324
+ high: ["Handle errors explicitly", "Use HTTPS"],
325
+ standard: ["Keep dependencies updated", "Write tests"],
326
+ },
327
+ };
328
+
329
+ const vibecheckDir = path.join(projectPath, ".vibecheck");
330
+ if (!fs.existsSync(vibecheckDir)) {
331
+ fs.mkdirSync(vibecheckDir, { recursive: true });
332
+ }
333
+
334
+ fs.writeFileSync(
335
+ path.join(vibecheckDir, "ai-contract.json"),
336
+ JSON.stringify(contract, null, 2)
337
+ );
338
+
339
+ // Write human-readable version
340
+ const contractMd = `# AI Contract
341
+
342
+ > This document defines what AI agents may and may not do in this repository.
343
+ > Generated by Forge v1.0
344
+
345
+ ## Permissions
346
+
347
+ ### Allowed Actions
348
+ ${contract.allowed.map(a => `- ✅ ${a}`).join("\n")}
349
+
350
+ ### Forbidden Actions
351
+ ${contract.forbidden.map(f => `- ❌ ${f}`).join("\n")}
352
+
353
+ ### Requires Confirmation
354
+ ${contract.requiresConfirmation.map(r => `- ⚠️ ${r}`).join("\n")}
355
+
356
+ ## Safety Rules
357
+
358
+ ### Critical (Never Violate)
359
+ ${contract.safetyRules.critical.map(r => `- 🔴 ${r}`).join("\n")}
360
+
361
+ ### High Priority
362
+ ${contract.safetyRules.high.map(r => `- 🟠 ${r}`).join("\n")}
363
+
364
+ ---
365
+ *Generated at: ${contract.generatedAt}*
366
+ `;
367
+
368
+ fs.writeFileSync(path.join(vibecheckDir, "AI_CONTRACT.md"), contractMd);
369
+ }
370
+
371
+ /**
372
+ * Generate a simple truthpack
373
+ */
374
+ function generateSimpleTruthpack(projectPath) {
375
+ const truthpack = {
376
+ version: "2.0.0",
377
+ generatedAt: new Date().toISOString(),
378
+ projectPath: projectPath,
379
+ contentHash: crypto.createHash("sha256").update(projectPath).digest("hex").slice(0, 16),
380
+ sections: {
381
+ routes: { server: [], clientRefs: [], serverOnly: [], clientOnly: [], methodMismatches: [] },
382
+ env: { declared: [], used: [], unused: [], missing: [], sensitive: [] },
383
+ components: { components: [], maxDepth: 0, orphans: [] },
384
+ graph: { modules: {}, cycles: [], entryPoints: [], shared: [] },
385
+ },
386
+ confidence: 0.75,
387
+ validationIssues: [],
388
+ };
389
+
390
+ const truthDir = path.join(projectPath, ".vibecheck", "truth");
391
+ if (!fs.existsSync(truthDir)) {
392
+ fs.mkdirSync(truthDir, { recursive: true });
393
+ }
394
+
395
+ fs.writeFileSync(
396
+ path.join(truthDir, "truthpack.json"),
397
+ JSON.stringify(truthpack, null, 2)
398
+ );
399
+ }
400
+
401
+ module.exports = { runForge };
402
+
403
+ // Run if called directly
404
+ if (require.main === module) {
405
+ runForge(process.argv.slice(2))
406
+ .then(code => process.exit(code))
407
+ .catch(err => {
408
+ console.error(err);
409
+ process.exit(1);
410
+ });
411
+ }