@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.
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -98
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -318
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -484
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -418
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -333
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -622
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -102
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -352
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -283
- package/bin/runners/lib/agent-firewall/interceptor/base.js +7 -3
- package/bin/runners/lib/engine/ast-cache.js +210 -210
- package/bin/runners/lib/engine/auth-extractor.js +211 -211
- package/bin/runners/lib/engine/billing-extractor.js +112 -112
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -100
- package/bin/runners/lib/engine/env-extractor.js +207 -207
- package/bin/runners/lib/engine/express-extractor.js +208 -208
- package/bin/runners/lib/engine/extractors.js +849 -849
- package/bin/runners/lib/engine/index.js +207 -207
- package/bin/runners/lib/engine/repo-index.js +514 -514
- package/bin/runners/lib/engine/types.js +124 -124
- package/bin/runners/runIntent.js +906 -906
- package/bin/runners/runPacks.js +2089 -2089
- package/bin/runners/runReality.js +178 -1
- package/bin/runners/runShield.js +1282 -1282
- package/mcp-server/handlers/index.ts +2 -2
- package/mcp-server/handlers/tool-handler.ts +47 -8
- package/mcp-server/lib/executor.ts +5 -5
- package/mcp-server/lib/index.ts +14 -4
- package/mcp-server/lib/sandbox.test.ts +4 -4
- package/mcp-server/lib/sandbox.ts +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/registry.test.ts +18 -12
- package/mcp-server/tsconfig.json +1 -0
- 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 (!
|
|
2230
|
+
if (!argsOrOpts.json && !argsOrOpts.quiet) {
|
|
2054
2231
|
const { formatRealityOutput } = require('./lib/reality-output');
|
|
2055
2232
|
|
|
2056
2233
|
// Build test results from findings
|