paseo-acp-agy 1.2.2 → 1.2.4
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/asar.d.ts +11 -2
- package/dist/asar.js +65 -20
- package/dist/paseo-patcher.js +177 -46
- package/package.json +1 -1
package/dist/asar.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ export interface AsarNode {
|
|
|
4
4
|
offset?: string;
|
|
5
5
|
executable?: boolean;
|
|
6
6
|
unpacked?: boolean;
|
|
7
|
+
link?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ExtractResult {
|
|
10
|
+
unpackedPaths: string[];
|
|
11
|
+
originalHeader: AsarNode;
|
|
7
12
|
}
|
|
8
13
|
/**
|
|
9
14
|
* Reads and parses the ASAR archive header and returns the root node and base offset for data.
|
|
@@ -20,9 +25,13 @@ export declare function listPackage(archivePath: string): string[];
|
|
|
20
25
|
* Pure TypeScript, zero-dependency ASAR archive extractor.
|
|
21
26
|
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
22
27
|
*/
|
|
23
|
-
export declare function extractAll(archivePath: string, destDir: string):
|
|
28
|
+
export declare function extractAll(archivePath: string, destDir: string): ExtractResult;
|
|
29
|
+
export interface CreatePackageOptions {
|
|
30
|
+
unpackedPaths?: string[];
|
|
31
|
+
originalHeader?: AsarNode;
|
|
32
|
+
}
|
|
24
33
|
/**
|
|
25
34
|
* Pure TypeScript, zero-dependency ASAR archive builder.
|
|
26
35
|
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
27
36
|
*/
|
|
28
|
-
export declare function createPackage(srcDir: string, destFile: string): Promise<void>;
|
|
37
|
+
export declare function createPackage(srcDir: string, destFile: string, options?: CreatePackageOptions): Promise<void>;
|
package/dist/asar.js
CHANGED
|
@@ -61,6 +61,7 @@ export function listPackage(archivePath) {
|
|
|
61
61
|
export function extractAll(archivePath, destDir) {
|
|
62
62
|
const { header, dataBaseOffset } = readArchiveHeader(archivePath);
|
|
63
63
|
const fd = fs.openSync(archivePath, "r");
|
|
64
|
+
const unpackedPaths = [];
|
|
64
65
|
try {
|
|
65
66
|
function extractNode(node, currentPath, relParts = []) {
|
|
66
67
|
if (node.files) {
|
|
@@ -69,6 +70,20 @@ export function extractAll(archivePath, destDir) {
|
|
|
69
70
|
extractNode(child, path.join(currentPath, name), [...relParts, name]);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
73
|
+
else if (node.link) {
|
|
74
|
+
fs.mkdirSync(path.dirname(currentPath), { recursive: true });
|
|
75
|
+
try {
|
|
76
|
+
fs.unlinkSync(currentPath);
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
fs.symlinkSync(node.link, currentPath);
|
|
80
|
+
}
|
|
81
|
+
else if (node.unpacked) {
|
|
82
|
+
// Unpacked files belong in archive.unpacked and must NOT be copied into destDir,
|
|
83
|
+
// so that re-packing does not duplicate external binaries into the asar payload.
|
|
84
|
+
const relPath = relParts.join("/");
|
|
85
|
+
unpackedPaths.push(relPath);
|
|
86
|
+
}
|
|
72
87
|
else if (node.size !== undefined && node.offset !== undefined) {
|
|
73
88
|
const fileOffset = dataBaseOffset + parseInt(node.offset, 10);
|
|
74
89
|
const fileBuf = Buffer.alloc(node.size);
|
|
@@ -80,15 +95,9 @@ export function extractAll(archivePath, destDir) {
|
|
|
80
95
|
mode: node.executable ? 0o755 : 0o644,
|
|
81
96
|
});
|
|
82
97
|
}
|
|
83
|
-
else if (node.unpacked) {
|
|
84
|
-
const unpackedSrc = path.join(archivePath + ".unpacked", ...relParts);
|
|
85
|
-
if (fs.existsSync(unpackedSrc)) {
|
|
86
|
-
fs.mkdirSync(path.dirname(currentPath), { recursive: true });
|
|
87
|
-
fs.copyFileSync(unpackedSrc, currentPath);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
98
|
}
|
|
91
99
|
extractNode(header, destDir);
|
|
100
|
+
return { unpackedPaths, originalHeader: header };
|
|
92
101
|
}
|
|
93
102
|
finally {
|
|
94
103
|
fs.closeSync(fd);
|
|
@@ -98,7 +107,7 @@ export function extractAll(archivePath, destDir) {
|
|
|
98
107
|
* Pure TypeScript, zero-dependency ASAR archive builder.
|
|
99
108
|
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
100
109
|
*/
|
|
101
|
-
export async function createPackage(srcDir, destFile) {
|
|
110
|
+
export async function createPackage(srcDir, destFile, options) {
|
|
102
111
|
const files = [];
|
|
103
112
|
function walk(dir, rel = "") {
|
|
104
113
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -106,16 +115,25 @@ export async function createPackage(srcDir, destFile) {
|
|
|
106
115
|
for (const e of entries) {
|
|
107
116
|
const entryRel = rel ? `${rel}/${e.name}` : e.name;
|
|
108
117
|
const full = path.join(dir, e.name);
|
|
109
|
-
|
|
118
|
+
const lstat = fs.lstatSync(full);
|
|
119
|
+
if (lstat.isSymbolicLink()) {
|
|
120
|
+
files.push({
|
|
121
|
+
relPath: entryRel,
|
|
122
|
+
fullPath: full,
|
|
123
|
+
size: 0,
|
|
124
|
+
isLink: true,
|
|
125
|
+
linkTarget: fs.readlinkSync(full),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else if (lstat.isDirectory()) {
|
|
110
129
|
walk(full, entryRel);
|
|
111
130
|
}
|
|
112
|
-
else if (
|
|
113
|
-
const
|
|
114
|
-
const executable = Boolean(stat.mode & 0o111);
|
|
131
|
+
else if (lstat.isFile()) {
|
|
132
|
+
const executable = Boolean(lstat.mode & 0o111);
|
|
115
133
|
files.push({
|
|
116
134
|
relPath: entryRel,
|
|
117
135
|
fullPath: full,
|
|
118
|
-
size:
|
|
136
|
+
size: lstat.size,
|
|
119
137
|
executable: executable || undefined,
|
|
120
138
|
});
|
|
121
139
|
}
|
|
@@ -134,12 +152,39 @@ export async function createPackage(srcDir, destFile) {
|
|
|
134
152
|
curr = curr[parts[i]].files;
|
|
135
153
|
}
|
|
136
154
|
const leaf = parts[parts.length - 1];
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
if (f.isLink) {
|
|
156
|
+
curr[leaf] = { link: f.linkTarget };
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
curr[leaf] = {
|
|
160
|
+
size: f.size,
|
|
161
|
+
offset: String(currentOffset),
|
|
162
|
+
executable: f.executable,
|
|
163
|
+
};
|
|
164
|
+
currentOffset += f.size;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Restore unpacked file references from original archive if provided
|
|
168
|
+
if (options?.unpackedPaths && options?.originalHeader) {
|
|
169
|
+
for (const relPath of options.unpackedPaths) {
|
|
170
|
+
const parts = relPath.split("/");
|
|
171
|
+
let origNode = options.originalHeader;
|
|
172
|
+
for (const p of parts) {
|
|
173
|
+
origNode = origNode?.files?.[p];
|
|
174
|
+
}
|
|
175
|
+
let curr = header.files;
|
|
176
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
177
|
+
if (!curr[parts[i]]) {
|
|
178
|
+
curr[parts[i]] = { files: {} };
|
|
179
|
+
}
|
|
180
|
+
curr = curr[parts[i]].files;
|
|
181
|
+
}
|
|
182
|
+
const leaf = parts[parts.length - 1];
|
|
183
|
+
curr[leaf] = {
|
|
184
|
+
size: origNode?.size ?? 0,
|
|
185
|
+
unpacked: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
143
188
|
}
|
|
144
189
|
const jsonBuf = Buffer.from(JSON.stringify(header), "utf8");
|
|
145
190
|
const alignedJsonLen = (jsonBuf.length + 3) & ~3;
|
|
@@ -159,7 +204,7 @@ export async function createPackage(srcDir, destFile) {
|
|
|
159
204
|
fs.writeSync(fd, sizePickle);
|
|
160
205
|
fs.writeSync(fd, headerPickle);
|
|
161
206
|
for (const f of files) {
|
|
162
|
-
if (f.size > 0) {
|
|
207
|
+
if (!f.isLink && f.size > 0) {
|
|
163
208
|
const content = fs.readFileSync(f.fullPath);
|
|
164
209
|
fs.writeSync(fd, content);
|
|
165
210
|
}
|
package/dist/paseo-patcher.js
CHANGED
|
@@ -129,7 +129,7 @@ export function findPaseoServerInstallations() {
|
|
|
129
129
|
"/Applications/Paseo.app/Contents/Resources/app/node_modules/@getpaseo/server",
|
|
130
130
|
];
|
|
131
131
|
if (home) {
|
|
132
|
-
posixLocations.push(path.join(home, ".local", "share", "pnpm", "global", "5", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"), path.join(home, ".bun", "install", "global", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"));
|
|
132
|
+
posixLocations.push(path.join(home, ".local", "lib", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"), path.join(home, ".local", "lib", "node_modules", "@getpaseo", "server"), path.join(home, ".local", "share", "pnpm", "global", "5", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"), path.join(home, ".bun", "install", "global", "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"));
|
|
133
133
|
// Check nvm paths if available
|
|
134
134
|
const nvmDir = path.join(home, ".nvm", "versions", "node");
|
|
135
135
|
if (fs.existsSync(nvmDir)) {
|
|
@@ -146,6 +146,38 @@ export function findPaseoServerInstallations() {
|
|
|
146
146
|
if (fs.existsSync(loc))
|
|
147
147
|
candidates.add(path.resolve(loc));
|
|
148
148
|
}
|
|
149
|
+
// Inspect which paseo on POSIX
|
|
150
|
+
try {
|
|
151
|
+
const whichOut = execFileSync("which", ["paseo"], {
|
|
152
|
+
encoding: "utf-8",
|
|
153
|
+
timeout: 3000,
|
|
154
|
+
}).trim();
|
|
155
|
+
for (const line of whichOut.split(/\r?\n/).map((l) => l.trim()).filter(Boolean)) {
|
|
156
|
+
let realLine = line;
|
|
157
|
+
try {
|
|
158
|
+
realLine = fs.realpathSync(line);
|
|
159
|
+
}
|
|
160
|
+
catch { }
|
|
161
|
+
const dirs = [path.dirname(line), path.dirname(realLine)];
|
|
162
|
+
for (const dir of dirs) {
|
|
163
|
+
const checks = [
|
|
164
|
+
path.join(dir, "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
|
|
165
|
+
path.join(dir, "node_modules", "@getpaseo", "server"),
|
|
166
|
+
path.join(path.dirname(dir), "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
|
|
167
|
+
path.join(path.dirname(dir), "node_modules", "@getpaseo", "server"),
|
|
168
|
+
path.join(path.dirname(path.dirname(dir)), "node_modules", "@getpaseo", "cli", "node_modules", "@getpaseo", "server"),
|
|
169
|
+
path.join(path.dirname(path.dirname(dir)), "node_modules", "@getpaseo", "server"),
|
|
170
|
+
path.join(dir, "resources", "app.asar.unpacked", "node_modules", "@getpaseo", "server"),
|
|
171
|
+
path.join(path.dirname(dir), "resources", "app.asar.unpacked", "node_modules", "@getpaseo", "server"),
|
|
172
|
+
];
|
|
173
|
+
for (const c of checks) {
|
|
174
|
+
if (fs.existsSync(c))
|
|
175
|
+
candidates.add(path.resolve(c));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch { }
|
|
149
181
|
try {
|
|
150
182
|
const npmRoot = execFileSync("npm", ["root", "-g"], { encoding: "utf-8", timeout: 2000 }).trim();
|
|
151
183
|
if (npmRoot && fs.existsSync(npmRoot)) {
|
|
@@ -618,39 +650,43 @@ export function patchPaseoServer(serverDir) {
|
|
|
618
650
|
}
|
|
619
651
|
}
|
|
620
652
|
// Patch handleUsageUpdate
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
653
|
+
const methodMatch = acpCode.match(/(?:^|\n)([ \t]*)handleUsageUpdate\s*\([^)]*\)\s*\{/);
|
|
654
|
+
if (methodMatch && methodMatch.index !== undefined) {
|
|
655
|
+
const startIdx = methodMatch.index + (methodMatch[0].startsWith("\n") ? 1 : 0);
|
|
656
|
+
const openBrace = acpCode.indexOf("{", startIdx);
|
|
657
|
+
if (openBrace !== -1) {
|
|
658
|
+
let depth = 1;
|
|
659
|
+
let i = openBrace + 1;
|
|
660
|
+
while (i < acpCode.length && depth > 0) {
|
|
661
|
+
if (acpCode[i] === "{")
|
|
662
|
+
depth++;
|
|
663
|
+
else if (acpCode[i] === "}")
|
|
664
|
+
depth--;
|
|
665
|
+
i++;
|
|
666
|
+
}
|
|
667
|
+
if (depth === 0) {
|
|
668
|
+
const currentMethodBody = acpCode.slice(startIdx, i);
|
|
669
|
+
const needsPatch = !currentMethodBody.includes('type: "usage_updated"') || currentMethodBody.includes("this.notifySubscribers");
|
|
670
|
+
if (needsPatch) {
|
|
671
|
+
const indent = methodMatch[1] || " ";
|
|
672
|
+
const newHandler = `${indent}handleUsageUpdate(update) {
|
|
673
|
+
${indent} if (!update) return;
|
|
674
|
+
${indent} const usage = mapACPUsage(update);
|
|
675
|
+
${indent} if (usage) {
|
|
676
|
+
${indent} this.currentTurnUsage = { ...this.currentTurnUsage, ...usage };
|
|
677
|
+
${indent} const event = {
|
|
678
|
+
${indent} type: "usage_updated",
|
|
679
|
+
${indent} provider: this.provider,
|
|
680
|
+
${indent} usage: this.currentTurnUsage,
|
|
681
|
+
${indent} ...(this.activeForegroundTurnId ? { turnId: this.activeForegroundTurnId } : {}),
|
|
682
|
+
${indent} };
|
|
683
|
+
${indent} if (typeof this.pushEvent === "function") {
|
|
684
|
+
${indent} this.pushEvent(event);
|
|
685
|
+
${indent} } else if (typeof this.deliverTranslatedEvents === "function") {
|
|
686
|
+
${indent} this.deliverTranslatedEvents([event]);
|
|
687
|
+
${indent} }
|
|
688
|
+
${indent} }
|
|
689
|
+
${indent}}`;
|
|
654
690
|
acpCode = acpCode.slice(0, startIdx) + newHandler + acpCode.slice(i);
|
|
655
691
|
acpModified = true;
|
|
656
692
|
}
|
|
@@ -762,7 +798,7 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
762
798
|
return { success: false, changes: [], error: `Asar archive not found: ${asarPath}` };
|
|
763
799
|
}
|
|
764
800
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "paseo-asar-extract-"));
|
|
765
|
-
extractAll(asarPath, tempDir);
|
|
801
|
+
const { unpackedPaths, originalHeader } = extractAll(asarPath, tempDir);
|
|
766
802
|
// Look for server directory in extracted files
|
|
767
803
|
const serverCandidates = [
|
|
768
804
|
path.join(tempDir, "node_modules", "@getpaseo", "server"),
|
|
@@ -805,8 +841,27 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
805
841
|
return { success: true, changes: [] };
|
|
806
842
|
}
|
|
807
843
|
changes.push(...patchResult.changes);
|
|
808
|
-
// Create backup if not already present
|
|
809
|
-
|
|
844
|
+
// Create backup if not already present.
|
|
845
|
+
// On macOS, never write backup inside .app bundle (e.g. app.asar.bak) because it breaks code signing seals.
|
|
846
|
+
let backupPath;
|
|
847
|
+
if (process.platform === "darwin" && asarPath.includes(".app")) {
|
|
848
|
+
const backupDir = path.join(os.homedir(), ".paseo", "backups");
|
|
849
|
+
if (!fs.existsSync(backupDir)) {
|
|
850
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
851
|
+
}
|
|
852
|
+
backupPath = path.join(backupDir, "app.asar.bak");
|
|
853
|
+
// Clean up any orphan backup inside the .app bundle from previous runs
|
|
854
|
+
const orphanBak = `${asarPath}.bak`;
|
|
855
|
+
if (fs.existsSync(orphanBak)) {
|
|
856
|
+
try {
|
|
857
|
+
fs.unlinkSync(orphanBak);
|
|
858
|
+
}
|
|
859
|
+
catch { }
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
backupPath = `${asarPath}.bak`;
|
|
864
|
+
}
|
|
810
865
|
if (!fs.existsSync(backupPath)) {
|
|
811
866
|
try {
|
|
812
867
|
fs.copyFileSync(asarPath, backupPath);
|
|
@@ -817,7 +872,7 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
817
872
|
}
|
|
818
873
|
}
|
|
819
874
|
tempAsar = path.join(os.tmpdir(), `app-${Date.now()}.asar`);
|
|
820
|
-
await createPackage(tempDir, tempAsar);
|
|
875
|
+
await createPackage(tempDir, tempAsar, { unpackedPaths, originalHeader });
|
|
821
876
|
// Replace original archive with locked file handling for Windows
|
|
822
877
|
try {
|
|
823
878
|
fs.copyFileSync(tempAsar, asarPath);
|
|
@@ -839,6 +894,21 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
839
894
|
throw copyErr;
|
|
840
895
|
}
|
|
841
896
|
}
|
|
897
|
+
// On macOS, re-sign application bundle if inside an .app directory to satisfy Gatekeeper
|
|
898
|
+
if (process.platform === "darwin" && asarPath.includes(".app")) {
|
|
899
|
+
const appIndex = asarPath.indexOf(".app");
|
|
900
|
+
const appBundlePath = asarPath.slice(0, appIndex + 4);
|
|
901
|
+
try {
|
|
902
|
+
execFileSync("codesign", ["--force", "--deep", "--sign", "-", appBundlePath], {
|
|
903
|
+
stdio: "ignore",
|
|
904
|
+
timeout: 15000,
|
|
905
|
+
});
|
|
906
|
+
changes.push(`Re-signed macOS bundle at ${appBundlePath}`);
|
|
907
|
+
}
|
|
908
|
+
catch (signErr) {
|
|
909
|
+
logger.warn(`Could not re-sign ${appBundlePath}`, { error: String(signErr) });
|
|
910
|
+
}
|
|
911
|
+
}
|
|
842
912
|
return { success: true, changes };
|
|
843
913
|
}
|
|
844
914
|
catch (err) {
|
|
@@ -914,6 +984,7 @@ export function isPaseoServerPatched(serverDir) {
|
|
|
914
984
|
try {
|
|
915
985
|
if (!fs.existsSync(serverDir))
|
|
916
986
|
return false;
|
|
987
|
+
// 1. Antigravity quota provider file
|
|
917
988
|
const antigravityJsCandidates = [
|
|
918
989
|
path.join(serverDir, "dist", "server", "services", "quota-fetcher", "providers", "antigravity.js"),
|
|
919
990
|
path.join(serverDir, "dist", "services", "quota-fetcher", "providers", "antigravity.js"),
|
|
@@ -940,20 +1011,80 @@ export function isPaseoServerPatched(serverDir) {
|
|
|
940
1011
|
};
|
|
941
1012
|
hasProvider = checkRecursive(path.join(serverDir, "dist"));
|
|
942
1013
|
}
|
|
943
|
-
if (hasProvider)
|
|
944
|
-
return
|
|
1014
|
+
if (!hasProvider)
|
|
1015
|
+
return false;
|
|
1016
|
+
// 2. Manifest check
|
|
945
1017
|
const manifestCandidates = [
|
|
946
1018
|
path.join(serverDir, "dist", "server", "services", "quota-fetcher", "manifest.js"),
|
|
947
1019
|
path.join(serverDir, "dist", "services", "quota-fetcher", "manifest.js"),
|
|
948
1020
|
];
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
if (
|
|
953
|
-
return
|
|
1021
|
+
let manifestFile = manifestCandidates.find((f) => fs.existsSync(f));
|
|
1022
|
+
if (!manifestFile && fs.existsSync(path.join(serverDir, "dist"))) {
|
|
1023
|
+
const findManifest = (dir, depth = 0) => {
|
|
1024
|
+
if (depth > 5)
|
|
1025
|
+
return null;
|
|
1026
|
+
try {
|
|
1027
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1028
|
+
for (const e of entries) {
|
|
1029
|
+
const full = path.join(dir, e.name);
|
|
1030
|
+
if (e.isDirectory() && e.name !== "node_modules") {
|
|
1031
|
+
const found = findManifest(full, depth + 1);
|
|
1032
|
+
if (found)
|
|
1033
|
+
return found;
|
|
1034
|
+
}
|
|
1035
|
+
else if (e.isFile() && e.name === "manifest.js" && dir.replace(/\\/g, "/").includes("quota-fetcher")) {
|
|
1036
|
+
return full;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
catch { }
|
|
1041
|
+
return null;
|
|
1042
|
+
};
|
|
1043
|
+
manifestFile = findManifest(path.join(serverDir, "dist")) || undefined;
|
|
1044
|
+
}
|
|
1045
|
+
if (manifestFile) {
|
|
1046
|
+
const content = fs.readFileSync(manifestFile, "utf-8");
|
|
1047
|
+
if (!content.includes('providerId: "antigravity"')) {
|
|
1048
|
+
return false;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// 3. ACP Agent check (context window telemetry & usage updates)
|
|
1052
|
+
const acpCandidates = [
|
|
1053
|
+
path.join(serverDir, "dist", "server", "server", "agent", "providers", "acp-agent.js"),
|
|
1054
|
+
path.join(serverDir, "dist", "server", "agent", "providers", "acp-agent.js"),
|
|
1055
|
+
path.join(serverDir, "dist", "agent", "providers", "acp-agent.js"),
|
|
1056
|
+
];
|
|
1057
|
+
let acpFile = acpCandidates.find((f) => fs.existsSync(f));
|
|
1058
|
+
if (!acpFile && fs.existsSync(path.join(serverDir, "dist"))) {
|
|
1059
|
+
const findAcp = (dir, depth = 0) => {
|
|
1060
|
+
if (depth > 5)
|
|
1061
|
+
return null;
|
|
1062
|
+
try {
|
|
1063
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1064
|
+
for (const e of entries) {
|
|
1065
|
+
const full = path.join(dir, e.name);
|
|
1066
|
+
if (e.isDirectory() && e.name !== "node_modules") {
|
|
1067
|
+
const found = findAcp(full, depth + 1);
|
|
1068
|
+
if (found)
|
|
1069
|
+
return found;
|
|
1070
|
+
}
|
|
1071
|
+
else if (e.isFile() && e.name === "acp-agent.js") {
|
|
1072
|
+
return full;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
catch { }
|
|
1077
|
+
return null;
|
|
1078
|
+
};
|
|
1079
|
+
acpFile = findAcp(path.join(serverDir, "dist")) || undefined;
|
|
1080
|
+
}
|
|
1081
|
+
if (acpFile) {
|
|
1082
|
+
const content = fs.readFileSync(acpFile, "utf-8");
|
|
1083
|
+
if (!content.includes('type: "usage_updated"') || !content.includes("contextWindowMaxTokens")) {
|
|
1084
|
+
return false;
|
|
954
1085
|
}
|
|
955
1086
|
}
|
|
956
|
-
return
|
|
1087
|
+
return true;
|
|
957
1088
|
}
|
|
958
1089
|
catch {
|
|
959
1090
|
return false;
|