@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 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.hooks };
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
- let updated = false;
765
- if (!gitignore.includes(".env")) {
766
- gitignore = gitignore.trimEnd() + "\n.env\n.env.local\n";
767
- updated = true;
768
- }
769
- if (!gitignore.includes(".mcp.json")) {
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 (updated) {
775
+ if (added.length > 0) {
774
776
  writeFileSync2(gitignorePath, gitignore);
775
- console.log(` Updated .gitignore (added .env + .mcp.json)`);
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 and .mcp.json excluded)`);
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.hooks };
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
- let updated = false;
348
- if (!gitignore.includes(".env")) {
349
- gitignore = gitignore.trimEnd() + "\n.env\n.env.local\n";
350
- updated = true;
351
- }
352
- if (!gitignore.includes(".mcp.json")) {
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 (updated) {
358
+ if (added.length > 0) {
357
359
  writeFileSync(gitignorePath, gitignore);
358
- console.log(` Updated .gitignore (added .env + .mcp.json)`);
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 and .mcp.json excluded)`);
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: 'claude-code',
74
- agent_name: 'Claude Code',
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: 'claude-code', agent_name: 'Claude Code',
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: 'claude-code', agent_name: 'Claude Code',
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: 'claude-code', agent_name: 'Claude Code',
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: 'claude-code', agent_name: 'Claude Code',
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: 'claude-code',
63
- agent_name: 'Claude Code',
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.5",
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": {