@solongate/proxy 0.40.0 → 0.42.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 +2 -4
- package/dist/index.js +25 -64
- package/dist/init.js +5 -49
- package/dist/lib.js +18 -11
- package/package.json +1 -1
package/dist/create.js
CHANGED
|
@@ -213,10 +213,8 @@ 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('
|
|
217
|
-
console.log('
|
|
218
|
-
console.log(' Cline VS Code extension, add server in settings');
|
|
219
|
-
console.log(' Zed Add to settings.json under mcp_servers');
|
|
216
|
+
console.log(' Gemini CLI Open this folder, .mcp.json is auto-detected');
|
|
217
|
+
console.log(' OpenClaw Uses openclaw.plugin.json config');
|
|
220
218
|
console.log('');
|
|
221
219
|
console.log('Press Ctrl+C to stop.');
|
|
222
220
|
`
|
package/dist/index.js
CHANGED
|
@@ -588,9 +588,6 @@ function parseInitArgs(argv) {
|
|
|
588
588
|
case "--gemini":
|
|
589
589
|
options.tools.push("gemini");
|
|
590
590
|
break;
|
|
591
|
-
case "--openclaw":
|
|
592
|
-
options.tools.push("openclaw");
|
|
593
|
-
break;
|
|
594
591
|
case "--help":
|
|
595
592
|
case "-h":
|
|
596
593
|
printHelp();
|
|
@@ -616,11 +613,10 @@ OPTIONS
|
|
|
616
613
|
AI TOOL HOOKS (default: all)
|
|
617
614
|
--claude-code Install hooks for Claude Code
|
|
618
615
|
--gemini Install hooks for Gemini CLI
|
|
619
|
-
--openclaw Install hooks for OpenClaw
|
|
620
616
|
|
|
621
617
|
EXAMPLES
|
|
622
618
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
623
|
-
npx @solongate/proxy init --all --claude-code
|
|
619
|
+
npx @solongate/proxy init --all --claude-code # Only Claude Code hooks
|
|
624
620
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
625
621
|
`;
|
|
626
622
|
console.log(help);
|
|
@@ -629,7 +625,7 @@ function readHookScript(filename) {
|
|
|
629
625
|
return readFileSync4(join2(HOOKS_DIR, filename), "utf-8");
|
|
630
626
|
}
|
|
631
627
|
function unlockProtectedDirs() {
|
|
632
|
-
const dirs = [".solongate", ".claude", ".gemini"
|
|
628
|
+
const dirs = [".solongate", ".claude", ".gemini"];
|
|
633
629
|
for (const dir of dirs) {
|
|
634
630
|
const fullDir = resolve3(dir);
|
|
635
631
|
if (!existsSync4(fullDir)) continue;
|
|
@@ -707,8 +703,7 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
707
703
|
}
|
|
708
704
|
const allClients = [
|
|
709
705
|
{ name: "Claude Code", dir: ".claude", key: "claude-code", agentId: "claude-code", agentName: "Claude Code" },
|
|
710
|
-
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" }
|
|
711
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" }
|
|
706
|
+
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" }
|
|
712
707
|
];
|
|
713
708
|
const clients = selectedTools.length > 0 ? allClients.filter((c3) => selectedTools.includes(c3.key)) : allClients;
|
|
714
709
|
const activatedNames = [];
|
|
@@ -723,10 +718,6 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
723
718
|
const result = installGeminiConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
724
719
|
if (result === "skipped") skippedNames.push(client.name);
|
|
725
720
|
else activatedNames.push(client.name);
|
|
726
|
-
} else if (client.key === "openclaw") {
|
|
727
|
-
const result = installOpenClawConfig(clientDir);
|
|
728
|
-
if (result === "skipped") skippedNames.push(client.name);
|
|
729
|
-
else activatedNames.push(client.name);
|
|
730
721
|
} else {
|
|
731
722
|
const result = installStandardHookConfig(clientDir, client.name, guardCmd, auditCmd, stopCmd);
|
|
732
723
|
if (result === "skipped") skippedNames.push(client.name);
|
|
@@ -809,40 +800,6 @@ function installGeminiConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcp
|
|
|
809
800
|
console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
|
|
810
801
|
return "installed";
|
|
811
802
|
}
|
|
812
|
-
function installOpenClawConfig(_clientDir) {
|
|
813
|
-
const yamlPath = resolve3("openclaw.yaml");
|
|
814
|
-
const pluginLine = "@solongate/openclaw-plugin";
|
|
815
|
-
if (existsSync4(yamlPath)) {
|
|
816
|
-
const content = readFileSync4(yamlPath, "utf-8");
|
|
817
|
-
if (content.includes(pluginLine)) {
|
|
818
|
-
return "skipped";
|
|
819
|
-
}
|
|
820
|
-
if (content.includes("plugins:")) {
|
|
821
|
-
const updated = content.replace(
|
|
822
|
-
/^(plugins:\s*\n)/m,
|
|
823
|
-
`$1 - "${pluginLine}"
|
|
824
|
-
`
|
|
825
|
-
);
|
|
826
|
-
writeFileSync2(yamlPath, updated);
|
|
827
|
-
} else {
|
|
828
|
-
const separator = content.endsWith("\n") ? "" : "\n";
|
|
829
|
-
writeFileSync2(yamlPath, content + `${separator}
|
|
830
|
-
plugins:
|
|
831
|
-
- "${pluginLine}"
|
|
832
|
-
`);
|
|
833
|
-
}
|
|
834
|
-
} else {
|
|
835
|
-
writeFileSync2(yamlPath, `# OpenClaw configuration
|
|
836
|
-
# SolonGate security plugin \u2014 manage policies at https://dashboard.solongate.com
|
|
837
|
-
|
|
838
|
-
plugins:
|
|
839
|
-
- "${pluginLine}"
|
|
840
|
-
`);
|
|
841
|
-
}
|
|
842
|
-
console.log(` Updated openclaw.yaml with SolonGate plugin`);
|
|
843
|
-
console.log(` \u2192 Run: npm install ${pluginLine}`);
|
|
844
|
-
return "installed";
|
|
845
|
-
}
|
|
846
803
|
function ensureEnvFile() {
|
|
847
804
|
let envChanged = false;
|
|
848
805
|
let gitignoreChanged = false;
|
|
@@ -883,8 +840,7 @@ SOLONGATE_API_KEY=sg_live_your_key_here
|
|
|
883
840
|
".mcp.json",
|
|
884
841
|
".solongate/**",
|
|
885
842
|
".claude/**",
|
|
886
|
-
".gemini/**"
|
|
887
|
-
".openclaw/**"
|
|
843
|
+
".gemini/**"
|
|
888
844
|
];
|
|
889
845
|
if (existsSync4(gitignorePath)) {
|
|
890
846
|
let gitignore = readFileSync4(gitignorePath, "utf-8");
|
|
@@ -1121,7 +1077,7 @@ async function main() {
|
|
|
1121
1077
|
console.log(" \u2502 \u2502");
|
|
1122
1078
|
console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
|
|
1123
1079
|
console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
|
|
1124
|
-
console.log(" \u2502 Claude Code, Gemini
|
|
1080
|
+
console.log(" \u2502 Claude Code, Gemini CLI \u2502");
|
|
1125
1081
|
console.log(" \u2502 API key \u2192 Set in .env \u2502");
|
|
1126
1082
|
console.log(" \u2502 \u2502");
|
|
1127
1083
|
console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
|
|
@@ -1662,10 +1618,8 @@ console.log('MCP servers communicate over stdin/stdout \u2014 not HTTP.');
|
|
|
1662
1618
|
console.log('You need an MCP client to connect:');
|
|
1663
1619
|
console.log('');
|
|
1664
1620
|
console.log(' Claude Code Open this folder, .mcp.json is auto-detected');
|
|
1665
|
-
console.log('
|
|
1666
|
-
console.log('
|
|
1667
|
-
console.log(' Cline VS Code extension, add server in settings');
|
|
1668
|
-
console.log(' Zed Add to settings.json under mcp_servers');
|
|
1621
|
+
console.log(' Gemini CLI Open this folder, .mcp.json is auto-detected');
|
|
1622
|
+
console.log(' OpenClaw Uses openclaw.plugin.json config');
|
|
1669
1623
|
console.log('');
|
|
1670
1624
|
console.log('Press Ctrl+C to stop.');
|
|
1671
1625
|
`
|
|
@@ -2733,9 +2687,23 @@ var TrustLevel = {
|
|
|
2733
2687
|
var Permission = {
|
|
2734
2688
|
READ: "READ",
|
|
2735
2689
|
WRITE: "WRITE",
|
|
2736
|
-
EXECUTE: "EXECUTE"
|
|
2690
|
+
EXECUTE: "EXECUTE",
|
|
2691
|
+
NETWORK: "NETWORK"
|
|
2737
2692
|
};
|
|
2738
|
-
var PermissionSchema = z.enum(["READ", "WRITE", "EXECUTE"]);
|
|
2693
|
+
var PermissionSchema = z.enum(["READ", "WRITE", "EXECUTE", "NETWORK"]);
|
|
2694
|
+
function guessPermission(toolName) {
|
|
2695
|
+
const name = toolName.toLowerCase();
|
|
2696
|
+
if (name.includes("exec") || name.includes("shell") || name.includes("run") || name.includes("eval")) {
|
|
2697
|
+
return Permission.EXECUTE;
|
|
2698
|
+
}
|
|
2699
|
+
if (name.includes("fetch") || name.includes("http") || name.includes("request") || name.includes("curl") || name.includes("network") || name.includes("download") || name.includes("upload")) {
|
|
2700
|
+
return Permission.NETWORK;
|
|
2701
|
+
}
|
|
2702
|
+
if (name.includes("write") || name.includes("create") || name.includes("delete") || name.includes("update") || name.includes("set") || name.includes("edit") || name.includes("remove") || name.includes("insert")) {
|
|
2703
|
+
return Permission.WRITE;
|
|
2704
|
+
}
|
|
2705
|
+
return Permission.READ;
|
|
2706
|
+
}
|
|
2739
2707
|
var NO_PERMISSIONS = Object.freeze(
|
|
2740
2708
|
/* @__PURE__ */ new Set()
|
|
2741
2709
|
);
|
|
@@ -4617,7 +4585,7 @@ async function interceptToolCall(params, upstreamCall, options) {
|
|
|
4617
4585
|
toolName: params.name,
|
|
4618
4586
|
serverName: "default",
|
|
4619
4587
|
arguments: params.arguments ?? {},
|
|
4620
|
-
requiredPermission:
|
|
4588
|
+
requiredPermission: guessPermission(params.name),
|
|
4621
4589
|
timestamp
|
|
4622
4590
|
};
|
|
4623
4591
|
if (options.rateLimiter) {
|
|
@@ -6527,14 +6495,7 @@ ${msg.content.text}`;
|
|
|
6527
6495
|
* Guess tool permissions from tool name.
|
|
6528
6496
|
*/
|
|
6529
6497
|
guessPermissions(toolName) {
|
|
6530
|
-
|
|
6531
|
-
if (name.includes("exec") || name.includes("shell") || name.includes("run") || name.includes("eval")) {
|
|
6532
|
-
return ["EXECUTE"];
|
|
6533
|
-
}
|
|
6534
|
-
if (name.includes("write") || name.includes("create") || name.includes("delete") || name.includes("update") || name.includes("set")) {
|
|
6535
|
-
return ["WRITE"];
|
|
6536
|
-
}
|
|
6537
|
-
return ["READ"];
|
|
6498
|
+
return [guessPermission(toolName)];
|
|
6538
6499
|
}
|
|
6539
6500
|
/**
|
|
6540
6501
|
* Register the upstream MCP server to the SolonGate Cloud API.
|
package/dist/init.js
CHANGED
|
@@ -169,9 +169,6 @@ function parseInitArgs(argv) {
|
|
|
169
169
|
case "--gemini":
|
|
170
170
|
options.tools.push("gemini");
|
|
171
171
|
break;
|
|
172
|
-
case "--openclaw":
|
|
173
|
-
options.tools.push("openclaw");
|
|
174
|
-
break;
|
|
175
172
|
case "--help":
|
|
176
173
|
case "-h":
|
|
177
174
|
printHelp();
|
|
@@ -197,11 +194,10 @@ OPTIONS
|
|
|
197
194
|
AI TOOL HOOKS (default: all)
|
|
198
195
|
--claude-code Install hooks for Claude Code
|
|
199
196
|
--gemini Install hooks for Gemini CLI
|
|
200
|
-
--openclaw Install hooks for OpenClaw
|
|
201
197
|
|
|
202
198
|
EXAMPLES
|
|
203
199
|
npx @solongate/proxy init --all # Protect everything, all tools
|
|
204
|
-
npx @solongate/proxy init --all --claude-code
|
|
200
|
+
npx @solongate/proxy init --all --claude-code # Only Claude Code hooks
|
|
205
201
|
npx @solongate/proxy init --all --policy policy.json # With custom policy
|
|
206
202
|
`;
|
|
207
203
|
console.log(help);
|
|
@@ -212,7 +208,7 @@ function readHookScript(filename) {
|
|
|
212
208
|
return readFileSync(join(HOOKS_DIR, filename), "utf-8");
|
|
213
209
|
}
|
|
214
210
|
function unlockProtectedDirs() {
|
|
215
|
-
const dirs = [".solongate", ".claude", ".gemini"
|
|
211
|
+
const dirs = [".solongate", ".claude", ".gemini"];
|
|
216
212
|
for (const dir of dirs) {
|
|
217
213
|
const fullDir = resolve(dir);
|
|
218
214
|
if (!existsSync(fullDir)) continue;
|
|
@@ -290,8 +286,7 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
290
286
|
}
|
|
291
287
|
const allClients = [
|
|
292
288
|
{ name: "Claude Code", dir: ".claude", key: "claude-code", agentId: "claude-code", agentName: "Claude Code" },
|
|
293
|
-
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" }
|
|
294
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" }
|
|
289
|
+
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" }
|
|
295
290
|
];
|
|
296
291
|
const clients = selectedTools.length > 0 ? allClients.filter((c2) => selectedTools.includes(c2.key)) : allClients;
|
|
297
292
|
const activatedNames = [];
|
|
@@ -306,10 +301,6 @@ function installHooks(selectedTools = [], wrappedMcpConfig) {
|
|
|
306
301
|
const result = installGeminiConfig(clientDir, guardCmd, auditCmd, stopCmd, wrappedMcpConfig);
|
|
307
302
|
if (result === "skipped") skippedNames.push(client.name);
|
|
308
303
|
else activatedNames.push(client.name);
|
|
309
|
-
} else if (client.key === "openclaw") {
|
|
310
|
-
const result = installOpenClawConfig(clientDir);
|
|
311
|
-
if (result === "skipped") skippedNames.push(client.name);
|
|
312
|
-
else activatedNames.push(client.name);
|
|
313
304
|
} else {
|
|
314
305
|
const result = installStandardHookConfig(clientDir, client.name, guardCmd, auditCmd, stopCmd);
|
|
315
306
|
if (result === "skipped") skippedNames.push(client.name);
|
|
@@ -392,40 +383,6 @@ function installGeminiConfig(clientDir, guardCmd, auditCmd, _stopCmd, wrappedMcp
|
|
|
392
383
|
console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
|
|
393
384
|
return "installed";
|
|
394
385
|
}
|
|
395
|
-
function installOpenClawConfig(_clientDir) {
|
|
396
|
-
const yamlPath = resolve("openclaw.yaml");
|
|
397
|
-
const pluginLine = "@solongate/openclaw-plugin";
|
|
398
|
-
if (existsSync(yamlPath)) {
|
|
399
|
-
const content = readFileSync(yamlPath, "utf-8");
|
|
400
|
-
if (content.includes(pluginLine)) {
|
|
401
|
-
return "skipped";
|
|
402
|
-
}
|
|
403
|
-
if (content.includes("plugins:")) {
|
|
404
|
-
const updated = content.replace(
|
|
405
|
-
/^(plugins:\s*\n)/m,
|
|
406
|
-
`$1 - "${pluginLine}"
|
|
407
|
-
`
|
|
408
|
-
);
|
|
409
|
-
writeFileSync(yamlPath, updated);
|
|
410
|
-
} else {
|
|
411
|
-
const separator = content.endsWith("\n") ? "" : "\n";
|
|
412
|
-
writeFileSync(yamlPath, content + `${separator}
|
|
413
|
-
plugins:
|
|
414
|
-
- "${pluginLine}"
|
|
415
|
-
`);
|
|
416
|
-
}
|
|
417
|
-
} else {
|
|
418
|
-
writeFileSync(yamlPath, `# OpenClaw configuration
|
|
419
|
-
# SolonGate security plugin \u2014 manage policies at https://dashboard.solongate.com
|
|
420
|
-
|
|
421
|
-
plugins:
|
|
422
|
-
- "${pluginLine}"
|
|
423
|
-
`);
|
|
424
|
-
}
|
|
425
|
-
console.log(` Updated openclaw.yaml with SolonGate plugin`);
|
|
426
|
-
console.log(` \u2192 Run: npm install ${pluginLine}`);
|
|
427
|
-
return "installed";
|
|
428
|
-
}
|
|
429
386
|
function ensureEnvFile() {
|
|
430
387
|
let envChanged = false;
|
|
431
388
|
let gitignoreChanged = false;
|
|
@@ -466,8 +423,7 @@ SOLONGATE_API_KEY=sg_live_your_key_here
|
|
|
466
423
|
".mcp.json",
|
|
467
424
|
".solongate/**",
|
|
468
425
|
".claude/**",
|
|
469
|
-
".gemini/**"
|
|
470
|
-
".openclaw/**"
|
|
426
|
+
".gemini/**"
|
|
471
427
|
];
|
|
472
428
|
if (existsSync(gitignorePath)) {
|
|
473
429
|
let gitignore = readFileSync(gitignorePath, "utf-8");
|
|
@@ -704,7 +660,7 @@ async function main() {
|
|
|
704
660
|
console.log(" \u2502 \u2502");
|
|
705
661
|
console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
|
|
706
662
|
console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
|
|
707
|
-
console.log(" \u2502 Claude Code, Gemini
|
|
663
|
+
console.log(" \u2502 Claude Code, Gemini CLI \u2502");
|
|
708
664
|
console.log(" \u2502 API key \u2192 Set in .env \u2502");
|
|
709
665
|
console.log(" \u2502 \u2502");
|
|
710
666
|
console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
|
package/dist/lib.js
CHANGED
|
@@ -634,9 +634,23 @@ var TrustLevel = {
|
|
|
634
634
|
var Permission = {
|
|
635
635
|
READ: "READ",
|
|
636
636
|
WRITE: "WRITE",
|
|
637
|
-
EXECUTE: "EXECUTE"
|
|
637
|
+
EXECUTE: "EXECUTE",
|
|
638
|
+
NETWORK: "NETWORK"
|
|
638
639
|
};
|
|
639
|
-
var PermissionSchema = z.enum(["READ", "WRITE", "EXECUTE"]);
|
|
640
|
+
var PermissionSchema = z.enum(["READ", "WRITE", "EXECUTE", "NETWORK"]);
|
|
641
|
+
function guessPermission(toolName) {
|
|
642
|
+
const name = toolName.toLowerCase();
|
|
643
|
+
if (name.includes("exec") || name.includes("shell") || name.includes("run") || name.includes("eval")) {
|
|
644
|
+
return Permission.EXECUTE;
|
|
645
|
+
}
|
|
646
|
+
if (name.includes("fetch") || name.includes("http") || name.includes("request") || name.includes("curl") || name.includes("network") || name.includes("download") || name.includes("upload")) {
|
|
647
|
+
return Permission.NETWORK;
|
|
648
|
+
}
|
|
649
|
+
if (name.includes("write") || name.includes("create") || name.includes("delete") || name.includes("update") || name.includes("set") || name.includes("edit") || name.includes("remove") || name.includes("insert")) {
|
|
650
|
+
return Permission.WRITE;
|
|
651
|
+
}
|
|
652
|
+
return Permission.READ;
|
|
653
|
+
}
|
|
640
654
|
var NO_PERMISSIONS = Object.freeze(
|
|
641
655
|
/* @__PURE__ */ new Set()
|
|
642
656
|
);
|
|
@@ -2694,7 +2708,7 @@ async function interceptToolCall(params, upstreamCall, options) {
|
|
|
2694
2708
|
toolName: params.name,
|
|
2695
2709
|
serverName: "default",
|
|
2696
2710
|
arguments: params.arguments ?? {},
|
|
2697
|
-
requiredPermission:
|
|
2711
|
+
requiredPermission: guessPermission(params.name),
|
|
2698
2712
|
timestamp
|
|
2699
2713
|
};
|
|
2700
2714
|
if (options.rateLimiter) {
|
|
@@ -4807,14 +4821,7 @@ ${msg.content.text}`;
|
|
|
4807
4821
|
* Guess tool permissions from tool name.
|
|
4808
4822
|
*/
|
|
4809
4823
|
guessPermissions(toolName) {
|
|
4810
|
-
|
|
4811
|
-
if (name.includes("exec") || name.includes("shell") || name.includes("run") || name.includes("eval")) {
|
|
4812
|
-
return ["EXECUTE"];
|
|
4813
|
-
}
|
|
4814
|
-
if (name.includes("write") || name.includes("create") || name.includes("delete") || name.includes("update") || name.includes("set")) {
|
|
4815
|
-
return ["WRITE"];
|
|
4816
|
-
}
|
|
4817
|
-
return ["READ"];
|
|
4824
|
+
return [guessPermission(toolName)];
|
|
4818
4825
|
}
|
|
4819
4826
|
/**
|
|
4820
4827
|
* Register the upstream MCP server to the SolonGate Cloud API.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.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": {
|