@solongate/proxy 0.28.5 → 0.28.7
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/index.js +49 -47
- package/dist/init.js +49 -47
- package/hooks/audit.mjs +6 -2
- package/hooks/guard.mjs +8 -4
- package/hooks/stop.mjs +6 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -681,41 +681,13 @@ function installHooks(selectedTools = []) {
|
|
|
681
681
|
const stopPath = join(hooksDir, "stop.mjs");
|
|
682
682
|
writeFileSync2(stopPath, readHookScript("stop.mjs"));
|
|
683
683
|
console.log(` Created ${stopPath}`);
|
|
684
|
-
const hookSettings = {
|
|
685
|
-
hooks: {
|
|
686
|
-
PreToolUse: [
|
|
687
|
-
{
|
|
688
|
-
matcher: "",
|
|
689
|
-
hooks: [
|
|
690
|
-
{ type: "command", command: "node .solongate/hooks/guard.mjs" }
|
|
691
|
-
]
|
|
692
|
-
}
|
|
693
|
-
],
|
|
694
|
-
PostToolUse: [
|
|
695
|
-
{
|
|
696
|
-
matcher: "",
|
|
697
|
-
hooks: [
|
|
698
|
-
{ type: "command", command: "node .solongate/hooks/audit.mjs" }
|
|
699
|
-
]
|
|
700
|
-
}
|
|
701
|
-
],
|
|
702
|
-
Stop: [
|
|
703
|
-
{
|
|
704
|
-
matcher: "",
|
|
705
|
-
hooks: [
|
|
706
|
-
{ type: "command", command: "node .solongate/hooks/stop.mjs" }
|
|
707
|
-
]
|
|
708
|
-
}
|
|
709
|
-
]
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
684
|
const allClients = [
|
|
713
|
-
{ name: "Claude Code", dir: ".claude", key: "claude" },
|
|
714
|
-
{ name: "Cursor", dir: ".cursor", key: "cursor" },
|
|
715
|
-
{ name: "Gemini CLI", dir: ".gemini", key: "gemini" },
|
|
716
|
-
{ name: "Antigravity", dir: ".antigravity", key: "antigravity" },
|
|
717
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw" },
|
|
718
|
-
{ name: "Perplexity", dir: ".perplexity", key: "perplexity" }
|
|
685
|
+
{ name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
|
|
686
|
+
{ name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
|
|
687
|
+
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" },
|
|
688
|
+
{ name: "Antigravity", dir: ".antigravity", key: "antigravity", agentId: "antigravity", agentName: "Antigravity" },
|
|
689
|
+
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" },
|
|
690
|
+
{ name: "Perplexity", dir: ".perplexity", key: "perplexity", agentId: "perplexity", agentName: "Perplexity" }
|
|
719
691
|
];
|
|
720
692
|
const clients = selectedTools.length > 0 ? allClients.filter((c3) => selectedTools.includes(c3.key)) : allClients;
|
|
721
693
|
const activatedNames = [];
|
|
@@ -723,12 +695,26 @@ function installHooks(selectedTools = []) {
|
|
|
723
695
|
const clientDir = resolve3(client.dir);
|
|
724
696
|
mkdirSync2(clientDir, { recursive: true });
|
|
725
697
|
const settingsPath = join(clientDir, "settings.json");
|
|
698
|
+
const guardCmd = `node .solongate/hooks/guard.mjs ${client.agentId} "${client.agentName}"`;
|
|
699
|
+
const auditCmd = `node .solongate/hooks/audit.mjs ${client.agentId} "${client.agentName}"`;
|
|
700
|
+
const stopCmd = `node .solongate/hooks/stop.mjs ${client.agentId} "${client.agentName}"`;
|
|
701
|
+
const hookSettings = {
|
|
702
|
+
PreToolUse: [
|
|
703
|
+
{ matcher: "", hooks: [{ type: "command", command: guardCmd }] }
|
|
704
|
+
],
|
|
705
|
+
PostToolUse: [
|
|
706
|
+
{ matcher: "", hooks: [{ type: "command", command: auditCmd }] }
|
|
707
|
+
],
|
|
708
|
+
Stop: [
|
|
709
|
+
{ matcher: "", hooks: [{ type: "command", command: stopCmd }] }
|
|
710
|
+
]
|
|
711
|
+
};
|
|
726
712
|
let existing = {};
|
|
727
713
|
try {
|
|
728
714
|
existing = JSON.parse(readFileSync4(settingsPath, "utf-8"));
|
|
729
715
|
} catch {
|
|
730
716
|
}
|
|
731
|
-
const merged = { ...existing, hooks: hookSettings
|
|
717
|
+
const merged = { ...existing, hooks: hookSettings };
|
|
732
718
|
writeFileSync2(settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
733
719
|
console.log(` Created ${settingsPath}`);
|
|
734
720
|
activatedNames.push(client.name);
|
|
@@ -757,26 +743,42 @@ GROQ_API_KEY=gsk_your_groq_key_here
|
|
|
757
743
|
console.log(` Created .env`);
|
|
758
744
|
console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
|
|
759
745
|
console.log("");
|
|
746
|
+
} else {
|
|
747
|
+
const existingEnv = readFileSync4(envPath, "utf-8");
|
|
748
|
+
if (!existingEnv.includes("SOLONGATE_API_KEY")) {
|
|
749
|
+
const separator = existingEnv.endsWith("\n") ? "" : "\n";
|
|
750
|
+
const appendContent = `${separator}
|
|
751
|
+
# SolonGate API key \u2014 get one at https://dashboard.solongate.com
|
|
752
|
+
SOLONGATE_API_KEY=sg_live_your_key_here
|
|
753
|
+
`;
|
|
754
|
+
writeFileSync2(envPath, existingEnv + appendContent);
|
|
755
|
+
console.log(` Updated .env (added SOLONGATE_API_KEY)`);
|
|
756
|
+
console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
|
|
757
|
+
console.log("");
|
|
758
|
+
}
|
|
760
759
|
}
|
|
761
760
|
const gitignorePath = resolve3(".gitignore");
|
|
761
|
+
const requiredEntries = [
|
|
762
|
+
{ pattern: ".env", lines: ".env\n.env.local" },
|
|
763
|
+
{ pattern: ".mcp.json", lines: ".mcp.json" },
|
|
764
|
+
{ pattern: ".solongate", lines: ".solongate/" }
|
|
765
|
+
];
|
|
762
766
|
if (existsSync4(gitignorePath)) {
|
|
763
767
|
let gitignore = readFileSync4(gitignorePath, "utf-8");
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
gitignore = gitignore.trimEnd() + "\n.mcp.json\n";
|
|
771
|
-
updated = true;
|
|
768
|
+
const added = [];
|
|
769
|
+
for (const entry of requiredEntries) {
|
|
770
|
+
if (!gitignore.includes(entry.pattern)) {
|
|
771
|
+
gitignore = gitignore.trimEnd() + "\n" + entry.lines + "\n";
|
|
772
|
+
added.push(entry.pattern);
|
|
773
|
+
}
|
|
772
774
|
}
|
|
773
|
-
if (
|
|
775
|
+
if (added.length > 0) {
|
|
774
776
|
writeFileSync2(gitignorePath, gitignore);
|
|
775
|
-
console.log(` Updated .gitignore (added .
|
|
777
|
+
console.log(` Updated .gitignore (added ${added.join(", ")})`);
|
|
776
778
|
}
|
|
777
779
|
} else {
|
|
778
|
-
writeFileSync2(gitignorePath, ".env\n.env.local\n.mcp.json\nnode_modules/\n");
|
|
779
|
-
console.log(` Created .gitignore (with .env
|
|
780
|
+
writeFileSync2(gitignorePath, ".env\n.env.local\n.mcp.json\n.solongate/\nnode_modules/\n");
|
|
781
|
+
console.log(` Created .gitignore (with .env, .mcp.json, .solongate/ excluded)`);
|
|
780
782
|
}
|
|
781
783
|
}
|
|
782
784
|
async function main() {
|
package/dist/init.js
CHANGED
|
@@ -264,41 +264,13 @@ function installHooks(selectedTools = []) {
|
|
|
264
264
|
const stopPath = join(hooksDir, "stop.mjs");
|
|
265
265
|
writeFileSync(stopPath, readHookScript("stop.mjs"));
|
|
266
266
|
console.log(` Created ${stopPath}`);
|
|
267
|
-
const hookSettings = {
|
|
268
|
-
hooks: {
|
|
269
|
-
PreToolUse: [
|
|
270
|
-
{
|
|
271
|
-
matcher: "",
|
|
272
|
-
hooks: [
|
|
273
|
-
{ type: "command", command: "node .solongate/hooks/guard.mjs" }
|
|
274
|
-
]
|
|
275
|
-
}
|
|
276
|
-
],
|
|
277
|
-
PostToolUse: [
|
|
278
|
-
{
|
|
279
|
-
matcher: "",
|
|
280
|
-
hooks: [
|
|
281
|
-
{ type: "command", command: "node .solongate/hooks/audit.mjs" }
|
|
282
|
-
]
|
|
283
|
-
}
|
|
284
|
-
],
|
|
285
|
-
Stop: [
|
|
286
|
-
{
|
|
287
|
-
matcher: "",
|
|
288
|
-
hooks: [
|
|
289
|
-
{ type: "command", command: "node .solongate/hooks/stop.mjs" }
|
|
290
|
-
]
|
|
291
|
-
}
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
267
|
const allClients = [
|
|
296
|
-
{ name: "Claude Code", dir: ".claude", key: "claude" },
|
|
297
|
-
{ name: "Cursor", dir: ".cursor", key: "cursor" },
|
|
298
|
-
{ name: "Gemini CLI", dir: ".gemini", key: "gemini" },
|
|
299
|
-
{ name: "Antigravity", dir: ".antigravity", key: "antigravity" },
|
|
300
|
-
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw" },
|
|
301
|
-
{ name: "Perplexity", dir: ".perplexity", key: "perplexity" }
|
|
268
|
+
{ name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
|
|
269
|
+
{ name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
|
|
270
|
+
{ name: "Gemini CLI", dir: ".gemini", key: "gemini", agentId: "gemini-cli", agentName: "Gemini CLI" },
|
|
271
|
+
{ name: "Antigravity", dir: ".antigravity", key: "antigravity", agentId: "antigravity", agentName: "Antigravity" },
|
|
272
|
+
{ name: "OpenClaw", dir: ".openclaw", key: "openclaw", agentId: "openclaw", agentName: "OpenClaw" },
|
|
273
|
+
{ name: "Perplexity", dir: ".perplexity", key: "perplexity", agentId: "perplexity", agentName: "Perplexity" }
|
|
302
274
|
];
|
|
303
275
|
const clients = selectedTools.length > 0 ? allClients.filter((c2) => selectedTools.includes(c2.key)) : allClients;
|
|
304
276
|
const activatedNames = [];
|
|
@@ -306,12 +278,26 @@ function installHooks(selectedTools = []) {
|
|
|
306
278
|
const clientDir = resolve(client.dir);
|
|
307
279
|
mkdirSync(clientDir, { recursive: true });
|
|
308
280
|
const settingsPath = join(clientDir, "settings.json");
|
|
281
|
+
const guardCmd = `node .solongate/hooks/guard.mjs ${client.agentId} "${client.agentName}"`;
|
|
282
|
+
const auditCmd = `node .solongate/hooks/audit.mjs ${client.agentId} "${client.agentName}"`;
|
|
283
|
+
const stopCmd = `node .solongate/hooks/stop.mjs ${client.agentId} "${client.agentName}"`;
|
|
284
|
+
const hookSettings = {
|
|
285
|
+
PreToolUse: [
|
|
286
|
+
{ matcher: "", hooks: [{ type: "command", command: guardCmd }] }
|
|
287
|
+
],
|
|
288
|
+
PostToolUse: [
|
|
289
|
+
{ matcher: "", hooks: [{ type: "command", command: auditCmd }] }
|
|
290
|
+
],
|
|
291
|
+
Stop: [
|
|
292
|
+
{ matcher: "", hooks: [{ type: "command", command: stopCmd }] }
|
|
293
|
+
]
|
|
294
|
+
};
|
|
309
295
|
let existing = {};
|
|
310
296
|
try {
|
|
311
297
|
existing = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
312
298
|
} catch {
|
|
313
299
|
}
|
|
314
|
-
const merged = { ...existing, hooks: hookSettings
|
|
300
|
+
const merged = { ...existing, hooks: hookSettings };
|
|
315
301
|
writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n");
|
|
316
302
|
console.log(` Created ${settingsPath}`);
|
|
317
303
|
activatedNames.push(client.name);
|
|
@@ -340,26 +326,42 @@ GROQ_API_KEY=gsk_your_groq_key_here
|
|
|
340
326
|
console.log(` Created .env`);
|
|
341
327
|
console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
|
|
342
328
|
console.log("");
|
|
329
|
+
} else {
|
|
330
|
+
const existingEnv = readFileSync(envPath, "utf-8");
|
|
331
|
+
if (!existingEnv.includes("SOLONGATE_API_KEY")) {
|
|
332
|
+
const separator = existingEnv.endsWith("\n") ? "" : "\n";
|
|
333
|
+
const appendContent = `${separator}
|
|
334
|
+
# SolonGate API key \u2014 get one at https://dashboard.solongate.com
|
|
335
|
+
SOLONGATE_API_KEY=sg_live_your_key_here
|
|
336
|
+
`;
|
|
337
|
+
writeFileSync(envPath, existingEnv + appendContent);
|
|
338
|
+
console.log(` Updated .env (added SOLONGATE_API_KEY)`);
|
|
339
|
+
console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
|
|
340
|
+
console.log("");
|
|
341
|
+
}
|
|
343
342
|
}
|
|
344
343
|
const gitignorePath = resolve(".gitignore");
|
|
344
|
+
const requiredEntries = [
|
|
345
|
+
{ pattern: ".env", lines: ".env\n.env.local" },
|
|
346
|
+
{ pattern: ".mcp.json", lines: ".mcp.json" },
|
|
347
|
+
{ pattern: ".solongate", lines: ".solongate/" }
|
|
348
|
+
];
|
|
345
349
|
if (existsSync(gitignorePath)) {
|
|
346
350
|
let gitignore = readFileSync(gitignorePath, "utf-8");
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
gitignore = gitignore.trimEnd() + "\n.mcp.json\n";
|
|
354
|
-
updated = true;
|
|
351
|
+
const added = [];
|
|
352
|
+
for (const entry of requiredEntries) {
|
|
353
|
+
if (!gitignore.includes(entry.pattern)) {
|
|
354
|
+
gitignore = gitignore.trimEnd() + "\n" + entry.lines + "\n";
|
|
355
|
+
added.push(entry.pattern);
|
|
356
|
+
}
|
|
355
357
|
}
|
|
356
|
-
if (
|
|
358
|
+
if (added.length > 0) {
|
|
357
359
|
writeFileSync(gitignorePath, gitignore);
|
|
358
|
-
console.log(` Updated .gitignore (added .
|
|
360
|
+
console.log(` Updated .gitignore (added ${added.join(", ")})`);
|
|
359
361
|
}
|
|
360
362
|
} else {
|
|
361
|
-
writeFileSync(gitignorePath, ".env\n.env.local\n.mcp.json\nnode_modules/\n");
|
|
362
|
-
console.log(` Created .gitignore (with .env
|
|
363
|
+
writeFileSync(gitignorePath, ".env\n.env.local\n.mcp.json\n.solongate/\nnode_modules/\n");
|
|
364
|
+
console.log(` Created .gitignore (with .env, .mcp.json, .solongate/ excluded)`);
|
|
363
365
|
}
|
|
364
366
|
}
|
|
365
367
|
async function main() {
|
package/hooks/audit.mjs
CHANGED
|
@@ -25,6 +25,10 @@ const dotenv = loadEnvKey(process.cwd());
|
|
|
25
25
|
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
|
+
// Agent identity from CLI args: node audit.mjs <agent_id> <agent_name>
|
|
29
|
+
const AGENT_ID = process.argv[2] || 'claude-code';
|
|
30
|
+
const AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
31
|
+
|
|
28
32
|
if (!API_KEY || !API_KEY.startsWith('sg_live_')) process.exit(0);
|
|
29
33
|
|
|
30
34
|
let input = '';
|
|
@@ -70,8 +74,8 @@ process.stdin.on('end', async () => {
|
|
|
70
74
|
reason: hasError ? 'tool returned error' : 'allowed',
|
|
71
75
|
source: 'claude-code-hook',
|
|
72
76
|
evaluationTimeMs: 0,
|
|
73
|
-
agent_id:
|
|
74
|
-
agent_name:
|
|
77
|
+
agent_id: AGENT_ID,
|
|
78
|
+
agent_name: AGENT_NAME,
|
|
75
79
|
}),
|
|
76
80
|
signal: AbortSignal.timeout(5000),
|
|
77
81
|
});
|
package/hooks/guard.mjs
CHANGED
|
@@ -40,6 +40,10 @@ const dotenv = loadEnvKey(hookCwdEarly);
|
|
|
40
40
|
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
|
+
// Agent identity from CLI args: node guard.mjs <agent_id> <agent_name>
|
|
44
|
+
const AGENT_ID = process.argv[2] || 'claude-code';
|
|
45
|
+
const AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
46
|
+
|
|
43
47
|
// Write flag file so stop.mjs knows a tool call (DENY) happened and doesn't log extra ALLOW
|
|
44
48
|
function writeDenyFlag() {
|
|
45
49
|
try {
|
|
@@ -355,7 +359,7 @@ process.stdin.on('end', async () => {
|
|
|
355
359
|
tool: data.tool_name || '', arguments: args,
|
|
356
360
|
decision: 'DENY', reason,
|
|
357
361
|
source: 'claude-code-guard',
|
|
358
|
-
agent_id:
|
|
362
|
+
agent_id: AGENT_ID, agent_name: AGENT_NAME,
|
|
359
363
|
}),
|
|
360
364
|
signal: AbortSignal.timeout(3000),
|
|
361
365
|
});
|
|
@@ -988,7 +992,7 @@ process.stdin.on('end', async () => {
|
|
|
988
992
|
decision: isLogOnly ? 'ALLOW' : 'DENY',
|
|
989
993
|
reason: msg,
|
|
990
994
|
source: 'claude-code-guard',
|
|
991
|
-
agent_id:
|
|
995
|
+
agent_id: AGENT_ID, agent_name: AGENT_NAME,
|
|
992
996
|
pi_detected: true,
|
|
993
997
|
pi_trust_score: piResult.trustScore,
|
|
994
998
|
pi_blocked: !isLogOnly,
|
|
@@ -1050,7 +1054,7 @@ process.stdin.on('end', async () => {
|
|
|
1050
1054
|
decision: 'ALLOW',
|
|
1051
1055
|
reason: 'Prompt injection detected but below threshold (trust: ' + (piResult.trustScore * 100).toFixed(0) + '%)',
|
|
1052
1056
|
source: 'claude-code-guard',
|
|
1053
|
-
agent_id:
|
|
1057
|
+
agent_id: AGENT_ID, agent_name: AGENT_NAME,
|
|
1054
1058
|
pi_detected: true,
|
|
1055
1059
|
pi_trust_score: piResult.trustScore,
|
|
1056
1060
|
pi_blocked: false,
|
|
@@ -1199,7 +1203,7 @@ Respond with ONLY valid JSON: {"decision": "ALLOW" or "DENY", "reason": "brief e
|
|
|
1199
1203
|
tool: toolName, arguments: args,
|
|
1200
1204
|
decision: 'DENY', reason,
|
|
1201
1205
|
source: 'claude-code-guard',
|
|
1202
|
-
agent_id:
|
|
1206
|
+
agent_id: AGENT_ID, agent_name: AGENT_NAME,
|
|
1203
1207
|
};
|
|
1204
1208
|
if (piResult) {
|
|
1205
1209
|
logEntry.pi_detected = true;
|
package/hooks/stop.mjs
CHANGED
|
@@ -26,6 +26,10 @@ const dotenv = loadEnvKey(process.cwd());
|
|
|
26
26
|
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
|
+
// Agent identity from CLI args: node stop.mjs <agent_id> <agent_name>
|
|
30
|
+
const AGENT_ID = process.argv[2] || 'claude-code';
|
|
31
|
+
const AGENT_NAME = process.argv[3] || 'Claude Code';
|
|
32
|
+
|
|
29
33
|
if (!API_KEY || !API_KEY.startsWith('sg_live_')) process.exit(0);
|
|
30
34
|
|
|
31
35
|
// Flag file: audit.mjs writes this when a tool call was logged in this turn.
|
|
@@ -59,8 +63,8 @@ process.stdin.on('end', async () => {
|
|
|
59
63
|
reason: 'text response (no tool calls)',
|
|
60
64
|
source: 'claude-code-hook',
|
|
61
65
|
evaluationTimeMs: 0,
|
|
62
|
-
agent_id:
|
|
63
|
-
agent_name:
|
|
66
|
+
agent_id: AGENT_ID,
|
|
67
|
+
agent_name: AGENT_NAME,
|
|
64
68
|
}),
|
|
65
69
|
signal: AbortSignal.timeout(5000),
|
|
66
70
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.7",
|
|
4
4
|
"description": "MCP security proxy — protect any MCP server with customizable policies, path/command constraints, rate limiting, and audit logging. Zero code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|