paseo-acp-agy 1.1.7 → 1.1.8

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.
@@ -204,8 +204,37 @@ export class ACPServer {
204
204
  }
205
205
  case ACP_METHODS.SESSION_LOAD:
206
206
  case ACP_METHODS.SESSION_LOAD_ALIAS: {
207
- if (!isNotification) {
208
- this.sendError(id, -32601, "session/load is not supported because agy-acp does not replay prior history; use session/resume");
207
+ const sessionId = String(params.sessionId || "");
208
+ const cwd = typeof params.cwd === "string" ? params.cwd : undefined;
209
+ if (!sessionId) {
210
+ if (!isNotification)
211
+ this.sendError(id, -32602, "sessionId is required");
212
+ break;
213
+ }
214
+ let session = this.sessionManager.getSession(sessionId);
215
+ let created = false;
216
+ try {
217
+ if (!session) {
218
+ session = this.sessionManager.createSession({
219
+ id: sessionId,
220
+ cwd,
221
+ binaryPath: this.binaryPath,
222
+ });
223
+ created = true;
224
+ }
225
+ if (!created && session.process.currentConversationId) {
226
+ await session.ensureReadyForResume();
227
+ }
228
+ if (!isNotification) {
229
+ this.sendSuccess(id, await this.sessionState(session));
230
+ this.publishCommands(session.id);
231
+ this.publishUsageUpdate(session);
232
+ }
233
+ }
234
+ catch (err) {
235
+ if (!isNotification) {
236
+ this.sendError(id, -32603, `Failed to load session ${sessionId}: ${err instanceof Error ? err.message : String(err)}`);
237
+ }
209
238
  }
210
239
  break;
211
240
  }
@@ -12,11 +12,24 @@ export function resolveDefaultAgyBinary() {
12
12
  const home = os.homedir();
13
13
  if (home) {
14
14
  if (process.platform === "win32") {
15
+ const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
16
+ const localAppData = process.env.LOCALAPPDATA || path.join(home, "AppData", "Local");
17
+ const programFiles = process.env.ProgramFiles || "C:\\Program Files";
18
+ const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
15
19
  const candidates = [
16
20
  path.join(home, ".local", "bin", "agy.exe"),
17
- path.join(home, "AppData", "Local", "Programs", "antigravity", "agy.exe"),
18
21
  path.join(home, ".local", "bin", "agy.cmd"),
19
22
  path.join(home, ".local", "bin", "agy.bat"),
23
+ path.join(appData, "npm", "agy.cmd"),
24
+ path.join(appData, "npm", "agy.exe"),
25
+ path.join(appData, "npm", "agy.bat"),
26
+ path.join(localAppData, "npm", "agy.cmd"),
27
+ path.join(localAppData, "npm", "agy.exe"),
28
+ path.join(localAppData, "Programs", "antigravity", "agy.exe"),
29
+ path.join(localAppData, "Programs", "Antigravity", "bin", "agy.exe"),
30
+ path.join(localAppData, "Microsoft", "WindowsApps", "agy.exe"),
31
+ path.join(programFiles, "Antigravity", "bin", "agy.exe"),
32
+ path.join(programFilesX86, "Antigravity", "bin", "agy.exe"),
20
33
  ];
21
34
  for (const cand of candidates) {
22
35
  if (fs.existsSync(cand))
package/dist/index.js CHANGED
@@ -48,21 +48,26 @@ if (args.includes("setup") ||
48
48
  args.includes("--patch")) {
49
49
  process.stdout.write("Checking Paseo installation and configuring Antigravity telemetry...\n");
50
50
  try {
51
- const res = ensurePaseoIntegration({ verbose: true });
51
+ const res = await ensurePaseoIntegration({ verbose: true });
52
52
  if (!res.found) {
53
- process.stdout.write("Notice: No active @getpaseo/server installation found in standard paths.\n" +
54
- "If Paseo is installed in a custom directory, set PASEO_SERVER_PATH and run setup again.\n");
53
+ process.stdout.write("Notice: No active @getpaseo/server installation or app.asar found in standard paths.\n" +
54
+ "If Paseo is installed in a custom directory, set PASEO_SERVER_PATH or PASEO_ASAR_PATH and run setup again.\n");
55
55
  }
56
56
  else {
57
- process.stdout.write(`Found ${res.serverPaths.length} Paseo server installation(s).\n`);
58
- if (res.patchedPaths.length > 0) {
59
- process.stdout.write(`Successfully integrated with: \n${res.patchedPaths.map((p) => ` - ${p}`).join("\n")}\n\n` +
57
+ const totalFound = res.serverPaths.length + (res.asarPaths?.length || 0);
58
+ process.stdout.write(`Found ${totalFound} Paseo installation target(s) (${res.serverPaths.length} server dir(s), ${res.asarPaths?.length || 0} asar package(s)).\n`);
59
+ const allPatched = [...res.patchedPaths, ...(res.patchedAsarPaths || [])];
60
+ if (allPatched.length > 0) {
61
+ process.stdout.write(`Successfully integrated with: \n${allPatched.map((p) => ` - ${p}`).join("\n")}\n\n` +
60
62
  `Antigravity quota provider and context-window telemetry are now enabled!\n` +
61
63
  `Please restart Paseo (or run 'paseo daemon restart') to apply changes.\n`);
62
64
  }
63
65
  else {
64
66
  process.stdout.write("Paseo is already up-to-date and configured for Antigravity telemetry.\n");
65
67
  }
68
+ if (res.errors.length > 0) {
69
+ process.stderr.write(`Notice: Some paths could not be modified (may require admin/close Paseo):\n${res.errors.map(e => ` - ${e}`).join("\n")}\n`);
70
+ }
66
71
  }
67
72
  }
68
73
  catch (err) {
@@ -71,10 +76,7 @@ if (args.includes("setup") ||
71
76
  process.exit(0);
72
77
  }
73
78
  // Auto-run integration in background when starting ACP server
74
- try {
75
- ensurePaseoIntegration();
76
- }
77
- catch { }
79
+ void ensurePaseoIntegration().catch(() => { });
78
80
  const server = new ACPServer();
79
81
  const cleanup = async () => {
80
82
  try {
@@ -2,6 +2,8 @@ export interface PatchResult {
2
2
  found: boolean;
3
3
  serverPaths: string[];
4
4
  patchedPaths: string[];
5
+ asarPaths?: string[];
6
+ patchedAsarPaths?: string[];
5
7
  errors: string[];
6
8
  }
7
9
  /**
@@ -26,9 +28,24 @@ export declare function patchPaseoServer(serverDir: string): {
26
28
  error?: string;
27
29
  };
28
30
  /**
29
- * Discovers and patches all accessible Paseo installations.
31
+ * Searches the host machine for Paseo Desktop app.asar archives across
32
+ * Windows, macOS, and Linux.
33
+ */
34
+ export declare function findPaseoAsarPaths(): string[];
35
+ /**
36
+ * Extracts, patches, and repacks a Paseo app.asar archive to integrate Antigravity
37
+ * quota fetchers and token telemetry.
38
+ */
39
+ export declare function patchPaseoAsar(asarPath: string): Promise<{
40
+ success: boolean;
41
+ changes: string[];
42
+ error?: string;
43
+ }>;
44
+ /**
45
+ * Discovers and patches all accessible Paseo installations (both directory and app.asar).
30
46
  */
31
47
  export declare function ensurePaseoIntegration(options?: {
32
48
  verbose?: boolean;
33
49
  targetPaths?: string[];
34
- }): PatchResult;
50
+ targetAsarPaths?: string[];
51
+ }): Promise<PatchResult>;
@@ -184,11 +184,25 @@ function resolveAgyBinary() {
184
184
  const home = os.homedir();
185
185
  if (home) {
186
186
  if (process.platform === "win32") {
187
+ const appData = process.env.APPDATA || path.join(home, "AppData", "Roaming");
188
+ const localAppData = process.env.LOCALAPPDATA || path.join(home, "AppData", "Local");
189
+ const programFiles = process.env.ProgramFiles || "C:\\\\Program Files";
190
+ const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\\\Program Files (x86)";
191
+
187
192
  const candidates = [
188
193
  path.join(home, ".local", "bin", "agy.exe"),
189
- path.join(home, "AppData", "Local", "Programs", "antigravity", "agy.exe"),
190
194
  path.join(home, ".local", "bin", "agy.cmd"),
191
195
  path.join(home, ".local", "bin", "agy.bat"),
196
+ path.join(appData, "npm", "agy.cmd"),
197
+ path.join(appData, "npm", "agy.exe"),
198
+ path.join(appData, "npm", "agy.bat"),
199
+ path.join(localAppData, "npm", "agy.cmd"),
200
+ path.join(localAppData, "npm", "agy.exe"),
201
+ path.join(localAppData, "Programs", "antigravity", "agy.exe"),
202
+ path.join(localAppData, "Programs", "Antigravity", "bin", "agy.exe"),
203
+ path.join(localAppData, "Microsoft", "WindowsApps", "agy.exe"),
204
+ path.join(programFiles, "Antigravity", "bin", "agy.exe"),
205
+ path.join(programFilesX86, "Antigravity", "bin", "agy.exe"),
192
206
  ];
193
207
  for (const cand of candidates) {
194
208
  if (fs.existsSync(cand)) return cand;
@@ -222,8 +236,8 @@ export class AntigravityQuotaProvider {
222
236
  bin = \`"\${bin}"\`;
223
237
  }
224
238
  const [usageRes, creditsRes] = await Promise.allSettled([
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 }),
239
+ execFileAsync(bin, ["--print-timeout", "24h", "--print", "/usage"], { timeout: 15000, env: process.env, shell: isWin, windowsHide: true }),
240
+ execFileAsync(bin, ["--print-timeout", "24h", "--print", "/credits"], { timeout: 15000, env: process.env, shell: isWin, windowsHide: true }),
227
241
  ]);
228
242
 
229
243
  const usageOut = usageRes.status === "fulfilled" ? usageRes.value.stdout || usageRes.value.stderr : "";
@@ -475,11 +489,166 @@ export function patchPaseoServer(serverDir) {
475
489
  }
476
490
  }
477
491
  /**
478
- * Discovers and patches all accessible Paseo installations.
492
+ * Searches the host machine for Paseo Desktop app.asar archives across
493
+ * Windows, macOS, and Linux.
494
+ */
495
+ export function findPaseoAsarPaths() {
496
+ const candidates = new Set();
497
+ const home = os.homedir();
498
+ if (process.env.PASEO_ASAR_PATH && fs.existsSync(process.env.PASEO_ASAR_PATH)) {
499
+ candidates.add(path.resolve(process.env.PASEO_ASAR_PATH));
500
+ }
501
+ if (process.platform === "win32") {
502
+ const localAppData = process.env.LOCALAPPDATA || (home ? path.join(home, "AppData", "Local") : "");
503
+ const appData = process.env.APPDATA || (home ? path.join(home, "AppData", "Roaming") : "");
504
+ const programFiles = process.env.ProgramFiles || "C:\\Program Files";
505
+ const programFilesX86 = process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)";
506
+ const winAsarLocations = [
507
+ path.join(localAppData, "Programs", "Paseo", "resources", "app.asar"),
508
+ path.join(localAppData, "Paseo", "resources", "app.asar"),
509
+ path.join(programFiles, "Paseo", "resources", "app.asar"),
510
+ path.join(programFilesX86, "Paseo", "resources", "app.asar"),
511
+ path.join(appData, "Paseo", "resources", "app.asar"),
512
+ ];
513
+ for (const loc of winAsarLocations) {
514
+ if (loc && fs.existsSync(loc))
515
+ candidates.add(path.resolve(loc));
516
+ }
517
+ try {
518
+ const whereOut = execFileSync("where.exe", ["paseo"], {
519
+ encoding: "utf-8",
520
+ timeout: 2000,
521
+ windowsHide: true,
522
+ }).trim();
523
+ for (const line of whereOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)) {
524
+ const asarCandidate = path.join(path.dirname(line), "resources", "app.asar");
525
+ if (fs.existsSync(asarCandidate))
526
+ candidates.add(path.resolve(asarCandidate));
527
+ }
528
+ }
529
+ catch { }
530
+ }
531
+ else if (process.platform === "darwin") {
532
+ const macLocations = [
533
+ "/Applications/Paseo.app/Contents/Resources/app.asar",
534
+ path.join(home, "Applications", "Paseo.app", "Contents", "Resources", "app.asar"),
535
+ ];
536
+ for (const loc of macLocations) {
537
+ if (fs.existsSync(loc))
538
+ candidates.add(path.resolve(loc));
539
+ }
540
+ }
541
+ else {
542
+ const linuxLocations = [
543
+ "/opt/Paseo/resources/app.asar",
544
+ "/usr/lib/paseo/resources/app.asar",
545
+ path.join(home, ".local", "share", "paseo", "resources", "app.asar"),
546
+ ];
547
+ for (const loc of linuxLocations) {
548
+ if (fs.existsSync(loc))
549
+ candidates.add(path.resolve(loc));
550
+ }
551
+ }
552
+ return Array.from(candidates);
553
+ }
554
+ /**
555
+ * Extracts, patches, and repacks a Paseo app.asar archive to integrate Antigravity
556
+ * quota fetchers and token telemetry.
479
557
  */
480
- export function ensurePaseoIntegration(options) {
558
+ export async function patchPaseoAsar(asarPath) {
559
+ const changes = [];
560
+ let tempDir = null;
561
+ let tempAsar = null;
562
+ try {
563
+ if (!fs.existsSync(asarPath)) {
564
+ return { success: false, changes: [], error: `Asar archive not found: ${asarPath}` };
565
+ }
566
+ // Dynamic import of @electron/asar
567
+ const asarModule = await import("@electron/asar");
568
+ const asar = asarModule.default || asarModule;
569
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "paseo-asar-extract-"));
570
+ asar.extractAll(asarPath, tempDir);
571
+ // Look for server directory in extracted files
572
+ const serverCandidates = [
573
+ path.join(tempDir, "node_modules", "@getpaseo", "server"),
574
+ path.join(tempDir, "dist", "node_modules", "@getpaseo", "server"),
575
+ ];
576
+ let serverDir = serverCandidates.find((c) => fs.existsSync(c));
577
+ if (!serverDir) {
578
+ // Search recursively within 3 levels
579
+ const searchDirs = [tempDir];
580
+ while (searchDirs.length > 0 && !serverDir) {
581
+ const current = searchDirs.shift();
582
+ try {
583
+ const entries = fs.readdirSync(current, { withFileTypes: true });
584
+ for (const ent of entries) {
585
+ if (ent.isDirectory()) {
586
+ const full = path.join(current, ent.name);
587
+ if (ent.name === "server" && full.includes(path.join("@getpaseo", "server"))) {
588
+ serverDir = full;
589
+ break;
590
+ }
591
+ if (full.split(path.sep).length - tempDir.split(path.sep).length < 4) {
592
+ searchDirs.push(full);
593
+ }
594
+ }
595
+ }
596
+ }
597
+ catch { }
598
+ }
599
+ }
600
+ if (!serverDir) {
601
+ return { success: false, changes: [], error: `Could not locate @getpaseo/server inside ${asarPath}` };
602
+ }
603
+ const patchResult = patchPaseoServer(serverDir);
604
+ if (!patchResult.success) {
605
+ return { success: false, changes: [], error: patchResult.error };
606
+ }
607
+ if (patchResult.changes.length === 0) {
608
+ // Already patched!
609
+ return { success: true, changes: [] };
610
+ }
611
+ changes.push(...patchResult.changes);
612
+ // Create backup if not already present
613
+ const backupPath = `${asarPath}.bak`;
614
+ if (!fs.existsSync(backupPath)) {
615
+ fs.copyFileSync(asarPath, backupPath);
616
+ changes.push(`Backed up original asar to ${backupPath}`);
617
+ }
618
+ tempAsar = path.join(os.tmpdir(), `app-${Date.now()}.asar`);
619
+ await asar.createPackage(tempDir, tempAsar);
620
+ // Replace original archive
621
+ fs.copyFileSync(tempAsar, asarPath);
622
+ changes.push(`Repacked updated asar archive at ${asarPath}`);
623
+ return { success: true, changes };
624
+ }
625
+ catch (err) {
626
+ const msg = err instanceof Error ? err.message : String(err);
627
+ return { success: false, changes, error: msg };
628
+ }
629
+ finally {
630
+ if (tempDir) {
631
+ try {
632
+ fs.rmSync(tempDir, { recursive: true, force: true });
633
+ }
634
+ catch { }
635
+ }
636
+ if (tempAsar) {
637
+ try {
638
+ fs.unlinkSync(tempAsar);
639
+ }
640
+ catch { }
641
+ }
642
+ }
643
+ }
644
+ /**
645
+ * Discovers and patches all accessible Paseo installations (both directory and app.asar).
646
+ */
647
+ export async function ensurePaseoIntegration(options) {
481
648
  const serverPaths = options?.targetPaths || findPaseoServerInstallations();
649
+ const asarPaths = options?.targetAsarPaths || findPaseoAsarPaths();
482
650
  const patchedPaths = [];
651
+ const patchedAsarPaths = [];
483
652
  const errors = [];
484
653
  for (const sPath of serverPaths) {
485
654
  const res = patchPaseoServer(sPath);
@@ -495,10 +664,26 @@ export function ensurePaseoIntegration(options) {
495
664
  errors.push(`${sPath}: ${res.error}`);
496
665
  }
497
666
  }
667
+ for (const aPath of asarPaths) {
668
+ const res = await patchPaseoAsar(aPath);
669
+ if (res.success) {
670
+ if (res.changes.length > 0) {
671
+ patchedAsarPaths.push(aPath);
672
+ if (options?.verbose) {
673
+ logger.info(`Integrated with Paseo desktop asar at ${aPath}`, { changes: res.changes });
674
+ }
675
+ }
676
+ }
677
+ else if (res.error) {
678
+ errors.push(`${aPath}: ${res.error}`);
679
+ }
680
+ }
498
681
  return {
499
- found: serverPaths.length > 0,
682
+ found: serverPaths.length > 0 || asarPaths.length > 0,
500
683
  serverPaths,
501
684
  patchedPaths,
685
+ asarPaths,
686
+ patchedAsarPaths,
502
687
  errors,
503
688
  };
504
689
  }
@@ -338,7 +338,7 @@ export function formatUsageOutput(rawText) {
338
338
  }
339
339
  async function runAgySlash(binaryPath, cwd, slashCommand) {
340
340
  const cmd = formatExecBinaryPath(binaryPath);
341
- const { stdout, stderr } = await execFileAsync(cmd, ["--print", slashCommand], {
341
+ const { stdout, stderr } = await execFileAsync(cmd, ["--print-timeout", "24h", "--print", slashCommand], {
342
342
  cwd,
343
343
  env: process.env,
344
344
  timeout: AGY_COMMAND_TIMEOUT_MS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paseo-acp-agy",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
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",
@@ -45,7 +45,8 @@
45
45
  },
46
46
  "homepage": "https://github.com/tucomel/paseo-acp-agy#readme",
47
47
  "dependencies": {
48
- "@agentclientprotocol/sdk": "^0.17.1"
48
+ "@agentclientprotocol/sdk": "^0.17.1",
49
+ "@electron/asar": "^4.3.0"
49
50
  },
50
51
  "devDependencies": {
51
52
  "@types/node": "^22.0.0",