@rajat-rastogi/maestro 0.2.5 → 0.2.6

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.
@@ -507,56 +507,77 @@ class AgentConnectionPool {
507
507
  if (local) env.PATH = `${local}\\Microsoft\\WinGet\\Links;${env.PATH ?? ""}`;
508
508
  return env;
509
509
  }
510
- /** Get a ready WebSocket for tunnelId, spawning devtunnel connect if needed. */
510
+ /**
511
+ * Discover the WSS URL for a tunnel by running `devtunnel show`.
512
+ * Parses the port line to find the HTTPS URL, converts to WSS.
513
+ */
514
+ discoverWssUrl(tunnelId) {
515
+ console.log(`[AgentPool] discovering WSS URL for "${tunnelId}"...`);
516
+ const output = child_process.execSync(`devtunnel show ${tunnelId}`, {
517
+ encoding: "utf8",
518
+ env: this.wingetEnv(),
519
+ timeout: 1e4
520
+ });
521
+ const portLine = output.split("\n").find((l) => l.includes("9741") && l.includes("https://"));
522
+ if (!portLine) {
523
+ throw new Error(`No port 9741 URL found in devtunnel show output for "${tunnelId}"`);
524
+ }
525
+ const match = portLine.match(/https:\/\/[^\s]+/);
526
+ if (!match) {
527
+ throw new Error(`Could not parse URL from: ${portLine.trim()}`);
528
+ }
529
+ const wssUrl = match[0].replace("https://", "wss://").replace(/\/$/, "");
530
+ console.log(`[AgentPool] discovered: ${wssUrl}`);
531
+ return wssUrl;
532
+ }
533
+ /** Get a ready WebSocket for tunnelId, connecting via WSS URL. */
511
534
  async getConnection(tunnelId) {
512
535
  const existing = this.pool.get(tunnelId);
513
536
  if (existing) {
514
- if (existing.ready && existing.ws?.readyState === WebSocket.OPEN) {
537
+ if (existing.ready && existing.ws.readyState === WebSocket.OPEN) {
515
538
  return existing.ws;
516
539
  }
517
- console.log(`[AgentPool] getConnection: "${tunnelId}" — queuing (connection in progress)`);
518
- return new Promise((resolve) => existing.queue.push(resolve));
540
+ if (!existing.ready) {
541
+ console.log(`[AgentPool] getConnection: "${tunnelId}" — queuing (connection in progress)`);
542
+ return new Promise((resolve) => existing.queue.push(resolve));
543
+ }
544
+ this.pool.delete(tunnelId);
545
+ }
546
+ let wssUrl;
547
+ try {
548
+ wssUrl = this.discoverWssUrl(tunnelId);
549
+ } catch (err) {
550
+ console.log(`[AgentPool] getConnection failed: ${err instanceof Error ? err.message : String(err)}`);
551
+ throw err;
519
552
  }
520
- const entry = { proc: null, ws: null, ready: false, queue: [] };
553
+ const entry = { ws: null, wssUrl, ready: false, queue: [] };
521
554
  this.pool.set(tunnelId, entry);
522
- console.log(`[AgentPool] getConnection: spawning "devtunnel connect ${tunnelId}"...`);
523
- entry.proc = child_process.spawn("devtunnel", ["connect", tunnelId], { shell: true, env: this.wingetEnv() });
524
- entry.proc.stderr?.on("data", (data) => {
525
- console.log(`[AgentPool] devtunnel stderr: ${data.toString().trim()}`);
526
- });
527
- entry.proc.on("error", (err) => {
528
- console.log(`[AgentPool] devtunnel process error: ${err.message}`);
529
- this.teardown(tunnelId);
530
- });
531
- entry.proc.on("exit", (code) => {
532
- console.log(`[AgentPool] devtunnel exited with code ${code}`);
533
- this.teardown(tunnelId);
534
- });
535
- console.log(`[AgentPool] getConnection: waiting 4s for devtunnel to establish port forwarding...`);
536
- await new Promise((r) => setTimeout(r, 4e3));
537
- console.log(`[AgentPool] getConnection: opening WebSocket to ws://127.0.0.1:9741...`);
538
- const ws = new WebSocket("ws://127.0.0.1:9741");
555
+ console.log(`[AgentPool] getConnection: opening WebSocket to ${wssUrl}...`);
556
+ const ws = new WebSocket(wssUrl);
539
557
  entry.ws = ws;
540
558
  return new Promise((resolve, reject) => {
541
559
  ws.on("open", () => {
542
- console.log(`[AgentPool] getConnection: WebSocket connected to agent`);
560
+ console.log(`[AgentPool] getConnection: connected to agent via ${wssUrl}`);
543
561
  entry.ready = true;
544
562
  entry.queue.forEach((cb) => cb(ws));
545
563
  entry.queue = [];
546
564
  resolve(ws);
547
565
  });
548
566
  ws.on("error", (err) => {
549
- console.log(`[AgentPool] getConnection: WebSocket error: ${err.message}`);
567
+ console.log(`[AgentPool] WebSocket error for "${tunnelId}": ${err.message}`);
550
568
  this.teardown(tunnelId);
551
569
  reject(new Error(`Agent WebSocket error: ${err.message}`));
552
570
  });
553
- ws.on("close", () => this.teardown(tunnelId));
571
+ ws.on("close", () => {
572
+ console.log(`[AgentPool] WebSocket closed for "${tunnelId}"`);
573
+ this.teardown(tunnelId);
574
+ });
554
575
  });
555
576
  }
556
577
  /** Ping the agent via WebSocket, return true if pong received within 5s. */
557
578
  async ping(tunnelId) {
558
579
  try {
559
- console.log(`[AgentPool] ping: connecting to tunnel "${tunnelId}"...`);
580
+ console.log(`[AgentPool] ping: connecting to "${tunnelId}"...`);
560
581
  const ws = await this.getConnection(tunnelId);
561
582
  console.log(`[AgentPool] ping: connected, sending ping...`);
562
583
  return new Promise((resolve) => {
@@ -588,10 +609,6 @@ class AgentConnectionPool {
588
609
  teardown(tunnelId) {
589
610
  const entry = this.pool.get(tunnelId);
590
611
  if (entry) {
591
- try {
592
- entry.proc?.kill();
593
- } catch {
594
- }
595
612
  try {
596
613
  entry.ws?.close();
597
614
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rajat-rastogi/maestro",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Conduct your codebase — autonomous AI coding orchestrator",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",