paseo-acp-agy 1.1.5 → 1.1.7

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.
@@ -23,7 +23,11 @@ export function resolveDefaultAgyBinary() {
23
23
  return cand;
24
24
  }
25
25
  try {
26
- const out = execFileSync("where.exe", ["agy"], { encoding: "utf-8", timeout: 1000 }).trim();
26
+ const out = execFileSync("where.exe", ["agy"], {
27
+ encoding: "utf-8",
28
+ timeout: 2000,
29
+ windowsHide: true,
30
+ }).trim();
27
31
  const first = out.split(/\r?\n/)[0]?.trim();
28
32
  if (first && fs.existsSync(first))
29
33
  return first;
@@ -156,7 +160,10 @@ export class AntigravityProcess extends EventEmitter {
156
160
  }
157
161
  else if (pid && process.platform === "win32") {
158
162
  try {
159
- execFileSync("taskkill", ["/F", "/T", "/PID", String(pid)], { stdio: "ignore" });
163
+ execFileSync("taskkill", ["/F", "/T", "/PID", String(pid)], {
164
+ stdio: "ignore",
165
+ windowsHide: true,
166
+ });
160
167
  return true;
161
168
  }
162
169
  catch {
@@ -253,6 +260,7 @@ export class AntigravityProcess extends EventEmitter {
253
260
  dangerouslySkipPermissions: this.permissions.dangerouslySkipPermissions,
254
261
  mode: this.mode,
255
262
  addDirs,
263
+ printTimeout: this.permissions.printTimeout,
256
264
  }, extraArgs);
257
265
  logger.info("Spawning agy process", {
258
266
  binary: this.binaryPath,
@@ -260,12 +268,14 @@ export class AntigravityProcess extends EventEmitter {
260
268
  cwd: this.cwd,
261
269
  effectiveEffort,
262
270
  });
271
+ const isWin = process.platform === "win32";
263
272
  const child = spawn(this.binaryPath, args, {
264
273
  cwd: this.cwd,
265
274
  env: this.env,
266
275
  stdio: ["pipe", "pipe", "pipe"],
267
- detached: process.platform !== "win32",
268
- shell: process.platform === "win32",
276
+ detached: !isWin,
277
+ shell: isWin,
278
+ windowsHide: true,
269
279
  });
270
280
  this.child = child;
271
281
  if (!child.stdin || !child.stdout || !child.stderr) {
@@ -34,6 +34,10 @@ export function findPaseoServerInstallations() {
34
34
  path.join(localAppData, "Programs", "Paseo", "resources", "app.asar.unpacked", "node_modules", "@getpaseo", "server"),
35
35
  path.join(localAppData, "Programs", "Paseo", "resources", "app", "node_modules", "@getpaseo", "server"),
36
36
  path.join(programFiles, "Paseo", "resources", "app.asar.unpacked", "node_modules", "@getpaseo", "server"),
37
+ path.join(home, "AppData", "Roaming", "npm", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
38
+ path.join(home, "AppData", "Roaming", "npm", "node_modules", "@getpaseo", "server"),
39
+ path.join(home, ".npm-global", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
40
+ path.join(home, ".npm-global", "node_modules", "@getpaseo", "server"),
37
41
  ];
38
42
  for (const loc of winLocations) {
39
43
  if (loc && fs.existsSync(loc))
@@ -43,7 +47,7 @@ export function findPaseoServerInstallations() {
43
47
  try {
44
48
  const npmRoot = execFileSync("cmd.exe", ["/c", "npm.cmd", "root", "-g"], {
45
49
  encoding: "utf-8",
46
- timeout: 2000,
50
+ timeout: 8000,
47
51
  windowsHide: true,
48
52
  }).trim();
49
53
  if (npmRoot && fs.existsSync(npmRoot)) {
@@ -56,18 +60,16 @@ export function findPaseoServerInstallations() {
56
60
  }
57
61
  }
58
62
  catch { }
59
- // Check where.exe paseo
63
+ // Try detecting npm global prefix
60
64
  try {
61
- const whereOut = execFileSync("where.exe", ["paseo"], {
65
+ const npmPrefix = execFileSync("cmd.exe", ["/c", "npm.cmd", "config", "get", "prefix"], {
62
66
  encoding: "utf-8",
63
- timeout: 2000,
67
+ timeout: 8000,
64
68
  windowsHide: true,
65
69
  }).trim();
66
- const first = whereOut.split(/\r?\n/)[0]?.trim();
67
- if (first) {
68
- const paseoDir = path.dirname(first);
69
- const p1 = path.join(paseoDir, "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server");
70
- const p2 = path.join(paseoDir, "node_modules", "@getpaseo", "server");
70
+ if (npmPrefix && fs.existsSync(npmPrefix)) {
71
+ const p1 = path.join(npmPrefix, "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server");
72
+ const p2 = path.join(npmPrefix, "node_modules", "@getpaseo", "server");
71
73
  if (fs.existsSync(p1))
72
74
  candidates.add(path.resolve(p1));
73
75
  if (fs.existsSync(p2))
@@ -75,6 +77,43 @@ export function findPaseoServerInstallations() {
75
77
  }
76
78
  }
77
79
  catch { }
80
+ // Check where.exe paseo across all output lines
81
+ try {
82
+ const whereOut = execFileSync("where.exe", ["paseo"], {
83
+ encoding: "utf-8",
84
+ timeout: 4000,
85
+ windowsHide: true,
86
+ }).trim();
87
+ for (const line of whereOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)) {
88
+ const paseoDir = path.dirname(line);
89
+ const checks = [
90
+ path.join(paseoDir, "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
91
+ path.join(paseoDir, "node_modules", "@getpaseo", "server"),
92
+ path.join(path.dirname(paseoDir), "node_modules", "@getpaseo", "server"),
93
+ path.join(paseoDir, "resources", "app.asar.unpacked", "node_modules", "@getpaseo", "server"),
94
+ path.join(paseoDir, "resources", "app", "node_modules", "@getpaseo", "server"),
95
+ ];
96
+ for (const c of checks) {
97
+ if (fs.existsSync(c))
98
+ candidates.add(path.resolve(c));
99
+ }
100
+ }
101
+ }
102
+ catch { }
103
+ // Search common PATH dirs for npm/node_modules
104
+ if (process.env.PATH) {
105
+ for (const p of process.env.PATH.split(";")) {
106
+ const trimmed = p.trim();
107
+ if (!trimmed || !fs.existsSync(trimmed))
108
+ continue;
109
+ const p1 = path.join(trimmed, "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server");
110
+ const p2 = path.join(trimmed, "node_modules", "@getpaseo", "server");
111
+ if (fs.existsSync(p1))
112
+ candidates.add(path.resolve(p1));
113
+ if (fs.existsSync(p2))
114
+ candidates.add(path.resolve(p2));
115
+ }
116
+ }
78
117
  }
79
118
  else {
80
119
  // POSIX locations (Linux / macOS)
@@ -131,7 +170,7 @@ export function findPaseoServerInstallations() {
131
170
  * injected into Paseo server's quota-fetcher providers.
132
171
  */
133
172
  export function generateAntigravityQuotaProviderJs() {
134
- return `import { execFile } from "node:child_process";
173
+ return `import { execFile, execFileSync } from "node:child_process";
135
174
  import { promisify } from "node:util";
136
175
  import fs from "node:fs";
137
176
  import os from "node:os";
@@ -155,8 +194,7 @@ function resolveAgyBinary() {
155
194
  if (fs.existsSync(cand)) return cand;
156
195
  }
157
196
  try {
158
- const { execFileSync } = require("node:child_process");
159
- const out = execFileSync("where.exe", ["agy"], { encoding: "utf-8", timeout: 1000 }).trim();
197
+ const out = execFileSync("where.exe", ["agy"], { encoding: "utf-8", timeout: 2000, windowsHide: true }).trim();
160
198
  const first = out.split(/\\r?\\n/)[0]?.trim();
161
199
  if (first && fs.existsSync(first)) return first;
162
200
  } catch {}
@@ -179,9 +217,13 @@ export class AntigravityQuotaProvider {
179
217
  async fetchUsage() {
180
218
  try {
181
219
  const isWin = process.platform === "win32";
220
+ let bin = this.binaryPath;
221
+ if (isWin && bin.includes(" ") && !bin.startsWith('"')) {
222
+ bin = \`"\${bin}"\`;
223
+ }
182
224
  const [usageRes, creditsRes] = await Promise.allSettled([
183
- execFileAsync(this.binaryPath, ["--print", "/usage"], { timeout: 8000, env: process.env, shell: isWin }),
184
- execFileAsync(this.binaryPath, ["--print", "/credits"], { timeout: 8000, env: process.env, shell: isWin }),
225
+ execFileAsync(bin, ["--print", "/usage"], { timeout: 8000, env: process.env, shell: isWin, windowsHide: true }),
226
+ execFileAsync(bin, ["--print", "/credits"], { timeout: 8000, env: process.env, shell: isWin, windowsHide: true }),
185
227
  ]);
186
228
 
187
229
  const usageOut = usageRes.status === "fulfilled" ? usageRes.value.stdout || usageRes.value.stderr : "";
@@ -394,23 +436,28 @@ export function patchPaseoServer(serverDir) {
394
436
  }
395
437
  }
396
438
  // Patch handleUsageUpdate
397
- if (acpCode.includes("handleUsageUpdate(update) {") && !acpCode.includes("this.notifySubscribers({")) {
398
- const oldHandlerRegex = /handleUsageUpdate\s*\(\s*update\s*\)\s*\{[\s\S]*?void\s+update;?[\s\S]*?\}/m;
439
+ if (acpCode.includes("handleUsageUpdate(update) {") && (!acpCode.includes("this.deliverTranslatedEvents") || acpCode.includes("this.notifySubscribers"))) {
440
+ const handlerRegex = /handleUsageUpdate\s*\(\s*update\s*\)\s*\{[\s\S]*?(?:void\s+update;|this\.notifySubscribers)[\s\S]*?\n\s*\}/m;
399
441
  const newHandler = `handleUsageUpdate(update) {
400
442
  if (!update) return;
401
443
  const usage = mapACPUsage(update);
402
444
  if (usage) {
403
445
  this.currentTurnUsage = { ...this.currentTurnUsage, ...usage };
404
- this.notifySubscribers({
446
+ const event = {
405
447
  type: "usage_updated",
406
448
  provider: this.provider,
407
449
  usage: this.currentTurnUsage,
408
450
  ...(this.activeForegroundTurnId ? { turnId: this.activeForegroundTurnId } : {}),
409
- });
451
+ };
452
+ if (typeof this.deliverTranslatedEvents === "function") {
453
+ this.deliverTranslatedEvents([event]);
454
+ } else if (typeof this.pushEvent === "function") {
455
+ this.pushEvent(event);
456
+ }
410
457
  }
411
458
  }`;
412
- if (oldHandlerRegex.test(acpCode)) {
413
- acpCode = acpCode.replace(oldHandlerRegex, newHandler);
459
+ if (handlerRegex.test(acpCode)) {
460
+ acpCode = acpCode.replace(handlerRegex, newHandler);
414
461
  acpModified = true;
415
462
  }
416
463
  }
@@ -3,11 +3,13 @@ export interface PermissionSettings {
3
3
  dangerouslySkipPermissions: boolean;
4
4
  mode?: string;
5
5
  addDirs?: string[];
6
+ printTimeout?: string;
6
7
  }
7
8
  export declare function resolvePermissionSettings(options?: {
8
9
  sandbox?: boolean;
9
10
  dangerouslySkipPermissions?: boolean;
10
11
  mode?: string;
11
12
  addDirs?: string[];
13
+ printTimeout?: string;
12
14
  }): PermissionSettings;
13
15
  export declare function buildAgyArgs(settings: PermissionSettings, extraArgs?: string[]): string[];
@@ -2,6 +2,7 @@
2
2
  export function resolvePermissionSettings(options) {
3
3
  const envSandbox = process.env.AGY_ACP_SANDBOX;
4
4
  const envSkipPerms = process.env.AGY_ACP_DANGEROUSLY_SKIP_PERMISSIONS;
5
+ const envPrintTimeout = process.env.AGY_ACP_PRINT_TIMEOUT;
5
6
  const sandbox = options?.sandbox ?? (envSandbox === "true" || envSandbox === "1");
6
7
  // In ACP mode, permissions and tool approvals are governed by the host application (e.g. Paseo).
7
8
  // Because agy runs non-interactively over stream-json pipes without an interactive TTY, agy's
@@ -9,15 +10,21 @@ export function resolvePermissionSettings(options) {
9
10
  // Therefore, dangerouslySkipPermissions defaults to true unless explicitly disabled.
10
11
  const dangerouslySkipPermissions = options?.dangerouslySkipPermissions ??
11
12
  (envSkipPerms !== undefined ? envSkipPerms === "true" || envSkipPerms === "1" : true);
13
+ // Default printTimeout to 24h (or env override) so that agy never terminates long turns prematurely
14
+ const printTimeout = options?.printTimeout ?? envPrintTimeout ?? "24h";
12
15
  return {
13
16
  sandbox,
14
17
  dangerouslySkipPermissions,
15
18
  mode: options?.mode,
16
19
  addDirs: options?.addDirs,
20
+ printTimeout,
17
21
  };
18
22
  }
19
23
  export function buildAgyArgs(settings, extraArgs) {
20
24
  const args = ["--input-format", "stream-json", "--output-format", "stream-json", "--print="];
25
+ if (settings.printTimeout) {
26
+ args.push("--print-timeout", settings.printTimeout);
27
+ }
21
28
  if (settings.sandbox) {
22
29
  args.push("--sandbox");
23
30
  }
package/dist/protocol.js CHANGED
@@ -300,12 +300,14 @@ export async function fetchAntigravityUsage(binaryPath = "agy", force = false) {
300
300
  maxBuffer: 1024 * 1024,
301
301
  env: process.env,
302
302
  shell: process.platform === "win32",
303
+ windowsHide: true,
303
304
  }),
304
305
  execFileAsync(cmd, ["--print", "/credits"], {
305
306
  timeout: 8_000,
306
307
  maxBuffer: 1024 * 1024,
307
308
  env: process.env,
308
309
  shell: process.platform === "win32",
310
+ windowsHide: true,
309
311
  }),
310
312
  ]);
311
313
  const balances = [];
@@ -434,6 +436,7 @@ export async function fetchAvailableModels(binaryPath = "agy", force = false) {
434
436
  env: process.env,
435
437
  maxBuffer: 4 * 1024 * 1024,
436
438
  shell: process.platform === "win32",
439
+ windowsHide: true,
437
440
  });
438
441
  const parsed = parseAgyModelsOutput(stdout);
439
442
  cachedModels = parsed;
@@ -344,6 +344,7 @@ async function runAgySlash(binaryPath, cwd, slashCommand) {
344
344
  timeout: AGY_COMMAND_TIMEOUT_MS,
345
345
  maxBuffer: AGY_COMMAND_MAX_BUFFER,
346
346
  shell: process.platform === "win32",
347
+ windowsHide: true,
347
348
  });
348
349
  return stdout.trim() || stderr.trim();
349
350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paseo-acp-agy",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "ACP (Agent Client Protocol) provider for Google Antigravity in Paseo and Zed",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",