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 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
- process.stdout.write(JSON.stringify(event) + "\n");
465
+ stdoutSync(JSON.stringify(event) + "\n");
453
466
  return;
454
467
  }
455
468
  if (!isTTY) {
456
- process.stdout.write(JSON.stringify(event) + "\n");
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
- process.stdout.write(parts.join(" ") + "\n");
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
- process.stdout.write("\n");
521
+ stdoutSync("\n");
501
522
  if (status === "pass") {
502
- process.stdout.write(green(bold("Run passed")) + "\n");
523
+ stdoutSync(green(bold("Run passed")) + "\n");
503
524
  } else {
504
- process.stdout.write(red(bold("Run failed")) + "\n");
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
- process.stdout.write(parts.join(dim(" \xB7 ")) + "\n");
532
+ stdoutSync(parts.join(dim(" \xB7 ")) + "\n");
512
533
  }
513
534
  }
514
535
  function printSummary(testResults, runComplete, runId, jsonMode) {
515
- if (jsonMode) {
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
- const status = r?.status ?? meta.status;
554
- return status && status !== "completed" && status !== "pass";
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
- process.stdout.write("\n" + bold("Failed tests:") + "\n");
558
- for (const event of failures) {
559
- const meta = event.metadata_json ?? {};
560
- const r = meta.result;
561
- const name = r?.name ?? meta.test_name ?? "test";
562
- const durationMs = r?.duration_ms ?? meta.duration_ms;
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
- process.stdout.write(" " + parts.join(" ") + "\n");
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
- process.stdout.write(line);
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 && testResults.length > 0) {
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 isTTY2 = process.stdout.isTTY;
5375
- const bold2 = (s) => isTTY2 ? `\x1B[1m${s}\x1B[0m` : s;
5376
- const dim2 = (s) => isTTY2 ? `\x1B[2m${s}\x1B[0m` : s;
5377
- const green2 = (s) => isTTY2 ? `\x1B[32m${s}\x1B[0m` : s;
5378
- const red2 = (s) => isTTY2 ? `\x1B[31m${s}\x1B[0m` : 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-HCBRPLMU.mjs");
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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vent-hq",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "type": "module",
5
5
  "description": "Vent CLI — CI/CD for voice AI agents",
6
6
  "bin": {