@vibecheckai/cli 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -98
  2. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -318
  3. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -484
  4. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -418
  5. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -333
  6. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -622
  7. package/bin/runners/lib/agent-firewall/intent/index.js +102 -102
  8. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -352
  9. package/bin/runners/lib/agent-firewall/intent/store.js +283 -283
  10. package/bin/runners/lib/agent-firewall/interceptor/base.js +7 -3
  11. package/bin/runners/lib/engine/ast-cache.js +210 -210
  12. package/bin/runners/lib/engine/auth-extractor.js +211 -211
  13. package/bin/runners/lib/engine/billing-extractor.js +112 -112
  14. package/bin/runners/lib/engine/enforcement-extractor.js +100 -100
  15. package/bin/runners/lib/engine/env-extractor.js +207 -207
  16. package/bin/runners/lib/engine/express-extractor.js +208 -208
  17. package/bin/runners/lib/engine/extractors.js +849 -849
  18. package/bin/runners/lib/engine/index.js +207 -207
  19. package/bin/runners/lib/engine/repo-index.js +514 -514
  20. package/bin/runners/lib/engine/types.js +124 -124
  21. package/bin/runners/runIntent.js +906 -906
  22. package/bin/runners/runPacks.js +2089 -2089
  23. package/bin/runners/runReality.js +178 -1
  24. package/bin/runners/runShield.js +1282 -1282
  25. package/mcp-server/handlers/index.ts +2 -2
  26. package/mcp-server/handlers/tool-handler.ts +47 -8
  27. package/mcp-server/lib/executor.ts +5 -5
  28. package/mcp-server/lib/index.ts +14 -4
  29. package/mcp-server/lib/sandbox.test.ts +4 -4
  30. package/mcp-server/lib/sandbox.ts +2 -2
  31. package/mcp-server/package.json +1 -1
  32. package/mcp-server/registry.test.ts +18 -12
  33. package/mcp-server/tsconfig.json +1 -0
  34. package/package.json +2 -1
@@ -1478,6 +1478,121 @@ function coverageFromTruthpack({ truthpack, visitedUrls }) {
1478
1478
  return { total, hit, percent: total ? Math.round((hit / total) * 100) : 0, missed: Array.from(uiPaths).filter(p => !visitedPaths.has(p)).slice(0, 50) };
1479
1479
  }
1480
1480
 
1481
+ // ═══════════════════════════════════════════════════════════════════════════════
1482
+ // REPLAY DATA BUILDERS (for API/dashboard)
1483
+ // ═══════════════════════════════════════════════════════════════════════════════
1484
+
1485
+ /**
1486
+ * Build timeline events from pass results for replay
1487
+ */
1488
+ function buildTimeline(anonPass, authPass) {
1489
+ const timeline = [];
1490
+ const baseTimestamp = Date.now();
1491
+
1492
+ // Add anon pass pages as timeline events
1493
+ if (anonPass?.pagesVisited) {
1494
+ for (let i = 0; i < anonPass.pagesVisited.length; i++) {
1495
+ const page = anonPass.pagesVisited[i];
1496
+ timeline.push({
1497
+ action: 'navigate',
1498
+ url: page.url,
1499
+ selector: null,
1500
+ timestamp: new Date(baseTimestamp + (i * 1000)).toISOString(),
1501
+ screenshot: null,
1502
+ pass: 'anon',
1503
+ status: page.status,
1504
+ });
1505
+ }
1506
+ }
1507
+
1508
+ // Add auth pass pages
1509
+ if (authPass?.pagesVisited) {
1510
+ const offset = (anonPass?.pagesVisited?.length || 0) * 1000;
1511
+ for (let i = 0; i < authPass.pagesVisited.length; i++) {
1512
+ const page = authPass.pagesVisited[i];
1513
+ timeline.push({
1514
+ action: 'navigate',
1515
+ url: page.url,
1516
+ selector: null,
1517
+ timestamp: new Date(baseTimestamp + offset + (i * 1000)).toISOString(),
1518
+ screenshot: null,
1519
+ pass: 'auth',
1520
+ status: page.status,
1521
+ });
1522
+ }
1523
+ }
1524
+
1525
+ return timeline;
1526
+ }
1527
+
1528
+ /**
1529
+ * Build network timeline from pass results
1530
+ */
1531
+ function buildNetworkTimeline(anonPass, authPass) {
1532
+ const network = [];
1533
+ const baseTimestamp = Date.now();
1534
+ let idx = 0;
1535
+
1536
+ // Extract network requests from page visits
1537
+ if (anonPass?.pagesVisited) {
1538
+ for (const page of anonPass.pagesVisited) {
1539
+ network.push({
1540
+ method: 'GET',
1541
+ url: page.url,
1542
+ status: page.status || 200,
1543
+ timestamp: new Date(baseTimestamp + (idx++ * 500)).toISOString(),
1544
+ });
1545
+ }
1546
+ }
1547
+
1548
+ // Add network errors as requests
1549
+ if (anonPass?.networkErrors) {
1550
+ for (const err of anonPass.networkErrors) {
1551
+ network.push({
1552
+ method: 'GET',
1553
+ url: err.url,
1554
+ status: 0,
1555
+ timestamp: new Date(baseTimestamp + (idx++ * 500)).toISOString(),
1556
+ error: err.failure,
1557
+ });
1558
+ }
1559
+ }
1560
+
1561
+ if (authPass?.networkErrors) {
1562
+ for (const err of authPass.networkErrors) {
1563
+ network.push({
1564
+ method: 'GET',
1565
+ url: err.url,
1566
+ status: 0,
1567
+ timestamp: new Date(baseTimestamp + (idx++ * 500)).toISOString(),
1568
+ error: err.failure,
1569
+ });
1570
+ }
1571
+ }
1572
+
1573
+ return network;
1574
+ }
1575
+
1576
+ /**
1577
+ * Build screenshots list from findings
1578
+ */
1579
+ function buildScreenshotsList(anonPass, authPass, root) {
1580
+ const screenshots = [];
1581
+ const allFindings = [...(anonPass?.findings || []), ...(authPass?.findings || [])];
1582
+
1583
+ for (const finding of allFindings) {
1584
+ if (finding.screenshot) {
1585
+ screenshots.push({
1586
+ url: finding.page || '',
1587
+ timestamp: new Date().toISOString(),
1588
+ path: finding.screenshot,
1589
+ });
1590
+ }
1591
+ }
1592
+
1593
+ return screenshots;
1594
+ }
1595
+
1481
1596
  // ═══════════════════════════════════════════════════════════════════════════════
1482
1597
  // FLAKINESS & STABILITY VERIFICATION
1483
1598
  // ═══════════════════════════════════════════════════════════════════════════════
@@ -2041,6 +2156,68 @@ async function runReality(argsOrOpts = {}) {
2041
2156
  fs.writeFileSync(path.join(latestDir, "last_reality.json"), JSON.stringify(report, null, 2), "utf8");
2042
2157
 
2043
2158
  const duration = Date.now() - startTime;
2159
+
2160
+ // ═══════════════════════════════════════════════════════════════════════════
2161
+ // SEND TO API (for dashboard replay)
2162
+ // ═══════════════════════════════════════════════════════════════════════════
2163
+
2164
+ // Build reality result for API (timeline, network, screenshots, deadUI, fakeSuccess)
2165
+ const realityResult = {
2166
+ timeline: buildTimeline(anonPass, authPass),
2167
+ network: buildNetworkTimeline(anonPass, authPass),
2168
+ screenshots: buildScreenshotsList(anonPass, authPass, root),
2169
+ deadUI: findings.filter(f => f.category === 'DeadUI').map((f, idx) => ({
2170
+ stepIndex: idx,
2171
+ selector: f.title || '',
2172
+ reason: f.reason || '',
2173
+ })),
2174
+ fakeSuccess: findings.filter(f => f.category === 'FakeResponse' || f.category === 'FakeDomain').map((f, idx) => ({
2175
+ stepIndex: idx,
2176
+ message: f.title || f.reason || '',
2177
+ actualStatus: 0, // Could be extracted from evidence
2178
+ })),
2179
+ };
2180
+
2181
+ // Try to send to API (non-blocking, doesn't fail the run)
2182
+ try {
2183
+ const { sendRunToApi, extractFindings, calculateScore } = require('../../packages/cli/dist/runtime/api-run-sender.js');
2184
+
2185
+ const runId = crypto.randomUUID ? crypto.randomUUID() : `reality-${Date.now()}`;
2186
+ const apiFindings = extractFindings ? extractFindings({ findings }) : findings.map(f => ({
2187
+ severity: f.severity?.toLowerCase() || 'medium',
2188
+ category: f.category || 'general',
2189
+ message: f.title || f.reason || 'Unknown issue',
2190
+ file: f.page,
2191
+ }));
2192
+
2193
+ const score = calculateScore ? calculateScore(verdict, apiFindings) : (verdict === 'SHIP' ? 100 : verdict === 'WARN' ? 50 : 0);
2194
+
2195
+ sendRunToApi({
2196
+ runId,
2197
+ command: 'reality',
2198
+ status: 'completed',
2199
+ verdict,
2200
+ score,
2201
+ exitCode: blocks ? 2 : warns ? 1 : 0,
2202
+ startTime: new Date(startTime).toISOString(),
2203
+ endTime: new Date().toISOString(),
2204
+ duration,
2205
+ projectPath: root,
2206
+ findings: apiFindings,
2207
+ metadata: {
2208
+ baseUrl,
2209
+ pagesVisited: anonPass.pagesVisited.length + (authPass?.pagesVisited?.length || 0),
2210
+ coverage: coverage?.percent,
2211
+ },
2212
+ realityResult,
2213
+ videoUrl: anonVideoPath ? path.relative(root, anonVideoPath).replace(/\\/g, "/") : undefined,
2214
+ traceUrl: anonTracePath ? path.relative(root, anonTracePath).replace(/\\/g, "/") : undefined,
2215
+ }).catch(() => {
2216
+ // Silently ignore API errors - CLI works offline
2217
+ });
2218
+ } catch (e) {
2219
+ // Module not available or other error - continue without API sync
2220
+ }
2044
2221
 
2045
2222
  // ═══════════════════════════════════════════════════════════════════════════
2046
2223
  // OUTPUT
@@ -2050,7 +2227,7 @@ async function runReality(argsOrOpts = {}) {
2050
2227
  const verdict = blocks > 0 ? 'BLOCK' : warns > 0 ? 'WARN' : 'SHIP';
2051
2228
 
2052
2229
  // Use Mission Control format
2053
- if (!opts.json && !opts.quiet) {
2230
+ if (!argsOrOpts.json && !argsOrOpts.quiet) {
2054
2231
  const { formatRealityOutput } = require('./lib/reality-output');
2055
2232
 
2056
2233
  // Build test results from findings