vibecheck-ai 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1689,9 +1689,264 @@ function createDriftEvent(type, severity, file2, operation, description, context
1689
1689
  context
1690
1690
  };
1691
1691
  }
1692
- var FEATURE_KEYS, FEATURE_METADATA, PLAN_DEFINITIONS, TIER_ORDER, UPGRADE_URLS, VERDICT_THRESHOLDS, SEVERITY_PENALTIES, PERMISSIONS;
1692
+ var ENTITLEMENTS, FREE_ENTITLEMENTS, PRO_ENTITLEMENTS, FEATURE_KEYS, FEATURE_METADATA, PLAN_DEFINITIONS, TIER_ORDER, UPGRADE_URLS, VERDICT_THRESHOLDS, SEVERITY_PENALTIES, PERMISSIONS;
1693
1693
  var init_dist = __esm({
1694
1694
  "../../packages/shared-types/dist/index.js"() {
1695
+ ENTITLEMENTS = {
1696
+ // === FREE Tier Entitlements ===
1697
+ SCAN_UNLIMITED: "scan_unlimited",
1698
+ SHIP_GATE: "ship_gate",
1699
+ DOCTOR: "doctor",
1700
+ REPORTS_HTML: "reports_html",
1701
+ CHECKPOINT: "checkpoint",
1702
+ MISSIONS_VIEW: "missions_view",
1703
+ TEMPLATES_BROWSE: "templates_browse",
1704
+ TEMPLATES_INSTALL: "templates_install",
1705
+ TRUTHPACK_GENERATE: "truthpack_generate",
1706
+ TRUTHPACK_VALIDATE: "truthpack_validate",
1707
+ FORGE_BASIC: "forge_basic",
1708
+ PROMPT_TEMPLATES_BASIC: "prompt_templates_basic",
1709
+ WATCH_MODE: "watch_mode",
1710
+ TRACE_ANALYSIS: "trace_analysis",
1711
+ GITHUB_ACTION_WARN: "github_action_warn",
1712
+ FIREWALL_OBSERVE: "firewall_observe",
1713
+ FILE_LOCKING: "file_locking",
1714
+ // === PRO Tier Entitlements ===
1715
+ REALITY_MODE: "reality_mode",
1716
+ CONTEXT_ENGINE: "context_engine",
1717
+ ISL_STUDIO: "isl_studio",
1718
+ FIREWALL_AGENT: "firewall_agent",
1719
+ FIREWALL_ENFORCE: "firewall_enforce",
1720
+ FIREWALL_LOCKDOWN: "firewall_lockdown",
1721
+ AUTOFIX: "autofix",
1722
+ AUTOFIX_APPLY: "autofix_apply",
1723
+ CERTIFY: "certify",
1724
+ BADGE_VERIFIED: "badge_verified",
1725
+ CHAOS_AGENT: "chaos_agent",
1726
+ REPORTS_PDF: "reports_pdf",
1727
+ REPORTS_EXECUTIVE: "reports_executive",
1728
+ FORGE_EXTENDED: "forge_extended",
1729
+ REPLAY_VIEWER_FULL: "replay_viewer_full",
1730
+ PROOF_HISTORY: "proof_history",
1731
+ CLOUD_SYNC: "cloud_sync",
1732
+ TEAM_COLLABORATION: "team_collaboration",
1733
+ API_ACCESS: "api_access",
1734
+ WEBHOOKS: "webhooks",
1735
+ CI_GATE_BLOCK: "ci_gate_block",
1736
+ AI_GENERATION: "ai_generation",
1737
+ POLICIES: "policies",
1738
+ WORKFLOWS: "workflows",
1739
+ PRIORITY_SUPPORT: "priority_support",
1740
+ PROMPT_TEMPLATES_PRO: "prompt_templates_pro",
1741
+ // === Enterprise Tier Entitlements ===
1742
+ SSO: "sso",
1743
+ AUDIT_LOGS: "audit_logs",
1744
+ CUSTOM_POLICIES: "custom_policies",
1745
+ ON_PREM: "on_prem",
1746
+ SLA: "sla",
1747
+ DEDICATED_SUPPORT: "dedicated_support",
1748
+ FORGE_COMPREHENSIVE: "forge_comprehensive",
1749
+ PROMPT_TEMPLATES_CUSTOM: "prompt_templates_custom",
1750
+ COMPLIANCE_REPORTS: "compliance_reports"
1751
+ };
1752
+ FREE_ENTITLEMENTS = /* @__PURE__ */ new Set([
1753
+ ENTITLEMENTS.SCAN_UNLIMITED,
1754
+ ENTITLEMENTS.SHIP_GATE,
1755
+ ENTITLEMENTS.DOCTOR,
1756
+ ENTITLEMENTS.REPORTS_HTML,
1757
+ ENTITLEMENTS.CHECKPOINT,
1758
+ ENTITLEMENTS.MISSIONS_VIEW,
1759
+ ENTITLEMENTS.TEMPLATES_BROWSE,
1760
+ ENTITLEMENTS.TEMPLATES_INSTALL,
1761
+ ENTITLEMENTS.TRUTHPACK_GENERATE,
1762
+ ENTITLEMENTS.TRUTHPACK_VALIDATE,
1763
+ ENTITLEMENTS.FORGE_BASIC,
1764
+ ENTITLEMENTS.PROMPT_TEMPLATES_BASIC,
1765
+ ENTITLEMENTS.WATCH_MODE,
1766
+ ENTITLEMENTS.TRACE_ANALYSIS,
1767
+ ENTITLEMENTS.GITHUB_ACTION_WARN,
1768
+ ENTITLEMENTS.FIREWALL_OBSERVE,
1769
+ ENTITLEMENTS.FILE_LOCKING
1770
+ ]);
1771
+ PRO_ENTITLEMENTS = /* @__PURE__ */ new Set([
1772
+ // Includes all FREE entitlements
1773
+ ...FREE_ENTITLEMENTS,
1774
+ // Plus PRO-only entitlements
1775
+ ENTITLEMENTS.REALITY_MODE,
1776
+ ENTITLEMENTS.CONTEXT_ENGINE,
1777
+ ENTITLEMENTS.ISL_STUDIO,
1778
+ ENTITLEMENTS.FIREWALL_AGENT,
1779
+ ENTITLEMENTS.FIREWALL_ENFORCE,
1780
+ ENTITLEMENTS.FIREWALL_LOCKDOWN,
1781
+ ENTITLEMENTS.AUTOFIX,
1782
+ ENTITLEMENTS.AUTOFIX_APPLY,
1783
+ ENTITLEMENTS.CERTIFY,
1784
+ ENTITLEMENTS.BADGE_VERIFIED,
1785
+ ENTITLEMENTS.CHAOS_AGENT,
1786
+ ENTITLEMENTS.REPORTS_PDF,
1787
+ ENTITLEMENTS.REPORTS_EXECUTIVE,
1788
+ ENTITLEMENTS.FORGE_EXTENDED,
1789
+ ENTITLEMENTS.REPLAY_VIEWER_FULL,
1790
+ ENTITLEMENTS.PROOF_HISTORY,
1791
+ ENTITLEMENTS.CLOUD_SYNC,
1792
+ ENTITLEMENTS.TEAM_COLLABORATION,
1793
+ ENTITLEMENTS.API_ACCESS,
1794
+ ENTITLEMENTS.WEBHOOKS,
1795
+ ENTITLEMENTS.CI_GATE_BLOCK,
1796
+ ENTITLEMENTS.AI_GENERATION,
1797
+ ENTITLEMENTS.POLICIES,
1798
+ ENTITLEMENTS.WORKFLOWS,
1799
+ ENTITLEMENTS.PRIORITY_SUPPORT,
1800
+ ENTITLEMENTS.PROMPT_TEMPLATES_PRO
1801
+ ]);
1802
+ /* @__PURE__ */ new Set([
1803
+ // Includes all PRO entitlements
1804
+ ...PRO_ENTITLEMENTS,
1805
+ // Plus Enterprise-only entitlements
1806
+ ENTITLEMENTS.SSO,
1807
+ ENTITLEMENTS.AUDIT_LOGS,
1808
+ ENTITLEMENTS.CUSTOM_POLICIES,
1809
+ ENTITLEMENTS.ON_PREM,
1810
+ ENTITLEMENTS.SLA,
1811
+ ENTITLEMENTS.DEDICATED_SUPPORT,
1812
+ ENTITLEMENTS.FORGE_COMPREHENSIVE,
1813
+ ENTITLEMENTS.PROMPT_TEMPLATES_CUSTOM,
1814
+ ENTITLEMENTS.COMPLIANCE_REPORTS
1815
+ ]);
1816
+ ({
1817
+ [ENTITLEMENTS.REALITY_MODE]: {
1818
+ entitlement: ENTITLEMENTS.REALITY_MODE,
1819
+ title: "Reality Mode",
1820
+ description: "Browser-based runtime verification catches issues static analysis misses.",
1821
+ benefits: [
1822
+ "Browser-based route testing",
1823
+ "Screenshot evidence",
1824
+ "Runtime error detection",
1825
+ "Network request validation"
1826
+ ],
1827
+ docsUrl: "/docs/reality-mode"
1828
+ },
1829
+ [ENTITLEMENTS.CONTEXT_ENGINE]: {
1830
+ entitlement: ENTITLEMENTS.CONTEXT_ENGINE,
1831
+ title: "Context Engine",
1832
+ description: "Full AI context generation for rules, agents, skills, and hooks.",
1833
+ benefits: [
1834
+ "Auto-generated AI rules",
1835
+ "Agent configuration",
1836
+ "Skill definitions",
1837
+ "Pre-commit hooks"
1838
+ ],
1839
+ docsUrl: "/docs/context-engine"
1840
+ },
1841
+ [ENTITLEMENTS.ISL_STUDIO]: {
1842
+ entitlement: ENTITLEMENTS.ISL_STUDIO,
1843
+ title: "ISL Studio",
1844
+ description: "Intent Specification Language builder for spec-first development.",
1845
+ benefits: [
1846
+ "Visual ISL editor",
1847
+ "Contract generation",
1848
+ "Verification integration",
1849
+ "Export to code"
1850
+ ],
1851
+ docsUrl: "/docs/isl-studio"
1852
+ },
1853
+ [ENTITLEMENTS.FIREWALL_ENFORCE]: {
1854
+ entitlement: ENTITLEMENTS.FIREWALL_ENFORCE,
1855
+ title: "Firewall Enforce Mode",
1856
+ description: "Block AI changes before they happen, not after.",
1857
+ benefits: [
1858
+ "Pre-save blocking",
1859
+ "Real-time validation",
1860
+ "Hallucination prevention",
1861
+ "Audit logging"
1862
+ ],
1863
+ docsUrl: "/docs/firewall"
1864
+ },
1865
+ [ENTITLEMENTS.AUTOFIX_APPLY]: {
1866
+ entitlement: ENTITLEMENTS.AUTOFIX_APPLY,
1867
+ title: "Auto-Fix Apply",
1868
+ description: "AI-powered code repair with rollback support.",
1869
+ benefits: [
1870
+ "One-click fixes",
1871
+ "Rollback support",
1872
+ "Fix verification",
1873
+ "Batch application"
1874
+ ],
1875
+ docsUrl: "/docs/autofix"
1876
+ },
1877
+ [ENTITLEMENTS.CERTIFY]: {
1878
+ entitlement: ENTITLEMENTS.CERTIFY,
1879
+ title: "Certify",
1880
+ description: "Generate proof bundles and certification for your code.",
1881
+ benefits: [
1882
+ "Signed proof bundles",
1883
+ "Verification endpoint",
1884
+ "Compliance documentation",
1885
+ "Badge generation"
1886
+ ],
1887
+ docsUrl: "/docs/certify"
1888
+ },
1889
+ [ENTITLEMENTS.BADGE_VERIFIED]: {
1890
+ entitlement: ENTITLEMENTS.BADGE_VERIFIED,
1891
+ title: "Verified Ship Badge",
1892
+ description: "Show your code quality commitment with a verified badge.",
1893
+ benefits: [
1894
+ "Dynamic SVG badge",
1895
+ "Real-time Ship Score",
1896
+ "Verified checkmark",
1897
+ "README embed code"
1898
+ ],
1899
+ docsUrl: "/docs/badges"
1900
+ },
1901
+ [ENTITLEMENTS.CHAOS_AGENT]: {
1902
+ entitlement: ENTITLEMENTS.CHAOS_AGENT,
1903
+ title: "Chaos Agent",
1904
+ description: "AI-powered bug hunting finds issues you would miss.",
1905
+ benefits: [
1906
+ "AI-powered exploration",
1907
+ "Edge case discovery",
1908
+ "Security testing",
1909
+ "Reproducible tests"
1910
+ ],
1911
+ docsUrl: "/docs/chaos-agent"
1912
+ },
1913
+ [ENTITLEMENTS.CLOUD_SYNC]: {
1914
+ entitlement: ENTITLEMENTS.CLOUD_SYNC,
1915
+ title: "Cloud Sync",
1916
+ description: "Sync truthpacks and scan history across devices and team.",
1917
+ benefits: [
1918
+ "Cross-device access",
1919
+ "Team sharing",
1920
+ "Automatic backup",
1921
+ "90-day retention"
1922
+ ],
1923
+ docsUrl: "/docs/cloud-sync"
1924
+ },
1925
+ [ENTITLEMENTS.TEAM_COLLABORATION]: {
1926
+ entitlement: ENTITLEMENTS.TEAM_COLLABORATION,
1927
+ title: "Team Collaboration",
1928
+ description: "Work together on code quality with your team.",
1929
+ benefits: [
1930
+ "Unlimited team members",
1931
+ "Role-based access",
1932
+ "Shared projects",
1933
+ "Team analytics"
1934
+ ],
1935
+ docsUrl: "/docs/teams"
1936
+ },
1937
+ [ENTITLEMENTS.API_ACCESS]: {
1938
+ entitlement: ENTITLEMENTS.API_ACCESS,
1939
+ title: "API Access",
1940
+ description: "Integrate VibeCheck into your existing tools and workflows.",
1941
+ benefits: [
1942
+ "RESTful API",
1943
+ "Webhook support",
1944
+ "CI/CD integration",
1945
+ "Custom automation"
1946
+ ],
1947
+ docsUrl: "/docs/api"
1948
+ }
1949
+ });
1695
1950
  FEATURE_KEYS = {
1696
1951
  // Dashboard features
1697
1952
  CLOUD_SYNC: "cloud_sync",
@@ -2334,45 +2589,53 @@ var init_dist = __esm({
2334
2589
  free: {
2335
2590
  id: "free",
2336
2591
  name: "Free",
2337
- tagline: "Perfect for individual developers",
2592
+ tagline: "Everything you need to find issues",
2338
2593
  price: 0,
2339
2594
  priceLabel: "$0",
2340
2595
  interval: "month",
2341
2596
  features: [
2342
- "Full CLI access (all commands)",
2343
- "5 scans per month",
2344
- "Basic SARIF output",
2345
- "3 local projects",
2346
- "7-day scan history",
2347
- "Community support"
2597
+ "Unlimited scans",
2598
+ "Unlimited ship decisions",
2599
+ "Doctor (health checks)",
2600
+ "HTML reports",
2601
+ "Checkpoint create/restore",
2602
+ "Mission packs (view)",
2603
+ "Template gallery + install",
2604
+ "Forge basic (5 rules)",
2605
+ "Watch mode",
2606
+ "7-day history"
2348
2607
  ],
2349
2608
  limits: {
2350
2609
  projects: 3,
2351
- scansPerMonth: 5,
2352
- // 5 per month for free tier
2610
+ scansPerMonth: -1,
2611
+ // Unlimited
2353
2612
  seats: 1,
2354
2613
  retentionDays: 7
2355
2614
  },
2356
- bestFor: "Solo developers and small side projects",
2615
+ bestFor: "Finding issues in your codebase",
2357
2616
  cta: "Current Plan",
2358
2617
  ctaVariant: "secondary"
2359
2618
  },
2360
2619
  pro: {
2361
2620
  id: "pro",
2362
2621
  name: "Pro",
2363
- tagline: "For teams shipping production code",
2364
- price: 29,
2365
- priceLabel: "$29",
2622
+ tagline: "Prevent issues and prove it",
2623
+ price: 19,
2624
+ priceLabel: "$19",
2366
2625
  interval: "month",
2367
2626
  features: [
2368
2627
  "Everything in Free",
2369
- "Cloud sync & dashboard",
2370
- "Unlimited projects",
2371
- "Team collaboration",
2628
+ "Reality Mode (runtime verification)",
2629
+ "Context Engine (full AI context)",
2630
+ "ISL Studio (spec-first workflow)",
2631
+ "Firewall Agent (enforce + lockdown)",
2632
+ "Auto-Fix (apply fixes)",
2633
+ "Certify + Verified Badge",
2634
+ "Chaos Agent (AI bug hunting)",
2635
+ "PDF & executive reports",
2636
+ "Cloud sync & teams",
2372
2637
  "API access & webhooks",
2373
- "Policy engine",
2374
- "90-day scan history",
2375
- "Priority support"
2638
+ "90-day history"
2376
2639
  ],
2377
2640
  limits: {
2378
2641
  projects: -1,
@@ -2381,7 +2644,7 @@ var init_dist = __esm({
2381
2644
  seats: -1,
2382
2645
  retentionDays: 90
2383
2646
  },
2384
- bestFor: "Growing teams and production applications",
2647
+ bestFor: "Teams shipping production code with confidence",
2385
2648
  popular: true,
2386
2649
  cta: "Upgrade to Pro",
2387
2650
  ctaVariant: "default"
@@ -2389,19 +2652,19 @@ var init_dist = __esm({
2389
2652
  enterprise: {
2390
2653
  id: "enterprise",
2391
2654
  name: "Enterprise",
2392
- tagline: "For organizations with advanced needs",
2655
+ tagline: "For organizations with compliance needs",
2393
2656
  price: null,
2394
2657
  priceLabel: "Custom",
2395
2658
  interval: null,
2396
2659
  features: [
2397
2660
  "Everything in Pro",
2398
- "SSO/SAML authentication",
2661
+ "SSO/SAML (Okta, Azure AD)",
2399
2662
  "Audit logs (365-day retention)",
2400
2663
  "Custom policies",
2401
2664
  "On-premises deployment",
2402
- "Dedicated support team",
2403
- "SLA guarantee",
2404
- "Custom training"
2665
+ "Compliance reports",
2666
+ "Dedicated support",
2667
+ "SLA guarantee"
2405
2668
  ],
2406
2669
  limits: {
2407
2670
  projects: -1,
@@ -2409,7 +2672,7 @@ var init_dist = __esm({
2409
2672
  seats: -1,
2410
2673
  retentionDays: 365
2411
2674
  },
2412
- bestFor: "Large organizations with compliance requirements",
2675
+ bestFor: "Organizations with security & compliance requirements",
2413
2676
  cta: "Contact Sales",
2414
2677
  ctaVariant: "outline"
2415
2678
  }
@@ -16238,8 +16501,6 @@ var init_chunk_KVOEVY4C = __esm({
16238
16501
  };
16239
16502
  }
16240
16503
  });
16241
-
16242
- // ../../packages/core/dist/chunk-VCXA3YAU.js
16243
16504
  function calculateHealthScore(counts) {
16244
16505
  const penalty = counts.critical * SEVERITY_PENALTIES.critical + counts.high * SEVERITY_PENALTIES.high + counts.medium * SEVERITY_PENALTIES.medium + counts.low * SEVERITY_PENALTIES.low;
16245
16506
  const score = Math.max(0, 100 - Math.min(100, penalty));
@@ -16518,6 +16779,173 @@ function formatShipScore(score) {
16518
16779
  };
16519
16780
  return `Ship Score: ${score.total}/100 ${verdictEmoji[score.verdict]} ${score.verdict}`;
16520
16781
  }
16782
+ function generateProofBundle(score, input, options) {
16783
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
16784
+ const evidence = [];
16785
+ const routes = input.truthpack?.routes || [];
16786
+ for (const route of routes.slice(0, 10)) {
16787
+ evidence.push({
16788
+ type: "route_verified",
16789
+ subject: `${route.method || "GET"} ${route.path}`,
16790
+ result: "pass",
16791
+ confidence: 0.9,
16792
+ timestamp
16793
+ });
16794
+ }
16795
+ const envVars = input.truthpack?.env || [];
16796
+ for (const env2 of envVars.slice(0, 10)) {
16797
+ evidence.push({
16798
+ type: "env_verified",
16799
+ subject: env2.name,
16800
+ result: env2.present ? "pass" : "fail",
16801
+ confidence: env2.present ? 0.95 : 0.8,
16802
+ timestamp
16803
+ });
16804
+ }
16805
+ if (input.truthpack?.auth) {
16806
+ evidence.push({
16807
+ type: "auth_verified",
16808
+ subject: "Auth Configuration",
16809
+ result: score.metrics.authConfigured ? "pass" : "fail",
16810
+ confidence: 0.85,
16811
+ details: `${score.metrics.protectedRoutes} protected routes`,
16812
+ timestamp
16813
+ });
16814
+ }
16815
+ if (input.realityResults?.ran) {
16816
+ evidence.push({
16817
+ type: "reality_test",
16818
+ subject: "Reality Mode Verification",
16819
+ result: input.realityResults.routesFailed === 0 ? "pass" : "fail",
16820
+ confidence: 0.95,
16821
+ details: `${input.realityResults.routesPassed}/${input.realityResults.routesTested} passed`,
16822
+ timestamp
16823
+ });
16824
+ }
16825
+ if (input.mockDetectionResults) {
16826
+ evidence.push({
16827
+ type: "mock_scan",
16828
+ subject: "Mock Data Scan",
16829
+ result: input.mockDetectionResults.summary.total === 0 ? "pass" : "fail",
16830
+ confidence: 0.9,
16831
+ details: `${input.mockDetectionResults.summary.total} findings`,
16832
+ timestamp
16833
+ });
16834
+ }
16835
+ const verificationChain = [
16836
+ {
16837
+ step: 1,
16838
+ action: "Ghost Risk Analysis",
16839
+ result: `${score.metrics.verifiedRoutes}/${score.metrics.totalRoutes} routes verified`,
16840
+ scoreContribution: score.dimensions.ghostRisk
16841
+ },
16842
+ {
16843
+ step: 2,
16844
+ action: "Auth Coverage Analysis",
16845
+ result: `${score.metrics.protectedRoutes} routes protected`,
16846
+ scoreContribution: score.dimensions.authCoverage
16847
+ },
16848
+ {
16849
+ step: 3,
16850
+ action: "Env Integrity Check",
16851
+ result: `${score.metrics.presentEnvVars}/${score.metrics.requiredEnvVars} required vars present`,
16852
+ scoreContribution: score.dimensions.envIntegrity
16853
+ },
16854
+ {
16855
+ step: 4,
16856
+ action: "Runtime Proof Collection",
16857
+ result: score.metrics.realityModeRan ? `${score.metrics.routesTestedInReality} routes tested, ${Math.round(score.metrics.realityPassRate * 100)}% pass rate` : "Reality mode not executed",
16858
+ scoreContribution: score.dimensions.runtimeProof
16859
+ },
16860
+ {
16861
+ step: 5,
16862
+ action: "Contract Alignment Check",
16863
+ result: `${score.metrics.alignedContracts}/${score.metrics.totalContracts} contracts aligned`,
16864
+ scoreContribution: score.dimensions.contractsAlignment
16865
+ },
16866
+ {
16867
+ step: 6,
16868
+ action: "Mock Data Cleanliness",
16869
+ result: score.metrics.mockDataFindings === 0 ? "No mock data found" : `${score.metrics.mockDataFindings} mock data findings`,
16870
+ scoreContribution: score.dimensions.mockDataCleanliness
16871
+ }
16872
+ ];
16873
+ let verdict;
16874
+ if (score.verdict === "SHIP" && score.total >= 80) {
16875
+ verdict = "PROVEN";
16876
+ } else if (score.verdict === "BLOCK") {
16877
+ verdict = "FAILED";
16878
+ } else {
16879
+ verdict = "INCOMPLETE_PROOF";
16880
+ }
16881
+ const bundleContent = {
16882
+ version: "1.0.0",
16883
+ timestamp,
16884
+ projectId: options?.projectId,
16885
+ commitHash: options?.commitHash,
16886
+ score,
16887
+ evidence,
16888
+ verificationChain,
16889
+ verdict
16890
+ };
16891
+ const contentString = JSON.stringify(bundleContent);
16892
+ const bundleId = crypto52.createHash("sha256").update(contentString).digest("hex").slice(0, 16);
16893
+ const bundle = {
16894
+ bundleId,
16895
+ ...bundleContent
16896
+ };
16897
+ if (options?.signingKey) {
16898
+ const signatureValue = crypto52.createHmac("sha256", options.signingKey).update(JSON.stringify(bundle)).digest("base64");
16899
+ bundle.signature = {
16900
+ algorithm: "HMAC-SHA256",
16901
+ value: signatureValue,
16902
+ keyId: crypto52.createHash("sha256").update(options.signingKey).digest("hex").slice(0, 8),
16903
+ signedAt: (/* @__PURE__ */ new Date()).toISOString()
16904
+ };
16905
+ }
16906
+ return bundle;
16907
+ }
16908
+ function verifyProofBundle(bundle, signingKey) {
16909
+ const { bundleId, signature, ...content } = bundle;
16910
+ const contentString = JSON.stringify(content);
16911
+ const expectedId = crypto52.createHash("sha256").update(contentString).digest("hex").slice(0, 16);
16912
+ if (bundleId !== expectedId) {
16913
+ return { valid: false, reason: "Bundle ID does not match content hash" };
16914
+ }
16915
+ if (bundle.signature && signingKey) {
16916
+ const expectedSignature = crypto52.createHmac("sha256", signingKey).update(JSON.stringify({ bundleId, ...content })).digest("base64");
16917
+ if (bundle.signature.value !== expectedSignature) {
16918
+ return { valid: false, reason: "Signature verification failed" };
16919
+ }
16920
+ }
16921
+ return { valid: true };
16922
+ }
16923
+ function formatProofBundle(bundle) {
16924
+ const lines = [];
16925
+ lines.push("");
16926
+ lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
16927
+ lines.push("\u2551 VIBECHECK PROOF BUNDLE \u2551");
16928
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
16929
+ lines.push(`\u2551 Bundle ID: ${bundle.bundleId.padEnd(50)} \u2551`);
16930
+ lines.push(`\u2551 Timestamp: ${bundle.timestamp.slice(0, 19).padEnd(50)} \u2551`);
16931
+ lines.push(`\u2551 Verdict: ${bundle.verdict.padEnd(50)} \u2551`);
16932
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
16933
+ lines.push(`\u2551 Ship Score: ${bundle.score.total}/100`.padEnd(67) + " \u2551");
16934
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
16935
+ lines.push("\u2551 Verification Chain: \u2551");
16936
+ for (const step of bundle.verificationChain) {
16937
+ const line = ` ${step.step}. ${step.action}: ${step.result}`.slice(0, 64);
16938
+ lines.push(`\u2551 ${line.padEnd(64)} \u2551`);
16939
+ }
16940
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
16941
+ lines.push(`\u2551 Evidence Items: ${bundle.evidence.length}`.padEnd(67) + " \u2551");
16942
+ if (bundle.signature) {
16943
+ lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
16944
+ lines.push(`\u2551 Signed: ${bundle.signature.algorithm} (key: ${bundle.signature.keyId})`.padEnd(67) + " \u2551");
16945
+ }
16946
+ lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
16947
+ return lines.join("\n");
16948
+ }
16521
16949
  function calculateHybridScore(input) {
16522
16950
  const { islResult, traditionalScore, mode } = input;
16523
16951
  if (mode === "isl" && islResult) {
@@ -16578,8 +17006,8 @@ function createISLScorer() {
16578
17006
  return new ISLScorer();
16579
17007
  }
16580
17008
  var CATEGORY_SCORE_CONFIG, MAX_DIMENSION_SCORE, VERDICT_THRESHOLDS2, GHOST_WEIGHTS, SENSITIVE_ROUTE_PATTERNS, ShipScoreCalculator, shipScoreCalculator, ISL_WEIGHTS, ISL_VERDICT_THRESHOLDS, ISLScorer, islScorer;
16581
- var init_chunk_VCXA3YAU = __esm({
16582
- "../../packages/core/dist/chunk-VCXA3YAU.js"() {
17009
+ var init_chunk_GXXYXSWF = __esm({
17010
+ "../../packages/core/dist/chunk-GXXYXSWF.js"() {
16583
17011
  init_dist();
16584
17012
  init_dist();
16585
17013
  CATEGORY_SCORE_CONFIG = {
@@ -25720,7 +26148,7 @@ var init_chunk_C5JUH5R4 = __esm({
25720
26148
  }
25721
26149
  });
25722
26150
 
25723
- // ../../packages/core/dist/chunk-QJNHJVEI.js
26151
+ // ../../packages/core/dist/chunk-GZFCACMG.js
25724
26152
  function getLogger2() {
25725
26153
  if (!loggerInstance) {
25726
26154
  loggerInstance = {
@@ -26298,8 +26726,8 @@ function gateFeature(userTier, feature, context) {
26298
26726
  }
26299
26727
  }
26300
26728
  var CATEGORY_INFO, TIER_INFO, loggerInstance, registry, TIER_LEVELS, TierAccessError, devMode, UPGRADE_TRIGGERS, FeatureGatedError;
26301
- var init_chunk_QJNHJVEI = __esm({
26302
- "../../packages/core/dist/chunk-QJNHJVEI.js"() {
26729
+ var init_chunk_GZFCACMG = __esm({
26730
+ "../../packages/core/dist/chunk-GZFCACMG.js"() {
26303
26731
  init_chunk_C5JUH5R4();
26304
26732
  init_dist();
26305
26733
  CATEGORY_INFO = {
@@ -26355,7 +26783,7 @@ var init_chunk_QJNHJVEI = __esm({
26355
26783
  name: "PRO",
26356
26784
  description: "Cloud features, team collaboration, API access",
26357
26785
  color: "blue",
26358
- price: "$29/dev/mo"
26786
+ price: "$19/dev/mo"
26359
26787
  },
26360
26788
  enterprise: {
26361
26789
  name: "ENTERPRISE",
@@ -26577,7 +27005,7 @@ function createConcurrencyLimiter(config = {}) {
26577
27005
  async function runWithConcurrency(items, operation, maxConcurrent) {
26578
27006
  const semaphore = new Semaphore(maxConcurrent);
26579
27007
  const results = [];
26580
- const promises2 = items.map(async (item, index) => {
27008
+ const promises3 = items.map(async (item, index) => {
26581
27009
  await semaphore.acquire();
26582
27010
  try {
26583
27011
  const result = await operation(item, index);
@@ -26586,7 +27014,7 @@ async function runWithConcurrency(items, operation, maxConcurrent) {
26586
27014
  semaphore.release();
26587
27015
  }
26588
27016
  });
26589
- await Promise.all(promises2);
27017
+ await Promise.all(promises3);
26590
27018
  return results;
26591
27019
  }
26592
27020
  function createSafetyGuard(config = {}) {
@@ -40726,8 +41154,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
40726
41154
  // ========================================
40727
41155
  // Import Declarations
40728
41156
  // ========================================
40729
- ImportDeclaration(path310) {
40730
- const node = path310.node;
41157
+ ImportDeclaration(path62) {
41158
+ const node = path62.node;
40731
41159
  const importInfo = extractImportInfo(node);
40732
41160
  if (!opts.includeTypeImports && importInfo.isTypeOnly) {
40733
41161
  return;
@@ -40747,8 +41175,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
40747
41175
  // ========================================
40748
41176
  // Dynamic Imports
40749
41177
  // ========================================
40750
- "CallExpression|OptionalCallExpression"(path310) {
40751
- const node = path310.node;
41178
+ "CallExpression|OptionalCallExpression"(path62) {
41179
+ const node = path62.node;
40752
41180
  if (node.callee.type === "Import") {
40753
41181
  const arg = node.arguments[0];
40754
41182
  let modulePath = "<dynamic>";
@@ -40784,8 +41212,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
40784
41212
  // ========================================
40785
41213
  // Track Defined Symbols
40786
41214
  // ========================================
40787
- VariableDeclarator(path310) {
40788
- const id = path310.node.id;
41215
+ VariableDeclarator(path62) {
41216
+ const id = path62.node.id;
40789
41217
  if (id.type === "Identifier") {
40790
41218
  definedSymbols.add(id.name);
40791
41219
  } else if (id.type === "ObjectPattern") {
@@ -40804,38 +41232,38 @@ function extractCallsFromSource(source, filePath, options = {}) {
40804
41232
  }
40805
41233
  }
40806
41234
  },
40807
- FunctionDeclaration(path310) {
40808
- if (path310.node.id) {
40809
- definedSymbols.add(path310.node.id.name);
41235
+ FunctionDeclaration(path62) {
41236
+ if (path62.node.id) {
41237
+ definedSymbols.add(path62.node.id.name);
40810
41238
  }
40811
- for (const param of path310.node.params) {
41239
+ for (const param of path62.node.params) {
40812
41240
  if (param.type === "Identifier") {
40813
41241
  definedSymbols.add(param.name);
40814
41242
  }
40815
41243
  }
40816
41244
  },
40817
- ClassDeclaration(path310) {
40818
- if (path310.node.id) {
40819
- definedSymbols.add(path310.node.id.name);
41245
+ ClassDeclaration(path62) {
41246
+ if (path62.node.id) {
41247
+ definedSymbols.add(path62.node.id.name);
40820
41248
  }
40821
41249
  },
40822
41250
  // Arrow functions assigned to const
40823
- ArrowFunctionExpression(path310) {
40824
- for (const param of path310.node.params) {
41251
+ ArrowFunctionExpression(path62) {
41252
+ for (const param of path62.node.params) {
40825
41253
  if (param.type === "Identifier") {
40826
41254
  definedSymbols.add(param.name);
40827
41255
  }
40828
41256
  }
40829
41257
  },
40830
41258
  // Type declarations (TypeScript)
40831
- TSTypeAliasDeclaration(path310) {
40832
- definedSymbols.add(path310.node.id.name);
41259
+ TSTypeAliasDeclaration(path62) {
41260
+ definedSymbols.add(path62.node.id.name);
40833
41261
  },
40834
- TSInterfaceDeclaration(path310) {
40835
- definedSymbols.add(path310.node.id.name);
41262
+ TSInterfaceDeclaration(path62) {
41263
+ definedSymbols.add(path62.node.id.name);
40836
41264
  },
40837
- TSEnumDeclaration(path310) {
40838
- definedSymbols.add(path310.node.id.name);
41265
+ TSEnumDeclaration(path62) {
41266
+ definedSymbols.add(path62.node.id.name);
40839
41267
  }
40840
41268
  });
40841
41269
  } catch (error) {
@@ -41268,6 +41696,22 @@ function shouldBlock(violation, context) {
41268
41696
  return false;
41269
41697
  }
41270
41698
  }
41699
+ function formatViolationMessage(violation) {
41700
+ const icon = violation.tier === "hard_block" ? "\u{1F6D1}" : violation.tier === "soft_block" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
41701
+ const lines = [
41702
+ `${icon} Blocked: ${violation.category}`,
41703
+ `Evidence: ${violation.evidence}`
41704
+ ];
41705
+ if (violation.quickFixes.length > 0) {
41706
+ lines.push("Fix:");
41707
+ violation.quickFixes.slice(0, 3).forEach((fix) => {
41708
+ lines.push(` \u2705 ${fix.label}`);
41709
+ });
41710
+ } else if (violation.suggestion) {
41711
+ lines.push(`Fix: ${violation.suggestion}`);
41712
+ }
41713
+ return lines.join("\n");
41714
+ }
41271
41715
  function createTieredViolation(rule, category, evidence, options = {}) {
41272
41716
  return {
41273
41717
  tier: options.tierOverride ?? getTierForRule(rule),
@@ -41327,9 +41771,35 @@ function getDefaultRules() {
41327
41771
  new UnsafeSideEffectRule().toPolicy()
41328
41772
  ];
41329
41773
  }
41330
- var DEFAULT_CONFIG10, DRIFT_WEIGHTS, ScopeCreepDetector, IntentValidator, DEFAULT_OPTIONS6, PARSER_OPTIONS, ClaimExtractor, DEFAULT_CONFIG25, BUILTIN_MODULES, EvidenceResolver, POLICY_LIMITS, VALID_SEVERITIES, PolicyEngine, UnblockPlanner, DEFAULT_CONFIG34, modeValidator, actionValidator, AgentFirewall, BEHAVIOR_TEMPLATES, ENTITY_TEMPLATES, ISLGenerator, globalGenerator, IntentStore, globalIntentStore, MissionService, globalMissionService, TIER_A_RULES, TIER_B_RULES, BaseRule, DEFAULT_CONFIG44, GhostRouteRule, DEFAULT_CONFIG54, GhostEnvRule, DEFAULT_CONFIG63, AuthDriftRule, DEFAULT_CONFIG72, ContractDriftRule, DEFAULT_CONFIG82, ScopeExplosionRule, DEFAULT_CONFIG92, UnsafeSideEffectRule;
41331
- var init_chunk_YK33YEF4 = __esm({
41332
- "../../packages/core/dist/chunk-YK33YEF4.js"() {
41774
+ function createObserveModeManager(onComplete) {
41775
+ return new ObserveModeManager({
41776
+ observeDuration: 120,
41777
+ // 2 minutes
41778
+ observeSaveCount: 20,
41779
+ // or 20 saves
41780
+ onComplete
41781
+ });
41782
+ }
41783
+ function createAllowlistManager(projectRoot) {
41784
+ return new AllowlistManager(projectRoot);
41785
+ }
41786
+ async function isAllowed(projectRoot, type, value) {
41787
+ const manager = new AllowlistManager(projectRoot);
41788
+ await manager.load();
41789
+ switch (type) {
41790
+ case "route":
41791
+ return manager.isRouteAllowed(value);
41792
+ case "env":
41793
+ return manager.isEnvVarAllowed(value);
41794
+ case "path":
41795
+ return manager.isPathIgnored(value);
41796
+ default:
41797
+ return false;
41798
+ }
41799
+ }
41800
+ var DEFAULT_CONFIG10, DRIFT_WEIGHTS, ScopeCreepDetector, IntentValidator, DEFAULT_OPTIONS6, PARSER_OPTIONS, ClaimExtractor, DEFAULT_CONFIG25, BUILTIN_MODULES, EvidenceResolver, POLICY_LIMITS, VALID_SEVERITIES, PolicyEngine, UnblockPlanner, DEFAULT_CONFIG34, modeValidator, actionValidator, AgentFirewall, ContractGenerator, ContractVerifier, DEFAULT_WEIGHTS, TrustScorer, BEHAVIOR_TEMPLATES, ENTITY_TEMPLATES, ISLGenerator, globalGenerator, IntentStore, globalIntentStore, MissionService, globalMissionService, TIER_A_RULES, TIER_B_RULES, TIER_C_RULES, BaseRule, DEFAULT_CONFIG44, GhostRouteRule, DEFAULT_CONFIG54, GhostEnvRule, DEFAULT_CONFIG63, AuthDriftRule, DEFAULT_CONFIG72, ContractDriftRule, DEFAULT_CONFIG82, ScopeExplosionRule, DEFAULT_CONFIG92, UnsafeSideEffectRule, ObserveModeManager, DEFAULT_ALLOWLIST, ALLOWLIST_FILENAME, AllowlistManager;
41801
+ var init_chunk_4MEEGNJS = __esm({
41802
+ "../../packages/core/dist/chunk-4MEEGNJS.js"() {
41333
41803
  init_chunk_DFJL4MLU();
41334
41804
  init_chunk_SKXQ6JUA();
41335
41805
  init_chunk_4EQXFW4J();
@@ -41589,23 +42059,23 @@ var init_chunk_YK33YEF4 = __esm({
41589
42059
  /**
41590
42060
  * Categorize a drift event
41591
42061
  */
41592
- categorizeDrift(path310, operation) {
41593
- if (this.matchesSensitivePattern(path310)) {
42062
+ categorizeDrift(path62, operation) {
42063
+ if (this.matchesSensitivePattern(path62)) {
41594
42064
  return {
41595
42065
  category: "sensitive_area",
41596
- reason: `Path "${path310}" touches sensitive area (auth/billing/security)`
42066
+ reason: `Path "${path62}" touches sensitive area (auth/billing/security)`
41597
42067
  };
41598
42068
  }
41599
- if (this.isDependencyFile(path310) && operation !== "read") {
42069
+ if (this.isDependencyFile(path62) && operation !== "read") {
41600
42070
  return {
41601
42071
  category: "dependency_drift",
41602
- reason: `Modifying dependency file "${path310}" without declaration`
42072
+ reason: `Modifying dependency file "${path62}" without declaration`
41603
42073
  };
41604
42074
  }
41605
- if (this.isInDifferentPackage(path310)) {
42075
+ if (this.isInDifferentPackage(path62)) {
41606
42076
  return {
41607
42077
  category: "package_drift",
41608
- reason: `Path "${path310}" is in a different package than declared scope`
42078
+ reason: `Path "${path62}" is in a different package than declared scope`
41609
42079
  };
41610
42080
  }
41611
42081
  if (!this.isAllowedOperation(operation)) {
@@ -41614,8 +42084,8 @@ var init_chunk_YK33YEF4 = __esm({
41614
42084
  reason: `Operation "${operation}" not allowed in current plan`
41615
42085
  };
41616
42086
  }
41617
- if (!this.isPathAllowed(path310)) {
41618
- const dir = this.getDirectory(path310);
42087
+ if (!this.isPathAllowed(path62)) {
42088
+ const dir = this.getDirectory(path62);
41619
42089
  if (dir && !this.existingDirectories.has(dir)) {
41620
42090
  return {
41621
42091
  category: "directory_outside_scope",
@@ -41624,12 +42094,12 @@ var init_chunk_YK33YEF4 = __esm({
41624
42094
  }
41625
42095
  return {
41626
42096
  category: "unpredicted_file",
41627
- reason: `File "${path310}" not in predicted files or allowed patterns`
42097
+ reason: `File "${path62}" not in predicted files or allowed patterns`
41628
42098
  };
41629
42099
  }
41630
42100
  return {
41631
42101
  category: "unpredicted_file",
41632
- reason: `File "${path310}" was not predicted by the change plan`
42102
+ reason: `File "${path62}" was not predicted by the change plan`
41633
42103
  };
41634
42104
  }
41635
42105
  // ============================================================================
@@ -41729,15 +42199,15 @@ var init_chunk_YK33YEF4 = __esm({
41729
42199
  }
41730
42200
  return patterns;
41731
42201
  }
41732
- isPredictedFile(path310) {
42202
+ isPredictedFile(path62) {
41733
42203
  if (!this.activePlan) return false;
41734
42204
  return this.activePlan.predictedFiles.some(
41735
- (predicted) => this.matchPath(path310, predicted)
42205
+ (predicted) => this.matchPath(path62, predicted)
41736
42206
  );
41737
42207
  }
41738
- isInScope(path310, operation) {
42208
+ isInScope(path62, operation) {
41739
42209
  if (!this.activePlan) return true;
41740
- if (this.activePlan.blockedPatterns.some((pattern) => this.matchGlob(path310, pattern))) {
42210
+ if (this.activePlan.blockedPatterns.some((pattern) => this.matchGlob(path62, pattern))) {
41741
42211
  return false;
41742
42212
  }
41743
42213
  if (!this.activePlan.expectedOperations.includes(operation)) {
@@ -41745,33 +42215,33 @@ var init_chunk_YK33YEF4 = __esm({
41745
42215
  return false;
41746
42216
  }
41747
42217
  }
41748
- if (this.isPredictedFile(path310)) {
42218
+ if (this.isPredictedFile(path62)) {
41749
42219
  return true;
41750
42220
  }
41751
- return this.isPathAllowed(path310);
42221
+ return this.isPathAllowed(path62);
41752
42222
  }
41753
- isPathAllowed(path310) {
42223
+ isPathAllowed(path62) {
41754
42224
  if (!this.activePlan) return true;
41755
42225
  return this.activePlan.allowedPatterns.some(
41756
- (pattern) => this.matchGlob(path310, pattern)
42226
+ (pattern) => this.matchGlob(path62, pattern)
41757
42227
  );
41758
42228
  }
41759
42229
  isAllowedOperation(operation) {
41760
42230
  if (!this.activePlan) return true;
41761
42231
  return this.activePlan.expectedOperations.includes(operation) || operation === "read";
41762
42232
  }
41763
- matchesSensitivePattern(path310) {
42233
+ matchesSensitivePattern(path62) {
41764
42234
  return this.config.sensitivePatterns.some(
41765
- (pattern) => this.matchGlob(path310, pattern)
42235
+ (pattern) => this.matchGlob(path62, pattern)
41766
42236
  );
41767
42237
  }
41768
- isDependencyFile(path310) {
41769
- const filename = path310.split("/").pop() ?? path310;
42238
+ isDependencyFile(path62) {
42239
+ const filename = path62.split("/").pop() ?? path62;
41770
42240
  return this.config.dependencyFiles.some(
41771
- (dep) => filename === dep || path310.endsWith(dep)
42241
+ (dep) => filename === dep || path62.endsWith(dep)
41772
42242
  );
41773
42243
  }
41774
- isInDifferentPackage(path310) {
42244
+ isInDifferentPackage(path62) {
41775
42245
  if (!this.activePlan) return false;
41776
42246
  const getPackage = (p7) => {
41777
42247
  for (const pkgDir of this.config.packageDirectories) {
@@ -41789,28 +42259,28 @@ var init_chunk_YK33YEF4 = __esm({
41789
42259
  if (pkg2) allowedPackages.add(pkg2);
41790
42260
  }
41791
42261
  if (allowedPackages.size === 0) return false;
41792
- const pathPackage = getPackage(path310);
42262
+ const pathPackage = getPackage(path62);
41793
42263
  if (!pathPackage) return false;
41794
42264
  return !allowedPackages.has(pathPackage);
41795
42265
  }
41796
- matchPath(path310, pattern) {
41797
- const normalizedPath = this.normalizePath(path310);
42266
+ matchPath(path62, pattern) {
42267
+ const normalizedPath = this.normalizePath(path62);
41798
42268
  const normalizedPattern = this.normalizePath(pattern);
41799
42269
  return normalizedPath === normalizedPattern || normalizedPath.endsWith(`/${normalizedPattern}`);
41800
42270
  }
41801
- matchGlob(path310, pattern) {
41802
- const normalizedPath = this.normalizePath(path310);
42271
+ matchGlob(path62, pattern) {
42272
+ const normalizedPath = this.normalizePath(path62);
41803
42273
  const normalizedPattern = this.normalizePath(pattern);
41804
42274
  if (normalizedPath === normalizedPattern) return true;
41805
42275
  const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<<GLOBSTAR>>>").replace(/\*/g, "[^/]*").replace(/<<<GLOBSTAR>>>/g, ".*").replace(/\?/g, ".");
41806
42276
  const regex = new RegExp(`^${regexPattern}$`);
41807
42277
  return regex.test(normalizedPath);
41808
42278
  }
41809
- normalizePath(path310) {
41810
- return path310.replace(/\\/g, "/").replace(/^\.\//, "");
42279
+ normalizePath(path62) {
42280
+ return path62.replace(/\\/g, "/").replace(/^\.\//, "");
41811
42281
  }
41812
- getDirectory(path310) {
41813
- const parts = path310.split("/");
42282
+ getDirectory(path62) {
42283
+ const parts = path62.split("/");
41814
42284
  if (parts.length <= 1) return null;
41815
42285
  return parts.slice(0, -1).join("/");
41816
42286
  }
@@ -44150,6 +44620,693 @@ var init_chunk_YK33YEF4 = __esm({
44150
44620
  this.logger.info("Agent firewall disposed");
44151
44621
  }
44152
44622
  };
44623
+ ContractGenerator = class {
44624
+ projectRoot;
44625
+ outputDir;
44626
+ contracts = /* @__PURE__ */ new Map();
44627
+ constructor(options) {
44628
+ this.projectRoot = options.projectRoot;
44629
+ this.outputDir = options.outputDir ?? path18.join(options.projectRoot, ".vibecheck", "contracts");
44630
+ }
44631
+ /**
44632
+ * Generate contracts from all detected sources
44633
+ */
44634
+ async generateAll() {
44635
+ const contracts = [];
44636
+ const zodContracts = await this.generateFromZod();
44637
+ contracts.push(...zodContracts);
44638
+ const tsContracts = await this.generateFromTypeScript();
44639
+ contracts.push(...tsContracts);
44640
+ const openApiContracts = await this.generateFromOpenAPI();
44641
+ contracts.push(...openApiContracts);
44642
+ const inferredContracts = await this.inferFromRoutes();
44643
+ contracts.push(...inferredContracts);
44644
+ await this.saveContracts(contracts);
44645
+ return contracts;
44646
+ }
44647
+ /**
44648
+ * Generate contracts from Zod schemas
44649
+ */
44650
+ async generateFromZod() {
44651
+ const contracts = [];
44652
+ const zodFiles = await this.findFiles(["**/*.ts", "**/*.tsx"], /z\.object|z\.string|z\.number/);
44653
+ for (const file2 of zodFiles) {
44654
+ try {
44655
+ const content = await fs15.promises.readFile(file2, "utf-8");
44656
+ const schemas = this.extractZodSchemas(content, file2);
44657
+ for (const schema of schemas) {
44658
+ const spec = this.zodSchemaToISL(schema);
44659
+ contracts.push({
44660
+ spec,
44661
+ metadata: {
44662
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
44663
+ source: {
44664
+ type: "zod",
44665
+ file: path18.relative(this.projectRoot, file2),
44666
+ confidence: 0.9
44667
+ },
44668
+ version: "1.0.0"
44669
+ },
44670
+ filePath: path18.join(this.outputDir, `${schema.name}.isl.json`)
44671
+ });
44672
+ }
44673
+ } catch {
44674
+ }
44675
+ }
44676
+ return contracts;
44677
+ }
44678
+ /**
44679
+ * Generate contracts from TypeScript interfaces
44680
+ */
44681
+ async generateFromTypeScript() {
44682
+ const contracts = [];
44683
+ const tsFiles = await this.findFiles(["**/*.ts", "**/*.d.ts"], /interface\s+\w+|type\s+\w+\s*=/);
44684
+ for (const file2 of tsFiles) {
44685
+ try {
44686
+ const content = await fs15.promises.readFile(file2, "utf-8");
44687
+ const interfaces = this.extractTypeScriptInterfaces(content, file2);
44688
+ for (const iface of interfaces) {
44689
+ const spec = this.interfaceToISL(iface);
44690
+ contracts.push({
44691
+ spec,
44692
+ metadata: {
44693
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
44694
+ source: {
44695
+ type: "typescript",
44696
+ file: path18.relative(this.projectRoot, file2),
44697
+ line: iface.line,
44698
+ confidence: 0.85
44699
+ },
44700
+ version: "1.0.0"
44701
+ },
44702
+ filePath: path18.join(this.outputDir, `${iface.name}.isl.json`)
44703
+ });
44704
+ }
44705
+ } catch {
44706
+ }
44707
+ }
44708
+ return contracts;
44709
+ }
44710
+ /**
44711
+ * Generate contracts from OpenAPI specs
44712
+ */
44713
+ async generateFromOpenAPI() {
44714
+ const contracts = [];
44715
+ const specFiles = await this.findFiles(
44716
+ ["**/openapi.yaml", "**/openapi.json", "**/swagger.yaml", "**/swagger.json"],
44717
+ null
44718
+ );
44719
+ for (const file2 of specFiles) {
44720
+ try {
44721
+ const content = await fs15.promises.readFile(file2, "utf-8");
44722
+ const spec = file2.endsWith(".json") ? JSON.parse(content) : this.parseYaml(content);
44723
+ const operations = this.extractOpenAPIOperations(spec);
44724
+ for (const op of operations) {
44725
+ const islSpec = this.operationToISL(op);
44726
+ contracts.push({
44727
+ spec: islSpec,
44728
+ metadata: {
44729
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
44730
+ source: {
44731
+ type: "openapi",
44732
+ file: path18.relative(this.projectRoot, file2),
44733
+ confidence: 0.95
44734
+ },
44735
+ version: "1.0.0"
44736
+ },
44737
+ filePath: path18.join(this.outputDir, `${op.operationId || op.path.replace(/\//g, "-")}.isl.json`)
44738
+ });
44739
+ }
44740
+ } catch {
44741
+ }
44742
+ }
44743
+ return contracts;
44744
+ }
44745
+ /**
44746
+ * Infer contracts from route handlers
44747
+ */
44748
+ async inferFromRoutes() {
44749
+ const contracts = [];
44750
+ const routeFiles = await this.findFiles(
44751
+ ["**/routes/**/*.ts", "**/api/**/*.ts", "**/pages/api/**/*.ts"],
44752
+ /app\.(get|post|put|delete|patch)|router\.(get|post|put|delete|patch)|export\s+(async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)/i
44753
+ );
44754
+ for (const file2 of routeFiles) {
44755
+ try {
44756
+ const content = await fs15.promises.readFile(file2, "utf-8");
44757
+ const handlers = this.extractRouteHandlers(content, file2);
44758
+ for (const handler of handlers) {
44759
+ const spec = this.handlerToISL(handler);
44760
+ contracts.push({
44761
+ spec,
44762
+ metadata: {
44763
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
44764
+ source: {
44765
+ type: "inferred",
44766
+ file: path18.relative(this.projectRoot, file2),
44767
+ line: handler.line,
44768
+ confidence: 0.7
44769
+ },
44770
+ version: "1.0.0"
44771
+ },
44772
+ filePath: path18.join(this.outputDir, `${handler.name}.isl.json`)
44773
+ });
44774
+ }
44775
+ } catch {
44776
+ }
44777
+ }
44778
+ return contracts;
44779
+ }
44780
+ /**
44781
+ * Save contracts to disk
44782
+ */
44783
+ async saveContracts(contracts) {
44784
+ await fs15.promises.mkdir(this.outputDir, { recursive: true });
44785
+ for (const contract of contracts) {
44786
+ await fs15.promises.writeFile(
44787
+ contract.filePath,
44788
+ JSON.stringify({ spec: contract.spec, metadata: contract.metadata }, null, 2)
44789
+ );
44790
+ this.contracts.set(contract.spec.domain, contract);
44791
+ }
44792
+ }
44793
+ /**
44794
+ * Get all loaded contracts
44795
+ */
44796
+ getContracts() {
44797
+ return Array.from(this.contracts.values());
44798
+ }
44799
+ // Helper methods
44800
+ async findFiles(patterns, contentFilter) {
44801
+ const files = [];
44802
+ const walk = async (dir) => {
44803
+ try {
44804
+ const entries = await fs15.promises.readdir(dir, { withFileTypes: true });
44805
+ for (const entry of entries) {
44806
+ const fullPath = path18.join(dir, entry.name);
44807
+ if (entry.isDirectory()) {
44808
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
44809
+ await walk(fullPath);
44810
+ }
44811
+ } else if (entry.isFile()) {
44812
+ const matches = patterns.some((p7) => {
44813
+ const ext = path18.extname(entry.name);
44814
+ return p7.includes(ext) || p7.includes("*");
44815
+ });
44816
+ if (matches) {
44817
+ if (contentFilter) {
44818
+ try {
44819
+ const content = await fs15.promises.readFile(fullPath, "utf-8");
44820
+ if (contentFilter.test(content)) {
44821
+ files.push(fullPath);
44822
+ }
44823
+ } catch {
44824
+ }
44825
+ } else {
44826
+ files.push(fullPath);
44827
+ }
44828
+ }
44829
+ }
44830
+ }
44831
+ } catch {
44832
+ }
44833
+ };
44834
+ await walk(this.projectRoot);
44835
+ return files;
44836
+ }
44837
+ extractZodSchemas(content, _file) {
44838
+ const schemas = [];
44839
+ const regex = /(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*z\.object\s*\(\s*\{([^}]+)\}/g;
44840
+ let match;
44841
+ while ((match = regex.exec(content)) !== null) {
44842
+ schemas.push({ name: match[1], schema: match[2] });
44843
+ }
44844
+ return schemas;
44845
+ }
44846
+ extractTypeScriptInterfaces(_content, _file) {
44847
+ return [];
44848
+ }
44849
+ extractOpenAPIOperations(_spec) {
44850
+ return [];
44851
+ }
44852
+ extractRouteHandlers(_content, _file) {
44853
+ return [];
44854
+ }
44855
+ zodSchemaToISL(schema) {
44856
+ return {
44857
+ version: "1.0",
44858
+ domain: schema.name,
44859
+ behaviors: [{
44860
+ name: `validate${schema.name}`,
44861
+ input: { fields: [] },
44862
+ output: { success: { type: schema.name } }
44863
+ }]
44864
+ };
44865
+ }
44866
+ interfaceToISL(iface) {
44867
+ return {
44868
+ version: "1.0",
44869
+ domain: iface.name,
44870
+ behaviors: []
44871
+ };
44872
+ }
44873
+ operationToISL(op) {
44874
+ return {
44875
+ version: "1.0",
44876
+ domain: op.operationId ?? op.path,
44877
+ behaviors: [{
44878
+ name: `${op.method}${op.path.replace(/\//g, "_")}`,
44879
+ input: { fields: [] },
44880
+ output: {}
44881
+ }]
44882
+ };
44883
+ }
44884
+ handlerToISL(handler) {
44885
+ return {
44886
+ version: "1.0",
44887
+ domain: handler.name,
44888
+ behaviors: [{
44889
+ name: handler.name,
44890
+ description: `${handler.method} ${handler.path}`,
44891
+ input: { fields: [] },
44892
+ output: {}
44893
+ }]
44894
+ };
44895
+ }
44896
+ parseYaml(_content) {
44897
+ return {};
44898
+ }
44899
+ };
44900
+ ContractVerifier = class {
44901
+ projectRoot;
44902
+ contractsDir;
44903
+ contracts = /* @__PURE__ */ new Map();
44904
+ strict;
44905
+ constructor(options) {
44906
+ this.projectRoot = options.projectRoot;
44907
+ this.contractsDir = options.contractsDir ?? path18.join(options.projectRoot, ".vibecheck", "contracts");
44908
+ this.strict = options.strict ?? false;
44909
+ }
44910
+ /**
44911
+ * Load contracts from disk
44912
+ */
44913
+ async loadContracts() {
44914
+ try {
44915
+ const files = await fs15.promises.readdir(this.contractsDir);
44916
+ for (const file2 of files) {
44917
+ if (file2.endsWith(".isl.json")) {
44918
+ try {
44919
+ const content = await fs15.promises.readFile(
44920
+ path18.join(this.contractsDir, file2),
44921
+ "utf-8"
44922
+ );
44923
+ const data = JSON.parse(content);
44924
+ this.contracts.set(data.spec.domain, {
44925
+ spec: data.spec,
44926
+ metadata: data.metadata,
44927
+ filePath: path18.join(this.contractsDir, file2)
44928
+ });
44929
+ } catch {
44930
+ }
44931
+ }
44932
+ }
44933
+ } catch {
44934
+ }
44935
+ }
44936
+ /**
44937
+ * Verify a file against its contracts
44938
+ */
44939
+ async verifyFile(filePath) {
44940
+ const violations = [];
44941
+ let verifiedBehaviors = 0;
44942
+ let totalBehaviors = 0;
44943
+ try {
44944
+ const content = await fs15.promises.readFile(filePath, "utf-8");
44945
+ const relativePath = path18.relative(this.projectRoot, filePath);
44946
+ for (const [domain, contract] of this.contracts) {
44947
+ if (this.isApplicable(relativePath, contract)) {
44948
+ for (const behavior of contract.spec.behaviors) {
44949
+ totalBehaviors++;
44950
+ const behaviorViolations = await this.verifyBehavior(
44951
+ content,
44952
+ behavior,
44953
+ domain,
44954
+ relativePath
44955
+ );
44956
+ if (behaviorViolations.length === 0) {
44957
+ verifiedBehaviors++;
44958
+ } else {
44959
+ violations.push(...behaviorViolations);
44960
+ }
44961
+ }
44962
+ }
44963
+ }
44964
+ } catch {
44965
+ violations.push({
44966
+ type: "contract_drift",
44967
+ severity: "error",
44968
+ message: `Could not read file: ${filePath}`,
44969
+ file: filePath,
44970
+ contractName: "unknown",
44971
+ autoFixable: false
44972
+ });
44973
+ }
44974
+ const coverage = totalBehaviors > 0 ? verifiedBehaviors / totalBehaviors * 100 : 100;
44975
+ return {
44976
+ passed: violations.filter((v) => v.severity === "error").length === 0,
44977
+ violations,
44978
+ verifiedBehaviors,
44979
+ totalBehaviors,
44980
+ coverage,
44981
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
44982
+ };
44983
+ }
44984
+ /**
44985
+ * Verify all files in the project
44986
+ */
44987
+ async verifyAll() {
44988
+ const allViolations = [];
44989
+ let totalVerified = 0;
44990
+ let totalBehaviors = 0;
44991
+ const files = await this.findSourceFiles();
44992
+ for (const file2 of files) {
44993
+ const result = await this.verifyFile(file2);
44994
+ allViolations.push(...result.violations);
44995
+ totalVerified += result.verifiedBehaviors;
44996
+ totalBehaviors += result.totalBehaviors;
44997
+ }
44998
+ const coverage = totalBehaviors > 0 ? totalVerified / totalBehaviors * 100 : 100;
44999
+ return {
45000
+ passed: allViolations.filter((v) => v.severity === "error").length === 0,
45001
+ violations: allViolations,
45002
+ verifiedBehaviors: totalVerified,
45003
+ totalBehaviors,
45004
+ coverage,
45005
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
45006
+ };
45007
+ }
45008
+ /**
45009
+ * Verify a single code change against contracts (for firewall integration)
45010
+ */
45011
+ async verifyChange(filePath, oldContent, newContent) {
45012
+ const violations = [];
45013
+ const relativePath = path18.relative(this.projectRoot, filePath);
45014
+ for (const [domain, contract] of this.contracts) {
45015
+ if (this.isApplicable(relativePath, contract)) {
45016
+ const driftViolations = this.detectDrift(
45017
+ oldContent,
45018
+ newContent,
45019
+ contract.spec,
45020
+ relativePath
45021
+ );
45022
+ violations.push(...driftViolations);
45023
+ for (const behavior of contract.spec.behaviors) {
45024
+ const behaviorViolations = await this.verifyBehavior(
45025
+ newContent,
45026
+ behavior,
45027
+ domain,
45028
+ relativePath
45029
+ );
45030
+ violations.push(...behaviorViolations);
45031
+ }
45032
+ }
45033
+ }
45034
+ return violations;
45035
+ }
45036
+ /**
45037
+ * Get all loaded contracts
45038
+ */
45039
+ getContracts() {
45040
+ return Array.from(this.contracts.values());
45041
+ }
45042
+ // Private helpers
45043
+ isApplicable(_filePath, _contract) {
45044
+ return true;
45045
+ }
45046
+ async verifyBehavior(content, behavior, contractName, filePath) {
45047
+ const violations = [];
45048
+ if (behavior.input.fields.length > 0) {
45049
+ const inputViolations = this.checkInputValidation(
45050
+ content,
45051
+ behavior,
45052
+ contractName,
45053
+ filePath
45054
+ );
45055
+ violations.push(...inputViolations);
45056
+ }
45057
+ if (behavior.preconditions) {
45058
+ for (const pre of behavior.preconditions) {
45059
+ if (!this.checkConstraint(content, pre)) {
45060
+ violations.push({
45061
+ type: "constraint_violation",
45062
+ severity: this.strict ? "error" : "warning",
45063
+ message: `Precondition not enforced: ${pre.message ?? pre.expression}`,
45064
+ file: filePath,
45065
+ contractName,
45066
+ behaviorName: behavior.name,
45067
+ suggestion: `Add validation: ${pre.expression}`,
45068
+ autoFixable: true
45069
+ });
45070
+ }
45071
+ }
45072
+ }
45073
+ if (behavior.postconditions) {
45074
+ for (const post of behavior.postconditions) {
45075
+ if (!this.checkConstraint(content, post)) {
45076
+ violations.push({
45077
+ type: "constraint_violation",
45078
+ severity: this.strict ? "error" : "warning",
45079
+ message: `Postcondition not guaranteed: ${post.message ?? post.expression}`,
45080
+ file: filePath,
45081
+ contractName,
45082
+ behaviorName: behavior.name,
45083
+ suggestion: `Ensure: ${post.expression}`,
45084
+ autoFixable: false
45085
+ });
45086
+ }
45087
+ }
45088
+ }
45089
+ if (behavior.errors && behavior.errors.length > 0) {
45090
+ const errorViolations = this.checkErrorHandling(
45091
+ content,
45092
+ behavior,
45093
+ contractName,
45094
+ filePath
45095
+ );
45096
+ violations.push(...errorViolations);
45097
+ }
45098
+ return violations;
45099
+ }
45100
+ checkInputValidation(content, behavior, contractName, filePath) {
45101
+ const violations = [];
45102
+ for (const field of behavior.input.fields) {
45103
+ const hasValidation = content.includes(`${field.name}`) && (content.includes("validate") || content.includes("z.") || content.includes("if ("));
45104
+ if (field.required && !hasValidation) {
45105
+ violations.push({
45106
+ type: "missing_field",
45107
+ severity: this.strict ? "error" : "warning",
45108
+ message: `Required field "${field.name}" lacks validation`,
45109
+ file: filePath,
45110
+ contractName,
45111
+ behaviorName: behavior.name,
45112
+ suggestion: `Add validation for "${field.name}"`,
45113
+ autoFixable: true
45114
+ });
45115
+ }
45116
+ }
45117
+ return violations;
45118
+ }
45119
+ checkConstraint(_content, _constraint) {
45120
+ return true;
45121
+ }
45122
+ checkErrorHandling(content, behavior, contractName, filePath) {
45123
+ const violations = [];
45124
+ for (const error of behavior.errors ?? []) {
45125
+ const hasErrorHandling = content.includes("catch") || content.includes("throw") || content.includes(error);
45126
+ if (!hasErrorHandling) {
45127
+ violations.push({
45128
+ type: "unverified_behavior",
45129
+ severity: "warning",
45130
+ message: `Error "${error}" not explicitly handled`,
45131
+ file: filePath,
45132
+ contractName,
45133
+ behaviorName: behavior.name,
45134
+ suggestion: `Add error handling for ${error}`,
45135
+ autoFixable: false
45136
+ });
45137
+ }
45138
+ }
45139
+ return violations;
45140
+ }
45141
+ detectDrift(oldContent, newContent, spec, filePath) {
45142
+ const violations = [];
45143
+ for (const behavior of spec.behaviors) {
45144
+ if (this.signatureChanged(oldContent, newContent, behavior.name)) {
45145
+ violations.push({
45146
+ type: "contract_drift",
45147
+ severity: "warning",
45148
+ message: `Behavior "${behavior.name}" signature may have changed`,
45149
+ file: filePath,
45150
+ contractName: spec.domain,
45151
+ behaviorName: behavior.name,
45152
+ suggestion: "Review contract compatibility",
45153
+ autoFixable: false
45154
+ });
45155
+ }
45156
+ }
45157
+ return violations;
45158
+ }
45159
+ signatureChanged(oldContent, newContent, behaviorName) {
45160
+ const oldMatch = oldContent.match(new RegExp(`function\\s+${behaviorName}\\s*\\([^)]*\\)`));
45161
+ const newMatch = newContent.match(new RegExp(`function\\s+${behaviorName}\\s*\\([^)]*\\)`));
45162
+ if (!oldMatch || !newMatch) return false;
45163
+ return oldMatch[0] !== newMatch[0];
45164
+ }
45165
+ async findSourceFiles() {
45166
+ const files = [];
45167
+ const walk = async (dir) => {
45168
+ try {
45169
+ const entries = await fs15.promises.readdir(dir, { withFileTypes: true });
45170
+ for (const entry of entries) {
45171
+ const fullPath = path18.join(dir, entry.name);
45172
+ if (entry.isDirectory()) {
45173
+ if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
45174
+ await walk(fullPath);
45175
+ }
45176
+ } else if (entry.isFile()) {
45177
+ if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
45178
+ files.push(fullPath);
45179
+ }
45180
+ }
45181
+ }
45182
+ } catch {
45183
+ }
45184
+ };
45185
+ await walk(this.projectRoot);
45186
+ return files;
45187
+ }
45188
+ };
45189
+ DEFAULT_WEIGHTS = {
45190
+ coverageWeight: 0.2,
45191
+ verificationWeight: 0.25,
45192
+ stabilityWeight: 0.15,
45193
+ qualityWeight: 0.15,
45194
+ errorHandlingWeight: 0.15,
45195
+ inputValidationWeight: 0.1,
45196
+ trustThreshold: 85,
45197
+ reviewThreshold: 60
45198
+ };
45199
+ TrustScorer = class {
45200
+ options;
45201
+ constructor(options = {}) {
45202
+ this.options = { ...DEFAULT_WEIGHTS, ...options };
45203
+ }
45204
+ /**
45205
+ * Calculate trust score from verification results and contracts
45206
+ */
45207
+ calculate(verificationResult, contracts) {
45208
+ const dimensions = this.calculateDimensions(verificationResult, contracts);
45209
+ const overall = this.calculateOverall(dimensions);
45210
+ const breakdown = this.createBreakdown(verificationResult, contracts);
45211
+ return {
45212
+ overall,
45213
+ dimensions,
45214
+ grade: this.getGrade(overall),
45215
+ verdict: this.getVerdict(overall),
45216
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
45217
+ breakdown
45218
+ };
45219
+ }
45220
+ /**
45221
+ * Calculate individual dimension scores
45222
+ */
45223
+ calculateDimensions(result, contracts) {
45224
+ const contractCoverage = result.coverage;
45225
+ const verificationRate = result.totalBehaviors > 0 ? result.verifiedBehaviors / result.totalBehaviors * 100 : 100;
45226
+ const driftViolations = result.violations.filter((v) => v.type === "contract_drift");
45227
+ const stability = Math.max(0, 100 - driftViolations.length * 10);
45228
+ const contractQuality = contracts.length > 0 ? contracts.reduce((sum, c) => sum + c.metadata.source.confidence, 0) / contracts.length * 100 : 50;
45229
+ const errorViolations = result.violations.filter((v) => v.type === "unverified_behavior");
45230
+ const errorHandling = Math.max(0, 100 - errorViolations.length * 15);
45231
+ const inputViolations = result.violations.filter((v) => v.type === "missing_field");
45232
+ const inputValidation = Math.max(0, 100 - inputViolations.length * 20);
45233
+ return {
45234
+ contractCoverage,
45235
+ verificationRate,
45236
+ stability,
45237
+ contractQuality,
45238
+ errorHandling,
45239
+ inputValidation
45240
+ };
45241
+ }
45242
+ /**
45243
+ * Calculate overall score from dimensions
45244
+ */
45245
+ calculateOverall(dimensions) {
45246
+ const weighted = dimensions.contractCoverage * this.options.coverageWeight + dimensions.verificationRate * this.options.verificationWeight + dimensions.stability * this.options.stabilityWeight + dimensions.contractQuality * this.options.qualityWeight + dimensions.errorHandling * this.options.errorHandlingWeight + dimensions.inputValidation * this.options.inputValidationWeight;
45247
+ return Math.round(Math.min(100, Math.max(0, weighted)));
45248
+ }
45249
+ /**
45250
+ * Create breakdown of factors
45251
+ */
45252
+ createBreakdown(result, contracts) {
45253
+ const errorViolations = result.violations.filter((v) => v.severity === "error");
45254
+ const warningViolations = result.violations.filter((v) => v.severity === "warning");
45255
+ const highConfidence = contracts.filter((c) => c.metadata.source.confidence >= 0.9);
45256
+ const mediumConfidence = contracts.filter(
45257
+ (c) => c.metadata.source.confidence >= 0.7 && c.metadata.source.confidence < 0.9
45258
+ );
45259
+ const lowConfidence = contracts.filter((c) => c.metadata.source.confidence < 0.7);
45260
+ return {
45261
+ totalBehaviors: result.totalBehaviors,
45262
+ verifiedBehaviors: result.verifiedBehaviors,
45263
+ violations: {
45264
+ errors: errorViolations.length,
45265
+ warnings: warningViolations.length,
45266
+ total: result.violations.length
45267
+ },
45268
+ contracts: {
45269
+ total: contracts.length,
45270
+ highConfidence: highConfidence.length,
45271
+ mediumConfidence: mediumConfidence.length,
45272
+ lowConfidence: lowConfidence.length
45273
+ }
45274
+ };
45275
+ }
45276
+ /**
45277
+ * Get letter grade from score
45278
+ */
45279
+ getGrade(score) {
45280
+ if (score >= 90) return "A";
45281
+ if (score >= 80) return "B";
45282
+ if (score >= 70) return "C";
45283
+ if (score >= 60) return "D";
45284
+ return "F";
45285
+ }
45286
+ /**
45287
+ * Get verdict from score
45288
+ */
45289
+ getVerdict(score) {
45290
+ if (score >= this.options.trustThreshold) return "TRUSTED";
45291
+ if (score >= this.options.reviewThreshold) return "NEEDS_REVIEW";
45292
+ return "UNTRUSTED";
45293
+ }
45294
+ /**
45295
+ * Calculate a quick score from violations only (for firewall use)
45296
+ */
45297
+ calculateFromViolations(violations) {
45298
+ if (violations.length === 0) return 100;
45299
+ const errorPenalty = violations.filter((v) => v.severity === "error").length * 15;
45300
+ const warningPenalty = violations.filter((v) => v.severity === "warning").length * 5;
45301
+ return Math.max(0, 100 - errorPenalty - warningPenalty);
45302
+ }
45303
+ /**
45304
+ * Update options
45305
+ */
45306
+ setOptions(options) {
45307
+ this.options = { ...this.options, ...options };
45308
+ }
45309
+ };
44153
45310
  BEHAVIOR_TEMPLATES = {
44154
45311
  // Authentication patterns
44155
45312
  login: {
@@ -44802,20 +45959,20 @@ domain ${params.domainName} version "${params.version}"
44802
45959
  }
44803
45960
  return this.currentIntent;
44804
45961
  }
44805
- isPathAllowed(path310, intent) {
44806
- return intent.allowedPaths.some((pattern) => this.matchPath(path310, pattern));
45962
+ isPathAllowed(path62, intent) {
45963
+ return intent.allowedPaths.some((pattern) => this.matchPath(path62, pattern));
44807
45964
  }
44808
- isPathExcluded(path310, intent) {
45965
+ isPathExcluded(path62, intent) {
44809
45966
  if (!intent.excludedPaths) return false;
44810
- return intent.excludedPaths.some((pattern) => this.matchPath(path310, pattern));
45967
+ return intent.excludedPaths.some((pattern) => this.matchPath(path62, pattern));
44811
45968
  }
44812
- isInTargetFiles(path310, targetFiles) {
45969
+ isInTargetFiles(path62, targetFiles) {
44813
45970
  return targetFiles.some(
44814
- (target) => path310 === target || path310.endsWith(target) || this.matchPath(path310, target)
45971
+ (target) => path62 === target || path62.endsWith(target) || this.matchPath(path62, target)
44815
45972
  );
44816
45973
  }
44817
- matchPath(path310, pattern) {
44818
- const normalizedPath = path310.replace(/\\/g, "/");
45974
+ matchPath(path62, pattern) {
45975
+ const normalizedPath = path62.replace(/\\/g, "/");
44819
45976
  const normalizedPattern = pattern.replace(/\\/g, "/");
44820
45977
  if (normalizedPath === normalizedPattern) return true;
44821
45978
  if (normalizedPattern.includes("*")) {
@@ -45242,22 +46399,22 @@ domain ${params.domainName} version "${params.version}"
45242
46399
  // ============================================================================
45243
46400
  // Path Matching Utilities
45244
46401
  // ============================================================================
45245
- isPathInScope(path310, scope) {
46402
+ isPathInScope(path62, scope) {
45246
46403
  if (scope.targetFiles && scope.targetFiles.length > 0) {
45247
46404
  return scope.targetFiles.some(
45248
- (target) => path310 === target || path310.endsWith(target) || this.matchGlob(path310, target)
46405
+ (target) => path62 === target || path62.endsWith(target) || this.matchGlob(path62, target)
45249
46406
  );
45250
46407
  }
45251
- return scope.allowedPaths.some((pattern) => this.matchGlob(path310, pattern));
46408
+ return scope.allowedPaths.some((pattern) => this.matchGlob(path62, pattern));
45252
46409
  }
45253
- isPathExcluded(path310, scope) {
45254
- return scope.excludedPaths.some((pattern) => this.matchGlob(path310, pattern));
46410
+ isPathExcluded(path62, scope) {
46411
+ return scope.excludedPaths.some((pattern) => this.matchGlob(path62, pattern));
45255
46412
  }
45256
- matchesSensitivePattern(path310, policy) {
45257
- return policy.sensitivePatterns.some((pattern) => this.matchGlob(path310, pattern));
46413
+ matchesSensitivePattern(path62, policy) {
46414
+ return policy.sensitivePatterns.some((pattern) => this.matchGlob(path62, pattern));
45258
46415
  }
45259
- matchGlob(path310, pattern) {
45260
- const normalizedPath = path310.replace(/\\/g, "/");
46416
+ matchGlob(path62, pattern) {
46417
+ const normalizedPath = path62.replace(/\\/g, "/");
45261
46418
  const normalizedPattern = pattern.replace(/\\/g, "/");
45262
46419
  if (normalizedPath === normalizedPattern) return true;
45263
46420
  if (normalizedPattern.includes("*")) {
@@ -45341,6 +46498,15 @@ domain ${params.domainName} version "${params.version}"
45341
46498
  "contract-drift"
45342
46499
  // Contract violation
45343
46500
  ];
46501
+ TIER_C_RULES = [
46502
+ "missing-error-handling",
46503
+ "rate-limiting-suggestion",
46504
+ "validation-suggestion",
46505
+ "low-confidence",
46506
+ "excessive-claims",
46507
+ "scope-explosion",
46508
+ "unsafe-side-effect"
46509
+ ];
45344
46510
  BaseRule = class {
45345
46511
  config;
45346
46512
  constructor(config = {}) {
@@ -45504,20 +46670,20 @@ domain ${params.domainName} version "${params.version}"
45504
46670
  suggestion
45505
46671
  );
45506
46672
  }
45507
- isExternalPath(path310) {
46673
+ isExternalPath(path62) {
45508
46674
  if (!this.config.allowedExternalPaths) return false;
45509
46675
  return this.config.allowedExternalPaths.some(
45510
- (pattern) => this.matchPattern(path310, pattern)
46676
+ (pattern) => this.matchPattern(path62, pattern)
45511
46677
  );
45512
46678
  }
45513
46679
  /**
45514
46680
  * Normalize path by removing query strings and fragments
45515
46681
  */
45516
- normalizePath(path310) {
45517
- return path310.split("?")[0].split("#")[0];
46682
+ normalizePath(path62) {
46683
+ return path62.split("?")[0].split("#")[0];
45518
46684
  }
45519
- isApiPath(path310) {
45520
- const normalized = this.normalizePath(path310);
46685
+ isApiPath(path62) {
46686
+ const normalized = this.normalizePath(path62);
45521
46687
  if (!this.config.apiPrefixes || this.config.apiPrefixes.length === 0) {
45522
46688
  return normalized.startsWith("/");
45523
46689
  }
@@ -45546,8 +46712,8 @@ domain ${params.domainName} version "${params.version}"
45546
46712
  }
45547
46713
  return similar.slice(0, 3);
45548
46714
  }
45549
- generateSuggestion(path310, context) {
45550
- const normalized = this.normalizePath(path310);
46715
+ generateSuggestion(path62, context) {
46716
+ const normalized = this.normalizePath(path62);
45551
46717
  if (context) {
45552
46718
  const similar = this.findSimilarRoutes(normalized, context);
45553
46719
  if (similar.length > 0) {
@@ -46294,6 +47460,492 @@ domain ${params.domainName} version "${params.version}"
46294
47460
  return "Review this code for potential security issues";
46295
47461
  }
46296
47462
  };
47463
+ ObserveModeManager = class _ObserveModeManager {
47464
+ state;
47465
+ onComplete;
47466
+ constructor(options = {}) {
47467
+ this.state = {
47468
+ startTime: Date.now(),
47469
+ saveCount: 0,
47470
+ observeDuration: options.observeDuration ?? 120,
47471
+ observeSaveCount: options.observeSaveCount ?? 20,
47472
+ isActive: true,
47473
+ detectedPatterns: /* @__PURE__ */ new Map(),
47474
+ observedViolations: [],
47475
+ suggestedAllows: []
47476
+ };
47477
+ this.onComplete = options.onComplete;
47478
+ }
47479
+ /**
47480
+ * Check if observe mode is still active
47481
+ */
47482
+ isObserving() {
47483
+ if (!this.state.isActive) return false;
47484
+ const elapsedSeconds = (Date.now() - this.state.startTime) / 1e3;
47485
+ const timeExpired = elapsedSeconds >= this.state.observeDuration;
47486
+ const savesReached = this.state.saveCount >= this.state.observeSaveCount;
47487
+ if (timeExpired || savesReached) {
47488
+ this.complete();
47489
+ return false;
47490
+ }
47491
+ return true;
47492
+ }
47493
+ /**
47494
+ * Get the remaining time/saves before observe mode ends
47495
+ */
47496
+ getProgress() {
47497
+ const elapsedSeconds = (Date.now() - this.state.startTime) / 1e3;
47498
+ const timeProgress = elapsedSeconds / this.state.observeDuration;
47499
+ const saveProgress = this.state.saveCount / this.state.observeSaveCount;
47500
+ const progressPercent = Math.max(timeProgress, saveProgress) * 100;
47501
+ return {
47502
+ elapsedSeconds: Math.round(elapsedSeconds),
47503
+ remainingSeconds: Math.max(0, this.state.observeDuration - elapsedSeconds),
47504
+ saveCount: this.state.saveCount,
47505
+ remainingSaves: Math.max(0, this.state.observeSaveCount - this.state.saveCount),
47506
+ progressPercent: Math.min(100, Math.round(progressPercent))
47507
+ };
47508
+ }
47509
+ /**
47510
+ * Record a save event during observation
47511
+ */
47512
+ recordSave(filePath) {
47513
+ if (!this.state.isActive) return;
47514
+ this.state.saveCount++;
47515
+ this.detectFilePatterns(filePath);
47516
+ this.isObserving();
47517
+ }
47518
+ /**
47519
+ * Record a violation that was observed (not blocked) during learning
47520
+ */
47521
+ recordViolation(violation) {
47522
+ if (!this.state.isActive) return;
47523
+ this.state.observedViolations.push(violation);
47524
+ this.analyzeViolationForPatterns(violation);
47525
+ }
47526
+ /**
47527
+ * Record a code pattern observed during a save
47528
+ */
47529
+ recordPattern(type, pattern, filePath, regex) {
47530
+ if (!this.state.isActive) return;
47531
+ const key = `${type}:${pattern}`;
47532
+ const existing = this.state.detectedPatterns.get(key);
47533
+ if (existing) {
47534
+ existing.count++;
47535
+ existing.lastSeen = Date.now();
47536
+ if (!existing.files.includes(filePath)) {
47537
+ existing.files.push(filePath);
47538
+ }
47539
+ if (existing.count >= 3) {
47540
+ existing.suggestedAllow = true;
47541
+ }
47542
+ } else {
47543
+ this.state.detectedPatterns.set(key, {
47544
+ type,
47545
+ pattern,
47546
+ regex,
47547
+ count: 1,
47548
+ firstSeen: Date.now(),
47549
+ lastSeen: Date.now(),
47550
+ files: [filePath],
47551
+ suggestedAllow: false
47552
+ });
47553
+ }
47554
+ }
47555
+ /**
47556
+ * Get current suggested allows based on observations
47557
+ */
47558
+ getSuggestedAllows() {
47559
+ return this.state.suggestedAllows;
47560
+ }
47561
+ /**
47562
+ * Get observed violations (would have blocked but didn't)
47563
+ */
47564
+ getObservedViolations() {
47565
+ return this.state.observedViolations;
47566
+ }
47567
+ /**
47568
+ * Complete observe mode and generate final suggestions
47569
+ */
47570
+ complete() {
47571
+ if (!this.state.isActive) return;
47572
+ this.state.isActive = false;
47573
+ this.generateSuggestedAllows();
47574
+ if (this.onComplete) {
47575
+ this.onComplete(this.state.suggestedAllows);
47576
+ }
47577
+ }
47578
+ /**
47579
+ * Detect patterns from file paths
47580
+ */
47581
+ detectFilePatterns(filePath) {
47582
+ if (filePath.includes(".gen.") || filePath.includes("generated/")) {
47583
+ this.recordPattern("generated_file", filePath.replace(/[^/]+$/, "*"), filePath);
47584
+ }
47585
+ const aliasMatch = filePath.match(/^@([^/]+)/);
47586
+ if (aliasMatch) {
47587
+ this.recordPattern("path_alias", `@${aliasMatch[1]}/*`, filePath);
47588
+ }
47589
+ }
47590
+ /**
47591
+ * Analyze violations for learnable patterns
47592
+ */
47593
+ analyzeViolationForPatterns(violation) {
47594
+ const evidence = violation.evidence;
47595
+ if (violation.rule === "ghost-route" && evidence.includes("${")) {
47596
+ const dynamicMatch = evidence.match(/\/api\/[^/]*\$\{[^}]+\}/);
47597
+ if (dynamicMatch) {
47598
+ this.recordPattern(
47599
+ "dynamic_route",
47600
+ dynamicMatch[0],
47601
+ violation.filePath ?? "",
47602
+ "^/api/[a-z]+/\\${[^}]+}$"
47603
+ );
47604
+ }
47605
+ }
47606
+ if (violation.rule === "ghost-route") {
47607
+ const wrapperMatch = evidence.match(/(api|client|fetch|axios)\.[a-z]+\s*\(['"]([^'"]+)/i);
47608
+ if (wrapperMatch) {
47609
+ this.recordPattern(
47610
+ "api_wrapper",
47611
+ wrapperMatch[2],
47612
+ violation.filePath ?? ""
47613
+ );
47614
+ }
47615
+ }
47616
+ if (violation.rule === "ghost-env") {
47617
+ const envMatch = evidence.match(/([A-Z]+_)/);
47618
+ if (envMatch) {
47619
+ const prefix = envMatch[1];
47620
+ if (prefix.length <= 10) {
47621
+ this.recordPattern(
47622
+ "env_prefix",
47623
+ `${prefix}*`,
47624
+ violation.filePath ?? "",
47625
+ `^${prefix}[A-Z_]+$`
47626
+ );
47627
+ }
47628
+ }
47629
+ }
47630
+ }
47631
+ /**
47632
+ * Generate final suggested allows from detected patterns
47633
+ */
47634
+ generateSuggestedAllows() {
47635
+ const allows = [];
47636
+ for (const [, pattern] of this.state.detectedPatterns) {
47637
+ if (!pattern.suggestedAllow && pattern.count < 2) continue;
47638
+ let type;
47639
+ switch (pattern.type) {
47640
+ case "dynamic_route":
47641
+ type = "dynamic_route";
47642
+ break;
47643
+ case "api_wrapper":
47644
+ case "framework_pattern":
47645
+ type = "route_prefix";
47646
+ break;
47647
+ case "env_prefix":
47648
+ type = "env_var";
47649
+ break;
47650
+ case "generated_file":
47651
+ case "path_alias":
47652
+ type = "ignored_path";
47653
+ break;
47654
+ default:
47655
+ continue;
47656
+ }
47657
+ allows.push({
47658
+ type,
47659
+ pattern: pattern.pattern,
47660
+ regex: pattern.regex,
47661
+ confidence: Math.min(1, pattern.count / 5),
47662
+ reason: `Seen ${pattern.count} times in ${pattern.files.length} files`,
47663
+ seenCount: pattern.count
47664
+ });
47665
+ }
47666
+ allows.sort((a, b) => b.confidence - a.confidence);
47667
+ this.state.suggestedAllows = allows;
47668
+ }
47669
+ /**
47670
+ * Force complete observe mode early
47671
+ */
47672
+ forceComplete() {
47673
+ this.complete();
47674
+ return this.state.suggestedAllows;
47675
+ }
47676
+ /**
47677
+ * Reset observe mode to start fresh
47678
+ */
47679
+ reset() {
47680
+ this.state = {
47681
+ startTime: Date.now(),
47682
+ saveCount: 0,
47683
+ observeDuration: this.state.observeDuration,
47684
+ observeSaveCount: this.state.observeSaveCount,
47685
+ isActive: true,
47686
+ detectedPatterns: /* @__PURE__ */ new Map(),
47687
+ observedViolations: [],
47688
+ suggestedAllows: []
47689
+ };
47690
+ }
47691
+ /**
47692
+ * Serialize state for persistence
47693
+ */
47694
+ toJSON() {
47695
+ return {
47696
+ startTime: this.state.startTime,
47697
+ saveCount: this.state.saveCount,
47698
+ observeDuration: this.state.observeDuration,
47699
+ observeSaveCount: this.state.observeSaveCount,
47700
+ isActive: this.state.isActive,
47701
+ detectedPatterns: Array.from(this.state.detectedPatterns.entries()),
47702
+ observedViolations: this.state.observedViolations,
47703
+ suggestedAllows: this.state.suggestedAllows
47704
+ };
47705
+ }
47706
+ /**
47707
+ * Restore state from persisted data
47708
+ */
47709
+ static fromJSON(data) {
47710
+ const manager = new _ObserveModeManager({
47711
+ observeDuration: data.observeDuration,
47712
+ observeSaveCount: data.observeSaveCount
47713
+ });
47714
+ manager.state.startTime = data.startTime;
47715
+ manager.state.saveCount = data.saveCount;
47716
+ manager.state.isActive = data.isActive;
47717
+ manager.state.observedViolations = data.observedViolations;
47718
+ manager.state.suggestedAllows = data.suggestedAllows;
47719
+ if (Array.isArray(data.detectedPatterns)) {
47720
+ manager.state.detectedPatterns = new Map(data.detectedPatterns);
47721
+ }
47722
+ return manager;
47723
+ }
47724
+ };
47725
+ DEFAULT_ALLOWLIST = {
47726
+ allowedRoutePrefixes: [],
47727
+ allowedDynamicRoutes: [],
47728
+ ignoredPaths: [
47729
+ "**/node_modules/**",
47730
+ "**/.git/**",
47731
+ "**/dist/**",
47732
+ "**/build/**",
47733
+ "**/*.gen.ts",
47734
+ "**/*.generated.*"
47735
+ ],
47736
+ allowedEnvVars: []
47737
+ };
47738
+ ALLOWLIST_FILENAME = "firewall.allow.json";
47739
+ AllowlistManager = class {
47740
+ allowlist;
47741
+ projectRoot;
47742
+ loaded = false;
47743
+ constructor(projectRoot) {
47744
+ this.projectRoot = projectRoot;
47745
+ this.allowlist = { ...DEFAULT_ALLOWLIST };
47746
+ }
47747
+ /**
47748
+ * Get the path to the allowlist file
47749
+ */
47750
+ get filePath() {
47751
+ return path18.join(this.projectRoot, ".vibecheck", ALLOWLIST_FILENAME);
47752
+ }
47753
+ /**
47754
+ * Load the allowlist from disk
47755
+ */
47756
+ async load() {
47757
+ try {
47758
+ const content = await fs102.readFile(this.filePath, "utf-8");
47759
+ const parsed = JSON.parse(content);
47760
+ this.allowlist = {
47761
+ allowedRoutePrefixes: parsed.allowedRoutePrefixes ?? [],
47762
+ allowedDynamicRoutes: parsed.allowedDynamicRoutes ?? [],
47763
+ ignoredPaths: parsed.ignoredPaths ?? DEFAULT_ALLOWLIST.ignoredPaths,
47764
+ allowedEnvVars: parsed.allowedEnvVars ?? [],
47765
+ _autoGenerated: parsed._autoGenerated
47766
+ };
47767
+ this.loaded = true;
47768
+ } catch {
47769
+ this.allowlist = { ...DEFAULT_ALLOWLIST };
47770
+ this.loaded = true;
47771
+ }
47772
+ return this.allowlist;
47773
+ }
47774
+ /**
47775
+ * Save the allowlist to disk
47776
+ */
47777
+ async save() {
47778
+ const dir = path18.dirname(this.filePath);
47779
+ try {
47780
+ await fs102.mkdir(dir, { recursive: true });
47781
+ } catch {
47782
+ }
47783
+ const content = JSON.stringify(this.allowlist, null, 2);
47784
+ await fs102.writeFile(this.filePath, content, "utf-8");
47785
+ }
47786
+ /**
47787
+ * Get the current allowlist
47788
+ */
47789
+ get() {
47790
+ return this.allowlist;
47791
+ }
47792
+ /**
47793
+ * Check if a route is allowed
47794
+ */
47795
+ isRouteAllowed(routePath) {
47796
+ for (const prefix of this.allowlist.allowedRoutePrefixes) {
47797
+ if (routePath.startsWith(prefix)) {
47798
+ return true;
47799
+ }
47800
+ }
47801
+ for (const pattern of this.allowlist.allowedDynamicRoutes) {
47802
+ try {
47803
+ const regex = new RegExp(pattern);
47804
+ if (regex.test(routePath)) {
47805
+ return true;
47806
+ }
47807
+ } catch {
47808
+ }
47809
+ }
47810
+ return false;
47811
+ }
47812
+ /**
47813
+ * Check if a file path should be ignored
47814
+ */
47815
+ isPathIgnored(filePath) {
47816
+ const normalized = filePath.replace(/\\/g, "/");
47817
+ for (const pattern of this.allowlist.ignoredPaths) {
47818
+ if (this.matchGlob(normalized, pattern)) {
47819
+ return true;
47820
+ }
47821
+ }
47822
+ return false;
47823
+ }
47824
+ /**
47825
+ * Check if an env var is allowed
47826
+ */
47827
+ isEnvVarAllowed(varName) {
47828
+ for (const allowed of this.allowlist.allowedEnvVars) {
47829
+ if (allowed.endsWith("*")) {
47830
+ const prefix = allowed.slice(0, -1);
47831
+ if (varName.startsWith(prefix)) {
47832
+ return true;
47833
+ }
47834
+ } else if (varName === allowed) {
47835
+ return true;
47836
+ }
47837
+ }
47838
+ return false;
47839
+ }
47840
+ /**
47841
+ * Add a route prefix to the allowlist
47842
+ */
47843
+ async addRoutePrefix(prefix) {
47844
+ if (!this.allowlist.allowedRoutePrefixes.includes(prefix)) {
47845
+ this.allowlist.allowedRoutePrefixes.push(prefix);
47846
+ await this.save();
47847
+ }
47848
+ }
47849
+ /**
47850
+ * Add a dynamic route pattern to the allowlist
47851
+ */
47852
+ async addDynamicRoute(pattern) {
47853
+ try {
47854
+ new RegExp(pattern);
47855
+ } catch {
47856
+ throw new Error(`Invalid regex pattern: ${pattern}`);
47857
+ }
47858
+ if (!this.allowlist.allowedDynamicRoutes.includes(pattern)) {
47859
+ this.allowlist.allowedDynamicRoutes.push(pattern);
47860
+ await this.save();
47861
+ }
47862
+ }
47863
+ /**
47864
+ * Add an ignored path pattern
47865
+ */
47866
+ async addIgnoredPath(pattern) {
47867
+ if (!this.allowlist.ignoredPaths.includes(pattern)) {
47868
+ this.allowlist.ignoredPaths.push(pattern);
47869
+ await this.save();
47870
+ }
47871
+ }
47872
+ /**
47873
+ * Add an allowed env var
47874
+ */
47875
+ async addEnvVar(varName) {
47876
+ if (!this.allowlist.allowedEnvVars.includes(varName)) {
47877
+ this.allowlist.allowedEnvVars.push(varName);
47878
+ await this.save();
47879
+ }
47880
+ }
47881
+ /**
47882
+ * Remove a route prefix from the allowlist
47883
+ */
47884
+ async removeRoutePrefix(prefix) {
47885
+ const index = this.allowlist.allowedRoutePrefixes.indexOf(prefix);
47886
+ if (index !== -1) {
47887
+ this.allowlist.allowedRoutePrefixes.splice(index, 1);
47888
+ await this.save();
47889
+ }
47890
+ }
47891
+ /**
47892
+ * Add entries from observe mode suggestions
47893
+ */
47894
+ async addFromObserveMode(suggestions) {
47895
+ for (const suggestion of suggestions) {
47896
+ switch (suggestion.type) {
47897
+ case "route_prefix":
47898
+ if (!this.allowlist.allowedRoutePrefixes.includes(suggestion.pattern)) {
47899
+ this.allowlist.allowedRoutePrefixes.push(suggestion.pattern);
47900
+ }
47901
+ break;
47902
+ case "dynamic_route":
47903
+ if (!this.allowlist.allowedDynamicRoutes.includes(suggestion.pattern)) {
47904
+ this.allowlist.allowedDynamicRoutes.push(suggestion.pattern);
47905
+ }
47906
+ break;
47907
+ case "env_var":
47908
+ if (!this.allowlist.allowedEnvVars.includes(suggestion.pattern)) {
47909
+ this.allowlist.allowedEnvVars.push(suggestion.pattern);
47910
+ }
47911
+ break;
47912
+ case "ignored_path":
47913
+ if (!this.allowlist.ignoredPaths.includes(suggestion.pattern)) {
47914
+ this.allowlist.ignoredPaths.push(suggestion.pattern);
47915
+ }
47916
+ break;
47917
+ }
47918
+ }
47919
+ this.allowlist._autoGenerated = {
47920
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47921
+ entries: suggestions.map((s) => ({
47922
+ type: s.type,
47923
+ pattern: s.pattern,
47924
+ reason: s.reason
47925
+ }))
47926
+ };
47927
+ await this.save();
47928
+ }
47929
+ /**
47930
+ * Clear auto-generated entries after user review
47931
+ */
47932
+ async clearAutoGenerated() {
47933
+ delete this.allowlist._autoGenerated;
47934
+ await this.save();
47935
+ }
47936
+ /**
47937
+ * Simple glob matching (supports ** and *)
47938
+ */
47939
+ matchGlob(path62, pattern) {
47940
+ let regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLE_STAR}}").replace(/\*/g, "[^/]*").replace(/{{DOUBLE_STAR}}/g, ".*");
47941
+ regexStr = `^${regexStr}$`;
47942
+ try {
47943
+ return new RegExp(regexStr).test(path62);
47944
+ } catch {
47945
+ return false;
47946
+ }
47947
+ }
47948
+ };
46297
47949
  }
46298
47950
  });
46299
47951
  function createQuickChain(claim, verified, source, details) {
@@ -46559,6 +48211,121 @@ async function resetVerificationEngine() {
46559
48211
  globalEngine = null;
46560
48212
  }
46561
48213
  }
48214
+ function sanitizeCode(code) {
48215
+ let sanitized = code;
48216
+ sanitized = sanitized.replace(/\beval\s*\(/g, '(function(){throw new Error("Security violation: eval removed")})(');
48217
+ sanitized = sanitized.replace(/new\s+Function\s*\(/g, "/* REMOVED: Function constructor */ undefined(");
48218
+ const secretPatterns = [
48219
+ /(?:api[_-]?key|apikey)\s*[:=]\s*["'`]([A-Za-z0-9_\-]{20,})["'`]/gi,
48220
+ /(?:secret|password|passwd|pwd)\s*[:=]\s*["'`]([^"'`]{8,})["'`]/gi,
48221
+ /(?:token)\s*[:=]\s*["'`]([A-Za-z0-9_\-\.]{20,})["'`]/gi
48222
+ ];
48223
+ for (const pattern of secretPatterns) {
48224
+ sanitized = sanitized.replace(pattern, (match) => {
48225
+ if (match.includes("process.env") || match.includes("import.meta.env")) {
48226
+ return match;
48227
+ }
48228
+ if (match.toLowerCase().includes("example") || match.toLowerCase().includes("placeholder")) {
48229
+ return match;
48230
+ }
48231
+ const keyMatch = match.match(/^([a-z_]+)\s*[:=]/i);
48232
+ const envKey = keyMatch ? keyMatch[1].toUpperCase().replace(/[^A-Z0-9]/g, "_") : "SECRET";
48233
+ return `${keyMatch ? keyMatch[1] + " = " : ""}process.env.${envKey}`;
48234
+ });
48235
+ }
48236
+ sanitized = sanitized.replace(/from\s+["'`]https?:\/\/[^"'`]+["'`]/g, 'from "/* REMOVED: HTTP import */"');
48237
+ return sanitized;
48238
+ }
48239
+ async function validateAndSanitizeFiles(files, config) {
48240
+ const validator = await getCodeValidator(config);
48241
+ const validFiles = [];
48242
+ const errors = [];
48243
+ const warnings = [];
48244
+ for (const file2 of files) {
48245
+ if (file2.path.includes("..") || file2.path.startsWith("/")) {
48246
+ errors.push({
48247
+ filePath: file2.path,
48248
+ type: "invalid_path",
48249
+ message: "Path traversal or absolute path detected"
48250
+ });
48251
+ continue;
48252
+ }
48253
+ const validExtensions = /\.(ts|tsx|js|jsx|json|md|sql|yaml|yml|css|scss|html|txt|sh|env)$/i;
48254
+ if (!validExtensions.test(file2.path) && !file2.path.toLowerCase().includes("dockerfile")) {
48255
+ errors.push({
48256
+ filePath: file2.path,
48257
+ type: "invalid_path",
48258
+ message: `Invalid file extension: ${file2.path}`
48259
+ });
48260
+ continue;
48261
+ }
48262
+ if (["typescript", "javascript"].includes(file2.language) || /\.(ts|tsx|js|jsx)$/i.test(file2.path)) {
48263
+ const result = await validator.validate(file2.content, file2.path);
48264
+ for (const error of result.errors) {
48265
+ errors.push({
48266
+ filePath: file2.path,
48267
+ type: error.type,
48268
+ message: error.message
48269
+ });
48270
+ }
48271
+ for (const warning of result.warnings) {
48272
+ warnings.push({
48273
+ filePath: file2.path,
48274
+ message: warning.message
48275
+ });
48276
+ }
48277
+ const hasSecurityIssues = result.warnings.some((w) => w.type === "security");
48278
+ const hasCriticalErrors = result.errors.some((e) => e.severity === "critical");
48279
+ if (hasSecurityIssues || hasCriticalErrors) {
48280
+ const sanitizedContent = sanitizeCode(file2.content);
48281
+ validFiles.push({
48282
+ ...file2,
48283
+ content: sanitizedContent,
48284
+ description: `${file2.description} (sanitized)`
48285
+ });
48286
+ } else {
48287
+ validFiles.push(file2);
48288
+ }
48289
+ } else {
48290
+ validFiles.push(file2);
48291
+ }
48292
+ }
48293
+ const issueCount = errors.length + warnings.length;
48294
+ let qualityScore = 100 - issueCount * 5;
48295
+ qualityScore = Math.max(0, Math.min(100, qualityScore));
48296
+ const criticalErrors = errors.filter(
48297
+ (e) => e.type === "security" || e.type === "syntax" || e.type === "invalid_path"
48298
+ );
48299
+ const isProductionReady = criticalErrors.length === 0 && validFiles.length > 0;
48300
+ return {
48301
+ validFiles,
48302
+ errors,
48303
+ warnings,
48304
+ qualityScore,
48305
+ isProductionReady
48306
+ };
48307
+ }
48308
+ async function calculateShipScore2(files, config) {
48309
+ const result = await validateAndSanitizeFiles(files, config);
48310
+ const issues = [
48311
+ ...result.errors.map((e) => `[ERROR] ${e.filePath}: ${e.message}`),
48312
+ ...result.warnings.map((w) => `[WARN] ${w.filePath}: ${w.message}`)
48313
+ ];
48314
+ let verdict;
48315
+ if (result.qualityScore >= 80 && result.isProductionReady) {
48316
+ verdict = "SHIP";
48317
+ } else if (result.qualityScore >= 60) {
48318
+ verdict = "WARN";
48319
+ } else {
48320
+ verdict = "BLOCK";
48321
+ }
48322
+ return {
48323
+ score: result.qualityScore,
48324
+ verdict,
48325
+ issues,
48326
+ isProductionReady: result.isProductionReady
48327
+ };
48328
+ }
46562
48329
  async function getCodeValidator(config) {
46563
48330
  if (!globalValidator) {
46564
48331
  globalValidator = new CodeValidator(config);
@@ -46573,8 +48340,8 @@ function getDriftDetector(config) {
46573
48340
  return globalDetector;
46574
48341
  }
46575
48342
  var DEFAULT_CONFIG11, BUILTIN_TYPES, WELLKNOWN_ENV, HallucinationDetector, SOURCE_RELIABILITY, DEFAULT_VERIFIER_CONFIG, DEFAULT_CALIBRATION_CONFIG, DEFAULT_CONFIG26, EvidenceChainBuilder, truthpackCache, truthpackVerifier, BUILTIN_MODULES2, packageJsonCache, packageJsonVerifier, filesystemVerifier, astVerifier, gitVerifier, typescriptVerifier, runtimeVerifier, ALL_VERIFIERS, DEFAULT_CONFIG35, ConfidenceCalibrator, globalCalibrator, DEFAULT_CONFIG45, VerificationEngine, globalEngine, DEFAULT_CONFIG55, MultiSourceVerifier, DEFAULT_CONFIG64, KNOWN_PACKAGES, HALLUCINATION_PATTERNS, SECURITY_PATTERNS2, CodeValidator, globalValidator, SAFETY_LIMITS2, DEFAULT_CONFIG73, ROUTE_FRAMEWORKS, DriftDetector, globalDetector;
46576
- var init_chunk_RPKCC72C = __esm({
46577
- "../../packages/core/dist/chunk-RPKCC72C.js"() {
48343
+ var init_chunk_WS67ECG2 = __esm({
48344
+ "../../packages/core/dist/chunk-WS67ECG2.js"() {
46578
48345
  init_chunk_A4CYIMGM();
46579
48346
  init_chunk_SKXQ6JUA();
46580
48347
  init_chunk_4EQXFW4J();
@@ -48682,16 +50449,38 @@ var init_chunk_RPKCC72C = __esm({
48682
50449
  { pattern: /return\s+(?:null|undefined|{});\s*\/\/\s*placeholder/gi, type: "invented_pattern" }
48683
50450
  ];
48684
50451
  SECURITY_PATTERNS2 = [
50452
+ // Critical: Code execution
48685
50453
  { pattern: /eval\s*\(/g, message: "Avoid eval() - it can execute arbitrary code", severity: "critical" },
48686
50454
  { pattern: /new\s+Function\s*\(/g, message: "Avoid new Function() - similar risks to eval()", severity: "critical" },
50455
+ { pattern: /\bsetTimeout\s*\(\s*["'`]/g, message: "setTimeout with string argument is dangerous", severity: "critical" },
50456
+ { pattern: /\bsetInterval\s*\(\s*["'`]/g, message: "setInterval with string argument is dangerous", severity: "critical" },
50457
+ // High: XSS and injection
48687
50458
  { pattern: /innerHTML\s*=/g, message: "innerHTML can lead to XSS - use textContent or sanitize", severity: "high" },
48688
50459
  { pattern: /document\.write\s*\(/g, message: "document.write is dangerous and deprecated", severity: "high" },
48689
50460
  { pattern: /dangerouslySetInnerHTML/g, message: "dangerouslySetInnerHTML can lead to XSS", severity: "medium" },
50461
+ { pattern: /\bchild_process\s*\.\s*exec\s*\(/g, message: "child_process.exec() can be dangerous - use execFile", severity: "high" },
50462
+ { pattern: /\bchild_process\s*\.\s*execSync\s*\(/g, message: "child_process.execSync() can be dangerous", severity: "high" },
50463
+ // Critical: Secrets
48690
50464
  { pattern: /(?:password|secret|api_key|apikey|token)\s*[:=]\s*['"`][^'"`]{8,}['"`]/gi, message: "Potential hardcoded secret detected", severity: "critical" },
50465
+ { pattern: /sk[-_](?:live|test)[-_][A-Za-z0-9]{20,}/g, message: "Stripe secret key detected", severity: "critical" },
50466
+ { pattern: /ghp_[A-Za-z0-9]{36,}/g, message: "GitHub personal access token detected", severity: "critical" },
50467
+ { pattern: /github_pat_[A-Za-z0-9_]{22,}/g, message: "GitHub fine-grained token detected", severity: "critical" },
50468
+ { pattern: /xox[baprs]-[A-Za-z0-9\-]{10,}/g, message: "Slack token detected", severity: "critical" },
50469
+ { pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g, message: "Private key detected in code", severity: "critical" },
50470
+ { pattern: /AKIA[A-Z0-9]{16}/g, message: "AWS access key detected", severity: "critical" },
50471
+ // Critical: Injection
48691
50472
  { pattern: /(?:SELECT|INSERT|UPDATE|DELETE).*\+.*(?:req\.|params\.|query\.)/gi, message: "Potential SQL injection - use parameterized queries", severity: "critical" },
48692
50473
  { pattern: /\$\{.*(?:req\.|params\.|query\.).*\}/g, message: "Template literal with user input - potential injection", severity: "high" },
48693
50474
  { pattern: /exec\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Command injection risk - sanitize input", severity: "critical" },
48694
- { pattern: /\.createReadStream\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Path traversal risk - validate file paths", severity: "high" }
50475
+ { pattern: /\.createReadStream\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Path traversal risk - validate file paths", severity: "high" },
50476
+ // High: Dynamic imports
50477
+ { pattern: /\brequire\s*\(\s*[^"'`\s]/g, message: "Dynamic require is dangerous", severity: "high" },
50478
+ { pattern: /\b__dirname\s*\+\s*[^"'`]/g, message: "Dynamic path construction can be dangerous", severity: "high" },
50479
+ { pattern: /from\s+["'`]https?:\/\//g, message: "HTTP import detected - use npm packages", severity: "high" },
50480
+ { pattern: /import\s*\(\s*["'`]https?:\/\//g, message: "Dynamic HTTP import detected", severity: "high" },
50481
+ // Medium: Destructive operations
50482
+ { pattern: /\bfs\s*\.\s*(?:unlink|rmdir|rm)Sync?\s*\(/g, message: "Destructive file operation detected", severity: "medium" },
50483
+ { pattern: /\bprocess\.exit\s*\(/g, message: "process.exit() detected - may cause unexpected termination", severity: "medium" }
48695
50484
  ];
48696
50485
  CodeValidator = class {
48697
50486
  config;
@@ -60529,6 +62318,7 @@ __export(dist_exports, {
60529
62318
  AdvancedContextManager: () => AdvancedContextManager,
60530
62319
  AdvancedScanner: () => AdvancedScanner,
60531
62320
  AgentFirewall: () => AgentFirewall,
62321
+ AllowlistManager: () => AllowlistManager,
60532
62322
  ArchitectAgent: () => ArchitectAgent,
60533
62323
  AuditLogger: () => AuditLogger,
60534
62324
  AuthDriftRule: () => AuthDriftRule,
@@ -60578,7 +62368,9 @@ __export(dist_exports, {
60578
62368
  ContextSync: () => ContextSync,
60579
62369
  ContextValidator: () => ContextValidator,
60580
62370
  ContractDriftRule: () => ContractDriftRule,
62371
+ ContractGenerator: () => ContractGenerator,
60581
62372
  ContractScanner: () => ContractScanner,
62373
+ ContractVerifier: () => ContractVerifier,
60582
62374
  ContractsSchema: () => ContractsSchema2,
60583
62375
  DARK_THEME_CSS: () => DARK_THEME_CSS,
60584
62376
  DARK_THEME_VARS: () => DARK_THEME_VARS,
@@ -60712,6 +62504,7 @@ __export(dist_exports, {
60712
62504
  MultiLevelCache: () => MultiLevelCache,
60713
62505
  MultiSourceVerifier: () => MultiSourceVerifier,
60714
62506
  NODE_TYPE_COLORS: () => NODE_TYPE_COLORS,
62507
+ ObserveModeManager: () => ObserveModeManager,
60715
62508
  Orchestrator: () => Orchestrator,
60716
62509
  PATTERNS: () => PATTERNS,
60717
62510
  PHASE_RULE_CONFIGS: () => PHASE_RULE_CONFIGS,
@@ -60784,7 +62577,10 @@ __export(dist_exports, {
60784
62577
  SkillsLoader: () => SkillsLoader,
60785
62578
  SsrfGuard: () => SsrfGuard,
60786
62579
  TEST_CONTEXT_PATTERNS: () => TEST_CONTEXT_PATTERNS,
62580
+ TIER_A_RULES: () => TIER_A_RULES,
62581
+ TIER_B_RULES: () => TIER_B_RULES,
60787
62582
  TIER_CONFIGS: () => TIER_CONFIGS,
62583
+ TIER_C_RULES: () => TIER_C_RULES,
60788
62584
  TIER_INFO: () => TIER_INFO,
60789
62585
  TOOL_NAME: () => TOOL_NAME,
60790
62586
  TOOL_URI: () => TOOL_URI,
@@ -60797,6 +62593,7 @@ __export(dist_exports, {
60797
62593
  TranslatorAssumption: () => TranslatorAssumption,
60798
62594
  TranslatorOutput: () => TranslatorOutput,
60799
62595
  TranslatorQuestion: () => TranslatorQuestion,
62596
+ TrustScorer: () => TrustScorer,
60800
62597
  TruthpackGenerator: () => TruthpackGenerator,
60801
62598
  TruthpackValidators: () => TruthpackValidators,
60802
62599
  UPGRADE_TRIGGERS: () => UPGRADE_TRIGGERS,
@@ -60857,7 +62654,6 @@ __export(dist_exports, {
60857
62654
  calculateScoreFromCounts: () => calculateScoreFromCounts,
60858
62655
  calculateScoreFromPassRate: () => calculateScoreFromPassRate,
60859
62656
  calculateSecurityScore: () => calculateSecurityScore,
60860
- calculateShipScore: () => calculateShipScore,
60861
62657
  calculateWorkerCount: () => calculateWorkerCount,
60862
62658
  checkCommandAccess: () => checkCommandAccess,
60863
62659
  checkConfig: () => checkConfig,
@@ -60889,6 +62685,7 @@ __export(dist_exports, {
60889
62685
  createActionClassifier: () => createActionClassifier,
60890
62686
  createAggressiveModeManager: () => createAggressiveModeManager,
60891
62687
  createAllowlistFix: () => createAllowlistFix,
62688
+ createAllowlistManager: () => createAllowlistManager,
60892
62689
  createBadgeGenerator: () => createBadgeGenerator,
60893
62690
  createBatchDetector: () => createBatchDetector,
60894
62691
  createCacheKey: () => createCacheKey,
@@ -60920,6 +62717,7 @@ __export(dist_exports, {
60920
62717
  createLearningStorage: () => createLearningStorage,
60921
62718
  createLearningSystem: () => createLearningSystem,
60922
62719
  createMissionGrouper: () => createMissionGrouper,
62720
+ createObserveModeManager: () => createObserveModeManager,
60923
62721
  createParallelAnalyzer: () => createParallelAnalyzer,
60924
62722
  createPluginLoader: () => createPluginLoader,
60925
62723
  createPluginManager: () => createPluginManager,
@@ -60943,6 +62741,7 @@ __export(dist_exports, {
60943
62741
  createSsrfGuard: () => createSsrfGuard,
60944
62742
  createTelemetryService: () => createTelemetryService,
60945
62743
  createTempFile: () => createTempFile,
62744
+ createTieredViolation: () => createTieredViolation,
60946
62745
  createTimeoutManager: () => createTimeoutManager,
60947
62746
  createUrlAllowlist: () => createUrlAllowlist,
60948
62747
  createVideoStorageService: () => createVideoStorageService,
@@ -60999,7 +62798,6 @@ __export(dist_exports, {
60999
62798
  findReferencedVariables: () => findReferencedVariables,
61000
62799
  findRelevantTemplates: () => findRelevantTemplates,
61001
62800
  findRunningServer: () => findRunningServer,
61002
- findSimilar: () => findSimilar2,
61003
62801
  findUnusedFunctions: () => findUnusedFunctions,
61004
62802
  findingToSarifResult: () => findingToSarifResult,
61005
62803
  fingerprint: () => fingerprint,
@@ -61017,6 +62815,7 @@ __export(dist_exports, {
61017
62815
  formatMetrics: () => formatMetrics,
61018
62816
  formatNumber: () => formatNumber,
61019
62817
  formatProgress: () => formatProgress,
62818
+ formatProofBundle: () => formatProofBundle,
61020
62819
  formatReceipt: () => formatReceipt,
61021
62820
  formatReceiptSummary: () => formatReceiptSummary,
61022
62821
  formatScanReport: () => formatScanReport,
@@ -61028,6 +62827,7 @@ __export(dist_exports, {
61028
62827
  formatTierBadge: () => formatTierBadge,
61029
62828
  formatUpgradePrompt: () => formatUpgradePrompt,
61030
62829
  formatVerdict: () => formatVerdict,
62830
+ formatViolationMessage: () => formatViolationMessage,
61031
62831
  gateFeature: () => gateFeature,
61032
62832
  generateAIContract: () => generateAIContract,
61033
62833
  generateAuditId: () => generateAuditId,
@@ -61055,6 +62855,7 @@ __export(dist_exports, {
61055
62855
  generatePRWorkflow: () => generatePRWorkflow,
61056
62856
  generatePdfBuffer: () => generatePdfBuffer,
61057
62857
  generatePdfReport: () => generatePdfReport,
62858
+ generateProofBundle: () => generateProofBundle,
61058
62859
  generateRealityCheckPdf: () => generateRealityCheckPdf,
61059
62860
  generateRealityCheckReport: () => generateRealityCheckReport,
61060
62861
  generateReceipt: () => generateReceipt,
@@ -61085,6 +62886,7 @@ __export(dist_exports, {
61085
62886
  getCheckpointAge: () => getCheckpointAge,
61086
62887
  getCircuitBreaker: () => getCircuitBreaker,
61087
62888
  getClaimExtractor: () => getClaimExtractor,
62889
+ getCodeValidator: () => getCodeValidator,
61088
62890
  getCommand: () => getCommand,
61089
62891
  getCommandsByCategory: () => getCommandsByCategory,
61090
62892
  getCommandsByTier: () => getCommandsByTier,
@@ -61191,6 +62993,7 @@ __export(dist_exports, {
61191
62993
  htmlToPdf: () => htmlToPdf,
61192
62994
  initTempCleanup: () => initTempCleanup,
61193
62995
  invalidateCache: () => invalidateCache,
62996
+ isAllowed: () => isAllowed,
61194
62997
  isBlockedIp: () => isBlockedIp,
61195
62998
  isCategoryRelevantForPhase: () => isCategoryRelevantForPhase,
61196
62999
  isConfidenceLevel: () => isConfidenceLevel,
@@ -61334,6 +63137,7 @@ __export(dist_exports, {
61334
63137
  runWithConcurrency: () => runWithConcurrency,
61335
63138
  runtimeVerifier: () => runtimeVerifier,
61336
63139
  sanitize: () => sanitize,
63140
+ sanitizeCode: () => sanitizeCode,
61337
63141
  sanitizeFilePath: () => sanitizeFilePath,
61338
63142
  sarifToJson: () => sarifToJson,
61339
63143
  scanCodeQuality: () => scanCodeQuality,
@@ -61380,6 +63184,7 @@ __export(dist_exports, {
61380
63184
  unregisterCommand: () => unregisterCommand,
61381
63185
  unregisterTempFile: () => unregisterTempFile,
61382
63186
  updateManifest: () => updateManifest,
63187
+ validateAndSanitizeFiles: () => validateAndSanitizeFiles,
61383
63188
  validateCallAgainstImports: () => validateCallAgainstImports,
61384
63189
  validateContract: () => validateContract,
61385
63190
  validateIssue: () => validateIssue,
@@ -61389,6 +63194,7 @@ __export(dist_exports, {
61389
63194
  validateRule: () => validateRule,
61390
63195
  validateTranslatorOutput: () => validateTranslatorOutput,
61391
63196
  verdictToBadgeStatus: () => verdictToBadgeStatus,
63197
+ verifyProofBundle: () => verifyProofBundle,
61392
63198
  verifyReceipt: () => verifyReceipt,
61393
63199
  verifyReceiptSignature: () => verifyReceiptSignature,
61394
63200
  visualizePath: () => visualizePath,
@@ -68210,24 +70016,25 @@ var init_dist3 = __esm({
68210
70016
  init_chunk_BQ2JBTLZ();
68211
70017
  init_chunk_DJEFLCF2();
68212
70018
  init_chunk_KVOEVY4C();
68213
- init_chunk_VCXA3YAU();
70019
+ init_chunk_GXXYXSWF();
68214
70020
  init_chunk_C6QLUUAJ();
68215
70021
  init_chunk_KCZC5WTF();
68216
70022
  init_chunk_HUPNY5JN();
68217
70023
  init_chunk_NUMYYREJ();
68218
70024
  init_chunk_2D2X5IRQ();
68219
70025
  init_chunk_F5SN54L7();
68220
- init_chunk_QJNHJVEI();
70026
+ init_chunk_GZFCACMG();
68221
70027
  init_chunk_3T7PUIDN();
68222
70028
  init_chunk_BXUMCGJG();
68223
70029
  init_chunk_ENJMGXRB();
68224
70030
  init_chunk_ENJMGXRB();
68225
70031
  init_chunk_VB6M3WM5();
68226
70032
  init_chunk_VB6M3WM5();
68227
- init_chunk_YK33YEF4();
70033
+ init_chunk_4MEEGNJS();
70034
+ init_chunk_4MEEGNJS();
68228
70035
  init_chunk_DFJL4MLU();
68229
- init_chunk_RPKCC72C();
68230
- init_chunk_RPKCC72C();
70036
+ init_chunk_WS67ECG2();
70037
+ init_chunk_WS67ECG2();
68231
70038
  init_chunk_A4CYIMGM();
68232
70039
  init_chunk_SKXQ6JUA();
68233
70040
  init_chunk_4EQXFW4J();
@@ -73864,6 +75671,8 @@ ${content}`;
73864
75671
  codeValidator = null;
73865
75672
  driftDetector = null;
73866
75673
  mockDetectorScanner = null;
75674
+ contractVerifier = null;
75675
+ truthpackGenerator = null;
73867
75676
  initialized = false;
73868
75677
  constructor(options) {
73869
75678
  this.options = { ...DEFAULT_OPTIONS7, ...options };
@@ -73931,6 +75740,28 @@ ${content}`;
73931
75740
  })()
73932
75741
  );
73933
75742
  }
75743
+ initPromises.push(
75744
+ (async () => {
75745
+ this.contractVerifier = new ContractVerifier({
75746
+ projectRoot: this.options.projectRoot,
75747
+ strict: false
75748
+ });
75749
+ await this.contractVerifier.loadContracts();
75750
+ this.truthpackGenerator = new TruthpackGenerator({
75751
+ projectRoot: this.options.projectRoot,
75752
+ outputDir: path18.join(this.options.projectRoot, ".vibecheck", "truthpack"),
75753
+ scanners: {
75754
+ routes: true,
75755
+ env: true,
75756
+ auth: true,
75757
+ contracts: true,
75758
+ uiGraph: false
75759
+ },
75760
+ watchMode: false,
75761
+ watchDebounceMs: 1e3
75762
+ });
75763
+ })()
75764
+ );
73934
75765
  await Promise.all(initPromises);
73935
75766
  this.initialized = true;
73936
75767
  const initTime = Date.now() - startTime;
@@ -74069,6 +75900,47 @@ ${content}`;
74069
75900
  error: mockDetection.summary.bySeverity.error
74070
75901
  });
74071
75902
  }
75903
+ let contractVerification;
75904
+ if (this.contractVerifier) {
75905
+ this.logger.debug("Starting contract verification");
75906
+ let truthpackContext;
75907
+ if (this.truthpackGenerator) {
75908
+ try {
75909
+ const truthpack = await this.truthpackGenerator.generate();
75910
+ truthpackContext = this.contractVerifier.createContext({
75911
+ routes: truthpack.routes,
75912
+ env: truthpack.env,
75913
+ auth: truthpack.auth
75914
+ });
75915
+ } catch {
75916
+ truthpackContext = this.contractVerifier.createContext();
75917
+ }
75918
+ }
75919
+ contractVerification = await this.contractVerifier.verifyAll(truthpackContext);
75920
+ for (const violation of contractVerification.violations) {
75921
+ findings.push({
75922
+ id: `contract-${violation.contractName}-${violation.behaviorName ?? "unknown"}-${violation.line ?? 0}`,
75923
+ type: this.mapViolationToType(violation.type),
75924
+ severity: violation.severity === "error" ? "error" : violation.severity === "warning" ? "warning" : "info",
75925
+ message: violation.message,
75926
+ file: violation.file,
75927
+ line: violation.line ?? null,
75928
+ column: violation.column ?? null,
75929
+ evidence: violation.evidence ?? [],
75930
+ confidence: violation.confidence ?? 0.7,
75931
+ verified: true,
75932
+ suggestion: violation.suggestion,
75933
+ autoFixable: violation.autoFixable,
75934
+ category: "hallucination"
75935
+ // Contract violations are potential hallucinations
75936
+ });
75937
+ }
75938
+ this.logger.debug("Contract verification complete", {
75939
+ verdict: contractVerification.verdict,
75940
+ violations: contractVerification.violations.length,
75941
+ coverage: contractVerification.coverage
75942
+ });
75943
+ }
74072
75944
  const durationMs = Date.now() - startTime;
74073
75945
  const metrics = {
74074
75946
  durationMs,
@@ -74460,6 +76332,16 @@ ${content}`;
74460
76332
  };
74461
76333
  return typeMap[category] ?? "invented_pattern";
74462
76334
  }
76335
+ mapViolationToType(violationType) {
76336
+ const typeMap = {
76337
+ "type_mismatch": "fake_type",
76338
+ "missing_field": "fake_type",
76339
+ "constraint_violation": "invented_pattern",
76340
+ "contract_drift": "type_drift",
76341
+ "unverified_behavior": "fake_api"
76342
+ };
76343
+ return typeMap[violationType] ?? "invented_pattern";
76344
+ }
74463
76345
  isAutoFixable(type) {
74464
76346
  const autoFixable = /* @__PURE__ */ new Set([
74465
76347
  "fake_import",
@@ -81358,10 +83240,10 @@ ${content}`;
81358
83240
  };
81359
83241
  }
81360
83242
  }
81361
- const isAllowed = this.config.allowedRoutes.some(
83243
+ const isAllowed2 = this.config.allowedRoutes.some(
81362
83244
  (pattern) => this.matchesPattern(pathname, pattern)
81363
83245
  );
81364
- if (!isAllowed) {
83246
+ if (!isAllowed2) {
81365
83247
  return {
81366
83248
  allowed: false,
81367
83249
  reason: "URL does not match any allowed pattern"
@@ -82349,11 +84231,13 @@ __export(scoring_exports, {
82349
84231
  createISLScorer: () => createISLScorer,
82350
84232
  createShipScoreCalculator: () => createShipScoreCalculator,
82351
84233
  determineVerdict: () => determineVerdict,
84234
+ formatProofBundle: () => formatProofBundle,
82352
84235
  formatScore: () => formatScore,
82353
84236
  formatScoreOutOf100: () => formatScoreOutOf100,
82354
84237
  formatScorePercent: () => formatScorePercent,
82355
84238
  formatShipScore: () => formatShipScore,
82356
84239
  formatVerdict: () => formatVerdict,
84240
+ generateProofBundle: () => generateProofBundle,
82357
84241
  getCategoryForEngine: () => getCategoryForEngine,
82358
84242
  getCategoryNames: () => getCategoryNames,
82359
84243
  getCategoryWeight: () => getCategoryWeight,
@@ -82364,11 +84248,12 @@ __export(scoring_exports, {
82364
84248
  getVerdictFromScore: () => getVerdictFromScore,
82365
84249
  islScorer: () => islScorer,
82366
84250
  shipScoreCalculator: () => shipScoreCalculator,
82367
- toSeverityCounts: () => toSeverityCounts
84251
+ toSeverityCounts: () => toSeverityCounts,
84252
+ verifyProofBundle: () => verifyProofBundle
82368
84253
  });
82369
84254
  var init_scoring = __esm({
82370
84255
  "../../packages/core/dist/scoring/index.js"() {
82371
- init_chunk_VCXA3YAU();
84256
+ init_chunk_GXXYXSWF();
82372
84257
  init_chunk_RRAR6G52();
82373
84258
  }
82374
84259
  });
@@ -82379,11 +84264,15 @@ __export(validation_exports, {
82379
84264
  CodeValidator: () => CodeValidator,
82380
84265
  DriftDetector: () => DriftDetector,
82381
84266
  HallucinationDetector: () => HallucinationDetector,
82382
- MultiSourceVerifier: () => MultiSourceVerifier
84267
+ MultiSourceVerifier: () => MultiSourceVerifier,
84268
+ calculateShipScore: () => calculateShipScore2,
84269
+ getCodeValidator: () => getCodeValidator,
84270
+ sanitizeCode: () => sanitizeCode,
84271
+ validateAndSanitizeFiles: () => validateAndSanitizeFiles
82383
84272
  });
82384
84273
  var init_validation = __esm({
82385
84274
  "../../packages/core/dist/validation/index.js"() {
82386
- init_chunk_RPKCC72C();
84275
+ init_chunk_WS67ECG2();
82387
84276
  init_chunk_A4CYIMGM();
82388
84277
  init_chunk_SKXQ6JUA();
82389
84278
  init_chunk_4EQXFW4J();
@@ -83183,7 +85072,7 @@ async function configureOutput(currentConfig) {
83183
85072
  }
83184
85073
 
83185
85074
  // src/lib/version.ts
83186
- var CLI_VERSION = "1.2.1" ;
85075
+ var CLI_VERSION = "1.2.2" ;
83187
85076
  var CLI_NAME = "vibecheck-ai" ;
83188
85077
 
83189
85078
  // src/ui/command-header.tsx
@@ -84439,11 +86328,6 @@ async function showLoginScreen() {
84439
86328
  label: "\u{1F4E7} " + chalk9.white("Email & Password"),
84440
86329
  hint: "Classic login"
84441
86330
  },
84442
- {
84443
- value: "github",
84444
- label: "\u{1F419} " + chalk9.white("Continue with GitHub"),
84445
- hint: "OAuth login"
84446
- },
84447
86331
  {
84448
86332
  value: "google",
84449
86333
  label: "\u{1F50D} " + chalk9.white("Continue with Google"),
@@ -84474,8 +86358,6 @@ async function showLoginScreen() {
84474
86358
  return await apiKeyLogin();
84475
86359
  case "email":
84476
86360
  return await emailLogin();
84477
- case "github":
84478
- return await oauthLogin("GitHub");
84479
86361
  case "google":
84480
86362
  return await oauthLogin("Google");
84481
86363
  case "magic":
@@ -84777,7 +86659,7 @@ async function signupFlow() {
84777
86659
  },
84778
86660
  {
84779
86661
  value: "pro",
84780
- label: "\u2B50 " + chalk9.yellow("Pro") + chalk9.dim(" - $29/dev/mo"),
86662
+ label: "\u2B50 " + chalk9.yellow("Pro") + chalk9.dim(" - $19/dev/mo"),
84781
86663
  hint: "Cloud sync, team collaboration, API access"
84782
86664
  },
84783
86665
  {
@@ -84837,7 +86719,7 @@ async function showLoginSuccess(session) {
84837
86719
  };
84838
86720
  const tierLabels = {
84839
86721
  free: "\u{1F193} Free",
84840
- pro: "\u2B50 Pro ($29/dev/mo)",
86722
+ pro: "\u2B50 Pro ($19/dev/mo)",
84841
86723
  enterprise: "\u{1F3E2} Enterprise"
84842
86724
  };
84843
86725
  console.log(" " + chalk9.dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
@@ -84920,6 +86802,10 @@ async function initializeFromCredentials() {
84920
86802
  function getCurrentTier() {
84921
86803
  return currentSession.tier;
84922
86804
  }
86805
+ async function getCurrentTierAsync() {
86806
+ await initializeFromCredentials();
86807
+ return currentSession.tier;
86808
+ }
84923
86809
  function isAuthenticated() {
84924
86810
  return currentSession.authenticated;
84925
86811
  }
@@ -84934,6 +86820,24 @@ var EXIT_CODES = {
84934
86820
  TIER_GATE: 10,
84935
86821
  INTERRUPTED: 130
84936
86822
  };
86823
+ async function checkEntitlements() {
86824
+ await initializeFromCredentials();
86825
+ const tier = getCurrentTier();
86826
+ const authenticated = isAuthenticated();
86827
+ return {
86828
+ isPro: tier === "pro" || tier === "enterprise",
86829
+ isEnterprise: tier === "enterprise",
86830
+ currentTier: tier,
86831
+ authenticated
86832
+ };
86833
+ }
86834
+ async function isPro() {
86835
+ await initializeFromCredentials();
86836
+ return currentSession.tier === "pro" || currentSession.tier === "enterprise";
86837
+ }
86838
+ function isProSync() {
86839
+ return currentSession.tier === "pro" || currentSession.tier === "enterprise";
86840
+ }
84937
86841
 
84938
86842
  // src/ui/upgrade-prompt.ts
84939
86843
  function renderUpgradePrompt(options) {
@@ -87241,60 +89145,16 @@ async function scanCommand(options) {
87241
89145
  const startTime = Date.now();
87242
89146
  const performanceTracker = getPerformanceTracker();
87243
89147
  const phaseTimings = {};
87244
- let quotaStatus = null;
87245
89148
  const scanStartTime = Date.now();
87246
89149
  try {
87247
89150
  validateOptions(options);
87248
89151
  checkSystemRequirements();
87249
89152
  const isAuth = await isAuthenticatedAsync();
87250
- if (!isAuth) {
89153
+ if (!isAuth && !options.quiet) {
87251
89154
  logger2.warn("");
87252
89155
  logger2.warn(chalk9.yellow("\u26A0\uFE0F Not authenticated - scan usage cannot be tracked."));
87253
- logger2.warn(chalk9.gray(" Run `vibecheck login` to authenticate and track your usage."));
87254
- logger2.warn(chalk9.gray(" Free tier: 5 scans/month | Pro tier: Unlimited scans"));
89156
+ logger2.warn(chalk9.gray(" Run `vibecheck login` to authenticate and sync to cloud."));
87255
89157
  logger2.warn("");
87256
- } else {
87257
- const quotaCheck = await checkScanAllowed();
87258
- if (!quotaCheck.success) {
87259
- if (quotaCheck.error?.code === "QUOTA_EXCEEDED") {
87260
- const details = quotaCheck.error.details;
87261
- logger2.error("");
87262
- logger2.error(chalk9.red("\u274C Scan quota exceeded!"));
87263
- logger2.error("");
87264
- logger2.error(chalk9.white(` You've used all ${details?.limit ?? 5} free scans this month.`));
87265
- if (details?.resetsAt) {
87266
- const resetDate = new Date(details.resetsAt);
87267
- logger2.error(chalk9.gray(` Quota resets: ${resetDate.toLocaleDateString()}`));
87268
- }
87269
- logger2.error("");
87270
- logger2.error(chalk9.cyan(" \u{1F680} Upgrade to Pro for unlimited scans:"));
87271
- logger2.error(chalk9.cyan(" https://vibecheckai.dev/pricing?action=checkout&plan=pro"));
87272
- logger2.error("");
87273
- process.exit(10);
87274
- } else if (quotaCheck.error?.code === "NETWORK_ERROR") {
87275
- logger2.warn("");
87276
- logger2.warn(chalk9.yellow("\u26A0\uFE0F Could not verify scan quota (offline mode)."));
87277
- logger2.warn(chalk9.gray(" Scan will proceed but usage may not be tracked."));
87278
- logger2.warn("");
87279
- } else {
87280
- logger2.warn("");
87281
- logger2.warn(chalk9.yellow(`\u26A0\uFE0F Quota check warning: ${quotaCheck.error?.message}`));
87282
- logger2.warn("");
87283
- }
87284
- } else if (quotaCheck.data) {
87285
- quotaStatus = quotaCheck.data;
87286
- if (quotaStatus.tier === "free" && quotaStatus.limit !== -1) {
87287
- const remaining = quotaStatus.remaining;
87288
- if (remaining <= 2) {
87289
- logger2.warn("");
87290
- logger2.warn(chalk9.yellow(`\u26A0\uFE0F ${formatQuotaMessage(quotaStatus)}`));
87291
- if (remaining <= 1) {
87292
- logger2.warn(chalk9.gray(" Upgrade to Pro for unlimited scans: vibecheck upgrade"));
87293
- }
87294
- logger2.warn("");
87295
- }
87296
- }
87297
- }
87298
89158
  }
87299
89159
  const configLoadStart = Date.now();
87300
89160
  let config;
@@ -87544,20 +89404,17 @@ async function scanCommand(options) {
87544
89404
  quiet: options.quiet,
87545
89405
  logger: logger2
87546
89406
  });
87547
- if (!options.json && !options.quiet && userTier === "free") {
89407
+ if (!options.json && !options.quiet && !isProSync()) {
87548
89408
  printForgeUpgradeSuggestion(userTier, logger2);
87549
89409
  }
87550
89410
  }
87551
89411
  if (await isAuthenticatedAsync()) {
87552
89412
  const scanDuration = Date.now() - scanStartTime;
87553
- const recordResult = await recordScan({
89413
+ await recordScan({
87554
89414
  scanType: "full",
87555
89415
  projectPath: process.cwd(),
87556
89416
  duration: scanDuration
87557
89417
  });
87558
- if (recordResult.success && recordResult.data) {
87559
- quotaStatus = recordResult.data;
87560
- }
87561
89418
  }
87562
89419
  if (options.json) {
87563
89420
  const commandResult = {
@@ -87645,34 +89502,7 @@ async function scanCommand(options) {
87645
89502
  logger2.dim(`Size: ${formatBytes(outputSize)}`);
87646
89503
  }
87647
89504
  logger2.dim(`Duration: ${formatDuration(results.duration)}`);
87648
- if (quotaStatus && quotaStatus.tier === "free" && quotaStatus.limit !== -1 && !options.quiet) {
87649
- logger2.newline();
87650
- const remaining = quotaStatus.remaining;
87651
- const used = quotaStatus.used;
87652
- const limit = quotaStatus.limit;
87653
- if (remaining === 0) {
87654
- console.log(colors.error("\u2501".repeat(50)));
87655
- console.log(`${chalk9.red("\u26A0")} ${chalk9.bold.red("No scans remaining this month")}`);
87656
- console.log(colors.error("\u2501".repeat(50)));
87657
- console.log("");
87658
- console.log(chalk9.white(` You've used all ${limit} free scans.`));
87659
- console.log("");
87660
- console.log(chalk9.cyan(" \u{1F680} Upgrade to Pro for unlimited scans:"));
87661
- console.log(chalk9.cyan(" vibecheck upgrade"));
87662
- console.log("");
87663
- } else if (remaining <= 2) {
87664
- console.log(colors.warning("\u2501".repeat(50)));
87665
- console.log(`${chalk9.yellow("\u26A1")} ${chalk9.bold(`${remaining} scan${remaining === 1 ? "" : "s"} remaining`)}`);
87666
- console.log(colors.warning("\u2501".repeat(50)));
87667
- console.log("");
87668
- console.log(chalk9.gray(` Used: ${used}/${limit} scans this month`));
87669
- console.log("");
87670
- console.log(chalk9.cyan(" Upgrade to Pro for unlimited scans: vibecheck upgrade"));
87671
- console.log("");
87672
- } else {
87673
- logger2.dim(`Scans remaining: ${remaining}/${limit} this month`);
87674
- }
87675
- } else if (!isAuthenticated() && !options.quiet) {
89505
+ if (!isAuthenticated() && !options.quiet) {
87676
89506
  logger2.newline();
87677
89507
  console.log(colors.primary("\u2501".repeat(50)));
87678
89508
  console.log(`${symbols.raw.star} ${chalk9.bold("Pro Features Available")}`);
@@ -88485,10 +90315,10 @@ function formatCategory(category) {
88485
90315
  };
88486
90316
  return categoryMap[category] || category;
88487
90317
  }
88488
- function renderFixCTA(hasFixableIssues, isPro = false) {
90318
+ function renderFixCTA(hasFixableIssues, isPro2 = false) {
88489
90319
  const lines = [];
88490
90320
  if (hasFixableIssues) {
88491
- if (isPro) {
90321
+ if (isPro2) {
88492
90322
  lines.push(chalk9.cyan("Fix these in 1 click: ") + chalk9.bold("vibecheck fix -i"));
88493
90323
  } else {
88494
90324
  lines.push(chalk9.cyan("Fix these in 1 click: ") + chalk9.bold("vibecheck fix -i"));
@@ -88677,7 +90507,7 @@ async function runQuickstartClean(projectRoot, showExplain) {
88677
90507
  console.log(` ${chalk9.cyan("\u2022")} Video replay viewer`);
88678
90508
  console.log(` ${chalk9.cyan("\u2022")} Chaos Agent for stress testing`);
88679
90509
  console.log("");
88680
- console.log(`${chalk9.dim("Start 3-day free trial:")} ${chalk9.cyan("vibecheck upgrade --trial")}`);
90510
+ console.log(`${chalk9.dim("Start 7-day free trial:")} ${chalk9.cyan("vibecheck upgrade --trial")}`);
88681
90511
  console.log("");
88682
90512
  console.log(chalk9.bold("Next step:"));
88683
90513
  console.log(` ${chalk9.cyan("vibecheck certify")} ${chalk9.dim("\u2014")} Get your first Ship Score`);
@@ -88946,7 +90776,7 @@ async function initCommand(options) {
88946
90776
  }
88947
90777
  try {
88948
90778
  const { TruthpackGenerator: TruthpackGenerator2 } = await Promise.resolve().then(() => (init_truthpack(), truthpack_exports));
88949
- const { calculateShipScore: calculateShipScore2, getTopFixableIssues: getTopFixableIssues2 } = await Promise.resolve().then(() => (init_scoring(), scoring_exports));
90779
+ const { calculateShipScore: calculateShipScore3, getTopFixableIssues: getTopFixableIssues2 } = await Promise.resolve().then(() => (init_scoring(), scoring_exports));
88950
90780
  const { DriftDetector: DriftDetector2 } = await Promise.resolve().then(() => (init_validation(), validation_exports));
88951
90781
  const scanStartTime = Date.now();
88952
90782
  const generator = new TruthpackGenerator2({
@@ -88976,7 +90806,7 @@ async function initCommand(options) {
88976
90806
  message: item.details,
88977
90807
  autoFixable: true
88978
90808
  }));
88979
- const score = calculateShipScore2({
90809
+ const score = calculateShipScore3({
88980
90810
  truthpack: {
88981
90811
  routes: truthpack.routes || [],
88982
90812
  env: truthpack.env?.map((e) => ({ name: e.name, required: e.required })) || [],
@@ -89126,13 +90956,12 @@ async function initCommand(options) {
89126
90956
  }
89127
90957
  console.log(JSON.stringify(jsonOutput, null, 2));
89128
90958
  } else if (quickModeResult) {
89129
- const userTier = getCurrentTier();
89130
90959
  console.log(renderQuickInitOutput(
89131
90960
  quickModeResult.score,
89132
90961
  quickModeResult.findings,
89133
90962
  duration,
89134
90963
  {
89135
- isPro: userTier === "pro" || userTier === "enterprise",
90964
+ isPro: isProSync(),
89136
90965
  projectPath: process.cwd()
89137
90966
  }
89138
90967
  ));
@@ -89175,11 +91004,9 @@ async function initCommand(options) {
89175
91004
  console.log(` ${symbols.info} ${instruction}`);
89176
91005
  }
89177
91006
  }
89178
- if (forgeResult?.ran) {
91007
+ if (forgeResult?.ran && !isProSync()) {
89179
91008
  const userTier = getCurrentTier();
89180
- if (userTier === "free") {
89181
- printForgeUpgradeSuggestion(userTier, logger2);
89182
- }
91009
+ printForgeUpgradeSuggestion(userTier, logger2);
89183
91010
  }
89184
91011
  }
89185
91012
  } catch (error) {
@@ -90814,10 +92641,9 @@ async function shipCommand(options) {
90814
92641
  }
90815
92642
  }
90816
92643
  if (ready && !options.quiet) {
90817
- const userTier = getCurrentTier();
90818
- const isPro = userTier === "pro" || userTier === "enterprise";
92644
+ const isPro2 = isProSync();
90819
92645
  logger2.newline();
90820
- if (isPro && isAuthenticated()) {
92646
+ if (isPro2 && isAuthenticated()) {
90821
92647
  console.log(`
90822
92648
  ${colors.primary("\u2501".repeat(50))}
90823
92649
  ${colors.success("\u2713")} ${chalk9.bold("Ship Badge Ready!")} ${colors.muted("(Pro Feature)")}
@@ -92236,8 +94062,7 @@ var DEFAULT_HTML_FILENAME = "vibecheck-report.html";
92236
94062
  var DEFAULT_PDF_FILENAME = "vibecheck-report.pdf";
92237
94063
  var PRO_REPORT_TYPES = ["executive-summary", "detailed-technical", "compliance"];
92238
94064
  function checkReportTierGate(options) {
92239
- const currentTier = getCurrentTier();
92240
- if (currentTier === "pro" || currentTier === "enterprise") {
94065
+ if (isProSync()) {
92241
94066
  return null;
92242
94067
  }
92243
94068
  if (options.type && PRO_REPORT_TYPES.includes(options.type)) {
@@ -93169,7 +94994,6 @@ function findProjectRootSync(startDir) {
93169
94994
  }
93170
94995
 
93171
94996
  // src/commands/forge.ts
93172
- init_credentials();
93173
94997
  function printForgeValue(logger2) {
93174
94998
  logger2.newline();
93175
94999
  logger2.info(chalk9.bold.magenta("What Forge Does For You:"));
@@ -93319,21 +95143,15 @@ var forgeCommand = new Command("forge").description("Generate AI context rules t
93319
95143
  logger2.error('Not in a VibeCheck project. Run "vibecheck init" first.');
93320
95144
  process.exit(1);
93321
95145
  }
93322
- let userTier = "free";
93323
- try {
93324
- const result = await loadCredentials();
93325
- if (result.valid && result.credentials) {
93326
- userTier = result.credentials.tier ?? "free";
93327
- }
93328
- } catch {
93329
- }
95146
+ const userTier = await getCurrentTierAsync();
93330
95147
  const tierConfig = options.tier ? { tier: options.tier, maxRules: getTierLimit(options.tier) } : getForgeConfigForTier(userTier);
93331
95148
  const platforms = options.platform === "both" ? ["cursor", "windsurf"] : [options.platform ?? "cursor"];
95149
+ const isPro2 = userTier === "pro" || userTier === "enterprise";
93332
95150
  const config = {
93333
95151
  tier: tierConfig.tier,
93334
95152
  maxRules: tierConfig.maxRules,
93335
95153
  incremental: options.incremental ?? true,
93336
- generateContract: options.contract ?? userTier !== "free",
95154
+ generateContract: options.contract ?? isPro2,
93337
95155
  verbose: globalOpts.verbose ?? false,
93338
95156
  platforms
93339
95157
  };
@@ -93353,12 +95171,13 @@ var forgeCommand = new Command("forge").description("Generate AI context rules t
93353
95171
  return;
93354
95172
  }
93355
95173
  printForgeStats(output, logger2, globalOpts.verbose ?? false);
93356
- if (userTier === "free") {
95174
+ if (!isPro2) {
93357
95175
  logger2.newline();
93358
95176
  logger2.info(chalk9.cyan("Tip: Upgrade to Pro for more rules and AI Contract"));
93359
95177
  logger2.dim(" - 20 rules instead of 5");
93360
95178
  logger2.dim(" - AI Contract with forbidden/required patterns");
93361
95179
  logger2.dim(" - Security, performance, and testing rules");
95180
+ logger2.dim(" Run: vibecheck upgrade");
93362
95181
  }
93363
95182
  logger2.newline();
93364
95183
  logger2.success("Forge complete! Your AI assistant now has accurate project context.");
@@ -93376,7 +95195,6 @@ function getTierLimit(tier) {
93376
95195
  };
93377
95196
  return limits[tier];
93378
95197
  }
93379
- init_credentials();
93380
95198
  var API_BASE = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
93381
95199
  function getBadgeUrl(projectId, style, verified) {
93382
95200
  const endpoint = verified ? "verified" : "svg";
@@ -93400,14 +95218,7 @@ async function badgeCommand(options) {
93400
95218
  json: options.json
93401
95219
  });
93402
95220
  const authenticated = isAuthenticated();
93403
- let isPro = false;
93404
- if (authenticated) {
93405
- const credResult = await loadCredentials();
93406
- if (credResult.success && credResult.credentials) {
93407
- const tier = credResult.credentials.user?.tier;
93408
- isPro = tier === "pro" || tier === "enterprise";
93409
- }
93410
- }
95221
+ const isPro2 = authenticated ? await isPro() : false;
93411
95222
  if (!options.json && !options.quiet) {
93412
95223
  safeRenderHeader({
93413
95224
  command: "badge",
@@ -93417,9 +95228,9 @@ async function badgeCommand(options) {
93417
95228
  vitals: [
93418
95229
  {
93419
95230
  label: "BADGE STATUS",
93420
- status: authenticated ? isPro ? "optimal" : "stable" : "warning",
93421
- value: isPro ? "Pro badges available" : "Basic badges",
93422
- percentage: isPro ? 100 : 50
95231
+ status: authenticated ? isPro2 ? "optimal" : "stable" : "warning",
95232
+ value: isPro2 ? "Pro badges available" : "Basic badges",
95233
+ percentage: isPro2 ? 100 : 50
93423
95234
  }
93424
95235
  ],
93425
95236
  diagnostics: [
@@ -93428,8 +95239,8 @@ async function badgeCommand(options) {
93428
95239
  message: authenticated ? "Authenticated" : "Not authenticated"
93429
95240
  },
93430
95241
  {
93431
- level: isPro ? "pass" : "info",
93432
- message: isPro ? "Verified badges enabled" : "Upgrade for verified badges"
95242
+ level: isPro2 ? "pass" : "info",
95243
+ message: isPro2 ? "Verified badges enabled" : "Upgrade for verified badges"
93433
95244
  }
93434
95245
  ]
93435
95246
  });
@@ -93484,7 +95295,7 @@ async function badgeCommand(options) {
93484
95295
  markdown: getMarkdownEmbed(projectId, style, false),
93485
95296
  html: getHtmlEmbed(projectId, style, false)
93486
95297
  },
93487
- verified: isPro ? {
95298
+ verified: isPro2 ? {
93488
95299
  url: getBadgeUrl(projectId, style, true),
93489
95300
  markdown: getMarkdownEmbed(projectId, style, true),
93490
95301
  html: getHtmlEmbed(projectId, style, true)
@@ -93500,14 +95311,14 @@ async function badgeCommand(options) {
93500
95311
  console.log("");
93501
95312
  console.log(chalk9.cyan(" " + badges.basic.markdown));
93502
95313
  console.log("");
93503
- if (isPro && badges.verified) {
95314
+ if (isPro2 && badges.verified) {
93504
95315
  console.log(chalk9.bold(" \u2705 Verified Badge ") + chalk9.dim("(Pro)"));
93505
95316
  console.log("");
93506
95317
  console.log(chalk9.dim(" Shows verified status with detailed score:"));
93507
95318
  console.log("");
93508
95319
  console.log(chalk9.cyan(" " + badges.verified.markdown));
93509
95320
  console.log("");
93510
- } else if (!isPro) {
95321
+ } else if (!isPro2) {
93511
95322
  console.log("");
93512
95323
  console.log(chalk9.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
93513
95324
  console.log("");
@@ -93544,7 +95355,7 @@ init_scoring();
93544
95355
  init_truthpack();
93545
95356
 
93546
95357
  // ../../packages/core/dist/firewall/index.js
93547
- init_chunk_YK33YEF4();
95358
+ init_chunk_4MEEGNJS();
93548
95359
  init_chunk_DFJL4MLU();
93549
95360
  init_chunk_SKXQ6JUA();
93550
95361
  init_chunk_4EQXFW4J();
@@ -93643,7 +95454,7 @@ async function certifyCommand(options) {
93643
95454
  result.verdict = result.score >= threshold ? "CERTIFIED" : result.score >= 70 ? "NEEDS_WORK" : "NOT_READY";
93644
95455
  result.passed = result.verdict === "CERTIFIED";
93645
95456
  result.duration = Date.now() - startTime;
93646
- result.proofBundlePath = await generateProofBundle(context, result, projectRoot);
95457
+ result.proofBundlePath = await generateProofBundle2(context, result, projectRoot);
93647
95458
  if (result.passed) {
93648
95459
  const outputDir = options.output ?? path18__default.join(projectRoot, ".vibecheck", "certification");
93649
95460
  result.certificatePath = await generateCertificate(context, result, outputDir);
@@ -94097,7 +95908,7 @@ function generateBadgeUrl(projectId, score) {
94097
95908
  const label = score >= 85 ? "certified" : "score";
94098
95909
  return `https://img.shields.io/badge/VibeCheck-${label}%20${score}%25-${color}`;
94099
95910
  }
94100
- async function generateProofBundle(context, result, projectRoot) {
95911
+ async function generateProofBundle2(context, result, projectRoot) {
94101
95912
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
94102
95913
  const bundleName = `proof_${timestamp}`;
94103
95914
  const proofsDir = path18__default.join(projectRoot, ".vibecheck", "proofs");
@@ -94348,22 +96159,25 @@ async function realityRunCommand(options) {
94348
96159
  const startTime = Date.now();
94349
96160
  const runId = nanoid(12);
94350
96161
  try {
94351
- const userTier = getCurrentTier();
94352
- if (userTier === "free") {
96162
+ const entitlements = await checkEntitlements();
96163
+ if (!entitlements.isPro) {
94353
96164
  if (options.json) {
94354
96165
  console.log(JSON.stringify({
94355
96166
  success: false,
94356
96167
  error: "Pro feature required",
94357
- message: "Reality Mode is a Pro feature. Upgrade to unlock runtime verification.",
94358
- upgradeUrl: "https://vibecheck.dev/pricing"
96168
+ code: "UPGRADE_REQUIRED",
96169
+ entitlement: "reality_mode",
96170
+ message: "Reality Mode requires Pro. Upgrade to unlock runtime verification.",
96171
+ upgradeUrl: "https://app.vibecheck.dev/checkout?plan=pro"
94359
96172
  }, null, 2));
94360
96173
  } else {
94361
96174
  logger2.error("");
94362
- logger2.error(colors.error(" Reality Mode is a Pro feature"));
96175
+ logger2.error(colors.error(" Reality Mode requires Pro"));
94363
96176
  logger2.error("");
94364
- logger2.error(colors.muted(" Runtime verification with proof bundles requires Pro tier."));
96177
+ logger2.error(colors.muted(" Runtime verification with proof bundles requires Pro."));
94365
96178
  logger2.error("");
94366
- logger2.error(colors.info(" Upgrade to Pro: https://vibecheck.dev/pricing"));
96179
+ logger2.error(colors.info(" Upgrade: vibecheck upgrade"));
96180
+ logger2.error(colors.info(" Or visit: https://app.vibecheck.dev/checkout?plan=pro"));
94367
96181
  logger2.error("");
94368
96182
  }
94369
96183
  process.exit(1);
@@ -95027,8 +96841,7 @@ async function findLatestProofBundle() {
95027
96841
  return bundles.length > 0 ? bundles[0].name : null;
95028
96842
  }
95029
96843
  async function openReplayViewer(bundlePath, runId, logger2, options) {
95030
- const currentTier = getCurrentTier();
95031
- const hasFull = currentTier === "pro" || currentTier === "enterprise";
96844
+ const hasFull = isProSync();
95032
96845
  if (!hasFull && !options.json) {
95033
96846
  console.log("");
95034
96847
  console.log(chalk9.cyan("\u2713") + " Replay viewer available");
@@ -95036,7 +96849,7 @@ async function openReplayViewer(bundlePath, runId, logger2, options) {
95036
96849
  console.log(chalk9.dim(" Free tier: Basic run summary"));
95037
96850
  console.log(chalk9.dim(" Pro tier: Full video + timeline + request trace"));
95038
96851
  console.log("");
95039
- console.log(chalk9.dim(` Upgrade: ${chalk9.cyan("https://app.vibecheckai.dev/upgrade")}`));
96852
+ console.log(chalk9.dim(` Upgrade: vibecheck upgrade`));
95040
96853
  console.log("");
95041
96854
  }
95042
96855
  const existingReport = path18__default.join(bundlePath, "report.html");