vent-hq 0.7.0 → 0.7.1

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
@@ -207,7 +207,7 @@ import { spawn } from "node:child_process";
207
207
  // ../relay-client/src/client.ts
208
208
  var RelayClient = class {
209
209
  controlWs = null;
210
- dataConnections = /* @__PURE__ */ new Map();
210
+ localConnections = /* @__PURE__ */ new Map();
211
211
  config;
212
212
  closed = false;
213
213
  handlers = /* @__PURE__ */ new Map();
@@ -234,6 +234,7 @@ var RelayClient = class {
234
234
  const controlUrl = `${wsBase}/relay/control?run_id=${this.config.runId}&token=${this.config.relayToken}`;
235
235
  return new Promise((resolve, reject) => {
236
236
  const ws = new WebSocket(controlUrl);
237
+ ws.binaryType = "arraybuffer";
237
238
  let configReceived = false;
238
239
  let settled = false;
239
240
  const settle = (fn) => {
@@ -283,26 +284,56 @@ var RelayClient = class {
283
284
  }
284
285
  async disconnect() {
285
286
  this.closed = true;
286
- for (const [connId, conn] of this.dataConnections) {
287
- conn.relay.close();
288
- conn.local.close();
289
- this.dataConnections.delete(connId);
287
+ for (const [connId, conn] of this.localConnections) {
288
+ if (conn.local.readyState !== WebSocket.CLOSED) conn.local.close();
289
+ this.localConnections.delete(connId);
290
290
  }
291
291
  if (this.controlWs) {
292
292
  this.controlWs.close();
293
293
  this.controlWs = null;
294
294
  }
295
295
  }
296
+ sendControlMessage(msg) {
297
+ if (this.controlWs?.readyState === WebSocket.OPEN) {
298
+ this.controlWs.send(JSON.stringify(msg));
299
+ }
300
+ }
301
+ sendBinaryFrame(connId, payload) {
302
+ if (!this.controlWs || this.controlWs.readyState !== WebSocket.OPEN) return;
303
+ const header = new Uint8Array(37);
304
+ header[0] = 1;
305
+ const connIdBytes = new TextEncoder().encode(connId);
306
+ header.set(connIdBytes, 1);
307
+ const frame = new Uint8Array(37 + payload.byteLength);
308
+ frame.set(header);
309
+ frame.set(payload, 37);
310
+ this.controlWs.send(frame);
311
+ }
296
312
  setupControlHandlers(ws) {
297
313
  ws.addEventListener("message", (event) => {
314
+ if (event.data instanceof ArrayBuffer) {
315
+ const data = new Uint8Array(event.data);
316
+ if (data.length < 37 || data[0] !== 1) return;
317
+ const connId = new TextDecoder().decode(data.subarray(1, 37));
318
+ const payload = data.subarray(37);
319
+ const conn = this.localConnections.get(connId);
320
+ if (conn?.local.readyState === WebSocket.OPEN) {
321
+ conn.local.send(payload);
322
+ }
323
+ return;
324
+ }
298
325
  try {
299
- const data = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
300
- const msg = JSON.parse(data);
326
+ const raw = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
327
+ const msg = JSON.parse(raw);
301
328
  if (msg.type === "config" && msg.env) {
302
329
  this._agentEnv = msg.env;
303
330
  this.emit("config_received");
304
331
  } else if (msg.type === "new_connection" && msg.conn_id) {
305
332
  this.handleNewConnection(msg.conn_id);
333
+ } else if (msg.type === "close" && msg.conn_id) {
334
+ const conn = this.localConnections.get(msg.conn_id);
335
+ if (conn?.local.readyState !== WebSocket.CLOSED) conn?.local.close();
336
+ this.localConnections.delete(msg.conn_id);
306
337
  } else if (msg.type === "run_complete") {
307
338
  this.emit("run_complete");
308
339
  }
@@ -319,47 +350,30 @@ var RelayClient = class {
319
350
  this.emit("error", new Error(ev.message ?? "WebSocket error"));
320
351
  });
321
352
  }
322
- async handleNewConnection(connId) {
353
+ handleNewConnection(connId) {
323
354
  const agentUrl = `ws://localhost:${this.config.agentPort}`;
324
- const wsBase = this.config.apiUrl.replace(/^http/, "ws");
325
- const dataUrl = `${wsBase}/relay/data?run_id=${this.config.runId}&conn_id=${connId}&token=${this.config.relayToken}`;
326
355
  try {
327
- const [localWs, relayWs] = await Promise.all([
328
- this.openWebSocket(agentUrl),
329
- this.openWebSocket(dataUrl)
330
- ]);
331
- localWs.addEventListener("message", (event) => {
332
- if (relayWs.readyState === WebSocket.OPEN) {
333
- relayWs.send(event.data);
334
- }
356
+ const localWs = new WebSocket(agentUrl);
357
+ localWs.binaryType = "arraybuffer";
358
+ localWs.addEventListener("open", () => {
359
+ this.sendControlMessage({ type: "open_ack", conn_id: connId });
360
+ this.localConnections.set(connId, { local: localWs, connId });
335
361
  });
336
- relayWs.addEventListener("message", (event) => {
337
- if (localWs.readyState === WebSocket.OPEN) {
338
- localWs.send(event.data);
339
- }
362
+ localWs.addEventListener("message", (event) => {
363
+ const payload = event.data instanceof ArrayBuffer ? new Uint8Array(event.data) : new TextEncoder().encode(event.data);
364
+ this.sendBinaryFrame(connId, payload);
340
365
  });
341
366
  const cleanup = () => {
342
367
  if (localWs.readyState !== WebSocket.CLOSED) localWs.close();
343
- if (relayWs.readyState !== WebSocket.CLOSED) relayWs.close();
344
- this.dataConnections.delete(connId);
368
+ this.localConnections.delete(connId);
369
+ this.sendControlMessage({ type: "close", conn_id: connId });
345
370
  };
346
371
  localWs.addEventListener("close", cleanup);
347
- relayWs.addEventListener("close", cleanup);
348
372
  localWs.addEventListener("error", cleanup);
349
- relayWs.addEventListener("error", cleanup);
350
- this.dataConnections.set(connId, { relay: relayWs, local: localWs, connId });
351
373
  } catch (err) {
352
- console.error(`[relay] Failed to establish connection ${connId}:`, err);
374
+ console.error(`[relay] Failed to connect local agent for ${connId}:`, err);
353
375
  }
354
376
  }
355
- openWebSocket(url) {
356
- return new Promise((resolve, reject) => {
357
- const ws = new WebSocket(url);
358
- ws.binaryType = "arraybuffer";
359
- ws.addEventListener("open", () => resolve(ws));
360
- ws.addEventListener("error", (ev) => reject(new Error(ev.message ?? `WS connect failed: ${url}`)));
361
- });
362
- }
363
377
  };
364
378
 
365
379
  // src/lib/relay.ts
@@ -6353,7 +6367,7 @@ async function main() {
6353
6367
  return 0;
6354
6368
  }
6355
6369
  if (command === "--version" || command === "-v") {
6356
- const pkg = await import("./package-HAMS4TVQ.mjs");
6370
+ const pkg = await import("./package-QCFQTJ7U.mjs");
6357
6371
  console.log(`vent-hq ${pkg.default.version}`);
6358
6372
  return 0;
6359
6373
  }
@@ -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.1",
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.0",
3
+ "version": "0.7.1",
4
4
  "type": "module",
5
5
  "description": "Vent CLI — CI/CD for voice AI agents",
6
6
  "bin": {