vent-hq 0.8.2 → 0.8.3
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 +116 -59
- package/dist/package-ULWE2HB5.mjs +51 -0
- package/package.json +9 -9
- package/LICENSE +0 -21
package/dist/index.mjs
CHANGED
|
@@ -287,13 +287,17 @@ function printError(message) {
|
|
|
287
287
|
}
|
|
288
288
|
function printInfo(message, { force } = {}) {
|
|
289
289
|
if (!force && !isTTY && !_verbose) return;
|
|
290
|
-
|
|
291
|
-
|
|
290
|
+
const line = blue("\u25B8") + ` ${message}
|
|
291
|
+
`;
|
|
292
|
+
process.stderr.write(line);
|
|
293
|
+
if (!isTTY && force) stdoutSync(line);
|
|
292
294
|
}
|
|
293
295
|
function printSuccess(message, { force } = {}) {
|
|
294
296
|
if (!force && !isTTY && !_verbose) return;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
+
const line = green("\u2714") + ` ${message}
|
|
298
|
+
`;
|
|
299
|
+
process.stderr.write(line);
|
|
300
|
+
if (!isTTY && force) stdoutSync(line);
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
// src/lib/sse.ts
|
|
@@ -304,68 +308,109 @@ function log(msg) {
|
|
|
304
308
|
`;
|
|
305
309
|
process.stderr.write(line);
|
|
306
310
|
}
|
|
311
|
+
var MAX_RETRIES = 5;
|
|
312
|
+
var RETRY_DELAY_MS = 2e3;
|
|
307
313
|
async function* streamRunEvents(runId, apiKey, signal) {
|
|
308
314
|
const url = `${API_BASE}/runs/${runId}/stream`;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
315
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
316
|
+
let retries = 0;
|
|
317
|
+
while (retries <= MAX_RETRIES) {
|
|
318
|
+
if (retries > 0) {
|
|
319
|
+
log(`reconnecting (attempt ${retries}/${MAX_RETRIES}) after ${RETRY_DELAY_MS}ms\u2026`);
|
|
320
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
321
|
+
}
|
|
322
|
+
log(`connecting to ${url}`);
|
|
323
|
+
let res;
|
|
324
|
+
try {
|
|
325
|
+
res = await fetch(url, {
|
|
326
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
327
|
+
signal
|
|
328
|
+
});
|
|
329
|
+
} catch (err) {
|
|
330
|
+
if (err.name === "AbortError") throw err;
|
|
331
|
+
log(`fetch error: ${err.message}`);
|
|
332
|
+
retries++;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
log(`response: status=${res.status} content-type=${res.headers.get("content-type")}`);
|
|
336
|
+
if (!res.ok) {
|
|
337
|
+
const body = await res.text();
|
|
338
|
+
log(`error body: ${body}`);
|
|
339
|
+
throw new Error(`SSE stream failed (${res.status}): ${body}`);
|
|
340
|
+
}
|
|
341
|
+
if (!res.body) {
|
|
342
|
+
throw new Error("SSE stream returned no body");
|
|
343
|
+
}
|
|
344
|
+
const reader = res.body.getReader();
|
|
345
|
+
const decoder = new TextDecoder();
|
|
346
|
+
let buffer = "";
|
|
347
|
+
let chunkCount = 0;
|
|
348
|
+
let eventCount = 0;
|
|
349
|
+
let gotRunComplete = false;
|
|
350
|
+
let streamError = null;
|
|
351
|
+
try {
|
|
352
|
+
while (true) {
|
|
353
|
+
let readResult;
|
|
354
|
+
try {
|
|
355
|
+
readResult = await reader.read();
|
|
356
|
+
} catch (err) {
|
|
357
|
+
if (err.name === "AbortError") throw err;
|
|
358
|
+
streamError = err;
|
|
359
|
+
log(`read error: ${streamError.message}`);
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
const { done, value } = readResult;
|
|
363
|
+
if (done) {
|
|
364
|
+
log(`stream done after ${chunkCount} chunks, ${eventCount} events`);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
chunkCount++;
|
|
368
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
369
|
+
buffer += chunk;
|
|
370
|
+
if (chunkCount <= 3 || chunkCount % 10 === 0) {
|
|
371
|
+
log(`chunk #${chunkCount} (${chunk.length} bytes) buffer=${buffer.length} bytes`);
|
|
372
|
+
}
|
|
373
|
+
const lines = buffer.split("\n");
|
|
374
|
+
buffer = lines.pop();
|
|
375
|
+
for (const line of lines) {
|
|
376
|
+
if (line.startsWith("data: ")) {
|
|
377
|
+
const raw = line.slice(6);
|
|
378
|
+
try {
|
|
379
|
+
const event = JSON.parse(raw);
|
|
380
|
+
eventCount++;
|
|
381
|
+
if (event.id && seenIds.has(event.id)) {
|
|
382
|
+
log(`skipping duplicate event ${event.id}`);
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (event.id) seenIds.add(event.id);
|
|
386
|
+
log(`parsed event #${eventCount}: type=${event.event_type}`);
|
|
387
|
+
yield event;
|
|
388
|
+
if (event.event_type === "run_complete") {
|
|
389
|
+
log("run_complete received \u2014 closing stream");
|
|
390
|
+
gotRunComplete = true;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
} catch {
|
|
394
|
+
log(`malformed JSON: ${raw.slice(0, 200)}`);
|
|
395
|
+
}
|
|
396
|
+
} else if (line.startsWith(": ")) {
|
|
397
|
+
if (chunkCount <= 3) {
|
|
398
|
+
log(`heartbeat: "${line}"`);
|
|
354
399
|
}
|
|
355
|
-
} catch {
|
|
356
|
-
log(`malformed JSON: ${raw.slice(0, 200)}`);
|
|
357
|
-
}
|
|
358
|
-
} else if (line.startsWith(": ")) {
|
|
359
|
-
if (chunkCount <= 3) {
|
|
360
|
-
log(`heartbeat: "${line}"`);
|
|
361
400
|
}
|
|
362
401
|
}
|
|
363
402
|
}
|
|
403
|
+
} finally {
|
|
404
|
+
reader.releaseLock();
|
|
405
|
+
log("reader released");
|
|
406
|
+
}
|
|
407
|
+
if (gotRunComplete) return;
|
|
408
|
+
retries++;
|
|
409
|
+
if (retries <= MAX_RETRIES) {
|
|
410
|
+
log(`stream ended without run_complete \u2014 will retry (${retries}/${MAX_RETRIES})`);
|
|
364
411
|
}
|
|
365
|
-
} finally {
|
|
366
|
-
reader.releaseLock();
|
|
367
|
-
log("reader released");
|
|
368
412
|
}
|
|
413
|
+
log(`exhausted ${MAX_RETRIES} retries without run_complete`);
|
|
369
414
|
}
|
|
370
415
|
|
|
371
416
|
// src/lib/relay.ts
|
|
@@ -720,6 +765,17 @@ async function runCommand(args) {
|
|
|
720
765
|
}
|
|
721
766
|
debug(`filtered to test: ${args.test}`);
|
|
722
767
|
}
|
|
768
|
+
const cfgPlatform = config;
|
|
769
|
+
if (cfgPlatform.connection?.platform?.api_key_env && !cfgPlatform.connection.platform.api_key) {
|
|
770
|
+
const envName = cfgPlatform.connection.platform.api_key_env;
|
|
771
|
+
const resolved = process.env[envName];
|
|
772
|
+
if (!resolved) {
|
|
773
|
+
printError(`Platform API key not found: environment variable ${envName} is not set.`);
|
|
774
|
+
return 2;
|
|
775
|
+
}
|
|
776
|
+
cfgPlatform.connection.platform.api_key = resolved;
|
|
777
|
+
debug(`resolved platform API key from ${envName}`);
|
|
778
|
+
}
|
|
723
779
|
const cfg = config;
|
|
724
780
|
if (cfg.connection?.start_command) {
|
|
725
781
|
const freePort = await findFreePort();
|
|
@@ -5037,6 +5093,7 @@ var ToolCallMetricsSchema = external_exports.object({
|
|
|
5037
5093
|
var PlatformConfigSchema = external_exports.object({
|
|
5038
5094
|
provider: external_exports.enum(["vapi", "retell", "elevenlabs", "bland"]),
|
|
5039
5095
|
api_key_env: external_exports.string(),
|
|
5096
|
+
api_key: external_exports.string().optional(),
|
|
5040
5097
|
agent_id: external_exports.string().optional()
|
|
5041
5098
|
});
|
|
5042
5099
|
var AudioAnalysisGradeThresholdsSchema = external_exports.object({
|
|
@@ -6577,7 +6634,7 @@ async function main() {
|
|
|
6577
6634
|
return 0;
|
|
6578
6635
|
}
|
|
6579
6636
|
if (command === "--version" || command === "-v") {
|
|
6580
|
-
const pkg = await import("./package-
|
|
6637
|
+
const pkg = await import("./package-ULWE2HB5.mjs");
|
|
6581
6638
|
console.log(`vent-hq ${pkg.default.version}`);
|
|
6582
6639
|
return 0;
|
|
6583
6640
|
}
|
|
@@ -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.8.3",
|
|
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.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vent CLI — CI/CD for voice AI agents",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "node scripts/bundle.mjs",
|
|
14
|
+
"clean": "rm -rf dist"
|
|
15
|
+
},
|
|
12
16
|
"keywords": [
|
|
13
17
|
"vent",
|
|
14
18
|
"cli",
|
|
@@ -33,12 +37,8 @@
|
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
35
39
|
"@types/ws": "^8.5.0",
|
|
36
|
-
"
|
|
37
|
-
"@vent/
|
|
38
|
-
"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "node scripts/bundle.mjs",
|
|
42
|
-
"clean": "rm -rf dist"
|
|
40
|
+
"@vent/relay-client": "workspace:*",
|
|
41
|
+
"@vent/shared": "workspace:*",
|
|
42
|
+
"esbuild": "^0.24.0"
|
|
43
43
|
}
|
|
44
|
-
}
|
|
44
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Stephan Gazarov
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|