paseo-acp-agy 1.1.9 → 1.2.0
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/acp-server.d.ts +2 -0
- package/dist/acp-server.js +66 -4
- package/dist/antigravity-process.d.ts +2 -0
- package/dist/antigravity-process.js +7 -0
- package/dist/asar.d.ts +28 -0
- package/dist/asar.js +171 -0
- package/dist/attachments.js +3 -0
- package/dist/index.js +14 -7
- package/dist/paseo-patcher.js +19 -9
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.js +12 -0
- package/dist/protocol.d.ts +45 -0
- package/dist/protocol.js +124 -0
- package/dist/session-store.d.ts +1 -0
- package/dist/session-store.js +3 -0
- package/dist/session.d.ts +3 -0
- package/dist/session.js +20 -2
- package/dist/version.js +1 -1
- package/package.json +5 -4
package/dist/acp-server.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare class ACPServer {
|
|
|
5
5
|
private input;
|
|
6
6
|
private output;
|
|
7
7
|
private binaryPath;
|
|
8
|
+
private skipNarration;
|
|
8
9
|
private rl;
|
|
9
10
|
private isRunning;
|
|
10
11
|
constructor(options?: {
|
|
@@ -12,6 +13,7 @@ export declare class ACPServer {
|
|
|
12
13
|
output?: Writable;
|
|
13
14
|
sessionManager?: SessionManager;
|
|
14
15
|
binaryPath?: string;
|
|
16
|
+
skipNarration?: boolean;
|
|
15
17
|
});
|
|
16
18
|
start(): void;
|
|
17
19
|
private send;
|
package/dist/acp-server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import readline from "node:readline";
|
|
2
2
|
import { logger } from "./logger.js";
|
|
3
|
-
import { ACP_METHODS, AVAILABLE_MODES, fetchAvailableModels,
|
|
3
|
+
import { ACP_METHODS, AVAILABLE_MODES, AVAILABLE_PERMISSIONS, fetchAvailableModels, buildConfigOptionsForSession, extractPromptText, mapToolNameToKind, extractImageMarkdownLink, isNarrationText, calculateUsageCostUsd, roundUsageCostUsd, getModelContextWindow, fetchAntigravityUsage, } from "./protocol.js";
|
|
4
4
|
import { SessionManager } from "./session.js";
|
|
5
5
|
import { executeSlashCommand, AVAILABLE_SLASH_COMMANDS } from "./slash-commands.js";
|
|
6
6
|
import { getShortVersion } from "./version.js";
|
|
@@ -21,12 +21,15 @@ export class ACPServer {
|
|
|
21
21
|
input;
|
|
22
22
|
output;
|
|
23
23
|
binaryPath;
|
|
24
|
+
skipNarration;
|
|
24
25
|
rl = null;
|
|
25
26
|
isRunning = false;
|
|
26
27
|
constructor(options = {}) {
|
|
27
28
|
this.input = options.input || process.stdin;
|
|
28
29
|
this.output = options.output || process.stdout;
|
|
29
30
|
this.binaryPath = options.binaryPath || resolveDefaultAgyBinary();
|
|
31
|
+
this.skipNarration =
|
|
32
|
+
options.skipNarration ?? (process.env.AGY_ACP_SKIP_NARRATION === "true");
|
|
30
33
|
this.sessionManager =
|
|
31
34
|
options.sessionManager || new SessionManager({ defaultBinaryPath: this.binaryPath });
|
|
32
35
|
}
|
|
@@ -112,7 +115,13 @@ export class ACPServer {
|
|
|
112
115
|
availableModels,
|
|
113
116
|
currentModelId: session.model,
|
|
114
117
|
},
|
|
115
|
-
configOptions:
|
|
118
|
+
configOptions: buildConfigOptionsForSession({
|
|
119
|
+
modelId: session.model,
|
|
120
|
+
currentEffort: session.effort,
|
|
121
|
+
currentMode: session.mode,
|
|
122
|
+
currentPermission: session.permission,
|
|
123
|
+
availableModels,
|
|
124
|
+
}),
|
|
116
125
|
};
|
|
117
126
|
}
|
|
118
127
|
requireSession(sessionId) {
|
|
@@ -329,11 +338,19 @@ export class ACPServer {
|
|
|
329
338
|
this.sendSuccess(id, { stopReason: "end_turn" });
|
|
330
339
|
break;
|
|
331
340
|
}
|
|
341
|
+
let hasSentNonNarration = false;
|
|
332
342
|
const onStepUpdate = (event) => {
|
|
333
343
|
const step = event.step_update;
|
|
334
344
|
if (!step)
|
|
335
345
|
return;
|
|
336
346
|
if (step.step_type === "agent_response" && step.text_delta) {
|
|
347
|
+
if (this.skipNarration && !hasSentNonNarration) {
|
|
348
|
+
if (isNarrationText(step.text_delta)) {
|
|
349
|
+
logger.debug("Skipping pure narration text chunk", { delta: step.text_delta });
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
hasSentNonNarration = true;
|
|
353
|
+
}
|
|
337
354
|
this.sendNotification(ACP_METHODS.SESSION_UPDATE, {
|
|
338
355
|
sessionId: session.id,
|
|
339
356
|
update: {
|
|
@@ -343,6 +360,7 @@ export class ACPServer {
|
|
|
343
360
|
});
|
|
344
361
|
}
|
|
345
362
|
else if (step.step_type === "thought" && step.text_delta) {
|
|
363
|
+
hasSentNonNarration = true;
|
|
346
364
|
this.sendNotification(ACP_METHODS.SESSION_UPDATE, {
|
|
347
365
|
sessionId: session.id,
|
|
348
366
|
update: {
|
|
@@ -352,6 +370,7 @@ export class ACPServer {
|
|
|
352
370
|
});
|
|
353
371
|
}
|
|
354
372
|
else if (step.step_type === "tool" && step.tool_info) {
|
|
373
|
+
hasSentNonNarration = true;
|
|
355
374
|
const toolCallId = `tool_${step.step_index}`;
|
|
356
375
|
const toolName = step.tool_name || step.tool_info.name || "tool";
|
|
357
376
|
const toolKind = mapToolNameToKind(toolName);
|
|
@@ -377,6 +396,16 @@ export class ACPServer {
|
|
|
377
396
|
rawOutput: step.tool_info.output ?? "",
|
|
378
397
|
},
|
|
379
398
|
});
|
|
399
|
+
const imageMarkdown = extractImageMarkdownLink(toolName, step.tool_info.output, step.tool_info.parameters);
|
|
400
|
+
if (imageMarkdown) {
|
|
401
|
+
this.sendNotification(ACP_METHODS.SESSION_UPDATE, {
|
|
402
|
+
sessionId: session.id,
|
|
403
|
+
update: {
|
|
404
|
+
sessionUpdate: "agent_message_chunk",
|
|
405
|
+
content: { type: "text", text: `\n\n${imageMarkdown}\n\n` },
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
}
|
|
380
409
|
}
|
|
381
410
|
else if (step.state === "ERROR") {
|
|
382
411
|
this.sendNotification(ACP_METHODS.SESSION_UPDATE, {
|
|
@@ -496,6 +525,7 @@ export class ACPServer {
|
|
|
496
525
|
break;
|
|
497
526
|
}
|
|
498
527
|
case ACP_METHODS.SESSION_SET_MODE:
|
|
528
|
+
case ACP_METHODS.SESSION_SET_MODE_CAMEL:
|
|
499
529
|
case ACP_METHODS.SESSION_SET_MODE_ALIAS: {
|
|
500
530
|
const sessionId = String(params.sessionId || "");
|
|
501
531
|
const modeId = String(params.modeId || params.mode || "default");
|
|
@@ -516,6 +546,7 @@ export class ACPServer {
|
|
|
516
546
|
break;
|
|
517
547
|
}
|
|
518
548
|
case ACP_METHODS.SESSION_SET_MODEL:
|
|
549
|
+
case ACP_METHODS.SESSION_SET_MODEL_CAMEL:
|
|
519
550
|
case ACP_METHODS.SESSION_SET_MODEL_ALIAS: {
|
|
520
551
|
const sessionId = String(params.sessionId || "");
|
|
521
552
|
const session = this.requireSession(sessionId);
|
|
@@ -546,12 +577,19 @@ export class ACPServer {
|
|
|
546
577
|
if (parsedModel.effort)
|
|
547
578
|
session.setEffort(parsedModel.effort);
|
|
548
579
|
session.setModel(model.modelId);
|
|
549
|
-
const configOptions =
|
|
580
|
+
const configOptions = buildConfigOptionsForSession({
|
|
581
|
+
modelId: session.model,
|
|
582
|
+
currentEffort: session.effort,
|
|
583
|
+
currentMode: session.mode,
|
|
584
|
+
currentPermission: session.permission,
|
|
585
|
+
availableModels: models,
|
|
586
|
+
});
|
|
550
587
|
if (!isNotification)
|
|
551
588
|
this.sendSuccess(id, { configOptions });
|
|
552
589
|
break;
|
|
553
590
|
}
|
|
554
591
|
case ACP_METHODS.SESSION_SET_CONFIG_OPTION:
|
|
592
|
+
case ACP_METHODS.SESSION_SET_CONFIG_OPTION_CAMEL:
|
|
555
593
|
case ACP_METHODS.SESSION_SET_CONFIG_OPTION_ALIAS: {
|
|
556
594
|
const sessionId = String(params.sessionId || "");
|
|
557
595
|
const configId = String(params.configId || "");
|
|
@@ -584,12 +622,36 @@ export class ACPServer {
|
|
|
584
622
|
session.setModel(value);
|
|
585
623
|
logger.info("Updated model for session via config option", { sessionId, model: value });
|
|
586
624
|
}
|
|
625
|
+
else if (configId === "mode") {
|
|
626
|
+
if (!AVAILABLE_MODES.some((candidate) => candidate.id === value)) {
|
|
627
|
+
if (!isNotification)
|
|
628
|
+
this.sendError(id, -32602, `Unsupported mode: ${value}`);
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
session.setMode(value);
|
|
632
|
+
logger.info("Updated mode for session via config option", { sessionId, mode: value });
|
|
633
|
+
}
|
|
634
|
+
else if (configId === "permission") {
|
|
635
|
+
if (!AVAILABLE_PERMISSIONS.some((candidate) => candidate.id === value)) {
|
|
636
|
+
if (!isNotification)
|
|
637
|
+
this.sendError(id, -32602, `Unsupported permission: ${value}`);
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
session.setPermission(value);
|
|
641
|
+
logger.info("Updated permission for session via config option", { sessionId, permission: value });
|
|
642
|
+
}
|
|
587
643
|
else {
|
|
588
644
|
if (!isNotification)
|
|
589
645
|
this.sendError(id, -32602, `Unsupported config option: ${configId}`);
|
|
590
646
|
break;
|
|
591
647
|
}
|
|
592
|
-
const configOptions =
|
|
648
|
+
const configOptions = buildConfigOptionsForSession({
|
|
649
|
+
modelId: session.model,
|
|
650
|
+
currentEffort: session.effort,
|
|
651
|
+
currentMode: session.mode,
|
|
652
|
+
currentPermission: session.permission,
|
|
653
|
+
availableModels: models,
|
|
654
|
+
});
|
|
593
655
|
if (!isNotification)
|
|
594
656
|
this.sendSuccess(id, { configOptions });
|
|
595
657
|
break;
|
|
@@ -40,6 +40,8 @@ export declare class AntigravityProcess extends EventEmitter {
|
|
|
40
40
|
setModel(model: string): void;
|
|
41
41
|
setEffort(effort: string): void;
|
|
42
42
|
setMode(mode: string): void;
|
|
43
|
+
get currentPermissions(): PermissionSettings;
|
|
44
|
+
setPermissions(permissions: Partial<PermissionSettings>): void;
|
|
43
45
|
setConversationId(conversationId?: string): void;
|
|
44
46
|
private scheduleRestart;
|
|
45
47
|
private isProcessTreeAlive;
|
|
@@ -189,6 +189,13 @@ export class AntigravityProcess extends EventEmitter {
|
|
|
189
189
|
this.scheduleRestart();
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
+
get currentPermissions() {
|
|
193
|
+
return this.permissions;
|
|
194
|
+
}
|
|
195
|
+
setPermissions(permissions) {
|
|
196
|
+
this.permissions = { ...this.permissions, ...permissions };
|
|
197
|
+
this.scheduleRestart();
|
|
198
|
+
}
|
|
192
199
|
setConversationId(conversationId) {
|
|
193
200
|
if (this.conversationId !== conversationId) {
|
|
194
201
|
this.conversationId = conversationId;
|
package/dist/asar.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface AsarNode {
|
|
2
|
+
files?: Record<string, AsarNode>;
|
|
3
|
+
size?: number;
|
|
4
|
+
offset?: string;
|
|
5
|
+
executable?: boolean;
|
|
6
|
+
unpacked?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Reads and parses the ASAR archive header and returns the root node and base offset for data.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readArchiveHeader(archivePath: string): {
|
|
12
|
+
header: AsarNode;
|
|
13
|
+
dataBaseOffset: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Lists all file paths inside an ASAR archive.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listPackage(archivePath: string): string[];
|
|
19
|
+
/**
|
|
20
|
+
* Pure TypeScript, zero-dependency ASAR archive extractor.
|
|
21
|
+
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractAll(archivePath: string, destDir: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Pure TypeScript, zero-dependency ASAR archive builder.
|
|
26
|
+
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createPackage(srcDir: string, destFile: string): Promise<void>;
|
package/dist/asar.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Reads and parses the ASAR archive header and returns the root node and base offset for data.
|
|
5
|
+
*/
|
|
6
|
+
export function readArchiveHeader(archivePath) {
|
|
7
|
+
if (!fs.existsSync(archivePath)) {
|
|
8
|
+
throw new Error(`ASAR archive not found: ${archivePath}`);
|
|
9
|
+
}
|
|
10
|
+
const fd = fs.openSync(archivePath, "r");
|
|
11
|
+
try {
|
|
12
|
+
const sizeBuf = Buffer.alloc(8);
|
|
13
|
+
const bytesRead = fs.readSync(fd, sizeBuf, 0, 8, 0);
|
|
14
|
+
if (bytesRead < 8) {
|
|
15
|
+
throw new Error(`Invalid ASAR archive: file too small (${bytesRead} bytes)`);
|
|
16
|
+
}
|
|
17
|
+
const payloadSize = sizeBuf.readUInt32LE(0);
|
|
18
|
+
const headerSize = sizeBuf.readUInt32LE(4);
|
|
19
|
+
if (payloadSize !== 4 || headerSize <= 0) {
|
|
20
|
+
throw new Error(`Invalid ASAR archive header size: payloadSize=${payloadSize}, headerSize=${headerSize}`);
|
|
21
|
+
}
|
|
22
|
+
const headerPickleBuf = Buffer.alloc(headerSize);
|
|
23
|
+
const headerRead = fs.readSync(fd, headerPickleBuf, 0, headerSize, 8);
|
|
24
|
+
if (headerRead < headerSize) {
|
|
25
|
+
throw new Error(`Truncated ASAR header: expected ${headerSize} bytes, got ${headerRead}`);
|
|
26
|
+
}
|
|
27
|
+
const strLen = headerPickleBuf.readUInt32LE(4);
|
|
28
|
+
const jsonStr = headerPickleBuf.subarray(8, 8 + strLen).toString("utf8");
|
|
29
|
+
const header = JSON.parse(jsonStr);
|
|
30
|
+
const dataBaseOffset = 8 + headerSize;
|
|
31
|
+
return { header, dataBaseOffset };
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
fs.closeSync(fd);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Lists all file paths inside an ASAR archive.
|
|
39
|
+
*/
|
|
40
|
+
export function listPackage(archivePath) {
|
|
41
|
+
const { header } = readArchiveHeader(archivePath);
|
|
42
|
+
const result = [];
|
|
43
|
+
function walk(node, currentPrefix) {
|
|
44
|
+
if (node.files) {
|
|
45
|
+
for (const [name, child] of Object.entries(node.files)) {
|
|
46
|
+
const next = currentPrefix ? `${currentPrefix}/${name}` : `/${name}`;
|
|
47
|
+
walk(child, next);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
result.push(currentPrefix);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
walk(header, "");
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Pure TypeScript, zero-dependency ASAR archive extractor.
|
|
59
|
+
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
60
|
+
*/
|
|
61
|
+
export function extractAll(archivePath, destDir) {
|
|
62
|
+
const { header, dataBaseOffset } = readArchiveHeader(archivePath);
|
|
63
|
+
const fd = fs.openSync(archivePath, "r");
|
|
64
|
+
try {
|
|
65
|
+
function extractNode(node, currentPath, relParts = []) {
|
|
66
|
+
if (node.files) {
|
|
67
|
+
fs.mkdirSync(currentPath, { recursive: true });
|
|
68
|
+
for (const [name, child] of Object.entries(node.files)) {
|
|
69
|
+
extractNode(child, path.join(currentPath, name), [...relParts, name]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (node.size !== undefined && node.offset !== undefined) {
|
|
73
|
+
const fileOffset = dataBaseOffset + parseInt(node.offset, 10);
|
|
74
|
+
const fileBuf = Buffer.alloc(node.size);
|
|
75
|
+
if (node.size > 0) {
|
|
76
|
+
fs.readSync(fd, fileBuf, 0, node.size, fileOffset);
|
|
77
|
+
}
|
|
78
|
+
fs.mkdirSync(path.dirname(currentPath), { recursive: true });
|
|
79
|
+
fs.writeFileSync(currentPath, fileBuf, {
|
|
80
|
+
mode: node.executable ? 0o755 : 0o644,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
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
|
+
}
|
|
91
|
+
extractNode(header, destDir);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
fs.closeSync(fd);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Pure TypeScript, zero-dependency ASAR archive builder.
|
|
99
|
+
* Compatible with all Node.js versions (Node 18, 20, 22, 24+) across Windows, macOS, and Linux.
|
|
100
|
+
*/
|
|
101
|
+
export async function createPackage(srcDir, destFile) {
|
|
102
|
+
const files = [];
|
|
103
|
+
function walk(dir, rel = "") {
|
|
104
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
105
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
106
|
+
for (const e of entries) {
|
|
107
|
+
const entryRel = rel ? `${rel}/${e.name}` : e.name;
|
|
108
|
+
const full = path.join(dir, e.name);
|
|
109
|
+
if (e.isDirectory()) {
|
|
110
|
+
walk(full, entryRel);
|
|
111
|
+
}
|
|
112
|
+
else if (e.isFile()) {
|
|
113
|
+
const stat = fs.statSync(full);
|
|
114
|
+
const executable = Boolean(stat.mode & 0o111);
|
|
115
|
+
files.push({
|
|
116
|
+
relPath: entryRel,
|
|
117
|
+
fullPath: full,
|
|
118
|
+
size: stat.size,
|
|
119
|
+
executable: executable || undefined,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
walk(srcDir);
|
|
125
|
+
const header = { files: {} };
|
|
126
|
+
let currentOffset = 0;
|
|
127
|
+
for (const f of files) {
|
|
128
|
+
const parts = f.relPath.split("/");
|
|
129
|
+
let curr = header.files;
|
|
130
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
131
|
+
if (!curr[parts[i]]) {
|
|
132
|
+
curr[parts[i]] = { files: {} };
|
|
133
|
+
}
|
|
134
|
+
curr = curr[parts[i]].files;
|
|
135
|
+
}
|
|
136
|
+
const leaf = parts[parts.length - 1];
|
|
137
|
+
curr[leaf] = {
|
|
138
|
+
size: f.size,
|
|
139
|
+
offset: String(currentOffset),
|
|
140
|
+
executable: f.executable,
|
|
141
|
+
};
|
|
142
|
+
currentOffset += f.size;
|
|
143
|
+
}
|
|
144
|
+
const jsonBuf = Buffer.from(JSON.stringify(header), "utf8");
|
|
145
|
+
const alignedJsonLen = (jsonBuf.length + 3) & ~3;
|
|
146
|
+
const headerPayloadSize = 4 + alignedJsonLen;
|
|
147
|
+
// Header pickle: payloadSize (uint32LE) + stringLength (uint32LE) + json bytes (padded to multiple of 4)
|
|
148
|
+
const headerPickle = Buffer.alloc(4 + headerPayloadSize, 0);
|
|
149
|
+
headerPickle.writeUInt32LE(headerPayloadSize, 0);
|
|
150
|
+
headerPickle.writeUInt32LE(jsonBuf.length, 4);
|
|
151
|
+
jsonBuf.copy(headerPickle, 8);
|
|
152
|
+
// Size pickle: 4 (uint32LE payload size) + headerPickle.length (uint32LE)
|
|
153
|
+
const sizePickle = Buffer.alloc(8, 0);
|
|
154
|
+
sizePickle.writeUInt32LE(4, 0);
|
|
155
|
+
sizePickle.writeUInt32LE(headerPickle.length, 4);
|
|
156
|
+
fs.mkdirSync(path.dirname(destFile), { recursive: true });
|
|
157
|
+
const fd = fs.openSync(destFile, "w");
|
|
158
|
+
try {
|
|
159
|
+
fs.writeSync(fd, sizePickle);
|
|
160
|
+
fs.writeSync(fd, headerPickle);
|
|
161
|
+
for (const f of files) {
|
|
162
|
+
if (f.size > 0) {
|
|
163
|
+
const content = fs.readFileSync(f.fullPath);
|
|
164
|
+
fs.writeSync(fd, content);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
fs.closeSync(fd);
|
|
170
|
+
}
|
|
171
|
+
}
|
package/dist/attachments.js
CHANGED
|
@@ -7,6 +7,9 @@ const DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
|
7
7
|
function getStateRoot() {
|
|
8
8
|
if (process.env.AGY_ACP_STATE_DIR)
|
|
9
9
|
return process.env.AGY_ACP_STATE_DIR;
|
|
10
|
+
if (process.platform === "win32" && process.env.LOCALAPPDATA) {
|
|
11
|
+
return path.join(process.env.LOCALAPPDATA, "agy-acp");
|
|
12
|
+
}
|
|
10
13
|
const stateHome = process.env.XDG_STATE_HOME || path.join(os.homedir(), ".local", "state");
|
|
11
14
|
return path.join(stateHome, "agy-acp");
|
|
12
15
|
}
|
package/dist/index.js
CHANGED
|
@@ -32,18 +32,22 @@ Commands:
|
|
|
32
32
|
doctor Diagnose Antigravity binary, quota provider, and Paseo status
|
|
33
33
|
|
|
34
34
|
Options:
|
|
35
|
-
--acp
|
|
36
|
-
--setup
|
|
37
|
-
--doctor
|
|
38
|
-
-
|
|
39
|
-
--
|
|
40
|
-
-
|
|
35
|
+
--acp Start ACP server over stdio (default)
|
|
36
|
+
--setup Integrate Antigravity with local Paseo server installation
|
|
37
|
+
--doctor Run environment, binary, and telemetry diagnostics
|
|
38
|
+
--skip-naration Drop leading narration-only assistant chunks (e.g. 'I will...')
|
|
39
|
+
--skip-narration Alias for --skip-naration
|
|
40
|
+
-v, --version Show version
|
|
41
|
+
--json Show version in JSON format (with --version)
|
|
42
|
+
-h, --help Show help
|
|
41
43
|
|
|
42
44
|
Environment Variables:
|
|
43
45
|
AGY_ACP_LOG_LEVEL debug | info | warn | error (default: info)
|
|
44
46
|
AGY_ACP_LOG_DIR Directory for log files
|
|
45
47
|
AGY_ACP_SANDBOX Set to 'true' to run agy in sandbox mode
|
|
46
48
|
AGY_ACP_DANGEROUSLY_SKIP_PERMISSIONS Set to 'true' to auto-approve tool permissions
|
|
49
|
+
AGY_ACP_SKIP_NARRATION Set to 'true' to drop leading narration chunks
|
|
50
|
+
AGY_EXTRA_ARGS Extra space-separated CLI arguments passed to agy
|
|
47
51
|
AGY_BIN_PATH Path to agy binary (default: agy in PATH or ~/.local/bin/agy)
|
|
48
52
|
PASEO_SERVER_PATH Path to local @getpaseo/server directory
|
|
49
53
|
PASEO_ASAR_PATH Path to local Paseo app.asar package
|
|
@@ -239,7 +243,10 @@ if (args.includes("setup") ||
|
|
|
239
243
|
}
|
|
240
244
|
// Auto-run integration in background when starting ACP server
|
|
241
245
|
void ensurePaseoIntegration().catch(() => { });
|
|
242
|
-
const
|
|
246
|
+
const skipNarration = args.includes("--skip-naration") ||
|
|
247
|
+
args.includes("--skip-narration") ||
|
|
248
|
+
process.env.AGY_ACP_SKIP_NARRATION === "true";
|
|
249
|
+
const server = new ACPServer({ skipNarration });
|
|
243
250
|
const cleanup = async () => {
|
|
244
251
|
try {
|
|
245
252
|
await server.stop();
|
package/dist/paseo-patcher.js
CHANGED
|
@@ -3,6 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { logger } from "./logger.js";
|
|
6
|
+
import { extractAll, createPackage, listPackage } from "./asar.js";
|
|
6
7
|
/**
|
|
7
8
|
* Searches the host machine for @getpaseo/server installations across
|
|
8
9
|
* Windows, macOS, and Linux.
|
|
@@ -160,7 +161,12 @@ export function findPaseoServerInstallations() {
|
|
|
160
161
|
}
|
|
161
162
|
// Filter out any paths that do not actually have a dist directory or package.json
|
|
162
163
|
const verified = [];
|
|
164
|
+
const seen = new Set();
|
|
163
165
|
for (const dir of candidates) {
|
|
166
|
+
const key = process.platform === "win32" ? dir.toLowerCase() : dir;
|
|
167
|
+
if (seen.has(key))
|
|
168
|
+
continue;
|
|
169
|
+
seen.add(key);
|
|
164
170
|
if (fs.existsSync(path.join(dir, "dist")) || fs.existsSync(path.join(dir, "package.json"))) {
|
|
165
171
|
verified.push(dir);
|
|
166
172
|
}
|
|
@@ -649,7 +655,16 @@ export function findPaseoAsarPaths() {
|
|
|
649
655
|
candidates.add(path.resolve(loc));
|
|
650
656
|
}
|
|
651
657
|
}
|
|
652
|
-
|
|
658
|
+
const result = [];
|
|
659
|
+
const seen = new Set();
|
|
660
|
+
for (const loc of candidates) {
|
|
661
|
+
const key = process.platform === "win32" ? loc.toLowerCase() : loc;
|
|
662
|
+
if (!seen.has(key)) {
|
|
663
|
+
seen.add(key);
|
|
664
|
+
result.push(loc);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return result;
|
|
653
668
|
}
|
|
654
669
|
/**
|
|
655
670
|
* Extracts, patches, and repacks a Paseo app.asar archive to integrate Antigravity
|
|
@@ -663,11 +678,8 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
663
678
|
if (!fs.existsSync(asarPath)) {
|
|
664
679
|
return { success: false, changes: [], error: `Asar archive not found: ${asarPath}` };
|
|
665
680
|
}
|
|
666
|
-
// Dynamic import of @electron/asar
|
|
667
|
-
const asarModule = await import("@electron/asar");
|
|
668
|
-
const asar = asarModule.default || asarModule;
|
|
669
681
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "paseo-asar-extract-"));
|
|
670
|
-
|
|
682
|
+
extractAll(asarPath, tempDir);
|
|
671
683
|
// Look for server directory in extracted files
|
|
672
684
|
const serverCandidates = [
|
|
673
685
|
path.join(tempDir, "node_modules", "@getpaseo", "server"),
|
|
@@ -722,7 +734,7 @@ export async function patchPaseoAsar(asarPath) {
|
|
|
722
734
|
}
|
|
723
735
|
}
|
|
724
736
|
tempAsar = path.join(os.tmpdir(), `app-${Date.now()}.asar`);
|
|
725
|
-
await
|
|
737
|
+
await createPackage(tempDir, tempAsar);
|
|
726
738
|
// Replace original archive with locked file handling for Windows
|
|
727
739
|
try {
|
|
728
740
|
fs.copyFileSync(tempAsar, asarPath);
|
|
@@ -871,9 +883,7 @@ export async function isPaseoAsarPatched(asarPath) {
|
|
|
871
883
|
try {
|
|
872
884
|
if (!fs.existsSync(asarPath))
|
|
873
885
|
return false;
|
|
874
|
-
const
|
|
875
|
-
const asar = asarModule.default || asarModule;
|
|
876
|
-
const files = asar.listPackage(asarPath);
|
|
886
|
+
const files = listPackage(asarPath);
|
|
877
887
|
return files.some((f) => f.includes("antigravity.js"));
|
|
878
888
|
}
|
|
879
889
|
catch {
|
package/dist/permissions.d.ts
CHANGED
|
@@ -12,4 +12,5 @@ export declare function resolvePermissionSettings(options?: {
|
|
|
12
12
|
addDirs?: string[];
|
|
13
13
|
printTimeout?: string;
|
|
14
14
|
}): PermissionSettings;
|
|
15
|
+
export declare function parseExtraArgs(raw?: string): string[];
|
|
15
16
|
export declare function buildAgyArgs(settings: PermissionSettings, extraArgs?: string[]): string[];
|
package/dist/permissions.js
CHANGED
|
@@ -20,6 +20,14 @@ export function resolvePermissionSettings(options) {
|
|
|
20
20
|
printTimeout,
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
export function parseExtraArgs(raw) {
|
|
24
|
+
if (!raw || !raw.trim())
|
|
25
|
+
return [];
|
|
26
|
+
const matches = raw.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
|
|
27
|
+
if (!matches)
|
|
28
|
+
return [];
|
|
29
|
+
return matches.map((m) => m.replace(/^["']|["']$/g, ""));
|
|
30
|
+
}
|
|
23
31
|
export function buildAgyArgs(settings, extraArgs) {
|
|
24
32
|
const args = ["--input-format", "stream-json", "--output-format", "stream-json", "--print="];
|
|
25
33
|
if (settings.printTimeout) {
|
|
@@ -41,6 +49,10 @@ export function buildAgyArgs(settings, extraArgs) {
|
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
}
|
|
52
|
+
const envExtra = parseExtraArgs(process.env.AGY_EXTRA_ARGS);
|
|
53
|
+
if (envExtra.length > 0) {
|
|
54
|
+
args.push(...envExtra);
|
|
55
|
+
}
|
|
44
56
|
if (extraArgs && extraArgs.length > 0) {
|
|
45
57
|
args.push(...extraArgs);
|
|
46
58
|
}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -113,10 +113,13 @@ export declare const ACP_METHODS: {
|
|
|
113
113
|
readonly SESSION_CLOSE: "session/close";
|
|
114
114
|
readonly SESSION_CLOSE_ALIAS: "unstable_closeSession";
|
|
115
115
|
readonly SESSION_SET_MODE: "session/set_mode";
|
|
116
|
+
readonly SESSION_SET_MODE_CAMEL: "session/setMode";
|
|
116
117
|
readonly SESSION_SET_MODE_ALIAS: "setSessionMode";
|
|
117
118
|
readonly SESSION_SET_MODEL: "session/set_model";
|
|
119
|
+
readonly SESSION_SET_MODEL_CAMEL: "session/setModel";
|
|
118
120
|
readonly SESSION_SET_MODEL_ALIAS: "unstable_setSessionModel";
|
|
119
121
|
readonly SESSION_SET_CONFIG_OPTION: "session/set_config_option";
|
|
122
|
+
readonly SESSION_SET_CONFIG_OPTION_CAMEL: "session/setConfigOption";
|
|
120
123
|
readonly SESSION_SET_CONFIG_OPTION_ALIAS: "setSessionConfigOption";
|
|
121
124
|
readonly SESSION_UPDATE: "session/update";
|
|
122
125
|
};
|
|
@@ -193,6 +196,11 @@ export declare const AVAILABLE_MODES: {
|
|
|
193
196
|
name: string;
|
|
194
197
|
description: string;
|
|
195
198
|
}[];
|
|
199
|
+
export declare const AVAILABLE_PERMISSIONS: {
|
|
200
|
+
id: string;
|
|
201
|
+
name: string;
|
|
202
|
+
description: string;
|
|
203
|
+
}[];
|
|
196
204
|
export declare function buildConfigOptionsForModel(modelId: string, currentEffort?: string, availableModels?: ModelDefinition[]): {
|
|
197
205
|
id: string;
|
|
198
206
|
name: string;
|
|
@@ -205,3 +213,40 @@ export declare function buildConfigOptionsForModel(modelId: string, currentEffor
|
|
|
205
213
|
description: string;
|
|
206
214
|
}[];
|
|
207
215
|
}[];
|
|
216
|
+
export declare function buildConfigOptionsForSession(options: {
|
|
217
|
+
modelId: string;
|
|
218
|
+
currentEffort?: string;
|
|
219
|
+
currentMode?: string;
|
|
220
|
+
currentPermission?: string;
|
|
221
|
+
availableModels?: ModelDefinition[];
|
|
222
|
+
}): {
|
|
223
|
+
id: string;
|
|
224
|
+
name: string;
|
|
225
|
+
category: string;
|
|
226
|
+
type: "select";
|
|
227
|
+
currentValue: string;
|
|
228
|
+
options: {
|
|
229
|
+
value: string;
|
|
230
|
+
name: string;
|
|
231
|
+
description: string;
|
|
232
|
+
}[];
|
|
233
|
+
}[];
|
|
234
|
+
/**
|
|
235
|
+
* Escapes characters in URLs/paths for Markdown image/link syntax.
|
|
236
|
+
* Escapes backslashes `\` and parentheses `)` to prevent premature link termination,
|
|
237
|
+
* especially crucial for Windows paths (e.g. C:\path\img (1).png).
|
|
238
|
+
*/
|
|
239
|
+
export declare function escapeMarkdownUrl(urlOrPath: string): string;
|
|
240
|
+
/**
|
|
241
|
+
* Normalizes an image path or file URL and formats it as an inline Markdown image link.
|
|
242
|
+
*/
|
|
243
|
+
export declare function formatImageMarkdown(filePathOrUrl: string): string;
|
|
244
|
+
/**
|
|
245
|
+
* Extracts an image reference from a tool execution output or parameters,
|
|
246
|
+
* returning a formatted Markdown image string if detected.
|
|
247
|
+
*/
|
|
248
|
+
export declare function extractImageMarkdownLink(toolName: string, output: unknown, parameters?: Record<string, unknown>): string | null;
|
|
249
|
+
/**
|
|
250
|
+
* Detects whether text consists entirely of conversational narration (e.g. "I will...", "I'll...").
|
|
251
|
+
*/
|
|
252
|
+
export declare function isNarrationText(text: string): boolean;
|
package/dist/protocol.js
CHANGED
|
@@ -23,10 +23,13 @@ export const ACP_METHODS = {
|
|
|
23
23
|
SESSION_CLOSE: "session/close",
|
|
24
24
|
SESSION_CLOSE_ALIAS: "unstable_closeSession",
|
|
25
25
|
SESSION_SET_MODE: "session/set_mode",
|
|
26
|
+
SESSION_SET_MODE_CAMEL: "session/setMode",
|
|
26
27
|
SESSION_SET_MODE_ALIAS: "setSessionMode",
|
|
27
28
|
SESSION_SET_MODEL: "session/set_model",
|
|
29
|
+
SESSION_SET_MODEL_CAMEL: "session/setModel",
|
|
28
30
|
SESSION_SET_MODEL_ALIAS: "unstable_setSessionModel",
|
|
29
31
|
SESSION_SET_CONFIG_OPTION: "session/set_config_option",
|
|
32
|
+
SESSION_SET_CONFIG_OPTION_CAMEL: "session/setConfigOption",
|
|
30
33
|
SESSION_SET_CONFIG_OPTION_ALIAS: "setSessionConfigOption",
|
|
31
34
|
SESSION_UPDATE: "session/update",
|
|
32
35
|
};
|
|
@@ -485,6 +488,12 @@ export function getEffectiveEffortForModel(modelId, requestedEffort, models) {
|
|
|
485
488
|
export const AVAILABLE_MODES = [
|
|
486
489
|
{ id: "default", name: "Default (Accept Edits)", description: "Standard autonomous execution and coding mode" },
|
|
487
490
|
{ id: "plan", name: "Plan Mode", description: "Planning and read-only analysis without file modifications" },
|
|
491
|
+
{ id: "accept-edits", name: "Accept Edits", description: "Run agy with --mode accept-edits" },
|
|
492
|
+
];
|
|
493
|
+
export const AVAILABLE_PERMISSIONS = [
|
|
494
|
+
{ id: "default", name: "Default", description: "Standard permission flow" },
|
|
495
|
+
{ id: "sandbox", name: "Sandbox", description: "Run agy with --sandbox" },
|
|
496
|
+
{ id: "bypass", name: "Bypass", description: "Run agy with --dangerously-skip-permissions" },
|
|
488
497
|
];
|
|
489
498
|
export function buildConfigOptionsForModel(modelId, currentEffort = "high", availableModels) {
|
|
490
499
|
const modelList = availableModels || cachedModels || FALLBACK_MODELS;
|
|
@@ -513,3 +522,118 @@ export function buildConfigOptionsForModel(modelId, currentEffort = "high", avai
|
|
|
513
522
|
},
|
|
514
523
|
];
|
|
515
524
|
}
|
|
525
|
+
export function buildConfigOptionsForSession(options) {
|
|
526
|
+
const modelOptions = buildConfigOptionsForModel(options.modelId, options.currentEffort, options.availableModels);
|
|
527
|
+
const modeOption = {
|
|
528
|
+
id: "mode",
|
|
529
|
+
name: "Execution Mode",
|
|
530
|
+
category: "mode",
|
|
531
|
+
type: "select",
|
|
532
|
+
currentValue: options.currentMode || "default",
|
|
533
|
+
options: AVAILABLE_MODES.map((m) => ({
|
|
534
|
+
value: m.id,
|
|
535
|
+
name: m.name,
|
|
536
|
+
description: m.description,
|
|
537
|
+
})),
|
|
538
|
+
};
|
|
539
|
+
const permissionOption = {
|
|
540
|
+
id: "permission",
|
|
541
|
+
name: "Permission Policy",
|
|
542
|
+
category: "permission",
|
|
543
|
+
type: "select",
|
|
544
|
+
currentValue: options.currentPermission || "default",
|
|
545
|
+
options: AVAILABLE_PERMISSIONS.map((p) => ({
|
|
546
|
+
value: p.id,
|
|
547
|
+
name: p.name,
|
|
548
|
+
description: p.description,
|
|
549
|
+
})),
|
|
550
|
+
};
|
|
551
|
+
return [...modelOptions, modeOption, permissionOption];
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Escapes characters in URLs/paths for Markdown image/link syntax.
|
|
555
|
+
* Escapes backslashes `\` and parentheses `)` to prevent premature link termination,
|
|
556
|
+
* especially crucial for Windows paths (e.g. C:\path\img (1).png).
|
|
557
|
+
*/
|
|
558
|
+
export function escapeMarkdownUrl(urlOrPath) {
|
|
559
|
+
return urlOrPath.replace(/\\/g, "\\\\").replace(/\)/g, "\\)");
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Normalizes an image path or file URL and formats it as an inline Markdown image link.
|
|
563
|
+
*/
|
|
564
|
+
export function formatImageMarkdown(filePathOrUrl) {
|
|
565
|
+
let clean = filePathOrUrl.trim();
|
|
566
|
+
if (clean.startsWith("file://")) {
|
|
567
|
+
try {
|
|
568
|
+
clean = fileURLToPath(clean);
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
clean = clean.replace(/^file:\/\//, "");
|
|
572
|
+
if (process.platform === "win32" && /^\/[a-zA-Z]:/.test(clean)) {
|
|
573
|
+
clean = clean.slice(1);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return `})`;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Extracts an image reference from a tool execution output or parameters,
|
|
581
|
+
* returning a formatted Markdown image string if detected.
|
|
582
|
+
*/
|
|
583
|
+
export function extractImageMarkdownLink(toolName, output, parameters) {
|
|
584
|
+
const name = toolName.toLowerCase();
|
|
585
|
+
const isImageTool = name.includes("image") || name.includes("generate_image");
|
|
586
|
+
let rawPath = null;
|
|
587
|
+
if (typeof output === "string") {
|
|
588
|
+
const fileUriMatch = output.match(/file:\/\/[^\s)"]+\.(png|jpe?g|webp|gif|svg|bmp)/i);
|
|
589
|
+
if (fileUriMatch) {
|
|
590
|
+
rawPath = fileUriMatch[0];
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
const winPathMatch = output.match(/[a-zA-Z]:\\[^\s)"]+\.(png|jpe?g|webp|gif|svg|bmp)/i);
|
|
594
|
+
if (winPathMatch) {
|
|
595
|
+
rawPath = winPathMatch[0];
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
const posixPathMatch = output.match(/\/[^\s)"]+\.(png|jpe?g|webp|gif|svg|bmp)/i);
|
|
599
|
+
if (posixPathMatch) {
|
|
600
|
+
rawPath = posixPathMatch[0];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
else if (output && typeof output === "object") {
|
|
606
|
+
const obj = output;
|
|
607
|
+
if (typeof obj.path === "string")
|
|
608
|
+
rawPath = obj.path;
|
|
609
|
+
else if (typeof obj.filePath === "string")
|
|
610
|
+
rawPath = obj.filePath;
|
|
611
|
+
else if (typeof obj.uri === "string")
|
|
612
|
+
rawPath = obj.uri;
|
|
613
|
+
}
|
|
614
|
+
if (!rawPath && isImageTool && parameters) {
|
|
615
|
+
if (typeof parameters.TargetFile === "string" &&
|
|
616
|
+
/\.(png|jpe?g|webp|gif|svg|bmp)$/i.test(parameters.TargetFile)) {
|
|
617
|
+
rawPath = parameters.TargetFile;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!rawPath)
|
|
621
|
+
return null;
|
|
622
|
+
return formatImageMarkdown(rawPath);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Detects whether text consists entirely of conversational narration (e.g. "I will...", "I'll...").
|
|
626
|
+
*/
|
|
627
|
+
export function isNarrationText(text) {
|
|
628
|
+
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
629
|
+
if (lines.length === 0)
|
|
630
|
+
return false;
|
|
631
|
+
return lines.every((l) => {
|
|
632
|
+
const lower = l.toLowerCase();
|
|
633
|
+
return (lower.startsWith("i will") ||
|
|
634
|
+
lower.startsWith("i'll") ||
|
|
635
|
+
lower.startsWith("i’ll") ||
|
|
636
|
+
lower.startsWith("let me") ||
|
|
637
|
+
lower.startsWith("i am going to"));
|
|
638
|
+
});
|
|
639
|
+
}
|
package/dist/session-store.d.ts
CHANGED
package/dist/session-store.js
CHANGED
|
@@ -7,6 +7,9 @@ function getStateRoot() {
|
|
|
7
7
|
if (process.env.AGY_ACP_STATE_DIR) {
|
|
8
8
|
return process.env.AGY_ACP_STATE_DIR;
|
|
9
9
|
}
|
|
10
|
+
if (process.platform === "win32" && process.env.LOCALAPPDATA) {
|
|
11
|
+
return path.join(process.env.LOCALAPPDATA, "agy-acp");
|
|
12
|
+
}
|
|
10
13
|
const stateHome = process.env.XDG_STATE_HOME || path.join(os.homedir(), ".local", "state");
|
|
11
14
|
return path.join(stateHome, "agy-acp");
|
|
12
15
|
}
|
package/dist/session.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface SessionOptions {
|
|
|
6
6
|
model?: string;
|
|
7
7
|
effort?: string;
|
|
8
8
|
mode?: string;
|
|
9
|
+
permission?: string;
|
|
9
10
|
conversationId?: string;
|
|
10
11
|
usage?: SessionUsageState;
|
|
11
12
|
sandbox?: boolean;
|
|
@@ -20,6 +21,7 @@ export declare class Session {
|
|
|
20
21
|
model: string;
|
|
21
22
|
effort: string;
|
|
22
23
|
mode: string;
|
|
24
|
+
permission: string;
|
|
23
25
|
readonly createdAt: Date;
|
|
24
26
|
lastActivity: Date;
|
|
25
27
|
isCancelled: boolean;
|
|
@@ -36,6 +38,7 @@ export declare class Session {
|
|
|
36
38
|
setModel(model: string): void;
|
|
37
39
|
setEffort(effort: string): void;
|
|
38
40
|
setMode(mode: string): void;
|
|
41
|
+
setPermission(permission: string): void;
|
|
39
42
|
setConversationId(conversationId?: string): void;
|
|
40
43
|
ensureReadyForResume(): Promise<void>;
|
|
41
44
|
resumeConversation(conversationId: string): Promise<void>;
|
package/dist/session.js
CHANGED
|
@@ -10,6 +10,7 @@ export class Session {
|
|
|
10
10
|
model;
|
|
11
11
|
effort;
|
|
12
12
|
mode;
|
|
13
|
+
permission;
|
|
13
14
|
createdAt;
|
|
14
15
|
lastActivity;
|
|
15
16
|
isCancelled = false;
|
|
@@ -23,6 +24,9 @@ export class Session {
|
|
|
23
24
|
this.model = options.model || "gemini-3.7-flash";
|
|
24
25
|
this.effort = options.effort || "high";
|
|
25
26
|
this.mode = options.mode || "default";
|
|
27
|
+
this.permission =
|
|
28
|
+
options.permission ||
|
|
29
|
+
(options.sandbox ? "sandbox" : options.dangerouslySkipPermissions ? "bypass" : "default");
|
|
26
30
|
this.createdAt = new Date();
|
|
27
31
|
this.lastActivity = new Date();
|
|
28
32
|
this.store = options.store || sessionStore;
|
|
@@ -35,9 +39,11 @@ export class Session {
|
|
|
35
39
|
contextWindowUsedTokens: 0,
|
|
36
40
|
contextWindowMaxTokens: getModelContextWindow(this.model),
|
|
37
41
|
};
|
|
42
|
+
const isSandbox = this.permission === "sandbox" || options.sandbox;
|
|
43
|
+
const isBypass = this.permission === "bypass" || options.dangerouslySkipPermissions;
|
|
38
44
|
const permissions = resolvePermissionSettings({
|
|
39
|
-
sandbox:
|
|
40
|
-
dangerouslySkipPermissions:
|
|
45
|
+
sandbox: isSandbox,
|
|
46
|
+
dangerouslySkipPermissions: isBypass,
|
|
41
47
|
mode: this.mode,
|
|
42
48
|
});
|
|
43
49
|
this.process = new AntigravityProcess({
|
|
@@ -62,6 +68,7 @@ export class Session {
|
|
|
62
68
|
model: this.model,
|
|
63
69
|
effort: this.effort,
|
|
64
70
|
mode: this.mode,
|
|
71
|
+
permission: this.permission,
|
|
65
72
|
usage: this.usage,
|
|
66
73
|
updatedAt: new Date().toISOString(),
|
|
67
74
|
};
|
|
@@ -98,6 +105,16 @@ export class Session {
|
|
|
98
105
|
this.process.setMode(mode);
|
|
99
106
|
this.persist();
|
|
100
107
|
}
|
|
108
|
+
setPermission(permission) {
|
|
109
|
+
this.permission = permission;
|
|
110
|
+
const isSandbox = permission === "sandbox";
|
|
111
|
+
const isBypass = permission === "bypass";
|
|
112
|
+
this.process.setPermissions({
|
|
113
|
+
sandbox: isSandbox,
|
|
114
|
+
dangerouslySkipPermissions: isBypass || (!isSandbox && this.process.currentPermissions.dangerouslySkipPermissions),
|
|
115
|
+
});
|
|
116
|
+
this.persist();
|
|
117
|
+
}
|
|
101
118
|
setConversationId(conversationId) {
|
|
102
119
|
this.process.setConversationId(conversationId);
|
|
103
120
|
this.persist();
|
|
@@ -185,6 +202,7 @@ export class SessionManager {
|
|
|
185
202
|
model: options.model || persisted?.model,
|
|
186
203
|
effort: options.effort || persisted?.effort,
|
|
187
204
|
mode: options.mode || persisted?.mode,
|
|
205
|
+
permission: options.permission || persisted?.permission,
|
|
188
206
|
conversationId: options.conversationId || persisted?.conversationId,
|
|
189
207
|
usage: options.usage || persisted?.usage,
|
|
190
208
|
sandbox: options.sandbox,
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paseo-acp-agy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
@@ -43,10 +43,11 @@
|
|
|
43
43
|
"bugs": {
|
|
44
44
|
"url": "https://github.com/tucomel/paseo-acp-agy/issues"
|
|
45
45
|
},
|
|
46
|
-
"
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
},
|
|
47
49
|
"dependencies": {
|
|
48
|
-
"@agentclientprotocol/sdk": "^0.17.1"
|
|
49
|
-
"@electron/asar": "^4.3.0"
|
|
50
|
+
"@agentclientprotocol/sdk": "^0.17.1"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/node": "^22.0.0",
|