@wrongstack/acp 0.296.3 → 0.297.0

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.js CHANGED
@@ -916,6 +916,14 @@ var ClientTransport = class {
916
916
  ]);
917
917
  return new Promise((resolve3, reject) => {
918
918
  const timeout = setTimeout(() => {
919
+ const child2 = this.child;
920
+ this.child = null;
921
+ if (child2) {
922
+ try {
923
+ treeKill(child2);
924
+ } catch {
925
+ }
926
+ }
919
927
  reject(
920
928
  new Error(`ACP child process failed to start within ${this.opts.handshakeTimeoutMs}ms`)
921
929
  );
@@ -2014,7 +2022,12 @@ var WebSocketClientTransport = class {
2014
2022
  this.maxBufferedBytes = finitePositiveLimit(opts.maxBufferedBytes, 32 * 1024 * 1024);
2015
2023
  this.maxMessageChars = finitePositiveLimit(opts.maxMessageChars, 20 * 1024 * 1024);
2016
2024
  }
2025
+ /** Pending start() promise resolve/reject — settled in stop() to avoid leaking. */
2026
+ pendingStart = null;
2017
2027
  start() {
2028
+ if (this.closed || this.ws !== null || this.pendingStart !== null) {
2029
+ return Promise.reject(new Error("WebSocket transport has already been started or stopped"));
2030
+ }
2018
2031
  const WS = globalThis.WebSocket;
2019
2032
  if (!WS) {
2020
2033
  return Promise.reject(
@@ -2025,35 +2038,45 @@ var WebSocketClientTransport = class {
2025
2038
  }
2026
2039
  const timeoutMs = this.opts.handshakeTimeoutMs ?? 3e4;
2027
2040
  return new Promise((resolve3, reject) => {
2028
- let settled = false;
2029
2041
  const ws = new WS(this.opts.url, this.opts.protocols);
2030
2042
  this.ws = ws;
2031
2043
  const timer = setTimeout(() => {
2032
- settled = true;
2044
+ const pending = this.pendingStart;
2045
+ if (pending === null) return;
2046
+ this.pendingStart = null;
2033
2047
  try {
2034
2048
  ws.close();
2035
2049
  } catch {
2036
2050
  }
2037
- reject(new Error(`WebSocket failed to open within ${timeoutMs}ms`));
2051
+ pending.reject(new Error(`WebSocket failed to open within ${timeoutMs}ms`));
2038
2052
  }, timeoutMs);
2053
+ this.pendingStart = { resolve: resolve3, reject, timer };
2039
2054
  ws.addEventListener("open", () => {
2040
- if (settled) return;
2041
- settled = true;
2042
- clearTimeout(timer);
2043
- resolve3();
2055
+ const pending = this.pendingStart;
2056
+ if (pending === null) return;
2057
+ this.pendingStart = null;
2058
+ clearTimeout(pending.timer);
2059
+ pending.resolve();
2044
2060
  });
2045
2061
  ws.addEventListener("error", (ev) => {
2046
- if (settled) {
2062
+ const pending = this.pendingStart;
2063
+ if (pending === null) {
2047
2064
  this.closed = true;
2048
2065
  return;
2049
2066
  }
2050
- settled = true;
2051
- clearTimeout(timer);
2067
+ this.pendingStart = null;
2068
+ clearTimeout(pending.timer);
2052
2069
  const message = ev && typeof ev === "object" && "message" in ev ? String(ev.message) : "WebSocket error";
2053
- reject(new Error(message));
2070
+ pending.reject(new Error(message));
2054
2071
  });
2055
2072
  ws.addEventListener("close", () => {
2056
2073
  this.closed = true;
2074
+ const pending = this.pendingStart;
2075
+ if (pending !== null) {
2076
+ this.pendingStart = null;
2077
+ clearTimeout(pending.timer);
2078
+ pending.reject(new Error("WebSocket closed before the connection opened"));
2079
+ }
2057
2080
  });
2058
2081
  ws.addEventListener("message", (ev) => {
2059
2082
  this.onData(ev.data);
@@ -2083,6 +2106,15 @@ var WebSocketClientTransport = class {
2083
2106
  }
2084
2107
  stop() {
2085
2108
  this.closed = true;
2109
+ if (this.pendingStart !== null) {
2110
+ const pending = this.pendingStart;
2111
+ this.pendingStart = null;
2112
+ clearTimeout(pending.timer);
2113
+ try {
2114
+ pending.reject(new Error("WebSocket transport stopped while connecting"));
2115
+ } catch {
2116
+ }
2117
+ }
2086
2118
  if (this.ws) {
2087
2119
  try {
2088
2120
  this.ws.close();
@@ -2495,7 +2527,15 @@ var ACPSession = class _ACPSession {
2495
2527
  if (opts.env !== void 0) transportOpts.env = opts.env;
2496
2528
  if (opts.cwd !== void 0) transportOpts.cwd = opts.cwd;
2497
2529
  const transport = new ClientTransport(transportOpts);
2498
- return _ACPSession.attach(opts, transport, `failed to spawn ${opts.command}`);
2530
+ try {
2531
+ return await _ACPSession.attach(opts, transport, `failed to spawn ${opts.command}`);
2532
+ } catch (err) {
2533
+ try {
2534
+ transport.stop();
2535
+ } catch {
2536
+ }
2537
+ throw err;
2538
+ }
2499
2539
  }
2500
2540
  /**
2501
2541
  * Connect to a REMOTE ACP agent over a WebSocket instead of spawning a