@solongate/proxy 0.82.10 → 0.82.12
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/audit/index.js +74 -61
- package/dist/audit/types.d.ts +3 -3
- package/dist/create.js +1 -1
- package/dist/global-install.d.ts +3 -0
- package/dist/global-install.js +60 -2
- package/dist/index.js +57 -5
- package/dist/lib.js +1 -1
- package/dist/login.js +41 -2
- package/dist/tui/index.js +54 -2
- package/hooks/guard.bundled.mjs +30 -8
- package/hooks/guard.mjs +37 -10
- package/package.json +1 -1
package/dist/audit/index.js
CHANGED
|
@@ -84,7 +84,7 @@ function listDirs() {
|
|
|
84
84
|
const home = homedir();
|
|
85
85
|
console.log("\n Default log directories:");
|
|
86
86
|
console.log(` Claude Code \u2192 ${resolve(home, ".claude", "projects")}`);
|
|
87
|
-
console.log(`
|
|
87
|
+
console.log(` Antigravity \u2192 ${resolve(home, ".gemini", "antigravity", "brain")}`);
|
|
88
88
|
console.log(` OpenClaw \u2192 ${resolve(home, ".openclaw", "agents", "main", "sessions")}`);
|
|
89
89
|
if (config.customDirs.length === 0) {
|
|
90
90
|
console.log("\n Custom directories: (none)");
|
|
@@ -106,7 +106,7 @@ function searchLogs() {
|
|
|
106
106
|
console.log("\n Searching for AI tool logs...\n");
|
|
107
107
|
const defaults = [
|
|
108
108
|
{ name: "Claude Code", path: resolve(home, ".claude", "projects") },
|
|
109
|
-
{ name: "
|
|
109
|
+
{ name: "Antigravity", path: resolve(home, ".gemini", "antigravity", "brain") },
|
|
110
110
|
{ name: "OpenClaw", path: resolve(home, ".openclaw", "agents", "main", "sessions") }
|
|
111
111
|
];
|
|
112
112
|
for (const d of defaults) {
|
|
@@ -129,7 +129,7 @@ function searchLogs() {
|
|
|
129
129
|
}
|
|
130
130
|
const otherPaths = [
|
|
131
131
|
{ name: `Claude Code (${user})`, path: resolve(userHome, ".claude", "projects") },
|
|
132
|
-
{ name: `
|
|
132
|
+
{ name: `Antigravity (${user})`, path: resolve(userHome, ".gemini", "antigravity", "brain") },
|
|
133
133
|
{ name: `OpenClaw (${user})`, path: resolve(userHome, ".openclaw", "agents", "main", "sessions") }
|
|
134
134
|
];
|
|
135
135
|
for (const d of otherPaths) {
|
|
@@ -152,7 +152,7 @@ function searchLogs() {
|
|
|
152
152
|
if (userHome === home) continue;
|
|
153
153
|
const otherPaths = [
|
|
154
154
|
{ name: `Claude Code (${user})`, path: resolve(userHome, ".claude", "projects") },
|
|
155
|
-
{ name: `
|
|
155
|
+
{ name: `Antigravity (${user})`, path: resolve(userHome, ".gemini", "antigravity", "brain") },
|
|
156
156
|
{ name: `OpenClaw (${user})`, path: resolve(userHome, ".openclaw", "agents", "main", "sessions") }
|
|
157
157
|
];
|
|
158
158
|
for (const d of otherPaths) {
|
|
@@ -261,61 +261,74 @@ function collectClaude() {
|
|
|
261
261
|
}
|
|
262
262
|
return sessions;
|
|
263
263
|
}
|
|
264
|
-
function
|
|
264
|
+
function collectAntigravity() {
|
|
265
265
|
const sessions = [];
|
|
266
|
-
const
|
|
267
|
-
if (!existsSync2(
|
|
268
|
-
for (const
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
266
|
+
const brainDir = resolve2(homedir2(), ".gemini", "antigravity", "brain");
|
|
267
|
+
if (!existsSync2(brainDir)) return sessions;
|
|
268
|
+
for (const convId of readdirSync(brainDir)) {
|
|
269
|
+
const convPath = join2(brainDir, convId);
|
|
270
|
+
try {
|
|
271
|
+
if (!statSync(convPath).isDirectory()) continue;
|
|
272
|
+
} catch {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const transcript = join2(convPath, ".system_generated", "logs", "transcript.jsonl");
|
|
276
|
+
if (!existsSync2(transcript)) continue;
|
|
277
|
+
try {
|
|
278
|
+
const lines = readFileSync2(transcript, "utf-8").split("\n").filter(Boolean);
|
|
279
|
+
const toolCalls = [];
|
|
280
|
+
const userMessages = [];
|
|
281
|
+
let startTime = "";
|
|
282
|
+
let endTime = "";
|
|
283
|
+
let model = "";
|
|
284
|
+
for (const line of lines) {
|
|
285
|
+
try {
|
|
286
|
+
const entry = JSON.parse(line);
|
|
287
|
+
const ts = entry.timestamp || entry.time || entry.ts || "";
|
|
288
|
+
if (ts) {
|
|
289
|
+
if (!startTime) startTime = ts;
|
|
290
|
+
endTime = ts;
|
|
285
291
|
}
|
|
286
|
-
if (!
|
|
287
|
-
|
|
292
|
+
if (!model && typeof entry.model === "string") model = entry.model;
|
|
293
|
+
const tc = entry.toolCall || (entry.type === "tool_call" ? entry : null);
|
|
294
|
+
if (tc && typeof tc === "object" && (tc.name || tc.toolName)) {
|
|
288
295
|
toolCalls.push({
|
|
289
|
-
id: tc.id || "",
|
|
290
|
-
toolName: tc.name || "",
|
|
296
|
+
id: tc.id || (entry.stepIdx != null ? String(entry.stepIdx) : ""),
|
|
297
|
+
toolName: tc.name || tc.toolName || "",
|
|
291
298
|
arguments: tc.args || tc.arguments || {},
|
|
292
|
-
result:
|
|
293
|
-
isError:
|
|
294
|
-
timestamp:
|
|
295
|
-
source: "
|
|
296
|
-
sessionId
|
|
299
|
+
result: entry.result ? JSON.stringify(entry.result).slice(0, 2e3) : void 0,
|
|
300
|
+
isError: entry.status === "error" || entry.isError === true,
|
|
301
|
+
timestamp: ts,
|
|
302
|
+
source: "antigravity",
|
|
303
|
+
sessionId: convId
|
|
297
304
|
});
|
|
298
305
|
}
|
|
306
|
+
const role = entry.role || entry.type;
|
|
307
|
+
if ((role === "user" || role === "user_message") && (entry.text || entry.content)) {
|
|
308
|
+
const text = String(entry.text || entry.content).slice(0, 500);
|
|
309
|
+
if (text.length > 0) userMessages.push({ timestamp: ts, text });
|
|
310
|
+
}
|
|
311
|
+
} catch {
|
|
299
312
|
}
|
|
300
|
-
for (const um of userMessages) {
|
|
301
|
-
const umTime = new Date(um.timestamp).getTime();
|
|
302
|
-
const nextIdx = toolCalls.findIndex((tc) => new Date(tc.timestamp).getTime() > umTime);
|
|
303
|
-
if (nextIdx >= 0) um.nextToolCallIndex = nextIdx;
|
|
304
|
-
}
|
|
305
|
-
if (toolCalls.length > 0) {
|
|
306
|
-
sessions.push({
|
|
307
|
-
id: sessionId,
|
|
308
|
-
source: "gemini",
|
|
309
|
-
startTime: data.startTime || "",
|
|
310
|
-
endTime: data.lastUpdated || "",
|
|
311
|
-
model: data.messages?.[0]?.model || "",
|
|
312
|
-
toolCalls,
|
|
313
|
-
userMessages,
|
|
314
|
-
filePath
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
} catch {
|
|
318
313
|
}
|
|
314
|
+
for (const um of userMessages) {
|
|
315
|
+
const umTime = new Date(um.timestamp).getTime();
|
|
316
|
+
const nextIdx = toolCalls.findIndex((tc) => new Date(tc.timestamp).getTime() > umTime);
|
|
317
|
+
if (nextIdx >= 0) um.nextToolCallIndex = nextIdx;
|
|
318
|
+
}
|
|
319
|
+
if (toolCalls.length > 0) {
|
|
320
|
+
sessions.push({
|
|
321
|
+
id: convId,
|
|
322
|
+
source: "antigravity",
|
|
323
|
+
startTime,
|
|
324
|
+
endTime,
|
|
325
|
+
model,
|
|
326
|
+
toolCalls,
|
|
327
|
+
userMessages,
|
|
328
|
+
filePath: transcript
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
} catch {
|
|
319
332
|
}
|
|
320
333
|
}
|
|
321
334
|
return sessions;
|
|
@@ -485,11 +498,11 @@ function collectCustomDirs() {
|
|
|
485
498
|
for (const msg of data.messages) {
|
|
486
499
|
if (!msg.toolCalls || !Array.isArray(msg.toolCalls)) continue;
|
|
487
500
|
for (const tc of msg.toolCalls) {
|
|
488
|
-
toolCalls.push({ id: tc.id || "", toolName: tc.name || "", arguments: tc.args || tc.arguments || {}, result: tc.result ? JSON.stringify(tc.result).slice(0, 2e3) : void 0, isError: tc.status === "error", timestamp: tc.timestamp || msg.timestamp || data.startTime || "", source: "
|
|
501
|
+
toolCalls.push({ id: tc.id || "", toolName: tc.name || "", arguments: tc.args || tc.arguments || {}, result: tc.result ? JSON.stringify(tc.result).slice(0, 2e3) : void 0, isError: tc.status === "error", timestamp: tc.timestamp || msg.timestamp || data.startTime || "", source: "antigravity", sessionId });
|
|
489
502
|
}
|
|
490
503
|
}
|
|
491
504
|
if (toolCalls.length > 0) {
|
|
492
|
-
sessions.push({ id: sessionId, source: "
|
|
505
|
+
sessions.push({ id: sessionId, source: "antigravity", startTime: data.startTime || "", endTime: data.lastUpdated || "", model: data.messages?.[0]?.model || "", toolCalls, filePath });
|
|
493
506
|
}
|
|
494
507
|
} catch {
|
|
495
508
|
}
|
|
@@ -502,13 +515,13 @@ function collectCustomDirs() {
|
|
|
502
515
|
}
|
|
503
516
|
function collectLogs() {
|
|
504
517
|
const claudeSessions = collectClaude();
|
|
505
|
-
const
|
|
518
|
+
const antigravitySessions = collectAntigravity();
|
|
506
519
|
const openclawSessions = collectOpenClaw();
|
|
507
520
|
const customSessions = collectCustomDirs();
|
|
508
|
-
const sessions = [...claudeSessions, ...
|
|
521
|
+
const sessions = [...claudeSessions, ...antigravitySessions, ...openclawSessions, ...customSessions].sort((a, b) => (a.startTime || "").localeCompare(b.startTime || ""));
|
|
509
522
|
const sources = [];
|
|
510
523
|
if (claudeSessions.length > 0) sources.push("Claude Code");
|
|
511
|
-
if (
|
|
524
|
+
if (antigravitySessions.length > 0) sources.push("Antigravity");
|
|
512
525
|
if (openclawSessions.length > 0) sources.push("OpenClaw");
|
|
513
526
|
const allCalls = sessions.flatMap((s) => s.toolCalls);
|
|
514
527
|
const timestamps = allCalls.map((t) => t.timestamp).filter(Boolean).sort();
|
|
@@ -2599,12 +2612,12 @@ function printFooter(results) {
|
|
|
2599
2612
|
}
|
|
2600
2613
|
var SOURCE_COLOR = {
|
|
2601
2614
|
claude: source_default.magenta,
|
|
2602
|
-
|
|
2615
|
+
antigravity: source_default.blue,
|
|
2603
2616
|
openclaw: source_default.green
|
|
2604
2617
|
};
|
|
2605
2618
|
var SOURCE_LABEL = {
|
|
2606
2619
|
claude: "Claude",
|
|
2607
|
-
|
|
2620
|
+
antigravity: "Antigravity",
|
|
2608
2621
|
openclaw: "OClaw"
|
|
2609
2622
|
};
|
|
2610
2623
|
function truncate(s, max) {
|
|
@@ -2807,7 +2820,7 @@ function exportHTML({ data, results }) {
|
|
|
2807
2820
|
};
|
|
2808
2821
|
const sourceLabel = {
|
|
2809
2822
|
claude: "Claude",
|
|
2810
|
-
|
|
2823
|
+
antigravity: "Antigravity",
|
|
2811
2824
|
openclaw: "OpenClaw"
|
|
2812
2825
|
};
|
|
2813
2826
|
const pillClass = {
|
|
@@ -2922,7 +2935,7 @@ function exportHTML({ data, results }) {
|
|
|
2922
2935
|
.code-tag { color: var(--accent); font-weight: 600; font-size: 11px; }
|
|
2923
2936
|
.src-tag { display: inline-block; padding: 1px 7px; border-radius: 3px; font-size: 10px; font-weight: 600; }
|
|
2924
2937
|
.src-claude { background: rgba(192,132,252,0.12); color: #c084fc; }
|
|
2925
|
-
.src-
|
|
2938
|
+
.src-antigravity { background: rgba(96,165,250,0.12); color: #60a5fa; }
|
|
2926
2939
|
.src-openclaw { background: rgba(74,222,128,0.12); color: #4ade80; }
|
|
2927
2940
|
.err-tag { background: rgba(239,68,68,0.15); color: #f87171; padding: 0 5px; border-radius: 3px; font-size: 9px; font-weight: 700; margin-left: 4px; }
|
|
2928
2941
|
.cat { font-weight: 500; }
|
|
@@ -3038,7 +3051,7 @@ function exportHTML({ data, results }) {
|
|
|
3038
3051
|
<div class="sec-hdr">Tool Calls <span class="sec-count">${allCalls.length.toLocaleString()}</span></div>
|
|
3039
3052
|
<div class="filters">
|
|
3040
3053
|
<input type="text" id="q" placeholder="Search..." oninput="applyFilters()">
|
|
3041
|
-
<select id="sf" onchange="applyFilters()"><option value="">All sources</option><option value="claude">Claude</option><option value="
|
|
3054
|
+
<select id="sf" onchange="applyFilters()"><option value="">All sources</option><option value="claude">Claude</option><option value="antigravity">Antigravity</option><option value="openclaw">OpenClaw</option></select>
|
|
3042
3055
|
<select id="ef" onchange="applyFilters()"><option value="">All</option><option value="e">Errors</option><option value="s">Success</option></select>
|
|
3043
3056
|
<select id="df" onchange="applyFilters()"><option value="">All dates</option></select>
|
|
3044
3057
|
</div>
|
package/dist/audit/types.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface ToolCall {
|
|
|
19
19
|
result?: string;
|
|
20
20
|
isError?: boolean;
|
|
21
21
|
timestamp: string;
|
|
22
|
-
source: 'claude' | '
|
|
22
|
+
source: 'claude' | 'antigravity' | 'openclaw';
|
|
23
23
|
sessionId: string;
|
|
24
24
|
}
|
|
25
25
|
export interface UserMessage {
|
|
@@ -29,7 +29,7 @@ export interface UserMessage {
|
|
|
29
29
|
}
|
|
30
30
|
export interface SessionInfo {
|
|
31
31
|
id: string;
|
|
32
|
-
source: 'claude' | '
|
|
32
|
+
source: 'claude' | 'antigravity' | 'openclaw';
|
|
33
33
|
startTime: string;
|
|
34
34
|
endTime?: string;
|
|
35
35
|
model?: string;
|
|
@@ -74,7 +74,7 @@ export interface PermissionDrift {
|
|
|
74
74
|
newToolTypes: string[];
|
|
75
75
|
}
|
|
76
76
|
export interface SessionBaseline {
|
|
77
|
-
source: 'claude' | '
|
|
77
|
+
source: 'claude' | 'antigravity' | 'openclaw' | 'all';
|
|
78
78
|
avgToolCalls: number;
|
|
79
79
|
stddevToolCalls: number;
|
|
80
80
|
toolTypeDistribution: Record<string, number>;
|
package/dist/create.js
CHANGED
|
@@ -213,7 +213,7 @@ console.log('MCP servers communicate over stdin/stdout \u2014 not HTTP.');
|
|
|
213
213
|
console.log('You need an MCP client to connect:');
|
|
214
214
|
console.log('');
|
|
215
215
|
console.log(' Claude Code Open this folder, .mcp.json is auto-detected');
|
|
216
|
-
console.log('
|
|
216
|
+
console.log(' Antigravity .agents/mcp_config.json (or ~/.gemini/config/mcp_config.json)');
|
|
217
217
|
console.log(' OpenClaw Uses openclaw.plugin.json config');
|
|
218
218
|
console.log('');
|
|
219
219
|
console.log('Press Ctrl+C to stop.');
|
package/dist/global-install.d.ts
CHANGED
|
@@ -5,9 +5,12 @@ export declare function globalPaths(): {
|
|
|
5
5
|
sgDir: string;
|
|
6
6
|
hooksDir: string;
|
|
7
7
|
claudeDir: string;
|
|
8
|
+
antigravityDir: string;
|
|
8
9
|
settingsPath: string;
|
|
9
10
|
backupPath: string;
|
|
10
11
|
configPath: string;
|
|
12
|
+
antigravityHooksPath: string;
|
|
13
|
+
antigravityBackupPath: string;
|
|
11
14
|
};
|
|
12
15
|
export declare function clearGuardUpdateCheck(): boolean;
|
|
13
16
|
export declare function runGlobalRestore(): void;
|
package/dist/global-install.js
CHANGED
|
@@ -71,7 +71,8 @@ function protectedTargets() {
|
|
|
71
71
|
join(p.hooksDir, "stop.mjs"),
|
|
72
72
|
join(p.hooksDir, "shield.mjs"),
|
|
73
73
|
p.configPath,
|
|
74
|
-
p.settingsPath
|
|
74
|
+
p.settingsPath,
|
|
75
|
+
p.antigravityHooksPath
|
|
75
76
|
];
|
|
76
77
|
}
|
|
77
78
|
function lockProtected() {
|
|
@@ -85,14 +86,21 @@ function globalPaths() {
|
|
|
85
86
|
const sgDir = join(home, ".solongate");
|
|
86
87
|
const hooksDir = join(sgDir, "hooks");
|
|
87
88
|
const claudeDir = join(home, ".claude");
|
|
89
|
+
const antigravityDir = join(home, ".gemini", "config");
|
|
88
90
|
return {
|
|
89
91
|
home,
|
|
90
92
|
sgDir,
|
|
91
93
|
hooksDir,
|
|
92
94
|
claudeDir,
|
|
95
|
+
antigravityDir,
|
|
93
96
|
settingsPath: join(claudeDir, "settings.json"),
|
|
94
97
|
backupPath: join(claudeDir, "settings.solongate.bak"),
|
|
95
|
-
configPath: join(sgDir, "cloud-guard.json")
|
|
98
|
+
configPath: join(sgDir, "cloud-guard.json"),
|
|
99
|
+
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
100
|
+
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
101
|
+
// covered by the passive session-log collector, not a hook.
|
|
102
|
+
antigravityHooksPath: join(antigravityDir, "hooks.json"),
|
|
103
|
+
antigravityBackupPath: join(antigravityDir, "hooks.solongate.bak")
|
|
96
104
|
};
|
|
97
105
|
}
|
|
98
106
|
function clearGuardUpdateCheck() {
|
|
@@ -110,6 +118,42 @@ function readGuard() {
|
|
|
110
118
|
const bundled = join(HOOKS_DIR, "guard.bundled.mjs");
|
|
111
119
|
return existsSync(bundled) ? readFileSync(bundled, "utf-8") : readHook("guard.mjs");
|
|
112
120
|
}
|
|
121
|
+
var ANTIGRAVITY_GROUP = "solongate-guard";
|
|
122
|
+
function antigravityHookCommand(guardAbs) {
|
|
123
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
124
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
125
|
+
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
126
|
+
}
|
|
127
|
+
function installAntigravityGuard(p, guardAbs) {
|
|
128
|
+
mkdirSync(p.antigravityDir, { recursive: true });
|
|
129
|
+
let existing = {};
|
|
130
|
+
if (existsSync(p.antigravityHooksPath)) {
|
|
131
|
+
const raw = readFileSync(p.antigravityHooksPath, "utf-8");
|
|
132
|
+
if (!existsSync(p.antigravityBackupPath)) writeFileSync(p.antigravityBackupPath, raw);
|
|
133
|
+
try {
|
|
134
|
+
existing = JSON.parse(raw);
|
|
135
|
+
} catch {
|
|
136
|
+
existing = {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const merged = {
|
|
140
|
+
...existing,
|
|
141
|
+
[ANTIGRAVITY_GROUP]: {
|
|
142
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
writeFileSync(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
146
|
+
}
|
|
147
|
+
function removeAntigravityGuard(p) {
|
|
148
|
+
if (!existsSync(p.antigravityHooksPath)) return;
|
|
149
|
+
try {
|
|
150
|
+
const s = JSON.parse(readFileSync(p.antigravityHooksPath, "utf-8"));
|
|
151
|
+
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
152
|
+
delete s[ANTIGRAVITY_GROUP];
|
|
153
|
+
writeFileSync(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
113
157
|
function ask(question) {
|
|
114
158
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
115
159
|
return new Promise((res) => rl.question(question, (a) => {
|
|
@@ -121,6 +165,7 @@ function runGlobalRestore() {
|
|
|
121
165
|
const p = globalPaths();
|
|
122
166
|
unlockProtected();
|
|
123
167
|
removeClaudeShim();
|
|
168
|
+
removeAntigravityGuard(p);
|
|
124
169
|
if (existsSync(p.backupPath)) {
|
|
125
170
|
writeFileSync(p.settingsPath, readFileSync(p.backupPath, "utf-8"));
|
|
126
171
|
console.log(` Restored ${p.settingsPath} from backup.`);
|
|
@@ -179,6 +224,10 @@ function installGlobalQuiet() {
|
|
|
179
224
|
}
|
|
180
225
|
};
|
|
181
226
|
writeFileSync(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
227
|
+
try {
|
|
228
|
+
installAntigravityGuard(p, join(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
182
231
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
183
232
|
return { ok: true, message: "guard installed (open a new session)" };
|
|
184
233
|
} catch (e) {
|
|
@@ -218,6 +267,10 @@ function uninstallGlobalQuiet() {
|
|
|
218
267
|
const p = globalPaths();
|
|
219
268
|
unlockProtected();
|
|
220
269
|
removeClaudeShim();
|
|
270
|
+
try {
|
|
271
|
+
removeAntigravityGuard(p);
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
221
274
|
if (!existsSync(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
222
275
|
const s = JSON.parse(readFileSync(p.settingsPath, "utf-8"));
|
|
223
276
|
delete s.hooks;
|
|
@@ -356,6 +409,11 @@ async function runGlobalInstall(opts = {}) {
|
|
|
356
409
|
};
|
|
357
410
|
writeFileSync(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
358
411
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
412
|
+
try {
|
|
413
|
+
installAntigravityGuard(p, guardAbs);
|
|
414
|
+
console.log(` Registered Antigravity CLI guard \u2192 ${p.antigravityHooksPath}`);
|
|
415
|
+
} catch {
|
|
416
|
+
}
|
|
359
417
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
360
418
|
lockProtected();
|
|
361
419
|
console.log(" Locked protection files (OS-level read-only/immutable).");
|
package/dist/index.js
CHANGED
|
@@ -10210,7 +10210,8 @@ function protectedTargets() {
|
|
|
10210
10210
|
join11(p.hooksDir, "stop.mjs"),
|
|
10211
10211
|
join11(p.hooksDir, "shield.mjs"),
|
|
10212
10212
|
p.configPath,
|
|
10213
|
-
p.settingsPath
|
|
10213
|
+
p.settingsPath,
|
|
10214
|
+
p.antigravityHooksPath
|
|
10214
10215
|
];
|
|
10215
10216
|
}
|
|
10216
10217
|
function lockProtected() {
|
|
@@ -10224,14 +10225,21 @@ function globalPaths() {
|
|
|
10224
10225
|
const sgDir = join11(home, ".solongate");
|
|
10225
10226
|
const hooksDir = join11(sgDir, "hooks");
|
|
10226
10227
|
const claudeDir = join11(home, ".claude");
|
|
10228
|
+
const antigravityDir = join11(home, ".gemini", "config");
|
|
10227
10229
|
return {
|
|
10228
10230
|
home,
|
|
10229
10231
|
sgDir,
|
|
10230
10232
|
hooksDir,
|
|
10231
10233
|
claudeDir,
|
|
10234
|
+
antigravityDir,
|
|
10232
10235
|
settingsPath: join11(claudeDir, "settings.json"),
|
|
10233
10236
|
backupPath: join11(claudeDir, "settings.solongate.bak"),
|
|
10234
|
-
configPath: join11(sgDir, "cloud-guard.json")
|
|
10237
|
+
configPath: join11(sgDir, "cloud-guard.json"),
|
|
10238
|
+
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
10239
|
+
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
10240
|
+
// covered by the passive session-log collector, not a hook.
|
|
10241
|
+
antigravityHooksPath: join11(antigravityDir, "hooks.json"),
|
|
10242
|
+
antigravityBackupPath: join11(antigravityDir, "hooks.solongate.bak")
|
|
10235
10243
|
};
|
|
10236
10244
|
}
|
|
10237
10245
|
function readHook(filename) {
|
|
@@ -10241,6 +10249,41 @@ function readGuard() {
|
|
|
10241
10249
|
const bundled = join11(HOOKS_DIR, "guard.bundled.mjs");
|
|
10242
10250
|
return existsSync4(bundled) ? readFileSync9(bundled, "utf-8") : readHook("guard.mjs");
|
|
10243
10251
|
}
|
|
10252
|
+
function antigravityHookCommand(guardAbs) {
|
|
10253
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
10254
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
10255
|
+
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
10256
|
+
}
|
|
10257
|
+
function installAntigravityGuard(p, guardAbs) {
|
|
10258
|
+
mkdirSync8(p.antigravityDir, { recursive: true });
|
|
10259
|
+
let existing = {};
|
|
10260
|
+
if (existsSync4(p.antigravityHooksPath)) {
|
|
10261
|
+
const raw = readFileSync9(p.antigravityHooksPath, "utf-8");
|
|
10262
|
+
if (!existsSync4(p.antigravityBackupPath)) writeFileSync9(p.antigravityBackupPath, raw);
|
|
10263
|
+
try {
|
|
10264
|
+
existing = JSON.parse(raw);
|
|
10265
|
+
} catch {
|
|
10266
|
+
existing = {};
|
|
10267
|
+
}
|
|
10268
|
+
}
|
|
10269
|
+
const merged = {
|
|
10270
|
+
...existing,
|
|
10271
|
+
[ANTIGRAVITY_GROUP]: {
|
|
10272
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
10273
|
+
}
|
|
10274
|
+
};
|
|
10275
|
+
writeFileSync9(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10276
|
+
}
|
|
10277
|
+
function removeAntigravityGuard(p) {
|
|
10278
|
+
if (!existsSync4(p.antigravityHooksPath)) return;
|
|
10279
|
+
try {
|
|
10280
|
+
const s = JSON.parse(readFileSync9(p.antigravityHooksPath, "utf-8"));
|
|
10281
|
+
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
10282
|
+
delete s[ANTIGRAVITY_GROUP];
|
|
10283
|
+
writeFileSync9(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
10284
|
+
} catch {
|
|
10285
|
+
}
|
|
10286
|
+
}
|
|
10244
10287
|
function installGlobalQuiet() {
|
|
10245
10288
|
try {
|
|
10246
10289
|
const p = globalPaths();
|
|
@@ -10283,6 +10326,10 @@ function installGlobalQuiet() {
|
|
|
10283
10326
|
}
|
|
10284
10327
|
};
|
|
10285
10328
|
writeFileSync9(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
10329
|
+
try {
|
|
10330
|
+
installAntigravityGuard(p, join11(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
10331
|
+
} catch {
|
|
10332
|
+
}
|
|
10286
10333
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
10287
10334
|
return { ok: true, message: "guard installed (open a new session)" };
|
|
10288
10335
|
} catch (e) {
|
|
@@ -10322,6 +10369,10 @@ function uninstallGlobalQuiet() {
|
|
|
10322
10369
|
const p = globalPaths();
|
|
10323
10370
|
unlockProtected();
|
|
10324
10371
|
removeClaudeShim();
|
|
10372
|
+
try {
|
|
10373
|
+
removeAntigravityGuard(p);
|
|
10374
|
+
} catch {
|
|
10375
|
+
}
|
|
10325
10376
|
if (!existsSync4(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
10326
10377
|
const s = JSON.parse(readFileSync9(p.settingsPath, "utf-8"));
|
|
10327
10378
|
delete s.hooks;
|
|
@@ -10364,12 +10415,13 @@ function removeClaudeShim() {
|
|
|
10364
10415
|
}
|
|
10365
10416
|
}
|
|
10366
10417
|
}
|
|
10367
|
-
var __dirname, HOOKS_DIR, SHIM_BEGIN, SHIM_END;
|
|
10418
|
+
var __dirname, HOOKS_DIR, ANTIGRAVITY_GROUP, SHIM_BEGIN, SHIM_END;
|
|
10368
10419
|
var init_global_install = __esm({
|
|
10369
10420
|
"src/global-install.ts"() {
|
|
10370
10421
|
"use strict";
|
|
10371
10422
|
__dirname = dirname3(fileURLToPath3(import.meta.url));
|
|
10372
10423
|
HOOKS_DIR = resolve4(__dirname, "..", "hooks");
|
|
10424
|
+
ANTIGRAVITY_GROUP = "solongate-guard";
|
|
10373
10425
|
SHIM_BEGIN = "# >>> SolonGate shield (auto secret redaction) >>>";
|
|
10374
10426
|
SHIM_END = "# <<< SolonGate shield <<<";
|
|
10375
10427
|
}
|
|
@@ -13453,7 +13505,7 @@ console.log('MCP servers communicate over stdin/stdout \u2014 not HTTP.');
|
|
|
13453
13505
|
console.log('You need an MCP client to connect:');
|
|
13454
13506
|
console.log('');
|
|
13455
13507
|
console.log(' Claude Code Open this folder, .mcp.json is auto-detected');
|
|
13456
|
-
console.log('
|
|
13508
|
+
console.log(' Antigravity .agents/mcp_config.json (or ~/.gemini/config/mcp_config.json)');
|
|
13457
13509
|
console.log(' OpenClaw Uses openclaw.plugin.json config');
|
|
13458
13510
|
console.log('');
|
|
13459
13511
|
console.log('Press Ctrl+C to stop.');
|
|
@@ -16390,7 +16442,7 @@ var SolonGateProxy = class {
|
|
|
16390
16442
|
const lower = raw.toLowerCase();
|
|
16391
16443
|
if (lower.includes("claude-code") || lower === "claude code") return { id: "claude-code", name: "Claude Code" };
|
|
16392
16444
|
if (lower.includes("claude")) return { id: "claude-desktop", name: "Claude Desktop" };
|
|
16393
|
-
if (lower.includes("
|
|
16445
|
+
if (lower.includes("antigravity") || lower === "agy") return { id: "antigravity", name: "Antigravity" };
|
|
16394
16446
|
return { id: raw.toLowerCase().replace(/\s+/g, "-"), name: raw };
|
|
16395
16447
|
}
|
|
16396
16448
|
/** Extract sub-agent identity from MCP _meta field */
|
package/dist/lib.js
CHANGED
|
@@ -9394,7 +9394,7 @@ var SolonGateProxy = class {
|
|
|
9394
9394
|
const lower = raw.toLowerCase();
|
|
9395
9395
|
if (lower.includes("claude-code") || lower === "claude code") return { id: "claude-code", name: "Claude Code" };
|
|
9396
9396
|
if (lower.includes("claude")) return { id: "claude-desktop", name: "Claude Desktop" };
|
|
9397
|
-
if (lower.includes("
|
|
9397
|
+
if (lower.includes("antigravity") || lower === "agy") return { id: "antigravity", name: "Antigravity" };
|
|
9398
9398
|
return { id: raw.toLowerCase().replace(/\s+/g, "-"), name: raw };
|
|
9399
9399
|
}
|
|
9400
9400
|
/** Extract sub-agent identity from MCP _meta field */
|
package/dist/login.js
CHANGED
|
@@ -98,7 +98,8 @@ function protectedTargets() {
|
|
|
98
98
|
join(p.hooksDir, "stop.mjs"),
|
|
99
99
|
join(p.hooksDir, "shield.mjs"),
|
|
100
100
|
p.configPath,
|
|
101
|
-
p.settingsPath
|
|
101
|
+
p.settingsPath,
|
|
102
|
+
p.antigravityHooksPath
|
|
102
103
|
];
|
|
103
104
|
}
|
|
104
105
|
function lockProtected() {
|
|
@@ -112,14 +113,21 @@ function globalPaths() {
|
|
|
112
113
|
const sgDir = join(home, ".solongate");
|
|
113
114
|
const hooksDir = join(sgDir, "hooks");
|
|
114
115
|
const claudeDir = join(home, ".claude");
|
|
116
|
+
const antigravityDir = join(home, ".gemini", "config");
|
|
115
117
|
return {
|
|
116
118
|
home,
|
|
117
119
|
sgDir,
|
|
118
120
|
hooksDir,
|
|
119
121
|
claudeDir,
|
|
122
|
+
antigravityDir,
|
|
120
123
|
settingsPath: join(claudeDir, "settings.json"),
|
|
121
124
|
backupPath: join(claudeDir, "settings.solongate.bak"),
|
|
122
|
-
configPath: join(sgDir, "cloud-guard.json")
|
|
125
|
+
configPath: join(sgDir, "cloud-guard.json"),
|
|
126
|
+
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
127
|
+
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
128
|
+
// covered by the passive session-log collector, not a hook.
|
|
129
|
+
antigravityHooksPath: join(antigravityDir, "hooks.json"),
|
|
130
|
+
antigravityBackupPath: join(antigravityDir, "hooks.solongate.bak")
|
|
123
131
|
};
|
|
124
132
|
}
|
|
125
133
|
function readHook(filename) {
|
|
@@ -129,6 +137,32 @@ function readGuard() {
|
|
|
129
137
|
const bundled = join(HOOKS_DIR, "guard.bundled.mjs");
|
|
130
138
|
return existsSync(bundled) ? readFileSync(bundled, "utf-8") : readHook("guard.mjs");
|
|
131
139
|
}
|
|
140
|
+
var ANTIGRAVITY_GROUP = "solongate-guard";
|
|
141
|
+
function antigravityHookCommand(guardAbs) {
|
|
142
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
143
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
144
|
+
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
145
|
+
}
|
|
146
|
+
function installAntigravityGuard(p, guardAbs) {
|
|
147
|
+
mkdirSync(p.antigravityDir, { recursive: true });
|
|
148
|
+
let existing = {};
|
|
149
|
+
if (existsSync(p.antigravityHooksPath)) {
|
|
150
|
+
const raw = readFileSync(p.antigravityHooksPath, "utf-8");
|
|
151
|
+
if (!existsSync(p.antigravityBackupPath)) writeFileSync(p.antigravityBackupPath, raw);
|
|
152
|
+
try {
|
|
153
|
+
existing = JSON.parse(raw);
|
|
154
|
+
} catch {
|
|
155
|
+
existing = {};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const merged = {
|
|
159
|
+
...existing,
|
|
160
|
+
[ANTIGRAVITY_GROUP]: {
|
|
161
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
writeFileSync(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
165
|
+
}
|
|
132
166
|
function ask(question) {
|
|
133
167
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
134
168
|
return new Promise((res) => rl.question(question, (a) => {
|
|
@@ -257,6 +291,11 @@ async function runGlobalInstall(opts = {}) {
|
|
|
257
291
|
};
|
|
258
292
|
writeFileSync(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
259
293
|
console.log(` Registered global hooks \u2192 ${p.settingsPath}`);
|
|
294
|
+
try {
|
|
295
|
+
installAntigravityGuard(p, guardAbs);
|
|
296
|
+
console.log(` Registered Antigravity CLI guard \u2192 ${p.antigravityHooksPath}`);
|
|
297
|
+
} catch {
|
|
298
|
+
}
|
|
260
299
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") {
|
|
261
300
|
lockProtected();
|
|
262
301
|
console.log(" Locked protection files (OS-level read-only/immutable).");
|
package/dist/tui/index.js
CHANGED
|
@@ -3268,7 +3268,8 @@ function protectedTargets() {
|
|
|
3268
3268
|
join6(p.hooksDir, "stop.mjs"),
|
|
3269
3269
|
join6(p.hooksDir, "shield.mjs"),
|
|
3270
3270
|
p.configPath,
|
|
3271
|
-
p.settingsPath
|
|
3271
|
+
p.settingsPath,
|
|
3272
|
+
p.antigravityHooksPath
|
|
3272
3273
|
];
|
|
3273
3274
|
}
|
|
3274
3275
|
function lockProtected() {
|
|
@@ -3282,14 +3283,21 @@ function globalPaths() {
|
|
|
3282
3283
|
const sgDir = join6(home, ".solongate");
|
|
3283
3284
|
const hooksDir = join6(sgDir, "hooks");
|
|
3284
3285
|
const claudeDir = join6(home, ".claude");
|
|
3286
|
+
const antigravityDir = join6(home, ".gemini", "config");
|
|
3285
3287
|
return {
|
|
3286
3288
|
home,
|
|
3287
3289
|
sgDir,
|
|
3288
3290
|
hooksDir,
|
|
3289
3291
|
claudeDir,
|
|
3292
|
+
antigravityDir,
|
|
3290
3293
|
settingsPath: join6(claudeDir, "settings.json"),
|
|
3291
3294
|
backupPath: join6(claudeDir, "settings.solongate.bak"),
|
|
3292
|
-
configPath: join6(sgDir, "cloud-guard.json")
|
|
3295
|
+
configPath: join6(sgDir, "cloud-guard.json"),
|
|
3296
|
+
// Antigravity reads global hooks from ~/.gemini/config/hooks.json. Only the
|
|
3297
|
+
// guard is registered there (PreToolUse); Antigravity's ALLOW-path audit is
|
|
3298
|
+
// covered by the passive session-log collector, not a hook.
|
|
3299
|
+
antigravityHooksPath: join6(antigravityDir, "hooks.json"),
|
|
3300
|
+
antigravityBackupPath: join6(antigravityDir, "hooks.solongate.bak")
|
|
3293
3301
|
};
|
|
3294
3302
|
}
|
|
3295
3303
|
function readHook(filename) {
|
|
@@ -3299,6 +3307,42 @@ function readGuard() {
|
|
|
3299
3307
|
const bundled = join6(HOOKS_DIR, "guard.bundled.mjs");
|
|
3300
3308
|
return existsSync2(bundled) ? readFileSync4(bundled, "utf-8") : readHook("guard.mjs");
|
|
3301
3309
|
}
|
|
3310
|
+
var ANTIGRAVITY_GROUP = "solongate-guard";
|
|
3311
|
+
function antigravityHookCommand(guardAbs) {
|
|
3312
|
+
const nodeBin = process.execPath.replace(/\\/g, "/");
|
|
3313
|
+
const call = process.platform === "win32" ? "& " : "";
|
|
3314
|
+
return `${call}"${nodeBin}" "${guardAbs.replace(/\\/g, "/")}" antigravity "Antigravity"`;
|
|
3315
|
+
}
|
|
3316
|
+
function installAntigravityGuard(p, guardAbs) {
|
|
3317
|
+
mkdirSync4(p.antigravityDir, { recursive: true });
|
|
3318
|
+
let existing = {};
|
|
3319
|
+
if (existsSync2(p.antigravityHooksPath)) {
|
|
3320
|
+
const raw = readFileSync4(p.antigravityHooksPath, "utf-8");
|
|
3321
|
+
if (!existsSync2(p.antigravityBackupPath)) writeFileSync5(p.antigravityBackupPath, raw);
|
|
3322
|
+
try {
|
|
3323
|
+
existing = JSON.parse(raw);
|
|
3324
|
+
} catch {
|
|
3325
|
+
existing = {};
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
const merged = {
|
|
3329
|
+
...existing,
|
|
3330
|
+
[ANTIGRAVITY_GROUP]: {
|
|
3331
|
+
PreToolUse: [{ matcher: "", hooks: [{ type: "command", command: antigravityHookCommand(guardAbs) }] }]
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
writeFileSync5(p.antigravityHooksPath, JSON.stringify(merged, null, 2) + "\n");
|
|
3335
|
+
}
|
|
3336
|
+
function removeAntigravityGuard(p) {
|
|
3337
|
+
if (!existsSync2(p.antigravityHooksPath)) return;
|
|
3338
|
+
try {
|
|
3339
|
+
const s = JSON.parse(readFileSync4(p.antigravityHooksPath, "utf-8"));
|
|
3340
|
+
if (!(ANTIGRAVITY_GROUP in s)) return;
|
|
3341
|
+
delete s[ANTIGRAVITY_GROUP];
|
|
3342
|
+
writeFileSync5(p.antigravityHooksPath, JSON.stringify(s, null, 2) + "\n");
|
|
3343
|
+
} catch {
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3302
3346
|
function installGlobalQuiet() {
|
|
3303
3347
|
try {
|
|
3304
3348
|
const p = globalPaths();
|
|
@@ -3341,6 +3385,10 @@ function installGlobalQuiet() {
|
|
|
3341
3385
|
}
|
|
3342
3386
|
};
|
|
3343
3387
|
writeFileSync5(p.settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
3388
|
+
try {
|
|
3389
|
+
installAntigravityGuard(p, join6(p.hooksDir, "guard.mjs").replace(/\\/g, "/"));
|
|
3390
|
+
} catch {
|
|
3391
|
+
}
|
|
3344
3392
|
if (process.env["SOLONGATE_OS_LOCK"] === "1") lockProtected();
|
|
3345
3393
|
return { ok: true, message: "guard installed (open a new session)" };
|
|
3346
3394
|
} catch (e) {
|
|
@@ -3380,6 +3428,10 @@ function uninstallGlobalQuiet() {
|
|
|
3380
3428
|
const p = globalPaths();
|
|
3381
3429
|
unlockProtected();
|
|
3382
3430
|
removeClaudeShim();
|
|
3431
|
+
try {
|
|
3432
|
+
removeAntigravityGuard(p);
|
|
3433
|
+
} catch {
|
|
3434
|
+
}
|
|
3383
3435
|
if (!existsSync2(p.settingsPath)) return { ok: true, message: "guard removed (open a new session)" };
|
|
3384
3436
|
const s = JSON.parse(readFileSync4(p.settingsPath, "utf-8"));
|
|
3385
3437
|
delete s.hooks;
|
package/hooks/guard.bundled.mjs
CHANGED
|
@@ -6536,7 +6536,7 @@ import { resolve, join, dirname, isAbsolute } from "node:path";
|
|
|
6536
6536
|
import { homedir } from "node:os";
|
|
6537
6537
|
import { gunzipSync } from "node:zlib";
|
|
6538
6538
|
import { createHash } from "node:crypto";
|
|
6539
|
-
var HOOK_VERSION =
|
|
6539
|
+
var HOOK_VERSION = 44;
|
|
6540
6540
|
function localLogsOnly(security) {
|
|
6541
6541
|
if (security && typeof security === "object") {
|
|
6542
6542
|
const l = security.localLogs;
|
|
@@ -6797,7 +6797,7 @@ function sgFinish(code) {
|
|
|
6797
6797
|
throw SG_DONE;
|
|
6798
6798
|
}
|
|
6799
6799
|
function blockTool(reason) {
|
|
6800
|
-
if (AGENT_TYPE === "
|
|
6800
|
+
if (AGENT_TYPE === "antigravity") {
|
|
6801
6801
|
process.stdout.write(JSON.stringify({
|
|
6802
6802
|
decision: "deny",
|
|
6803
6803
|
reason: `[SolonGate] ${reason}`
|
|
@@ -6817,7 +6817,7 @@ function blockTool(reason) {
|
|
|
6817
6817
|
}
|
|
6818
6818
|
}
|
|
6819
6819
|
function allowTool() {
|
|
6820
|
-
if (AGENT_TYPE === "
|
|
6820
|
+
if (AGENT_TYPE === "antigravity") {
|
|
6821
6821
|
process.stdout.write(JSON.stringify({ decision: "allow" }));
|
|
6822
6822
|
}
|
|
6823
6823
|
sgFinish(0);
|
|
@@ -7072,7 +7072,12 @@ var TAMPER_PATH_FIELDS = /* @__PURE__ */ new Set([
|
|
|
7072
7072
|
"to",
|
|
7073
7073
|
"directory",
|
|
7074
7074
|
"dir",
|
|
7075
|
-
"folder"
|
|
7075
|
+
"folder",
|
|
7076
|
+
// Antigravity CLI file-tool arg names (camelCase, lowercased here): its
|
|
7077
|
+
// write/read/list tools carry the path in these, so tamper protection sees it.
|
|
7078
|
+
"targetfile",
|
|
7079
|
+
"absolutepath",
|
|
7080
|
+
"filepath"
|
|
7076
7081
|
]);
|
|
7077
7082
|
function normTamperPath(p) {
|
|
7078
7083
|
return String(p || "").replace(/\\/g, "/").toLowerCase();
|
|
@@ -7763,13 +7768,30 @@ if (!REFRESH_MODE) {
|
|
|
7763
7768
|
}
|
|
7764
7769
|
let mappedToolName = raw.tool_name || raw.toolName || "";
|
|
7765
7770
|
let mappedToolInput = raw.tool_input || raw.toolInput || raw.params || {};
|
|
7771
|
+
let mappedSession = raw.session_id || raw.sessionId || raw.conversation_id || "";
|
|
7772
|
+
let mappedCwd = raw.cwd || "";
|
|
7773
|
+
if (raw.toolCall && typeof raw.toolCall === "object") {
|
|
7774
|
+
const tc = raw.toolCall;
|
|
7775
|
+
mappedToolName = mappedToolName || tc.name || "";
|
|
7776
|
+
const a = tc.args && typeof tc.args === "object" ? tc.args : {};
|
|
7777
|
+
mappedToolInput = { ...a };
|
|
7778
|
+
if (typeof a.CommandLine === "string" && mappedToolInput.command == null)
|
|
7779
|
+
mappedToolInput.command = a.CommandLine;
|
|
7780
|
+
mappedSession = mappedSession || raw.conversationId || "";
|
|
7781
|
+
if (!mappedCwd) {
|
|
7782
|
+
if (typeof a.Cwd === "string" && a.Cwd)
|
|
7783
|
+
mappedCwd = a.Cwd;
|
|
7784
|
+
else if (Array.isArray(raw.workspacePaths) && typeof raw.workspacePaths[0] === "string")
|
|
7785
|
+
mappedCwd = raw.workspacePaths[0];
|
|
7786
|
+
}
|
|
7787
|
+
}
|
|
7766
7788
|
const data = {
|
|
7767
7789
|
...raw,
|
|
7768
7790
|
tool_name: mappedToolName,
|
|
7769
7791
|
tool_input: mappedToolInput,
|
|
7770
7792
|
tool_response: raw.tool_response || raw.toolResponse || {},
|
|
7771
|
-
cwd:
|
|
7772
|
-
session_id:
|
|
7793
|
+
cwd: mappedCwd || process.cwd(),
|
|
7794
|
+
session_id: mappedSession
|
|
7773
7795
|
};
|
|
7774
7796
|
const args = data.tool_input;
|
|
7775
7797
|
const toolName = data.tool_name || "";
|
|
@@ -7943,7 +7965,7 @@ if (!REFRESH_MODE) {
|
|
|
7943
7965
|
} catch {
|
|
7944
7966
|
}
|
|
7945
7967
|
await maybeSelfUpdate();
|
|
7946
|
-
if (AGENT_TYPE === "
|
|
7968
|
+
if (AGENT_TYPE === "antigravity") {
|
|
7947
7969
|
process.stdout.write(JSON.stringify({ decision: "deny", reason: ghostHit }));
|
|
7948
7970
|
sgFinish(0);
|
|
7949
7971
|
}
|
|
@@ -7951,7 +7973,7 @@ if (!REFRESH_MODE) {
|
|
|
7951
7973
|
process.stderr.write(ghostHit + "\n");
|
|
7952
7974
|
sgFinish(2);
|
|
7953
7975
|
}
|
|
7954
|
-
if (AGENT_TYPE !== "
|
|
7976
|
+
if (AGENT_TYPE !== "antigravity" && toolName === "Bash") {
|
|
7955
7977
|
const rw = ghostListingRewrite(args, securityCfg.ghost);
|
|
7956
7978
|
if (rw) {
|
|
7957
7979
|
await maybeSelfUpdate();
|
package/hooks/guard.mjs
CHANGED
|
@@ -32,7 +32,7 @@ import { createHash } from 'node:crypto';
|
|
|
32
32
|
// the installed hook self-updates when the cloud version is higher (see
|
|
33
33
|
// maybeSelfUpdate). This is what makes guard fixes propagate without a manual
|
|
34
34
|
// reinstall — the same trust model as the OPA WASM this hook already runs.
|
|
35
|
-
const HOOK_VERSION =
|
|
35
|
+
const HOOK_VERSION = 44;
|
|
36
36
|
|
|
37
37
|
// True when local log storage is ON. In that mode logs are kept LOCAL ONLY and
|
|
38
38
|
// nothing is sent to the cloud audit log.
|
|
@@ -276,7 +276,7 @@ async function maybeSelfUpdate() {
|
|
|
276
276
|
// Two distinct identities, deliberately kept separate:
|
|
277
277
|
//
|
|
278
278
|
// AGENT_TYPE — the real AI client running this hook (claude-code /
|
|
279
|
-
//
|
|
279
|
+
// antigravity / openclaw). Baked into the hook registration by the installer
|
|
280
280
|
// as argv[2] (e.g. `node guard.mjs claude-code`). Decides the response
|
|
281
281
|
// format AND whether a selected policy actually applies to this client.
|
|
282
282
|
//
|
|
@@ -344,8 +344,8 @@ if (REFRESH_MODE) { try { setTimeout(() => { try { process.exit(process.exitCode
|
|
|
344
344
|
|
|
345
345
|
// ── Per-tool block/allow output ──
|
|
346
346
|
// Response format depends on the agent:
|
|
347
|
-
// Claude Code:
|
|
348
|
-
//
|
|
347
|
+
// Claude Code: exit 2 + stderr = BLOCK, exit 0 = ALLOW
|
|
348
|
+
// Antigravity CLI: {"decision": "deny/allow", "reason": "..."} on stdout (exit 0)
|
|
349
349
|
|
|
350
350
|
// Terminate the hook WITHOUT forcing process.exit(). On Windows + Node 24, calling
|
|
351
351
|
// process.exit() right after a fetch() (the cloud audit-log POST) aborts with
|
|
@@ -378,7 +378,7 @@ function sgFinish(code) {
|
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
function blockTool(reason) {
|
|
381
|
-
if (AGENT_TYPE === '
|
|
381
|
+
if (AGENT_TYPE === 'antigravity') {
|
|
382
382
|
process.stdout.write(JSON.stringify({
|
|
383
383
|
decision: 'deny',
|
|
384
384
|
reason: `[SolonGate] ${reason}`,
|
|
@@ -408,7 +408,7 @@ function blockTool(reason) {
|
|
|
408
408
|
}
|
|
409
409
|
|
|
410
410
|
function allowTool() {
|
|
411
|
-
if (AGENT_TYPE === '
|
|
411
|
+
if (AGENT_TYPE === 'antigravity') {
|
|
412
412
|
process.stdout.write(JSON.stringify({ decision: 'allow' }));
|
|
413
413
|
}
|
|
414
414
|
sgFinish(0);
|
|
@@ -784,6 +784,9 @@ const TAMPER_PATH_FIELDS = new Set([
|
|
|
784
784
|
'file_path', 'path', 'target_file', 'notebook_path',
|
|
785
785
|
'dest', 'destination', 'source', 'src', 'from', 'to',
|
|
786
786
|
'directory', 'dir', 'folder',
|
|
787
|
+
// Antigravity CLI file-tool arg names (camelCase, lowercased here): its
|
|
788
|
+
// write/read/list tools carry the path in these, so tamper protection sees it.
|
|
789
|
+
'targetfile', 'absolutepath', 'filepath',
|
|
787
790
|
]);
|
|
788
791
|
|
|
789
792
|
function normTamperPath(p) {
|
|
@@ -1581,6 +1584,30 @@ if (!REFRESH_MODE) { try { input += readFileSync(0, 'utf-8'); } catch {} }
|
|
|
1581
1584
|
|
|
1582
1585
|
let mappedToolName = raw.tool_name || raw.toolName || '';
|
|
1583
1586
|
let mappedToolInput = raw.tool_input || raw.toolInput || raw.params || {};
|
|
1587
|
+
let mappedSession = raw.session_id || raw.sessionId || raw.conversation_id || '';
|
|
1588
|
+
let mappedCwd = raw.cwd || '';
|
|
1589
|
+
|
|
1590
|
+
// Antigravity CLI (PreToolUse) nests the tool under a `toolCall` object
|
|
1591
|
+
// ({ name, args: { CommandLine, Cwd, ... } }) and carries metadata in
|
|
1592
|
+
// camelCase (conversationId, workspacePaths) — a different shape from the
|
|
1593
|
+
// flat Claude/Gemini payload. Flatten it into the fields the guard's
|
|
1594
|
+
// extractors read, and alias the shell command (args.CommandLine) to
|
|
1595
|
+
// `command` so extractCommands / tamperCheck / command policies see it. Tool
|
|
1596
|
+
// NAMES need no remapping: guessPermission/tamperCheck already classify
|
|
1597
|
+
// Antigravity's snake_case names (run_command → EXECUTE via "run",
|
|
1598
|
+
// write_to_file → WRITE, read_file → READ) by substring.
|
|
1599
|
+
if (raw.toolCall && typeof raw.toolCall === 'object') {
|
|
1600
|
+
const tc = raw.toolCall;
|
|
1601
|
+
mappedToolName = mappedToolName || tc.name || '';
|
|
1602
|
+
const a = (tc.args && typeof tc.args === 'object') ? tc.args : {};
|
|
1603
|
+
mappedToolInput = { ...a };
|
|
1604
|
+
if (typeof a.CommandLine === 'string' && mappedToolInput.command == null) mappedToolInput.command = a.CommandLine;
|
|
1605
|
+
mappedSession = mappedSession || raw.conversationId || '';
|
|
1606
|
+
if (!mappedCwd) {
|
|
1607
|
+
if (typeof a.Cwd === 'string' && a.Cwd) mappedCwd = a.Cwd;
|
|
1608
|
+
else if (Array.isArray(raw.workspacePaths) && typeof raw.workspacePaths[0] === 'string') mappedCwd = raw.workspacePaths[0];
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1584
1611
|
|
|
1585
1612
|
// Normalize field names across tools
|
|
1586
1613
|
const data = {
|
|
@@ -1588,8 +1615,8 @@ if (!REFRESH_MODE) { try { input += readFileSync(0, 'utf-8'); } catch {} }
|
|
|
1588
1615
|
tool_name: mappedToolName,
|
|
1589
1616
|
tool_input: mappedToolInput,
|
|
1590
1617
|
tool_response: raw.tool_response || raw.toolResponse || {},
|
|
1591
|
-
cwd:
|
|
1592
|
-
session_id:
|
|
1618
|
+
cwd: mappedCwd || process.cwd(),
|
|
1619
|
+
session_id: mappedSession,
|
|
1593
1620
|
};
|
|
1594
1621
|
const args = data.tool_input;
|
|
1595
1622
|
const toolName = data.tool_name || '';
|
|
@@ -1789,7 +1816,7 @@ if (!REFRESH_MODE) { try { input += readFileSync(0, 'utf-8'); } catch {} }
|
|
|
1789
1816
|
});
|
|
1790
1817
|
} catch {}
|
|
1791
1818
|
await maybeSelfUpdate();
|
|
1792
|
-
if (AGENT_TYPE === '
|
|
1819
|
+
if (AGENT_TYPE === 'antigravity') { process.stdout.write(JSON.stringify({ decision: 'deny', reason: ghostHit })); sgFinish(0); }
|
|
1793
1820
|
// Claude Code: JSON deny on stdout + exit 2 (reason on stderr). Exit 2 is
|
|
1794
1821
|
// the only block enforced in auto-accept mode (see blockTool); the JSON is
|
|
1795
1822
|
// the Windows fallback. ghostHit is a bare "No such file or directory", so
|
|
@@ -1800,7 +1827,7 @@ if (!REFRESH_MODE) { try { input += readFileSync(0, 'utf-8'); } catch {} }
|
|
|
1800
1827
|
}
|
|
1801
1828
|
// No direct hit: if this is a listing command, rewrite it so hidden
|
|
1802
1829
|
// entries are filtered out of its output (Claude Code only).
|
|
1803
|
-
if (AGENT_TYPE !== '
|
|
1830
|
+
if (AGENT_TYPE !== 'antigravity' && toolName === 'Bash') {
|
|
1804
1831
|
const rw = ghostListingRewrite(args, securityCfg.ghost);
|
|
1805
1832
|
if (rw) { await maybeSelfUpdate(); rewriteTool({ command: rw }); }
|
|
1806
1833
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.12",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|