@simonepri/refined-antigravity-acp 0.1.0 → 0.1.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.
Files changed (81) hide show
  1. package/dist/bin/cli.d.ts +3 -0
  2. package/dist/bin/cli.d.ts.map +1 -0
  3. package/dist/bin/cli.js +56 -0
  4. package/dist/bin/cli.js.map +1 -0
  5. package/dist/index.server.d.ts +4 -0
  6. package/dist/index.server.d.ts.map +1 -0
  7. package/dist/index.server.js +7 -0
  8. package/dist/index.server.js.map +1 -0
  9. package/dist/src/agy-patch.d.ts +65 -0
  10. package/dist/src/agy-patch.d.ts.map +1 -0
  11. package/dist/src/agy-patch.js +351 -0
  12. package/dist/src/agy-patch.js.map +1 -0
  13. package/dist/src/auth.d.ts +27 -0
  14. package/dist/src/auth.d.ts.map +1 -0
  15. package/dist/src/auth.js +113 -0
  16. package/dist/src/auth.js.map +1 -0
  17. package/dist/src/command.d.ts +5 -0
  18. package/dist/src/command.d.ts.map +1 -0
  19. package/dist/src/command.js +74 -0
  20. package/dist/src/command.js.map +1 -0
  21. package/dist/src/connector.d.ts +188 -0
  22. package/dist/src/connector.d.ts.map +1 -0
  23. package/dist/src/connector.js +1138 -0
  24. package/dist/src/connector.js.map +1 -0
  25. package/dist/src/history.d.ts +12 -0
  26. package/dist/src/history.d.ts.map +1 -0
  27. package/dist/src/history.js +152 -0
  28. package/dist/src/history.js.map +1 -0
  29. package/dist/src/mcp-proxy.d.ts +83 -0
  30. package/dist/src/mcp-proxy.d.ts.map +1 -0
  31. package/dist/src/mcp-proxy.js +308 -0
  32. package/dist/src/mcp-proxy.js.map +1 -0
  33. package/dist/src/provider.d.ts +11 -0
  34. package/dist/src/provider.d.ts.map +1 -0
  35. package/dist/src/provider.js +31 -0
  36. package/dist/src/provider.js.map +1 -0
  37. package/dist/src/sanitize.d.ts +29 -0
  38. package/dist/src/sanitize.d.ts.map +1 -0
  39. package/dist/src/sanitize.js +237 -0
  40. package/dist/src/sanitize.js.map +1 -0
  41. package/dist/src/skills.d.ts +17 -0
  42. package/dist/src/skills.d.ts.map +1 -0
  43. package/dist/src/skills.js +140 -0
  44. package/dist/src/skills.js.map +1 -0
  45. package/dist/src/steering.d.ts +30 -0
  46. package/dist/src/steering.d.ts.map +1 -0
  47. package/dist/src/steering.js +174 -0
  48. package/dist/src/steering.js.map +1 -0
  49. package/package.json +20 -13
  50. package/readme.md +3 -5
  51. package/.fallowrc.json +0 -11
  52. package/.github/workflows/ci.yml +0 -24
  53. package/.github/workflows/release.yml +0 -41
  54. package/.oxlintignore +0 -2
  55. package/.oxlintrc.json +0 -152
  56. package/.release-please-manifest.json +0 -3
  57. package/bin/cli.ts +0 -58
  58. package/index.server.ts +0 -9
  59. package/pnpm-workspace.yaml +0 -44
  60. package/release-please-config.json +0 -13
  61. package/server/agy-patch.test.ts +0 -445
  62. package/server/agy-patch.ts +0 -445
  63. package/server/auth.test.ts +0 -51
  64. package/server/auth.ts +0 -122
  65. package/server/command.test.ts +0 -18
  66. package/server/command.ts +0 -92
  67. package/server/connector.test.ts +0 -1136
  68. package/server/connector.ts +0 -1386
  69. package/server/history.test.ts +0 -139
  70. package/server/history.ts +0 -157
  71. package/server/mcp-proxy.test.ts +0 -368
  72. package/server/mcp-proxy.ts +0 -375
  73. package/server/provider.test.ts +0 -11
  74. package/server/provider.ts +0 -37
  75. package/server/sanitize.test.ts +0 -174
  76. package/server/sanitize.ts +0 -286
  77. package/server/skills.test.ts +0 -121
  78. package/server/skills.ts +0 -183
  79. package/server/steering.test.ts +0 -405
  80. package/server/steering.ts +0 -199
  81. package/tsconfig.json +0 -14
@@ -1,445 +0,0 @@
1
- import fs from "node:fs";
2
- import os from "node:os";
3
- import path from "node:path";
4
- import zlib from "node:zlib";
5
- import { describe, expect, it, afterEach } from "vitest";
6
- import {
7
- EVENT_PROCESSOR_ENTRY,
8
- ORIGINAL_ANCHOR,
9
- PROMPT_ANCHOR,
10
- PYCACHE_PREFIX,
11
- REPLACEMENT_CODE,
12
- classifyBinary,
13
- classifyBuffer,
14
- ensurePatchedBinary,
15
- gcCache,
16
- getCacheKey,
17
- parseZipArchive,
18
- patchBinary,
19
- patchBuffer,
20
- } from "./agy-patch.js";
21
-
22
- const DUMMY_MACHO_PREFIX = Buffer.from([
23
- 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00,
24
- 0x10, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25
- ]);
26
-
27
- const SIBLING_PYC_ENTRY = `${PYCACHE_PREFIX}cpython-314.pyc`;
28
-
29
- const DECORATIVE_COMMENTS = [
30
- " # ---------------------------------------------------------------------------",
31
- " # Dynamic policy evaluation",
32
- " # ---------------------------------------------------------------------------",
33
- ].join("\n");
34
-
35
- function createEventProcessorContent(anchor = ORIGINAL_ANCHOR): string {
36
- return [
37
- "# Copyright 2026 Google LLC",
38
- "# Antigravity event processor",
39
- "class EventProcessor:",
40
- " async def _process(self, tsu):",
41
- " if False:",
42
- " pass",
43
- anchor,
44
- ' if tsu.HasField("error"): await self.step_queue.put(None)',
45
- "",
46
- DECORATIVE_COMMENTS,
47
- "",
48
- " async def _finish(self):",
49
- " return True",
50
- ].join("\n");
51
- }
52
-
53
- interface SyntheticZipEntry {
54
- name: string;
55
- data: string | Buffer;
56
- method?: number;
57
- }
58
-
59
- interface BuildZipOptions {
60
- prefix?: Buffer;
61
- trailer?: Buffer;
62
- }
63
-
64
- function buildSyntheticZip(entries: SyntheticZipEntry[], options: BuildZipOptions = {}): Buffer {
65
- const prefix = options.prefix ?? DUMMY_MACHO_PREFIX;
66
- const trailer = options.trailer ?? Buffer.alloc(0);
67
-
68
- const localChunks: Buffer[] = [];
69
- const cdChunks: Buffer[] = [];
70
- let currentOffset = 0;
71
-
72
- const cdEntries: Array<{
73
- nameBuf: Buffer;
74
- dataLen: number;
75
- crc: number;
76
- method: number;
77
- localOffset: number;
78
- }> = [];
79
-
80
- for (const entry of entries) {
81
- const nameBuf = Buffer.from(entry.name, "utf8");
82
- const dataBuf = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data, "utf8");
83
- const crc = zlib.crc32(dataBuf);
84
- const method = entry.method ?? 0;
85
-
86
- const locHdr = Buffer.alloc(30);
87
- locHdr.writeUInt32LE(0x04034b50, 0);
88
- locHdr.writeUInt16LE(20, 4);
89
- locHdr.writeUInt16LE(0, 6);
90
- locHdr.writeUInt16LE(method, 8);
91
- locHdr.writeUInt16LE(0, 10);
92
- locHdr.writeUInt16LE(0, 12);
93
- locHdr.writeUInt32LE(crc, 14);
94
- locHdr.writeUInt32LE(dataBuf.length, 18);
95
- locHdr.writeUInt32LE(dataBuf.length, 22);
96
- locHdr.writeUInt16LE(nameBuf.length, 26);
97
- locHdr.writeUInt16LE(0, 28);
98
-
99
- const localOffset = currentOffset;
100
- localChunks.push(locHdr, nameBuf, dataBuf);
101
- currentOffset += 30 + nameBuf.length + dataBuf.length;
102
-
103
- cdEntries.push({
104
- nameBuf,
105
- dataLen: dataBuf.length,
106
- crc,
107
- method,
108
- localOffset,
109
- });
110
- }
111
-
112
- const cdStart = currentOffset;
113
- let cdSize = 0;
114
- for (const cde of cdEntries) {
115
- const cdHdr = Buffer.alloc(46);
116
- cdHdr.writeUInt32LE(0x02014b50, 0);
117
- cdHdr.writeUInt16LE(0x031e, 4);
118
- cdHdr.writeUInt16LE(20, 6);
119
- cdHdr.writeUInt16LE(0, 8);
120
- cdHdr.writeUInt16LE(cde.method, 10);
121
- cdHdr.writeUInt16LE(0, 12);
122
- cdHdr.writeUInt16LE(0, 14);
123
- cdHdr.writeUInt32LE(cde.crc, 16);
124
- cdHdr.writeUInt32LE(cde.dataLen, 20);
125
- cdHdr.writeUInt32LE(cde.dataLen, 24);
126
- cdHdr.writeUInt16LE(cde.nameBuf.length, 28);
127
- cdHdr.writeUInt16LE(0, 30);
128
- cdHdr.writeUInt16LE(0, 32);
129
- cdHdr.writeUInt16LE(0, 34);
130
- cdHdr.writeUInt16LE(0, 36);
131
- cdHdr.writeUInt32LE((0o100644 << 16) >>> 0, 38);
132
- cdHdr.writeUInt32LE(cde.localOffset, 42);
133
-
134
- cdChunks.push(cdHdr, cde.nameBuf);
135
- cdSize += 46 + cde.nameBuf.length;
136
- }
137
-
138
- const eocd = Buffer.alloc(22);
139
- eocd.writeUInt32LE(0x06054b50, 0);
140
- eocd.writeUInt16LE(0, 4);
141
- eocd.writeUInt16LE(0, 6);
142
- eocd.writeUInt16LE(entries.length, 8);
143
- eocd.writeUInt16LE(entries.length, 10);
144
- eocd.writeUInt32LE(cdSize, 12);
145
- eocd.writeUInt32LE(cdStart, 16);
146
- eocd.writeUInt16LE(0, 20);
147
-
148
- return Buffer.concat([prefix, ...localChunks, ...cdChunks, eocd, trailer]);
149
- }
150
-
151
- describe("agy-patch binary engine", () => {
152
- const tempDirs: string[] = [];
153
-
154
- function makeTempDir(prefix = "agy-patch-test"): string {
155
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), `${prefix}-`));
156
- tempDirs.push(dir);
157
- return dir;
158
- }
159
-
160
- afterEach(() => {
161
- delete process.env.PASEO_AGY_NO_PATCH;
162
- for (const dir of tempDirs) {
163
- fs.rmSync(dir, { recursive: true, force: true });
164
- }
165
- tempDirs.length = 0;
166
- });
167
-
168
- describe("classification", () => {
169
- it("classifies valid unpatched fixture as patchable", () => {
170
- const buf = buildSyntheticZip([
171
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
172
- { name: SIBLING_PYC_ENTRY, data: Buffer.from("dummy-pyc-bytecode") },
173
- ]);
174
- expect(classifyBuffer(buf)).toBe("patchable");
175
- });
176
-
177
- it("classifies fixed fixture as already-fixed", () => {
178
- const fixedContent = createEventProcessorContent(REPLACEMENT_CODE);
179
- const buf = buildSyntheticZip([{ name: EVENT_PROCESSOR_ENTRY, data: fixedContent }]);
180
- expect(classifyBuffer(buf)).toBe("already-fixed");
181
- });
182
-
183
- it("classifies missing event_processor.py as entry-missing", () => {
184
- const buf = buildSyntheticZip([{ name: "some/other/file.py", data: "print(123)" }]);
185
- expect(classifyBuffer(buf)).toBe("entry-missing");
186
- });
187
-
188
- it("classifies file without anchor or replacement as unrecognized", () => {
189
- const buf = buildSyntheticZip([{ name: EVENT_PROCESSOR_ENTRY, data: "def hello(): pass" }]);
190
- expect(classifyBuffer(buf)).toBe("unrecognized");
191
- });
192
-
193
- it("classifies non-stored (compressed) entry as unrecognized", () => {
194
- const buf = buildSyntheticZip([
195
- {
196
- name: EVENT_PROCESSOR_ENTRY,
197
- data: createEventProcessorContent(),
198
- method: 8,
199
- },
200
- ]);
201
- expect(classifyBuffer(buf)).toBe("unrecognized");
202
- });
203
-
204
- it("classifies entry without decorative comments as unrecognized", () => {
205
- const noComments = ["class EventProcessor:", ORIGINAL_ANCHOR, " pass"].join("\n");
206
- const buf = buildSyntheticZip([{ name: EVENT_PROCESSOR_ENTRY, data: noComments }]);
207
- expect(classifyBuffer(buf)).toBe("unrecognized");
208
- });
209
-
210
- it("classifies non-zip buffer as unrecognized", () => {
211
- const buf = Buffer.from("not a zip archive");
212
- expect(classifyBuffer(buf)).toBe("unrecognized");
213
- });
214
- });
215
-
216
- describe("patchBuffer", () => {
217
- it("patches in-place, preserving identical length, updating CRC, and renaming .pyc", () => {
218
- const originalContent = createEventProcessorContent();
219
- const pycData = Buffer.from("precompiled-cpython-bytecode");
220
-
221
- const buf = buildSyntheticZip(
222
- [
223
- { name: EVENT_PROCESSOR_ENTRY, data: originalContent },
224
- { name: SIBLING_PYC_ENTRY, data: pycData },
225
- ],
226
- {
227
- prefix: Buffer.alloc(128, 0xef),
228
- trailer: Buffer.alloc(64, 0x99),
229
- },
230
- );
231
-
232
- const originalLength = buf.length;
233
- const initialClassification = classifyBuffer(buf);
234
- expect(initialClassification).toBe("patchable");
235
-
236
- const result = patchBuffer(buf);
237
- expect(result.patched).toBe(true);
238
- expect(result.classification).toBe("already-fixed");
239
-
240
- // 1. Identical file length
241
- expect(buf.length).toBe(originalLength);
242
-
243
- // 2. Re-classification returns already-fixed
244
- expect(classifyBuffer(buf)).toBe("already-fixed");
245
-
246
- // 3. Parse zip and verify headers
247
- const zip = parseZipArchive(buf);
248
- expect(zip).not.toBeNull();
249
-
250
- // event_processor.py checks
251
- const pyEntry = zip!.entries.get(EVENT_PROCESSOR_ENTRY);
252
- expect(pyEntry).toBeDefined();
253
-
254
- const absLocalHdr = zip!.baseOffset + pyEntry!.localHeaderOffset;
255
- const localCrc = buf.readUInt32LE(absLocalHdr + 14);
256
- const cdCrc = pyEntry!.crc32;
257
- expect(localCrc).toBe(cdCrc);
258
-
259
- // Extract modified entry data and verify CRC matches zlib.crc32
260
- const dataOffset = absLocalHdr + 30 + pyEntry!.nameLength + pyEntry!.extraLength;
261
- const modifiedData = buf.subarray(dataOffset, dataOffset + pyEntry!.uncompSize);
262
- const computedCrc = zlib.crc32(modifiedData);
263
- expect(cdCrc).toBe(computedCrc);
264
-
265
- const modifiedText = modifiedData.toString("utf8");
266
- expect(modifiedText).toContain("STATE_WAITING_FOR_TASKS");
267
- expect(modifiedText).not.toContain(ORIGINAL_ANCHOR);
268
-
269
- // 4. Sibling .pyc is renamed to .bak in both CD and Local Header
270
- const expectedBakName = SIBLING_PYC_ENTRY.replace(/\.pyc$/, ".bak");
271
- const bakEntry = zip!.entries.get(expectedBakName);
272
- expect(bakEntry).toBeDefined();
273
-
274
- const bakLocalHdr = zip!.baseOffset + bakEntry!.localHeaderOffset;
275
- const bakLocalName = buf
276
- .subarray(bakLocalHdr + 30, bakLocalHdr + 30 + bakEntry!.nameLength)
277
- .toString("utf8");
278
- expect(bakLocalName).toBe(expectedBakName);
279
-
280
- // Original .pyc entry should no longer be in zip map
281
- expect(zip!.entries.get(SIBLING_PYC_ENTRY)).toBeUndefined();
282
- });
283
-
284
- it("is idempotent and avoids re-patching an already-fixed buffer", () => {
285
- const buf = buildSyntheticZip([
286
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
287
- { name: SIBLING_PYC_ENTRY, data: Buffer.from("dummy") },
288
- ]);
289
-
290
- const first = patchBuffer(buf);
291
- expect(first.patched).toBe(true);
292
-
293
- const second = patchBuffer(buf);
294
- expect(second.patched).toBe(false);
295
- expect(second.classification).toBe("already-fixed");
296
- });
297
-
298
- it("supports prompt anchor formatting with decorative comments", () => {
299
- const promptContent = ["class EventProcessor:", PROMPT_ANCHOR, DECORATIVE_COMMENTS].join(
300
- "\n",
301
- );
302
-
303
- const buf = buildSyntheticZip([{ name: EVENT_PROCESSOR_ENTRY, data: promptContent }]);
304
-
305
- expect(classifyBuffer(buf)).toBe("patchable");
306
- const res = patchBuffer(buf);
307
- expect(res.patched).toBe(true);
308
- expect(classifyBuffer(buf)).toBe("already-fixed");
309
- });
310
- });
311
-
312
- describe("patchBinary and caching", () => {
313
- it("respects PASEO_AGY_NO_PATCH=1 escape hatch", () => {
314
- process.env.PASEO_AGY_NO_PATCH = "1";
315
- const dir = makeTempDir();
316
- const binPath = path.join(dir, "agy_acp_server.par");
317
- const buf = buildSyntheticZip([
318
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
319
- ]);
320
- fs.writeFileSync(binPath, buf);
321
-
322
- const res = patchBinary(binPath, { skipSign: true });
323
- expect(res.patched).toBe(false);
324
- expect(res.path).toBe(binPath);
325
- });
326
-
327
- it("creates a clone in cache dir, patches clone, and leaves source intact", () => {
328
- const dir = makeTempDir();
329
- const cacheBase = path.join(dir, "cache");
330
- const binPath = path.join(dir, "agy_acp_server.par");
331
-
332
- const originalBuf = buildSyntheticZip([
333
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
334
- { name: SIBLING_PYC_ENTRY, data: Buffer.from("bytecode") },
335
- ]);
336
- fs.writeFileSync(binPath, originalBuf);
337
-
338
- const res = patchBinary(binPath, {
339
- cacheBaseDir: cacheBase,
340
- skipSign: true,
341
- });
342
-
343
- expect(res.patched).toBe(true);
344
- expect(res.cached).toBe(false);
345
- expect(res.classification).toBe("already-fixed");
346
- expect(res.path).not.toBe(binPath);
347
- expect(fs.existsSync(res.path)).toBe(true);
348
-
349
- // Verify original binary is unmodified
350
- const srcBuf = fs.readFileSync(binPath);
351
- expect(classifyBuffer(srcBuf)).toBe("patchable");
352
-
353
- // Verify cached clone is patched
354
- const cloneBuf = fs.readFileSync(res.path);
355
- expect(classifyBuffer(cloneBuf)).toBe("already-fixed");
356
- });
357
-
358
- it("hits cache on second call and avoids re-patching", () => {
359
- const dir = makeTempDir();
360
- const cacheBase = path.join(dir, "cache");
361
- const binPath = path.join(dir, "agy_acp_server.par");
362
-
363
- const originalBuf = buildSyntheticZip([
364
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
365
- { name: SIBLING_PYC_ENTRY, data: Buffer.from("bytecode") },
366
- ]);
367
- fs.writeFileSync(binPath, originalBuf);
368
-
369
- const first = patchBinary(binPath, {
370
- cacheBaseDir: cacheBase,
371
- skipSign: true,
372
- });
373
- expect(first.patched).toBe(true);
374
- expect(first.cached).toBe(false);
375
-
376
- const second = patchBinary(binPath, {
377
- cacheBaseDir: cacheBase,
378
- skipSign: true,
379
- });
380
- expect(second.patched).toBe(false);
381
- expect(second.cached).toBe(true);
382
- expect(second.path).toBe(first.path);
383
-
384
- // ensurePatchedBinary returns the cached path
385
- const ensured = ensurePatchedBinary(binPath, {
386
- cacheBaseDir: cacheBase,
387
- skipSign: true,
388
- });
389
- expect(ensured).toBe(first.path);
390
- });
391
-
392
- it("returns original path without patching for unrecognized binaries", () => {
393
- const dir = makeTempDir();
394
- const binPath = path.join(dir, "agy_acp_server.par");
395
- fs.writeFileSync(binPath, Buffer.from("random unpatchable data"));
396
-
397
- const res = patchBinary(binPath, { skipSign: true });
398
- expect(res.patched).toBe(false);
399
- expect(res.classification).toBe("unrecognized");
400
- expect(res.path).toBe(binPath);
401
- });
402
-
403
- it("garbage collects old cache directories while retaining the active key", () => {
404
- const dir = makeTempDir();
405
- const cacheBase = path.join(dir, "cache");
406
- const activeKey = "active-key-123";
407
- const oldKey1 = "old-key-456";
408
- const oldKey2 = "old-key-789";
409
-
410
- fs.mkdirSync(path.join(cacheBase, activeKey), { recursive: true });
411
- fs.mkdirSync(path.join(cacheBase, oldKey1), { recursive: true });
412
- fs.mkdirSync(path.join(cacheBase, oldKey2), { recursive: true });
413
-
414
- gcCache(cacheBase, activeKey);
415
-
416
- expect(fs.existsSync(path.join(cacheBase, activeKey))).toBe(true);
417
- expect(fs.existsSync(path.join(cacheBase, oldKey1))).toBe(false);
418
- expect(fs.existsSync(path.join(cacheBase, oldKey2))).toBe(false);
419
- });
420
-
421
- it("generates deterministic cache keys", () => {
422
- const dir = makeTempDir();
423
- const testFile = path.join(dir, "binary");
424
- fs.writeFileSync(testFile, "test");
425
- const stat = fs.statSync(testFile);
426
-
427
- const key1 = getCacheKey(testFile, stat);
428
- const key2 = getCacheKey(testFile, stat);
429
- expect(key1).toBe(key2);
430
- expect(typeof key1).toBe("string");
431
- expect(key1.length).toBe(32);
432
- });
433
-
434
- it("correctly classifies binary from filesystem via classifyBinary", () => {
435
- const dir = makeTempDir();
436
- const binPath = path.join(dir, "agy_acp_server.par");
437
- const buf = buildSyntheticZip([
438
- { name: EVENT_PROCESSOR_ENTRY, data: createEventProcessorContent() },
439
- ]);
440
- fs.writeFileSync(binPath, buf);
441
-
442
- expect(classifyBinary(binPath)).toBe("patchable");
443
- });
444
- });
445
- });