ada-agent 0.6.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ada-agent",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "A from-zero terminal coding agent with a Cursor-style routing backend, ~285 skills, MCP connectors, and ask/plan/auto modes",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,13 +30,22 @@ export function healthUrl(backendUrl: string): string {
30
30
  }
31
31
  }
32
32
 
33
- async function probe(url: string, timeoutMs = 800): Promise<boolean> {
34
- try {
35
- const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
36
- return res.ok;
37
- } catch {
38
- return false;
39
- }
33
+ // Plain node:http with agent:false, NOT fetch: undici's keep-alive socket from a probe lingers into
34
+ // process teardown and deterministically prints "Assertion failed: !(handle->flags &
35
+ // UV_HANDLE_CLOSING)" on Windows at exit. agent:false closes the socket with the response.
36
+ function probe(url: string, timeoutMs = 800): Promise<boolean> {
37
+ return new Promise((resolve) => {
38
+ import("node:http")
39
+ .then((http) => {
40
+ const req = http.get(url, { agent: false, timeout: timeoutMs }, (res) => {
41
+ res.resume(); // drain so the socket can close
42
+ resolve((res.statusCode ?? 500) < 400);
43
+ });
44
+ req.on("timeout", () => req.destroy());
45
+ req.on("error", () => resolve(false));
46
+ })
47
+ .catch(() => resolve(false));
48
+ });
40
49
  }
41
50
 
42
51
  /** Resolved path to bin/ada-server.mjs (sibling of bin/ada.mjs, packaged in the npm tarball). */
@@ -99,14 +99,21 @@ export function formatFile(abs: string): boolean {
99
99
  }
100
100
 
101
101
  // node-pty gives the bash tool a real terminal. It's a required dependency; if the native build is
102
- // ever broken on a platform, fall back to spawnSync so bash still works.
103
- const pty: typeof PtyType | null = (() => {
104
- try {
105
- return createRequire(import.meta.url)("node-pty") as typeof PtyType;
106
- } catch {
107
- return null;
102
+ // ever broken on a platform, fall back to spawnSync so bash still works. Loaded LAZILY on the first
103
+ // bash call: merely loading the native module on Windows sets up async handles whose teardown races
104
+ // process.exit and prints "Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)" — commands that
105
+ // never spawn a PTY (--version, catalog, --list-models, …) shouldn't pay that.
106
+ let ptyMod: typeof PtyType | null | undefined;
107
+ function getPty(): typeof PtyType | null {
108
+ if (ptyMod === undefined) {
109
+ try {
110
+ ptyMod = createRequire(import.meta.url)("node-pty") as typeof PtyType;
111
+ } catch {
112
+ ptyMod = null;
113
+ }
108
114
  }
109
- })();
115
+ return ptyMod;
116
+ }
110
117
 
111
118
  // Built via new RegExp (string escapes) so no literal ESC/BEL bytes live in the source.
112
119
  const ANSI = new RegExp("[\\u001B\\u009B][\\[\\]()#;?]*(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007|(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])", "g");
@@ -120,7 +127,7 @@ function runPty(command: string, timeoutMs = 120_000): Promise<{ output: string;
120
127
  const win = process.platform === "win32";
121
128
  const shell = win ? process.env.COMSPEC ?? "cmd.exe" : process.env.SHELL ?? "/bin/bash";
122
129
  const shellArgs = win ? ["/c", command] : ["-lc", command];
123
- const p = pty!.spawn(shell, shellArgs, { name: "xterm-256color", cols: 120, rows: 30, cwd: process.cwd(), env: process.env as Record<string, string> });
130
+ const p = getPty()!.spawn(shell, shellArgs, { name: "xterm-256color", cols: 120, rows: 30, cwd: process.cwd(), env: process.env as Record<string, string> });
124
131
  let out = "";
125
132
  const cap = 10 * 1024 * 1024;
126
133
  p.onData((d) => {
@@ -360,7 +367,7 @@ export const tools: Tool[] = [
360
367
  needsApproval: true,
361
368
  async run(args) {
362
369
  const command = String(args.command);
363
- if (pty) {
370
+ if (getPty()) {
364
371
  const { output, code } = await runPty(command);
365
372
  return { output: `exit ${code ?? "null"}\n${spillIfHuge(stripAnsi(output).trim() || "(no output)")}`, isError: code !== 0 };
366
373
  }