@solongate/proxy 0.32.0 → 0.33.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/create.js +1 -2
- package/dist/index.js +12 -124
- package/dist/init.js +10 -118
- package/dist/lib.js +1 -4
- package/hooks/audit.mjs +3 -33
- package/hooks/guard.mjs +8 -77
- package/hooks/stop.mjs +2 -3
- package/package.json +1 -1
package/dist/create.js
CHANGED
|
@@ -214,7 +214,6 @@ 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
216
|
console.log(' Claude Desktop Add to Settings > MCP Servers');
|
|
217
|
-
console.log(' Cursor Open this folder, .mcp.json is auto-detected');
|
|
218
217
|
console.log(' Windsurf Open this folder, .mcp.json is auto-detected');
|
|
219
218
|
console.log(' Cline VS Code extension, add server in settings');
|
|
220
219
|
console.log(' Zed Add to settings.json under mcp_servers');
|
|
@@ -312,7 +311,7 @@ async function main() {
|
|
|
312
311
|
bEmpty();
|
|
313
312
|
log(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
314
313
|
bEmpty();
|
|
315
|
-
bLine(`${c.yellow}Use with Claude Code /
|
|
314
|
+
bLine(`${c.yellow}Use with Claude Code / MCP client:${c.reset}`);
|
|
316
315
|
bEmpty();
|
|
317
316
|
bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .mcp.json`);
|
|
318
317
|
bLine(` ${c.dim}2.${c.reset} Open this folder in your MCP client`);
|
package/dist/index.js
CHANGED
|
@@ -461,7 +461,6 @@ var init_cli_utils = __esm({
|
|
|
461
461
|
var init_exports = {};
|
|
462
462
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
|
|
463
463
|
import { resolve as resolve3, join as join2, dirname as dirname2 } from "path";
|
|
464
|
-
import { homedir } from "os";
|
|
465
464
|
import { fileURLToPath } from "url";
|
|
466
465
|
import { execFileSync } from "child_process";
|
|
467
466
|
import { createInterface } from "readline";
|
|
@@ -580,24 +579,15 @@ function parseInitArgs(argv) {
|
|
|
580
579
|
case "--all":
|
|
581
580
|
options.all = true;
|
|
582
581
|
break;
|
|
583
|
-
case "--claude":
|
|
584
|
-
options.tools.push("claude");
|
|
585
|
-
break;
|
|
586
|
-
case "--cursor":
|
|
587
|
-
options.tools.push("cursor");
|
|
582
|
+
case "--claude-code":
|
|
583
|
+
options.tools.push("claude-code");
|
|
588
584
|
break;
|
|
589
585
|
case "--gemini":
|
|
590
586
|
options.tools.push("gemini");
|
|
591
587
|
break;
|
|
592
|
-
case "--antigravity":
|
|
593
|
-
options.tools.push("antigravity");
|
|
594
|
-
break;
|
|
595
588
|
case "--openclaw":
|
|
596
589
|
options.tools.push("openclaw");
|
|
597
590
|
break;
|
|
598
|
-
case "--perplexity":
|
|
599
|
-
options.tools.push("perplexity");
|
|
600
|
-
break;
|
|
601
591
|
case "--help":
|
|
602
592
|
case "-h":
|
|
603
593
|
printHelp();
|
|
@@ -621,16 +611,13 @@ OPTIONS
|
|
|
621
611
|
-h, --help Show this help message
|
|
622
612
|
|
|
623
613
|
AI TOOL HOOKS (default: all)
|
|
624
|
-
--claude
|
|
625
|
-
--cursor Install hooks for Cursor
|
|
614
|
+
--claude-code Install hooks for Claude Code
|
|
626
615
|
--gemini Install hooks for Gemini CLI
|
|
627
|
-
--antigravity Install hooks for Antigravity
|
|
628
616
|
--openclaw Install hooks for OpenClaw
|
|
629
|
-
--perplexity Install hooks for Perplexity
|
|
630
617
|
|
|
631
618
|
EXAMPLES
|
|
632
619
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
633
|
-
npx @solongate/proxy init --all --claude --
|
|
620
|
+
npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
|
|
634
621
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
635
622
|
`;
|
|
636
623
|
console.log(help);
|
|
@@ -639,7 +626,7 @@ function readHookScript(filename) {
|
|
|
639
626
|
return readFileSync4(join2(HOOKS_DIR, filename), "utf-8");
|
|
640
627
|
}
|
|
641
628
|
function unlockProtectedDirs() {
|
|
642
|
-
const dirs = [".solongate", ".claude", ".
|
|
629
|
+
const dirs = [".solongate", ".claude", ".gemini", ".openclaw"];
|
|
643
630
|
for (const dir of dirs) {
|
|
644
631
|
const fullDir = resolve3(dir);
|
|
645
632
|
if (!existsSync4(fullDir)) continue;
|
|
@@ -716,12 +703,9 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
716
703
|
console.log(` Hook files already up to date`);
|
|
717
704
|
}
|
|
718
705
|
const allClients = [
|
|
719
|
-
{ name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
|
|
720
|
-
{ name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
|
|
706
|
+
{ name: "Claude Code", dir: ".claude", key: "claude-code", agentId: "claude-code", agentName: "Claude Code" },
|
|
721
707
|
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" },
|
|
722
|
-
{ name: "
|
|
723
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" },
|
|
724
|
-
{ name: "Perplexity", dir: ".perplexity", key: "perplexity", agentId: "perplexity", agentName: "Perplexity" }
|
|
708
|
+
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" }
|
|
725
709
|
];
|
|
726
710
|
const clients = selectedTools.length > 0 ? allClients.filter((c3) => selectedTools.includes(c3.key)) : allClients;
|
|
727
711
|
const activatedNames = [];
|
|
@@ -732,11 +716,7 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
732
716
|
const guardCmd = `node .solongate/hooks/guard.mjs ${client.agentId} "${client.agentName}"`;
|
|
733
717
|
const auditCmd = `node .solongate/hooks/audit.mjs ${client.agentId} "${client.agentName}"`;
|
|
734
718
|
const stopCmd = `node .solongate/hooks/stop.mjs ${client.agentId} "${client.agentName}"`;
|
|
735
|
-
if (client.key === "
|
|
736
|
-
const result = installCursorConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
737
|
-
if (result === "skipped") skippedNames.push(client.name);
|
|
738
|
-
else activatedNames.push(client.name);
|
|
739
|
-
} else if (client.key === "gemini") {
|
|
719
|
+
if (client.key === "gemini") {
|
|
740
720
|
const result = installGeminiConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
741
721
|
if (result === "skipped") skippedNames.push(client.name);
|
|
742
722
|
else activatedNames.push(client.name);
|
|
@@ -788,90 +768,6 @@ function installStandardHookConfig(clientDir, clientName, guardCmd, auditCmd, st
|
|
|
788
768
|
console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
|
|
789
769
|
return "installed";
|
|
790
770
|
}
|
|
791
|
-
function installCursorConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcpConfig) {
|
|
792
|
-
let changed = false;
|
|
793
|
-
const hookConfig = {
|
|
794
|
-
preToolUse: [
|
|
795
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
796
|
-
],
|
|
797
|
-
postToolUse: [
|
|
798
|
-
{ matcher: "", command: auditCmd }
|
|
799
|
-
],
|
|
800
|
-
beforeShellExecution: [
|
|
801
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
802
|
-
],
|
|
803
|
-
afterShellExecution: [
|
|
804
|
-
{ matcher: "", command: auditCmd }
|
|
805
|
-
],
|
|
806
|
-
beforeReadFile: [
|
|
807
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
808
|
-
],
|
|
809
|
-
afterFileEdit: [
|
|
810
|
-
{ matcher: "", command: auditCmd }
|
|
811
|
-
],
|
|
812
|
-
beforeMCPExecution: [
|
|
813
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
814
|
-
],
|
|
815
|
-
afterMCPExecution: [
|
|
816
|
-
{ matcher: "", command: auditCmd }
|
|
817
|
-
]
|
|
818
|
-
};
|
|
819
|
-
const hooksContent = JSON.stringify({ version: 1, hooks: hookConfig }, null, 2) + "\n";
|
|
820
|
-
const userCursorDir = join2(homedir(), ".cursor");
|
|
821
|
-
if (existsSync4(userCursorDir)) {
|
|
822
|
-
const userHooksPath = join2(userCursorDir, "hooks.json");
|
|
823
|
-
const existingUserHooks = existsSync4(userHooksPath) ? readFileSync4(userHooksPath, "utf-8") : "";
|
|
824
|
-
if (hooksContent !== existingUserHooks) {
|
|
825
|
-
writeFileSync2(userHooksPath, hooksContent);
|
|
826
|
-
console.log(` ${existingUserHooks ? "Updated" : "Created"} ${userHooksPath} (user-level)`);
|
|
827
|
-
changed = true;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
const hooksPath = join2(clientDir, "hooks.json");
|
|
831
|
-
const existingHooks = existsSync4(hooksPath) ? readFileSync4(hooksPath, "utf-8") : "";
|
|
832
|
-
if (hooksContent !== existingHooks) {
|
|
833
|
-
writeFileSync2(hooksPath, hooksContent);
|
|
834
|
-
console.log(` ${existingHooks ? "Updated" : "Created"} ${hooksPath}`);
|
|
835
|
-
changed = true;
|
|
836
|
-
}
|
|
837
|
-
if (wrappedMcpConfig) {
|
|
838
|
-
const cursorMcpConfig = { mcpServers: {} };
|
|
839
|
-
for (const [name, server] of Object.entries(wrappedMcpConfig.mcpServers)) {
|
|
840
|
-
const args = [...server.args ?? []];
|
|
841
|
-
const agentIdx = args.indexOf("--agent-name");
|
|
842
|
-
if (agentIdx >= 0 && agentIdx + 1 < args.length) {
|
|
843
|
-
args[agentIdx + 1] = "cursor";
|
|
844
|
-
} else {
|
|
845
|
-
const sepIdx = args.indexOf("--");
|
|
846
|
-
if (sepIdx >= 0) {
|
|
847
|
-
args.splice(sepIdx, 0, "--agent-name", "cursor");
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
cursorMcpConfig.mcpServers[name] = { ...server, args };
|
|
851
|
-
}
|
|
852
|
-
const mcpPath = join2(clientDir, "mcp.json");
|
|
853
|
-
const mcpStr = JSON.stringify(cursorMcpConfig, null, 2) + "\n";
|
|
854
|
-
const existingMcp = existsSync4(mcpPath) ? readFileSync4(mcpPath, "utf-8") : "";
|
|
855
|
-
if (mcpStr !== existingMcp) {
|
|
856
|
-
writeFileSync2(mcpPath, mcpStr);
|
|
857
|
-
console.log(` ${existingMcp ? "Updated" : "Created"} ${mcpPath}`);
|
|
858
|
-
changed = true;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
const staleSettings = join2(clientDir, "settings.json");
|
|
862
|
-
if (existsSync4(staleSettings)) {
|
|
863
|
-
try {
|
|
864
|
-
const content = JSON.parse(readFileSync4(staleSettings, "utf-8"));
|
|
865
|
-
if (content.hooks?.PreToolUse || content.hooks?.PostToolUse) {
|
|
866
|
-
writeFileSync2(staleSettings, JSON.stringify({}, null, 2) + "\n");
|
|
867
|
-
console.log(` Cleaned stale ${staleSettings} (had wrong hook format)`);
|
|
868
|
-
changed = true;
|
|
869
|
-
}
|
|
870
|
-
} catch {
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
return changed ? "installed" : "skipped";
|
|
874
|
-
}
|
|
875
771
|
function installGeminiConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcpConfig) {
|
|
876
772
|
const settingsPath = join2(clientDir, "settings.json");
|
|
877
773
|
let existing = {};
|
|
@@ -965,11 +861,8 @@ SOLONGATE_API_KEY=sg_live_your_key_here
|
|
|
965
861
|
".mcp.json",
|
|
966
862
|
".solongate/**",
|
|
967
863
|
".claude/**",
|
|
968
|
-
".cursor/**",
|
|
969
864
|
".gemini/**",
|
|
970
|
-
".
|
|
971
|
-
".openclaw/**",
|
|
972
|
-
".perplexity/**"
|
|
865
|
+
".openclaw/**"
|
|
973
866
|
];
|
|
974
867
|
if (existsSync4(gitignorePath)) {
|
|
975
868
|
let gitignore = readFileSync4(gitignorePath, "utf-8");
|
|
@@ -1206,8 +1099,7 @@ async function main() {
|
|
|
1206
1099
|
console.log(" \u2502 \u2502");
|
|
1207
1100
|
console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
|
|
1208
1101
|
console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
|
|
1209
|
-
console.log(" \u2502 Claude
|
|
1210
|
-
console.log(" \u2502 OpenClaw, Perplexity \u2502");
|
|
1102
|
+
console.log(" \u2502 Claude Code, Gemini, OpenClaw \u2502");
|
|
1211
1103
|
console.log(" \u2502 API key \u2192 Set in .env \u2502");
|
|
1212
1104
|
console.log(" \u2502 \u2502");
|
|
1213
1105
|
console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
|
|
@@ -1749,7 +1641,6 @@ console.log('You need an MCP client to connect:');
|
|
|
1749
1641
|
console.log('');
|
|
1750
1642
|
console.log(' Claude Code Open this folder, .mcp.json is auto-detected');
|
|
1751
1643
|
console.log(' Claude Desktop Add to Settings > MCP Servers');
|
|
1752
|
-
console.log(' Cursor Open this folder, .mcp.json is auto-detected');
|
|
1753
1644
|
console.log(' Windsurf Open this folder, .mcp.json is auto-detected');
|
|
1754
1645
|
console.log(' Cline VS Code extension, add server in settings');
|
|
1755
1646
|
console.log(' Zed Add to settings.json under mcp_servers');
|
|
@@ -1847,7 +1738,7 @@ async function main3() {
|
|
|
1847
1738
|
bEmpty();
|
|
1848
1739
|
log3(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
1849
1740
|
bEmpty();
|
|
1850
|
-
bLine(`${c.yellow}Use with Claude Code /
|
|
1741
|
+
bLine(`${c.yellow}Use with Claude Code / MCP client:${c.reset}`);
|
|
1851
1742
|
bEmpty();
|
|
1852
1743
|
bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .mcp.json`);
|
|
1853
1744
|
bLine(` ${c.dim}2.${c.reset} Open this folder in your MCP client`);
|
|
@@ -6062,12 +5953,9 @@ var SolonGateProxy = class {
|
|
|
6062
5953
|
/** Normalize well-known MCP client names to display-friendly agent identities */
|
|
6063
5954
|
normalizeAgentName(raw) {
|
|
6064
5955
|
const lower = raw.toLowerCase();
|
|
6065
|
-
if (lower.includes("cursor")) return { id: "cursor", name: "Cursor" };
|
|
6066
5956
|
if (lower.includes("claude-code") || lower === "claude code") return { id: "claude-code", name: "Claude Code" };
|
|
6067
5957
|
if (lower.includes("claude")) return { id: "claude-desktop", name: "Claude Desktop" };
|
|
6068
5958
|
if (lower.includes("gemini")) return { id: "gemini-cli", name: "Gemini CLI" };
|
|
6069
|
-
if (lower.includes("antigravity")) return { id: "antigravity", name: "Antigravity" };
|
|
6070
|
-
if (lower.includes("perplexity")) return { id: "perplexity", name: "Perplexity" };
|
|
6071
5959
|
return { id: raw.toLowerCase().replace(/\s+/g, "-"), name: raw };
|
|
6072
5960
|
}
|
|
6073
5961
|
/** Extract sub-agent identity from MCP _meta field */
|
|
@@ -6710,7 +6598,7 @@ ${msg.content.text}`;
|
|
|
6710
6598
|
/**
|
|
6711
6599
|
* Start serving downstream.
|
|
6712
6600
|
* If --port is set, serves via StreamableHTTP on that port.
|
|
6713
|
-
* Otherwise, serves on stdio (default for Claude Code /
|
|
6601
|
+
* Otherwise, serves on stdio (default for Claude Code / etc).
|
|
6714
6602
|
*/
|
|
6715
6603
|
async serve() {
|
|
6716
6604
|
if (!this.server) throw new Error("Server not created");
|
package/dist/init.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// src/init.ts
|
|
4
4
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
5
5
|
import { resolve, join, dirname } from "path";
|
|
6
|
-
import { homedir } from "os";
|
|
7
6
|
import { fileURLToPath } from "url";
|
|
8
7
|
import { execFileSync } from "child_process";
|
|
9
8
|
import { createInterface } from "readline";
|
|
@@ -164,24 +163,15 @@ function parseInitArgs(argv) {
|
|
|
164
163
|
case "--all":
|
|
165
164
|
options.all = true;
|
|
166
165
|
break;
|
|
167
|
-
case "--claude":
|
|
168
|
-
options.tools.push("claude");
|
|
169
|
-
break;
|
|
170
|
-
case "--cursor":
|
|
171
|
-
options.tools.push("cursor");
|
|
166
|
+
case "--claude-code":
|
|
167
|
+
options.tools.push("claude-code");
|
|
172
168
|
break;
|
|
173
169
|
case "--gemini":
|
|
174
170
|
options.tools.push("gemini");
|
|
175
171
|
break;
|
|
176
|
-
case "--antigravity":
|
|
177
|
-
options.tools.push("antigravity");
|
|
178
|
-
break;
|
|
179
172
|
case "--openclaw":
|
|
180
173
|
options.tools.push("openclaw");
|
|
181
174
|
break;
|
|
182
|
-
case "--perplexity":
|
|
183
|
-
options.tools.push("perplexity");
|
|
184
|
-
break;
|
|
185
175
|
case "--help":
|
|
186
176
|
case "-h":
|
|
187
177
|
printHelp();
|
|
@@ -205,16 +195,13 @@ OPTIONS
|
|
|
205
195
|
-h, --help Show this help message
|
|
206
196
|
|
|
207
197
|
AI TOOL HOOKS (default: all)
|
|
208
|
-
--claude
|
|
209
|
-
--cursor Install hooks for Cursor
|
|
198
|
+
--claude-code Install hooks for Claude Code
|
|
210
199
|
--gemini Install hooks for Gemini CLI
|
|
211
|
-
--antigravity Install hooks for Antigravity
|
|
212
200
|
--openclaw Install hooks for OpenClaw
|
|
213
|
-
--perplexity Install hooks for Perplexity
|
|
214
201
|
|
|
215
202
|
EXAMPLES
|
|
216
203
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
217
|
-
npx @solongate/proxy init --all --claude --
|
|
204
|
+
npx @solongate/proxy init --all --claude-code --gemini # Only Claude Code + Gemini hooks
|
|
218
205
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
219
206
|
`;
|
|
220
207
|
console.log(help);
|
|
@@ -225,7 +212,7 @@ function readHookScript(filename) {
|
|
|
225
212
|
return readFileSync(join(HOOKS_DIR, filename), "utf-8");
|
|
226
213
|
}
|
|
227
214
|
function unlockProtectedDirs() {
|
|
228
|
-
const dirs = [".solongate", ".claude", ".
|
|
215
|
+
const dirs = [".solongate", ".claude", ".gemini", ".openclaw"];
|
|
229
216
|
for (const dir of dirs) {
|
|
230
217
|
const fullDir = resolve(dir);
|
|
231
218
|
if (!existsSync(fullDir)) continue;
|
|
@@ -302,12 +289,9 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
302
289
|
console.log(` Hook files already up to date`);
|
|
303
290
|
}
|
|
304
291
|
const allClients = [
|
|
305
|
-
{ name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
|
|
306
|
-
{ name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
|
|
292
|
+
{ name: "Claude Code", dir: ".claude", key: "claude-code", agentId: "claude-code", agentName: "Claude Code" },
|
|
307
293
|
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" },
|
|
308
|
-
{ name: "
|
|
309
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" },
|
|
310
|
-
{ name: "Perplexity", dir: ".perplexity", key: "perplexity", agentId: "perplexity", agentName: "Perplexity" }
|
|
294
|
+
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" }
|
|
311
295
|
];
|
|
312
296
|
const clients = selectedTools.length > 0 ? allClients.filter((c2) => selectedTools.includes(c2.key)) : allClients;
|
|
313
297
|
const activatedNames = [];
|
|
@@ -318,11 +302,7 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
318
302
|
const guardCmd = `node .solongate/hooks/guard.mjs ${client.agentId} "${client.agentName}"`;
|
|
319
303
|
const auditCmd = `node .solongate/hooks/audit.mjs ${client.agentId} "${client.agentName}"`;
|
|
320
304
|
const stopCmd = `node .solongate/hooks/stop.mjs ${client.agentId} "${client.agentName}"`;
|
|
321
|
-
if (client.key === "
|
|
322
|
-
const result = installCursorConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
323
|
-
if (result === "skipped") skippedNames.push(client.name);
|
|
324
|
-
else activatedNames.push(client.name);
|
|
325
|
-
} else if (client.key === "gemini") {
|
|
305
|
+
if (client.key === "gemini") {
|
|
326
306
|
const result = installGeminiConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
327
307
|
if (result === "skipped") skippedNames.push(client.name);
|
|
328
308
|
else activatedNames.push(client.name);
|
|
@@ -374,90 +354,6 @@ function installStandardHookConfig(clientDir, clientName, guardCmd, auditCmd, st
|
|
|
374
354
|
console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
|
|
375
355
|
return "installed";
|
|
376
356
|
}
|
|
377
|
-
function installCursorConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcpConfig) {
|
|
378
|
-
let changed = false;
|
|
379
|
-
const hookConfig = {
|
|
380
|
-
preToolUse: [
|
|
381
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
382
|
-
],
|
|
383
|
-
postToolUse: [
|
|
384
|
-
{ matcher: "", command: auditCmd }
|
|
385
|
-
],
|
|
386
|
-
beforeShellExecution: [
|
|
387
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
388
|
-
],
|
|
389
|
-
afterShellExecution: [
|
|
390
|
-
{ matcher: "", command: auditCmd }
|
|
391
|
-
],
|
|
392
|
-
beforeReadFile: [
|
|
393
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
394
|
-
],
|
|
395
|
-
afterFileEdit: [
|
|
396
|
-
{ matcher: "", command: auditCmd }
|
|
397
|
-
],
|
|
398
|
-
beforeMCPExecution: [
|
|
399
|
-
{ matcher: "", command: guardCmd, failClosed: true }
|
|
400
|
-
],
|
|
401
|
-
afterMCPExecution: [
|
|
402
|
-
{ matcher: "", command: auditCmd }
|
|
403
|
-
]
|
|
404
|
-
};
|
|
405
|
-
const hooksContent = JSON.stringify({ version: 1, hooks: hookConfig }, null, 2) + "\n";
|
|
406
|
-
const userCursorDir = join(homedir(), ".cursor");
|
|
407
|
-
if (existsSync(userCursorDir)) {
|
|
408
|
-
const userHooksPath = join(userCursorDir, "hooks.json");
|
|
409
|
-
const existingUserHooks = existsSync(userHooksPath) ? readFileSync(userHooksPath, "utf-8") : "";
|
|
410
|
-
if (hooksContent !== existingUserHooks) {
|
|
411
|
-
writeFileSync(userHooksPath, hooksContent);
|
|
412
|
-
console.log(` ${existingUserHooks ? "Updated" : "Created"} ${userHooksPath} (user-level)`);
|
|
413
|
-
changed = true;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
const hooksPath = join(clientDir, "hooks.json");
|
|
417
|
-
const existingHooks = existsSync(hooksPath) ? readFileSync(hooksPath, "utf-8") : "";
|
|
418
|
-
if (hooksContent !== existingHooks) {
|
|
419
|
-
writeFileSync(hooksPath, hooksContent);
|
|
420
|
-
console.log(` ${existingHooks ? "Updated" : "Created"} ${hooksPath}`);
|
|
421
|
-
changed = true;
|
|
422
|
-
}
|
|
423
|
-
if (wrappedMcpConfig) {
|
|
424
|
-
const cursorMcpConfig = { mcpServers: {} };
|
|
425
|
-
for (const [name, server] of Object.entries(wrappedMcpConfig.mcpServers)) {
|
|
426
|
-
const args = [...server.args ?? []];
|
|
427
|
-
const agentIdx = args.indexOf("--agent-name");
|
|
428
|
-
if (agentIdx >= 0 && agentIdx + 1 < args.length) {
|
|
429
|
-
args[agentIdx + 1] = "cursor";
|
|
430
|
-
} else {
|
|
431
|
-
const sepIdx = args.indexOf("--");
|
|
432
|
-
if (sepIdx >= 0) {
|
|
433
|
-
args.splice(sepIdx, 0, "--agent-name", "cursor");
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
cursorMcpConfig.mcpServers[name] = { ...server, args };
|
|
437
|
-
}
|
|
438
|
-
const mcpPath = join(clientDir, "mcp.json");
|
|
439
|
-
const mcpStr = JSON.stringify(cursorMcpConfig, null, 2) + "\n";
|
|
440
|
-
const existingMcp = existsSync(mcpPath) ? readFileSync(mcpPath, "utf-8") : "";
|
|
441
|
-
if (mcpStr !== existingMcp) {
|
|
442
|
-
writeFileSync(mcpPath, mcpStr);
|
|
443
|
-
console.log(` ${existingMcp ? "Updated" : "Created"} ${mcpPath}`);
|
|
444
|
-
changed = true;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
const staleSettings = join(clientDir, "settings.json");
|
|
448
|
-
if (existsSync(staleSettings)) {
|
|
449
|
-
try {
|
|
450
|
-
const content = JSON.parse(readFileSync(staleSettings, "utf-8"));
|
|
451
|
-
if (content.hooks?.PreToolUse || content.hooks?.PostToolUse) {
|
|
452
|
-
writeFileSync(staleSettings, JSON.stringify({}, null, 2) + "\n");
|
|
453
|
-
console.log(` Cleaned stale ${staleSettings} (had wrong hook format)`);
|
|
454
|
-
changed = true;
|
|
455
|
-
}
|
|
456
|
-
} catch {
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
return changed ? "installed" : "skipped";
|
|
460
|
-
}
|
|
461
357
|
function installGeminiConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcpConfig) {
|
|
462
358
|
const settingsPath = join(clientDir, "settings.json");
|
|
463
359
|
let existing = {};
|
|
@@ -551,11 +447,8 @@ SOLONGATE_API_KEY=sg_live_your_key_here
|
|
|
551
447
|
".mcp.json",
|
|
552
448
|
".solongate/**",
|
|
553
449
|
".claude/**",
|
|
554
|
-
".cursor/**",
|
|
555
450
|
".gemini/**",
|
|
556
|
-
".
|
|
557
|
-
".openclaw/**",
|
|
558
|
-
".perplexity/**"
|
|
451
|
+
".openclaw/**"
|
|
559
452
|
];
|
|
560
453
|
if (existsSync(gitignorePath)) {
|
|
561
454
|
let gitignore = readFileSync(gitignorePath, "utf-8");
|
|
@@ -792,8 +685,7 @@ async function main() {
|
|
|
792
685
|
console.log(" \u2502 \u2502");
|
|
793
686
|
console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
|
|
794
687
|
console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
|
|
795
|
-
console.log(" \u2502 Claude
|
|
796
|
-
console.log(" \u2502 OpenClaw, Perplexity \u2502");
|
|
688
|
+
console.log(" \u2502 Claude Code, Gemini, OpenClaw \u2502");
|
|
797
689
|
console.log(" \u2502 API key \u2192 Set in .env \u2502");
|
|
798
690
|
console.log(" \u2502 \u2502");
|
|
799
691
|
console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
|
package/dist/lib.js
CHANGED
|
@@ -4255,12 +4255,9 @@ var SolonGateProxy = class {
|
|
|
4255
4255
|
/** Normalize well-known MCP client names to display-friendly agent identities */
|
|
4256
4256
|
normalizeAgentName(raw) {
|
|
4257
4257
|
const lower = raw.toLowerCase();
|
|
4258
|
-
if (lower.includes("cursor")) return { id: "cursor", name: "Cursor" };
|
|
4259
4258
|
if (lower.includes("claude-code") || lower === "claude code") return { id: "claude-code", name: "Claude Code" };
|
|
4260
4259
|
if (lower.includes("claude")) return { id: "claude-desktop", name: "Claude Desktop" };
|
|
4261
4260
|
if (lower.includes("gemini")) return { id: "gemini-cli", name: "Gemini CLI" };
|
|
4262
|
-
if (lower.includes("antigravity")) return { id: "antigravity", name: "Antigravity" };
|
|
4263
|
-
if (lower.includes("perplexity")) return { id: "perplexity", name: "Perplexity" };
|
|
4264
4261
|
return { id: raw.toLowerCase().replace(/\s+/g, "-"), name: raw };
|
|
4265
4262
|
}
|
|
4266
4263
|
/** Extract sub-agent identity from MCP _meta field */
|
|
@@ -4903,7 +4900,7 @@ ${msg.content.text}`;
|
|
|
4903
4900
|
/**
|
|
4904
4901
|
* Start serving downstream.
|
|
4905
4902
|
* If --port is set, serves via StreamableHTTP on that port.
|
|
4906
|
-
* Otherwise, serves on stdio (default for Claude Code /
|
|
4903
|
+
* Otherwise, serves on stdio (default for Claude Code / etc).
|
|
4907
4904
|
*/
|
|
4908
4905
|
async serve() {
|
|
4909
4906
|
if (!this.server) throw new Error("Server not created");
|
package/hooks/audit.mjs
CHANGED
|
@@ -26,7 +26,7 @@ const API_KEY = process.env.SOLONGATE_API_KEY || dotenv.SOLONGATE_API_KEY || '';
|
|
|
26
26
|
const API_URL = process.env.SOLONGATE_API_URL || dotenv.SOLONGATE_API_URL || 'https://api.solongate.com';
|
|
27
27
|
|
|
28
28
|
// Agent identity from CLI args: node audit.mjs <agent_id> <agent_name>
|
|
29
|
-
// Can be overridden at runtime when stdin contains
|
|
29
|
+
// Can be overridden at runtime when stdin contains gemini_version
|
|
30
30
|
let AGENT_ID = process.argv[2] || 'claude-code';
|
|
31
31
|
let AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
32
32
|
|
|
@@ -40,48 +40,19 @@ process.stdin.on('end', async () => {
|
|
|
40
40
|
|
|
41
41
|
// Debug: append raw stdin to file for agent detection troubleshooting
|
|
42
42
|
try {
|
|
43
|
-
const debugLine = JSON.stringify({ ts: new Date().toISOString(), argv: process.argv.slice(2),
|
|
43
|
+
const debugLine = JSON.stringify({ ts: new Date().toISOString(), argv: process.argv.slice(2), tool_name: data.tool_name || data.toolName, agent_id: AGENT_ID }) + '\n';
|
|
44
44
|
const { appendFileSync: afs } = await import('node:fs');
|
|
45
45
|
afs(resolve('.solongate', '.debug-audit-log'), debugLine);
|
|
46
46
|
} catch {}
|
|
47
47
|
|
|
48
48
|
// Auto-detect agent from stdin data (overrides CLI args if detected)
|
|
49
|
-
if (data.
|
|
50
|
-
AGENT_ID = 'cursor';
|
|
51
|
-
AGENT_NAME = 'Cursor';
|
|
52
|
-
} else if (data.gemini_version) {
|
|
49
|
+
if (data.gemini_version) {
|
|
53
50
|
AGENT_ID = 'gemini-cli';
|
|
54
51
|
AGENT_NAME = 'Gemini CLI';
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
const hookEvent = data.hook_event_name || '';
|
|
58
|
-
|
|
59
|
-
// Map Cursor-specific hook events to standard tool_name/tool_input
|
|
60
54
|
let toolName = data.tool_name || data.toolName || '';
|
|
61
55
|
let toolInput = data.tool_input || data.toolInput || data.params || {};
|
|
62
|
-
|
|
63
|
-
if (!toolName && hookEvent) {
|
|
64
|
-
switch (hookEvent) {
|
|
65
|
-
case 'afterShellExecution':
|
|
66
|
-
toolName = 'Shell';
|
|
67
|
-
toolInput = { command: data.command || '' };
|
|
68
|
-
break;
|
|
69
|
-
case 'afterFileEdit':
|
|
70
|
-
toolName = 'Edit';
|
|
71
|
-
toolInput = { file_path: data.file_path || '' };
|
|
72
|
-
break;
|
|
73
|
-
case 'afterMCPExecution':
|
|
74
|
-
toolName = data.tool_name || data.toolName || `mcp:${data.server_name || 'unknown'}`;
|
|
75
|
-
toolInput = data.arguments || {};
|
|
76
|
-
break;
|
|
77
|
-
case 'postToolUse':
|
|
78
|
-
case 'postToolUseFailure':
|
|
79
|
-
toolName = data.tool_name || data.toolName || 'unknown';
|
|
80
|
-
break;
|
|
81
|
-
default:
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
56
|
if (!toolName) toolName = 'unknown';
|
|
86
57
|
|
|
87
58
|
if (toolName === 'Bash' && JSON.stringify(toolInput).includes('audit-logs')) {
|
|
@@ -101,7 +72,6 @@ process.stdin.on('end', async () => {
|
|
|
101
72
|
}
|
|
102
73
|
} catch {}
|
|
103
74
|
|
|
104
|
-
// Cursor uses tool_output, Claude uses tool_response
|
|
105
75
|
const toolResponse = data.tool_response || data.toolResponse || {};
|
|
106
76
|
const toolOutput = data.tool_output || data.toolOutput || '';
|
|
107
77
|
const resultJson = data.result_json ? (typeof data.result_json === 'string' ? data.result_json : JSON.stringify(data.result_json)) : '';
|
package/hooks/guard.mjs
CHANGED
|
@@ -41,60 +41,31 @@ const API_KEY = process.env.SOLONGATE_API_KEY || dotenv.SOLONGATE_API_KEY || '';
|
|
|
41
41
|
const API_URL = process.env.SOLONGATE_API_URL || dotenv.SOLONGATE_API_URL || 'https://api.solongate.com';
|
|
42
42
|
|
|
43
43
|
// Agent identity from CLI args: node guard.mjs <agent_id> <agent_name>
|
|
44
|
-
// Can be overridden at runtime when stdin contains
|
|
44
|
+
// Can be overridden at runtime when stdin contains gemini_version
|
|
45
45
|
let AGENT_ID = process.argv[2] || 'claude-code';
|
|
46
46
|
let AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
47
47
|
|
|
48
48
|
// ── Per-tool block/allow output ──
|
|
49
|
-
// Response format depends on
|
|
49
|
+
// Response format depends on the agent:
|
|
50
50
|
// Claude Code: exit 2 + stderr = BLOCK, exit 0 = ALLOW
|
|
51
|
-
// Cursor preToolUse: {"permission": "deny/allow", "user_message": "..."}
|
|
52
|
-
// Cursor before*: {"continue": false/true, "userMessage": "..."}
|
|
53
51
|
// Gemini CLI: {"decision": "deny/allow", "reason": "..."}
|
|
54
|
-
let HOOK_EVENT = ''; // set from stdin hook_event_name
|
|
55
|
-
const CURSOR_BEFORE_EVENTS = new Set([
|
|
56
|
-
'beforeShellExecution', 'beforeReadFile', 'beforeMCPExecution',
|
|
57
|
-
]);
|
|
58
52
|
|
|
59
53
|
function blockTool(reason) {
|
|
60
|
-
if (AGENT_ID === '
|
|
61
|
-
if (CURSOR_BEFORE_EVENTS.has(HOOK_EVENT)) {
|
|
62
|
-
// Cursor before* events use continue: false
|
|
63
|
-
process.stdout.write(JSON.stringify({
|
|
64
|
-
continue: false,
|
|
65
|
-
userMessage: `[SolonGate] ${reason}`,
|
|
66
|
-
agentMessage: `BLOCKED by SolonGate security policy: ${reason}`,
|
|
67
|
-
}));
|
|
68
|
-
} else {
|
|
69
|
-
// Cursor preToolUse uses permission: deny
|
|
70
|
-
process.stdout.write(JSON.stringify({
|
|
71
|
-
permission: 'deny',
|
|
72
|
-
user_message: `[SolonGate] ${reason}`,
|
|
73
|
-
agent_message: `BLOCKED by SolonGate security policy: ${reason}`,
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
process.exit(0);
|
|
77
|
-
} else if (AGENT_ID === 'gemini-cli') {
|
|
54
|
+
if (AGENT_ID === 'gemini-cli') {
|
|
78
55
|
process.stdout.write(JSON.stringify({
|
|
79
56
|
decision: 'deny',
|
|
80
57
|
reason: `[SolonGate] ${reason}`,
|
|
81
58
|
}));
|
|
82
59
|
process.exit(0);
|
|
83
60
|
} else {
|
|
84
|
-
// Claude Code
|
|
61
|
+
// Claude Code — exit code 2
|
|
85
62
|
process.stderr.write(reason);
|
|
86
63
|
process.exit(2);
|
|
87
64
|
}
|
|
88
65
|
}
|
|
89
66
|
|
|
90
67
|
function allowTool() {
|
|
91
|
-
if (AGENT_ID === '
|
|
92
|
-
if (CURSOR_BEFORE_EVENTS.has(HOOK_EVENT)) {
|
|
93
|
-
process.stdout.write(JSON.stringify({ continue: true }));
|
|
94
|
-
} else {
|
|
95
|
-
process.stdout.write(JSON.stringify({ permission: 'allow' }));
|
|
96
|
-
}
|
|
97
|
-
} else if (AGENT_ID === 'gemini-cli') {
|
|
68
|
+
if (AGENT_ID === 'gemini-cli') {
|
|
98
69
|
process.stdout.write(JSON.stringify({ decision: 'allow' }));
|
|
99
70
|
}
|
|
100
71
|
process.exit(0);
|
|
@@ -396,62 +367,22 @@ process.stdin.on('end', async () => {
|
|
|
396
367
|
const raw = JSON.parse(input);
|
|
397
368
|
|
|
398
369
|
// Auto-detect agent from stdin data (overrides CLI args if detected)
|
|
399
|
-
if (raw.
|
|
400
|
-
AGENT_ID = 'cursor';
|
|
401
|
-
AGENT_NAME = 'Cursor';
|
|
402
|
-
} else if (raw.gemini_version) {
|
|
370
|
+
if (raw.gemini_version) {
|
|
403
371
|
AGENT_ID = 'gemini-cli';
|
|
404
372
|
AGENT_NAME = 'Gemini CLI';
|
|
405
373
|
}
|
|
406
374
|
|
|
407
|
-
// Track hook event name for response format selection
|
|
408
|
-
HOOK_EVENT = raw.hook_event_name || '';
|
|
409
|
-
|
|
410
375
|
// Debug: append guard invocation to debug log
|
|
411
376
|
try {
|
|
412
377
|
const { appendFileSync: afs, mkdirSync: mds } = await import('node:fs');
|
|
413
378
|
mds(resolve('.solongate'), { recursive: true });
|
|
414
|
-
const debugLine = JSON.stringify({ ts: new Date().toISOString(), hook: 'guard', argv: process.argv.slice(2),
|
|
379
|
+
const debugLine = JSON.stringify({ ts: new Date().toISOString(), hook: 'guard', argv: process.argv.slice(2), tool_name: raw.tool_name || raw.toolName || raw.command, agent_id: AGENT_ID }) + '\n';
|
|
415
380
|
afs(resolve('.solongate', '.debug-guard-log'), debugLine);
|
|
416
381
|
} catch {}
|
|
417
382
|
|
|
418
|
-
// Map Cursor-specific hook events to standard tool_name/tool_input format
|
|
419
|
-
// beforeShellExecution: {command, cwd} → tool_name=Shell, tool_input={command}
|
|
420
|
-
// beforeReadFile: {file_path} → tool_name=Read, tool_input={file_path}
|
|
421
|
-
// afterFileEdit: {file_path, new_content} → tool_name=Edit, tool_input={file_path}
|
|
422
|
-
// beforeMCPExecution: {server_name, tool_name, arguments} → tool_name=<mcp_tool>, tool_input=arguments
|
|
423
383
|
let mappedToolName = raw.tool_name || raw.toolName || '';
|
|
424
384
|
let mappedToolInput = raw.tool_input || raw.toolInput || raw.params || {};
|
|
425
385
|
|
|
426
|
-
if (!mappedToolName && HOOK_EVENT) {
|
|
427
|
-
switch (HOOK_EVENT) {
|
|
428
|
-
case 'beforeShellExecution':
|
|
429
|
-
mappedToolName = 'Shell';
|
|
430
|
-
mappedToolInput = { command: raw.command || '', cwd: raw.cwd || '' };
|
|
431
|
-
break;
|
|
432
|
-
case 'afterShellExecution':
|
|
433
|
-
mappedToolName = 'Shell';
|
|
434
|
-
mappedToolInput = { command: raw.command || '', cwd: raw.cwd || '' };
|
|
435
|
-
break;
|
|
436
|
-
case 'beforeReadFile':
|
|
437
|
-
mappedToolName = 'Read';
|
|
438
|
-
mappedToolInput = { file_path: raw.file_path || '' };
|
|
439
|
-
break;
|
|
440
|
-
case 'afterFileEdit':
|
|
441
|
-
mappedToolName = 'Edit';
|
|
442
|
-
mappedToolInput = { file_path: raw.file_path || '', new_content: raw.new_content || '' };
|
|
443
|
-
break;
|
|
444
|
-
case 'beforeMCPExecution':
|
|
445
|
-
mappedToolName = raw.tool_name || raw.toolName || `mcp:${raw.server_name || 'unknown'}`;
|
|
446
|
-
mappedToolInput = raw.arguments || raw.tool_input || {};
|
|
447
|
-
break;
|
|
448
|
-
case 'afterMCPExecution':
|
|
449
|
-
mappedToolName = raw.tool_name || raw.toolName || `mcp:${raw.server_name || 'unknown'}`;
|
|
450
|
-
mappedToolInput = raw.arguments || raw.tool_input || {};
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
386
|
// Normalize field names across tools
|
|
456
387
|
const data = {
|
|
457
388
|
...raw,
|
|
@@ -467,7 +398,7 @@ process.stdin.on('end', async () => {
|
|
|
467
398
|
// Hardcoded, no bypass possible — runs before policy/PI config
|
|
468
399
|
// Fully protected: block ALL access (read, write, delete, move)
|
|
469
400
|
const protectedPaths = [
|
|
470
|
-
'.solongate', '.claude', '.
|
|
401
|
+
'.solongate', '.claude', '.gemini', '.openclaw',
|
|
471
402
|
'policy.json', '.mcp.json',
|
|
472
403
|
];
|
|
473
404
|
// Write-protected: block write/delete/modify, allow read (cat, grep, head, etc.)
|
package/hooks/stop.mjs
CHANGED
|
@@ -27,7 +27,7 @@ const API_KEY = process.env.SOLONGATE_API_KEY || dotenv.SOLONGATE_API_KEY || '';
|
|
|
27
27
|
const API_URL = process.env.SOLONGATE_API_URL || dotenv.SOLONGATE_API_URL || 'https://api.solongate.com';
|
|
28
28
|
|
|
29
29
|
// Agent identity from CLI args: node stop.mjs <agent_id> <agent_name>
|
|
30
|
-
// Can be overridden at runtime when stdin contains
|
|
30
|
+
// Can be overridden at runtime when stdin contains gemini_version
|
|
31
31
|
let AGENT_ID = process.argv[2] || 'claude-code';
|
|
32
32
|
let AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
33
33
|
|
|
@@ -46,8 +46,7 @@ process.stdin.on('end', async () => {
|
|
|
46
46
|
// Auto-detect agent from stdin data
|
|
47
47
|
try {
|
|
48
48
|
const raw = JSON.parse(input);
|
|
49
|
-
if (raw.
|
|
50
|
-
else if (raw.gemini_version) { AGENT_ID = 'gemini-cli'; AGENT_NAME = 'Gemini CLI'; }
|
|
49
|
+
if (raw.gemini_version) { AGENT_ID = 'gemini-cli'; AGENT_NAME = 'Gemini CLI'; }
|
|
51
50
|
} catch {}
|
|
52
51
|
|
|
53
52
|
// Check if tool calls were made in this turn
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "AI tool security proxy — protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|