@vibecheckai/cli 3.1.6 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +27 -32
  2. package/bin/registry.js +208 -343
  3. package/bin/runners/context/generators/mcp.js +18 -0
  4. package/bin/runners/context/index.js +72 -4
  5. package/bin/runners/context/proof-context.js +293 -1
  6. package/bin/runners/context/security-scanner.js +311 -73
  7. package/bin/runners/lib/analyzers.js +607 -20
  8. package/bin/runners/lib/detectors-v2.js +172 -15
  9. package/bin/runners/lib/entitlements-v2.js +48 -1
  10. package/bin/runners/lib/evidence-pack.js +678 -0
  11. package/bin/runners/lib/html-proof-report.js +913 -0
  12. package/bin/runners/lib/missions/plan.js +231 -41
  13. package/bin/runners/lib/missions/templates.js +125 -0
  14. package/bin/runners/lib/scan-output.js +492 -253
  15. package/bin/runners/lib/ship-output.js +901 -641
  16. package/bin/runners/runCheckpoint.js +44 -3
  17. package/bin/runners/runContext.d.ts +4 -0
  18. package/bin/runners/runContext.js +2 -3
  19. package/bin/runners/runDoctor.js +11 -4
  20. package/bin/runners/runFix.js +51 -341
  21. package/bin/runners/runInit.js +37 -20
  22. package/bin/runners/runPolish.d.ts +4 -0
  23. package/bin/runners/runPolish.js +608 -29
  24. package/bin/runners/runProve.js +210 -25
  25. package/bin/runners/runReality.js +861 -107
  26. package/bin/runners/runScan.js +238 -4
  27. package/bin/runners/runShip.js +19 -3
  28. package/bin/runners/runWatch.js +25 -5
  29. package/bin/vibecheck.js +35 -47
  30. package/mcp-server/consolidated-tools.js +408 -42
  31. package/mcp-server/index.js +152 -15
  32. package/mcp-server/package.json +1 -1
  33. package/mcp-server/proof-tools.js +571 -0
  34. package/mcp-server/tier-auth.js +22 -19
  35. package/mcp-server/tools-v3.js +744 -0
  36. package/mcp-server/truth-firewall-tools.js +190 -4
  37. package/package.json +3 -1
  38. package/bin/runners/runBadge.js +0 -916
  39. package/bin/runners/runContracts.js +0 -105
  40. package/bin/runners/runCtx.js +0 -680
  41. package/bin/runners/runCtxDiff.js +0 -301
  42. package/bin/runners/runCtxGuard.js +0 -176
  43. package/bin/runners/runCtxSync.js +0 -116
  44. package/bin/runners/runExport.js +0 -93
  45. package/bin/runners/runGraph.js +0 -454
  46. package/bin/runners/runInstall.js +0 -273
  47. package/bin/runners/runLabs.js +0 -341
  48. package/bin/runners/runLaunch.js +0 -181
  49. package/bin/runners/runPR.js +0 -255
  50. package/bin/runners/runPermissions.js +0 -310
  51. package/bin/runners/runPreflight.js +0 -580
  52. package/bin/runners/runReplay.js +0 -499
  53. package/bin/runners/runSecurity.js +0 -92
  54. package/bin/runners/runShare.js +0 -212
  55. package/bin/runners/runStatus.js +0 -102
  56. package/bin/runners/runVerify.js +0 -272
@@ -398,7 +398,7 @@ export async function handleTruthFirewallTool(toolName, args, projectPath = proc
398
398
  return await addAssumption(projectPath, args);
399
399
 
400
400
  case "vibecheck.validate_plan":
401
- return await validatePlanTool(projectPath, args);
401
+ return await getPlanValidationResult(projectPath, args);
402
402
 
403
403
  case "vibecheck.check_drift":
404
404
  return await checkDriftTool(projectPath, args);
@@ -421,8 +421,147 @@ const state = {
421
421
  assumptions: [],
422
422
  verifiedClaims: new Map(),
423
423
  maxAssumptions: 2,
424
+ lastValidationByProject: new Map(),
424
425
  };
425
426
 
427
+ const MAX_EVIDENCE_SNIPPET = 200;
428
+
429
+ /**
430
+ * Policy configuration - aligned with proof-context.js TRUTH_CONTRACT
431
+ */
432
+ const POLICY_CONFIG = {
433
+ strict: {
434
+ minConfidence: 0.8,
435
+ allowUnknown: false,
436
+ requireValidation: true,
437
+ blockOnDrift: true,
438
+ validationTTL: 5 * 60 * 1000, // 5 minutes
439
+ },
440
+ balanced: {
441
+ minConfidence: 0.6,
442
+ allowUnknown: false,
443
+ requireValidation: true,
444
+ blockOnDrift: false,
445
+ validationTTL: 10 * 60 * 1000, // 10 minutes
446
+ },
447
+ permissive: {
448
+ minConfidence: 0.4,
449
+ allowUnknown: true,
450
+ requireValidation: false,
451
+ blockOnDrift: false,
452
+ validationTTL: 30 * 60 * 1000, // 30 minutes
453
+ },
454
+ };
455
+
456
+ /**
457
+ * Get policy configuration
458
+ */
459
+ export function getPolicyConfig(policy = 'strict') {
460
+ return POLICY_CONFIG[policy] || POLICY_CONFIG.strict;
461
+ }
462
+
463
+ function confidenceToScore(confidence) {
464
+ if (typeof confidence === "number") return confidence;
465
+ switch (confidence) {
466
+ case "high":
467
+ return 0.9;
468
+ case "medium":
469
+ return 0.7;
470
+ case "low":
471
+ return 0.5;
472
+ default:
473
+ return 0.6;
474
+ }
475
+ }
476
+
477
+ async function readSnippet(projectPath, file, line) {
478
+ if (!file) return "";
479
+ try {
480
+ const content = await fs.readFile(path.join(projectPath, file), "utf8");
481
+ const lines = content.split("\n");
482
+ const idx = Math.max(0, Math.min(lines.length - 1, line - 1));
483
+ return (lines[idx] || "").slice(0, MAX_EVIDENCE_SNIPPET);
484
+ } catch {
485
+ return "";
486
+ }
487
+ }
488
+
489
+ async function normalizeEvidence(projectPath, evidence, fallback, confidence) {
490
+ const raw = Array.isArray(evidence) ? evidence : evidence ? [evidence] : [];
491
+ const normalized = [];
492
+
493
+ for (const item of raw) {
494
+ const file = item?.file || fallback?.file || "";
495
+ const line = Number(item?.line || item?.lines || fallback?.line || 1);
496
+ const snippet =
497
+ item?.snippet ||
498
+ item?.evidence ||
499
+ (await readSnippet(projectPath, file, line));
500
+
501
+ normalized.push({
502
+ file,
503
+ line,
504
+ snippet,
505
+ confidence: item?.confidence ?? confidenceToScore(confidence),
506
+ });
507
+ }
508
+
509
+ if (normalized.length === 0 && fallback?.file) {
510
+ normalized.push({
511
+ file: fallback.file,
512
+ line: fallback.line || 1,
513
+ snippet: await readSnippet(projectPath, fallback.file, fallback.line || 1),
514
+ confidence: confidenceToScore(confidence),
515
+ });
516
+ }
517
+
518
+ return normalized;
519
+ }
520
+
521
+ /**
522
+ * Check if there's a recent claim validation for the project.
523
+ * The TTL depends on the policy mode.
524
+ */
525
+ export function hasRecentClaimValidation(projectPath, policy = 'strict') {
526
+ const last = state.lastValidationByProject.get(projectPath);
527
+ if (typeof last !== "number") return false;
528
+
529
+ const config = getPolicyConfig(policy);
530
+ const maxAgeMs = config.validationTTL;
531
+ return Date.now() - last <= maxAgeMs;
532
+ }
533
+
534
+ /**
535
+ * Validate a claim result against policy thresholds.
536
+ * Returns an enforcement decision.
537
+ */
538
+ export function enforceClaimResult(result, policy = 'strict') {
539
+ const config = getPolicyConfig(policy);
540
+ const confidence = confidenceToScore(result.confidence || result.result === 'true' ? 0.9 : 0.3);
541
+
542
+ // Unknown results
543
+ if (result.result === 'unknown') {
544
+ if (!config.allowUnknown) {
545
+ return {
546
+ allowed: false,
547
+ reason: `Unknown claims are not allowed in ${policy} mode`,
548
+ suggestion: 'Use search_evidence to find proof or get_truthpack to refresh context',
549
+ };
550
+ }
551
+ }
552
+
553
+ // Low confidence
554
+ if (confidence < config.minConfidence) {
555
+ return {
556
+ allowed: false,
557
+ reason: `Confidence ${(confidence * 100).toFixed(0)}% below ${policy} threshold ${(config.minConfidence * 100).toFixed(0)}%`,
558
+ suggestion: 'Find additional evidence or use permissive policy',
559
+ };
560
+ }
561
+
562
+ return { allowed: true };
563
+ }
564
+
426
565
  async function getTruthPack(projectPath, args) {
427
566
  const scope = args.scope || 'all';
428
567
  const refresh = args.refresh || false;
@@ -439,6 +578,7 @@ async function getTruthPack(projectPath, args) {
439
578
  commitHash: getCommitHash(projectPath),
440
579
  sections: {},
441
580
  confidence: 0,
581
+ _attribution: CONTEXT_ATTRIBUTION,
442
582
  };
443
583
 
444
584
  if (scope === 'all' || scope === 'routes') {
@@ -510,22 +650,45 @@ async function validateClaim(projectPath, args) {
510
650
  result.nextSteps = [`Verification error: ${error.message}`];
511
651
  }
512
652
 
513
- // If unknown, add helpful next steps
653
+ // ENFORCED: Unknown claims must return explicit "unknown" error
654
+ // that blocks dependent actions in strict/balanced modes
514
655
  if (result.result === 'unknown') {
515
656
  result.nextSteps.push(
516
657
  'call vibecheck.search_evidence to find related code',
517
658
  'call vibecheck.get_truthpack to get full context',
518
659
  );
519
660
  result.warning = '⚠️ UNKNOWN claims BLOCK dependent actions. Verify before proceeding.';
661
+ result.enforcement = {
662
+ allowed: false,
663
+ reason: 'Claim result is unknown - cannot proceed without evidence',
664
+ blockedActions: ['fix', 'autopilot_apply', 'propose_patch'],
665
+ };
666
+ } else if (result.result === 'true') {
667
+ result.enforcement = {
668
+ allowed: true,
669
+ confidence: confidenceToScore(result.confidence),
670
+ };
671
+ } else {
672
+ // result is 'false'
673
+ result.enforcement = {
674
+ allowed: false,
675
+ reason: 'Claim is disproven - do not proceed with dependent actions',
676
+ };
520
677
  }
521
678
 
522
679
  // Cache result
523
- state.verifiedClaims.set(claimId, { result, timestamp: Date.now() });
680
+ state.verifiedClaims.set(claimId, { result, timestamp: Date.now(), projectPath });
681
+ state.lastValidationByProject.set(projectPath, Date.now());
524
682
 
525
683
  return {
526
684
  claimId,
527
685
  ...result,
686
+ evidence: await normalizeEvidence(projectPath, result.evidence, {
687
+ file: subject?.path || subject?.name,
688
+ line: 1,
689
+ }, result.confidence),
528
690
  timestamp: new Date().toISOString(),
691
+ _attribution: CONTEXT_ATTRIBUTION,
529
692
  };
530
693
  }
531
694
 
@@ -565,6 +728,7 @@ async function compileContext(projectPath, args) {
565
728
  invariants,
566
729
  tokenCount,
567
730
  warnings: generateContextWarnings(domains, policy, relevantRoutes.length),
731
+ _attribution: CONTEXT_ATTRIBUTION,
568
732
  };
569
733
  }
570
734
 
@@ -589,6 +753,7 @@ async function searchEvidence(projectPath, args) {
589
753
  line: i + 1,
590
754
  snippet: snippet.slice(0, 300),
591
755
  hash: crypto.createHash('sha256').update(lines[i]).digest('hex').slice(0, 16),
756
+ confidence: 0.6,
592
757
  });
593
758
 
594
759
  if (results.length >= limit) break;
@@ -604,6 +769,7 @@ async function searchEvidence(projectPath, args) {
604
769
  query,
605
770
  count: results.length,
606
771
  results,
772
+ _attribution: CONTEXT_ATTRIBUTION,
607
773
  };
608
774
  }
609
775
 
@@ -780,7 +946,7 @@ async function addAssumption(projectPath, args) {
780
946
  // PLAN VALIDATION & DRIFT DETECTION (Spec 10.3)
781
947
  // =============================================================================
782
948
 
783
- async function validatePlanTool(projectPath, args) {
949
+ async function getPlanValidationResult(projectPath, args) {
784
950
  const { plan, strict = false } = args;
785
951
 
786
952
  // Load contracts
@@ -1224,6 +1390,11 @@ export function getProjectFingerprint(projectPath) {
1224
1390
  };
1225
1391
  }
1226
1392
 
1393
+ /**
1394
+ * Context attribution message shown when AI uses vibecheck data
1395
+ */
1396
+ const CONTEXT_ATTRIBUTION = "🧠 Context enhanced by vibecheck";
1397
+
1227
1398
  /**
1228
1399
  * Wrap MCP response with standard metadata including fingerprint (Spec 10.2)
1229
1400
  */
@@ -1233,9 +1404,17 @@ export function wrapMcpResponse(data, projectPath) {
1233
1404
  version: '2.0.0',
1234
1405
  projectFingerprint: getProjectFingerprint(projectPath),
1235
1406
  data,
1407
+ _attribution: CONTEXT_ATTRIBUTION,
1236
1408
  };
1237
1409
  }
1238
1410
 
1411
+ /**
1412
+ * Get the context attribution message
1413
+ */
1414
+ export function getContextAttribution() {
1415
+ return CONTEXT_ATTRIBUTION;
1416
+ }
1417
+
1239
1418
  async function extractRoutes(projectPath) {
1240
1419
  const routes = [];
1241
1420
  const files = await findSourceFiles(projectPath);
@@ -1497,4 +1676,11 @@ async function findSourceFiles(projectPath) {
1497
1676
  export default {
1498
1677
  TRUTH_FIREWALL_TOOLS,
1499
1678
  handleTruthFirewallTool,
1679
+ hasRecentClaimValidation,
1680
+ enforceClaimResult,
1681
+ getPolicyConfig,
1682
+ getProjectFingerprint,
1683
+ wrapMcpResponse,
1684
+ getContextAttribution,
1685
+ CONTEXT_ATTRIBUTION,
1500
1686
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecheckai/cli",
3
- "version": "3.1.6",
3
+ "version": "3.2.0",
4
4
  "description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
5
5
  "main": "bin/vibecheck.js",
6
6
  "bin": {
@@ -28,6 +28,8 @@
28
28
  "@babel/parser": "^7.23.0",
29
29
  "@babel/traverse": "^7.23.0",
30
30
  "@babel/types": "^7.23.0",
31
+ "@vibecheck/core": "workspace:*",
32
+ "@vibecheck/security": "workspace:*",
31
33
  "chalk": "^5.3.0",
32
34
  "commander": "^12.0.0",
33
35
  "debug": "^4.3.4",