vent-hq 0.7.5 → 0.7.7
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.mjs +80 -64
- package/dist/package-GMLASC6S.mjs +51 -0
- package/dist/package-PU7T6XCQ.mjs +51 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -66,6 +66,7 @@ import { parseArgs } from "node:util";
|
|
|
66
66
|
|
|
67
67
|
// src/commands/run.ts
|
|
68
68
|
import * as fs2 from "node:fs/promises";
|
|
69
|
+
import { writeFileSync as writeFileSync2 } from "node:fs";
|
|
69
70
|
import * as net from "node:net";
|
|
70
71
|
|
|
71
72
|
// src/lib/config.ts
|
|
@@ -441,7 +442,19 @@ async function waitForHealth(port, endpoint, timeoutMs = 3e4) {
|
|
|
441
442
|
}
|
|
442
443
|
|
|
443
444
|
// src/lib/output.ts
|
|
445
|
+
import { writeFileSync } from "node:fs";
|
|
444
446
|
var isTTY = process.stdout.isTTY;
|
|
447
|
+
function stdoutSync(data) {
|
|
448
|
+
if (isTTY) {
|
|
449
|
+
process.stdout.write(data);
|
|
450
|
+
} else {
|
|
451
|
+
try {
|
|
452
|
+
writeFileSync("/dev/stdout", data);
|
|
453
|
+
} catch {
|
|
454
|
+
process.stdout.write(data);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
445
458
|
var bold = (s) => isTTY ? `\x1B[1m${s}\x1B[0m` : s;
|
|
446
459
|
var dim = (s) => isTTY ? `\x1B[2m${s}\x1B[0m` : s;
|
|
447
460
|
var green = (s) => isTTY ? `\x1B[32m${s}\x1B[0m` : s;
|
|
@@ -449,11 +462,19 @@ var red = (s) => isTTY ? `\x1B[31m${s}\x1B[0m` : s;
|
|
|
449
462
|
var blue = (s) => isTTY ? `\x1B[34m${s}\x1B[0m` : s;
|
|
450
463
|
function printEvent(event, jsonMode) {
|
|
451
464
|
if (jsonMode) {
|
|
452
|
-
|
|
465
|
+
stdoutSync(JSON.stringify(event) + "\n");
|
|
453
466
|
return;
|
|
454
467
|
}
|
|
455
468
|
if (!isTTY) {
|
|
456
|
-
|
|
469
|
+
const meta2 = event.metadata_json ?? {};
|
|
470
|
+
if (event.event_type === "test_completed") {
|
|
471
|
+
const name = meta2.test_name ?? "test";
|
|
472
|
+
const status = meta2.status ?? "unknown";
|
|
473
|
+
const durationMs = meta2.duration_ms;
|
|
474
|
+
const duration = durationMs != null ? (durationMs / 1e3).toFixed(1) + "s" : "";
|
|
475
|
+
process.stderr.write(` ${status === "completed" || status === "pass" ? "\u2714" : "\u2718"} ${name} ${duration}
|
|
476
|
+
`);
|
|
477
|
+
}
|
|
457
478
|
return;
|
|
458
479
|
}
|
|
459
480
|
const meta = event.metadata_json ?? {};
|
|
@@ -487,7 +508,7 @@ function printTestResult(meta) {
|
|
|
487
508
|
if (result?.latency?.p50_ttfw_ms != null) {
|
|
488
509
|
parts.push(`p50: ${result.latency.p50_ttfw_ms}ms`);
|
|
489
510
|
}
|
|
490
|
-
|
|
511
|
+
stdoutSync(parts.join(" ") + "\n");
|
|
491
512
|
}
|
|
492
513
|
function printRunComplete(meta) {
|
|
493
514
|
const status = meta.status;
|
|
@@ -497,75 +518,58 @@ function printRunComplete(meta) {
|
|
|
497
518
|
const total = meta.total_tests ?? counts?.total;
|
|
498
519
|
const passed = meta.passed_tests ?? counts?.passed;
|
|
499
520
|
const failed = meta.failed_tests ?? counts?.failed;
|
|
500
|
-
|
|
521
|
+
stdoutSync("\n");
|
|
501
522
|
if (status === "pass") {
|
|
502
|
-
|
|
523
|
+
stdoutSync(green(bold("Run passed")) + "\n");
|
|
503
524
|
} else {
|
|
504
|
-
|
|
525
|
+
stdoutSync(red(bold("Run failed")) + "\n");
|
|
505
526
|
}
|
|
506
527
|
if (total != null) {
|
|
507
528
|
const parts = [];
|
|
508
529
|
if (passed) parts.push(green(`${passed} passed`));
|
|
509
530
|
if (failed) parts.push(red(`${failed} failed`));
|
|
510
531
|
parts.push(`${total} total`);
|
|
511
|
-
|
|
532
|
+
stdoutSync(parts.join(dim(" \xB7 ")) + "\n");
|
|
512
533
|
}
|
|
513
534
|
}
|
|
514
535
|
function printSummary(testResults, runComplete, runId, jsonMode) {
|
|
515
|
-
|
|
516
|
-
const failedTests = testResults.filter((e) => {
|
|
517
|
-
const meta = e.metadata_json ?? {};
|
|
518
|
-
const r = meta.result;
|
|
519
|
-
const status = r?.status ?? meta.status;
|
|
520
|
-
return status && status !== "completed" && status !== "pass";
|
|
521
|
-
}).map((e) => {
|
|
522
|
-
const meta = e.metadata_json ?? {};
|
|
523
|
-
const r = meta.result;
|
|
524
|
-
return {
|
|
525
|
-
name: r?.name ?? meta.test_name ?? "test",
|
|
526
|
-
status: r?.status ?? meta.status,
|
|
527
|
-
duration_ms: r?.duration_ms ?? meta.duration_ms,
|
|
528
|
-
intent_accuracy: r?.behavior?.intent_accuracy?.score,
|
|
529
|
-
p50_ttfw_ms: r?.latency?.p50_ttfw_ms
|
|
530
|
-
};
|
|
531
|
-
});
|
|
532
|
-
const agg = runComplete.aggregate;
|
|
533
|
-
const counts = agg?.red_team_tests ?? agg?.conversation_tests;
|
|
534
|
-
process.stdout.write(
|
|
535
|
-
JSON.stringify({
|
|
536
|
-
event_type: "summary",
|
|
537
|
-
data: {
|
|
538
|
-
run_id: runId,
|
|
539
|
-
status: runComplete.status,
|
|
540
|
-
total: runComplete.total_tests ?? counts?.total,
|
|
541
|
-
passed: runComplete.passed_tests ?? counts?.passed,
|
|
542
|
-
failed: runComplete.failed_tests ?? counts?.failed,
|
|
543
|
-
failed_tests: failedTests,
|
|
544
|
-
check: `npx vent-hq status ${runId} --json`
|
|
545
|
-
}
|
|
546
|
-
}) + "\n"
|
|
547
|
-
);
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
const failures = testResults.filter((e) => {
|
|
536
|
+
const allTests = testResults.map((e) => {
|
|
551
537
|
const meta = e.metadata_json ?? {};
|
|
552
538
|
const r = meta.result;
|
|
553
|
-
|
|
554
|
-
|
|
539
|
+
return {
|
|
540
|
+
name: r?.name ?? meta.test_name ?? "test",
|
|
541
|
+
status: r?.status ?? meta.status,
|
|
542
|
+
duration_ms: r?.duration_ms ?? meta.duration_ms,
|
|
543
|
+
intent_accuracy: r?.behavior?.intent_accuracy?.score,
|
|
544
|
+
p50_ttfw_ms: r?.latency?.p50_ttfw_ms,
|
|
545
|
+
error: r?.error ?? void 0
|
|
546
|
+
};
|
|
555
547
|
});
|
|
548
|
+
const agg = runComplete.aggregate;
|
|
549
|
+
const counts = agg?.red_team_tests ?? agg?.conversation_tests;
|
|
550
|
+
const summaryData = {
|
|
551
|
+
run_id: runId,
|
|
552
|
+
status: runComplete.status,
|
|
553
|
+
total: runComplete.total_tests ?? counts?.total,
|
|
554
|
+
passed: runComplete.passed_tests ?? counts?.passed,
|
|
555
|
+
failed: runComplete.failed_tests ?? counts?.failed,
|
|
556
|
+
tests: allTests,
|
|
557
|
+
check: `npx vent-hq status ${runId} --json`
|
|
558
|
+
};
|
|
559
|
+
if (jsonMode || !isTTY) {
|
|
560
|
+
stdoutSync(JSON.stringify(summaryData) + "\n");
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
const failures = allTests.filter((t2) => t2.status && t2.status !== "completed" && t2.status !== "pass");
|
|
556
564
|
if (failures.length > 0) {
|
|
557
|
-
|
|
558
|
-
for (const
|
|
559
|
-
const
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const duration = durationMs != null ? (durationMs / 1e3).toFixed(1) + "s" : "\u2014";
|
|
564
|
-
const parts = [red("\u2718"), bold(name), dim(duration)];
|
|
565
|
-
if (r?.behavior?.intent_accuracy) {
|
|
566
|
-
parts.push(`intent: ${r.behavior.intent_accuracy.score}`);
|
|
565
|
+
stdoutSync("\n" + bold("Failed tests:") + "\n");
|
|
566
|
+
for (const t2 of failures) {
|
|
567
|
+
const duration = t2.duration_ms != null ? (t2.duration_ms / 1e3).toFixed(1) + "s" : "\u2014";
|
|
568
|
+
const parts = [red("\u2718"), bold(t2.name), dim(duration)];
|
|
569
|
+
if (t2.intent_accuracy != null) {
|
|
570
|
+
parts.push(`intent: ${t2.intent_accuracy}`);
|
|
567
571
|
}
|
|
568
|
-
|
|
572
|
+
stdoutSync(" " + parts.join(" ") + "\n");
|
|
569
573
|
}
|
|
570
574
|
}
|
|
571
575
|
process.stderr.write(dim(`Full details: vent status ${runId} --json`) + "\n");
|
|
@@ -575,7 +579,7 @@ function printError(message) {
|
|
|
575
579
|
`;
|
|
576
580
|
process.stderr.write(line);
|
|
577
581
|
if (!isTTY) {
|
|
578
|
-
|
|
582
|
+
stdoutSync(line);
|
|
579
583
|
}
|
|
580
584
|
}
|
|
581
585
|
function printInfo(message) {
|
|
@@ -588,6 +592,7 @@ function printSuccess(message) {
|
|
|
588
592
|
}
|
|
589
593
|
|
|
590
594
|
// src/commands/run.ts
|
|
595
|
+
var isTTY2 = process.stdout.isTTY;
|
|
591
596
|
function log2(msg) {
|
|
592
597
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
593
598
|
process.stderr.write(`[vent ${ts}] ${msg}
|
|
@@ -760,8 +765,19 @@ async function runCommand(args) {
|
|
|
760
765
|
}
|
|
761
766
|
}
|
|
762
767
|
log2(`summary: testResults=${testResults.length} runComplete=${!!runCompleteData} exitCode=${exitCode}`);
|
|
763
|
-
if (runCompleteData
|
|
768
|
+
if (runCompleteData) {
|
|
764
769
|
printSummary(testResults, runCompleteData, run_id, args.json);
|
|
770
|
+
} else if (!isTTY2) {
|
|
771
|
+
try {
|
|
772
|
+
writeFileSync2("/dev/stdout", JSON.stringify({
|
|
773
|
+
run_id,
|
|
774
|
+
status: exitCode === 0 ? "pass" : "error",
|
|
775
|
+
error: "Stream ended without run_complete event",
|
|
776
|
+
check: `npx vent-hq status ${run_id} --json`
|
|
777
|
+
}) + "\n");
|
|
778
|
+
} catch {
|
|
779
|
+
process.stdout.write(JSON.stringify({ run_id, status: "error" }) + "\n");
|
|
780
|
+
}
|
|
765
781
|
}
|
|
766
782
|
log2(`exiting with code ${exitCode}`);
|
|
767
783
|
return exitCode;
|
|
@@ -5371,11 +5387,11 @@ async function statusCommand(args) {
|
|
|
5371
5387
|
if (status2 === "running" || status2 === "queued") {
|
|
5372
5388
|
printInfo(`Run ${args.runId}: ${status2} (${testCount} tests completed so far)`);
|
|
5373
5389
|
} else {
|
|
5374
|
-
const
|
|
5375
|
-
const bold2 = (s) =>
|
|
5376
|
-
const dim2 = (s) =>
|
|
5377
|
-
const green2 = (s) =>
|
|
5378
|
-
const red2 = (s) =>
|
|
5390
|
+
const isTTY3 = process.stdout.isTTY;
|
|
5391
|
+
const bold2 = (s) => isTTY3 ? `\x1B[1m${s}\x1B[0m` : s;
|
|
5392
|
+
const dim2 = (s) => isTTY3 ? `\x1B[2m${s}\x1B[0m` : s;
|
|
5393
|
+
const green2 = (s) => isTTY3 ? `\x1B[32m${s}\x1B[0m` : s;
|
|
5394
|
+
const red2 = (s) => isTTY3 ? `\x1B[31m${s}\x1B[0m` : s;
|
|
5379
5395
|
if (status2 === "pass") {
|
|
5380
5396
|
process.stdout.write(green2(bold2("Run passed")) + "\n");
|
|
5381
5397
|
} else {
|
|
@@ -6814,7 +6830,7 @@ async function main() {
|
|
|
6814
6830
|
return 0;
|
|
6815
6831
|
}
|
|
6816
6832
|
if (command === "--version" || command === "-v") {
|
|
6817
|
-
const pkg = await import("./package-
|
|
6833
|
+
const pkg = await import("./package-PU7T6XCQ.mjs");
|
|
6818
6834
|
console.log(`vent-hq ${pkg.default.version}`);
|
|
6819
6835
|
return 0;
|
|
6820
6836
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-U4M3XDTH.mjs";
|
|
3
|
+
|
|
4
|
+
// package.json
|
|
5
|
+
var package_default = {
|
|
6
|
+
name: "vent-hq",
|
|
7
|
+
version: "0.7.6",
|
|
8
|
+
type: "module",
|
|
9
|
+
description: "Vent CLI \u2014 CI/CD for voice AI agents",
|
|
10
|
+
bin: {
|
|
11
|
+
"vent-hq": "dist/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
files: [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
scripts: {
|
|
17
|
+
build: "node scripts/bundle.mjs",
|
|
18
|
+
clean: "rm -rf dist"
|
|
19
|
+
},
|
|
20
|
+
keywords: [
|
|
21
|
+
"vent",
|
|
22
|
+
"cli",
|
|
23
|
+
"voice",
|
|
24
|
+
"agent",
|
|
25
|
+
"testing",
|
|
26
|
+
"ci-cd"
|
|
27
|
+
],
|
|
28
|
+
license: "MIT",
|
|
29
|
+
publishConfig: {
|
|
30
|
+
access: "public"
|
|
31
|
+
},
|
|
32
|
+
repository: {
|
|
33
|
+
type: "git",
|
|
34
|
+
url: "https://github.com/vent-hq/vent",
|
|
35
|
+
directory: "packages/cli"
|
|
36
|
+
},
|
|
37
|
+
homepage: "https://ventmcp.dev",
|
|
38
|
+
dependencies: {
|
|
39
|
+
"@clack/prompts": "^1.1.0",
|
|
40
|
+
ws: "^8.18.0"
|
|
41
|
+
},
|
|
42
|
+
devDependencies: {
|
|
43
|
+
"@types/ws": "^8.5.0",
|
|
44
|
+
"@vent/relay-client": "workspace:*",
|
|
45
|
+
"@vent/shared": "workspace:*",
|
|
46
|
+
esbuild: "^0.24.0"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
package_default as default
|
|
51
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-U4M3XDTH.mjs";
|
|
3
|
+
|
|
4
|
+
// package.json
|
|
5
|
+
var package_default = {
|
|
6
|
+
name: "vent-hq",
|
|
7
|
+
version: "0.7.7",
|
|
8
|
+
type: "module",
|
|
9
|
+
description: "Vent CLI \u2014 CI/CD for voice AI agents",
|
|
10
|
+
bin: {
|
|
11
|
+
"vent-hq": "dist/index.mjs"
|
|
12
|
+
},
|
|
13
|
+
files: [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
scripts: {
|
|
17
|
+
build: "node scripts/bundle.mjs",
|
|
18
|
+
clean: "rm -rf dist"
|
|
19
|
+
},
|
|
20
|
+
keywords: [
|
|
21
|
+
"vent",
|
|
22
|
+
"cli",
|
|
23
|
+
"voice",
|
|
24
|
+
"agent",
|
|
25
|
+
"testing",
|
|
26
|
+
"ci-cd"
|
|
27
|
+
],
|
|
28
|
+
license: "MIT",
|
|
29
|
+
publishConfig: {
|
|
30
|
+
access: "public"
|
|
31
|
+
},
|
|
32
|
+
repository: {
|
|
33
|
+
type: "git",
|
|
34
|
+
url: "https://github.com/vent-hq/vent",
|
|
35
|
+
directory: "packages/cli"
|
|
36
|
+
},
|
|
37
|
+
homepage: "https://ventmcp.dev",
|
|
38
|
+
dependencies: {
|
|
39
|
+
"@clack/prompts": "^1.1.0",
|
|
40
|
+
ws: "^8.18.0"
|
|
41
|
+
},
|
|
42
|
+
devDependencies: {
|
|
43
|
+
"@types/ws": "^8.5.0",
|
|
44
|
+
"@vent/relay-client": "workspace:*",
|
|
45
|
+
"@vent/shared": "workspace:*",
|
|
46
|
+
esbuild: "^0.24.0"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
package_default as default
|
|
51
|
+
};
|