@solongate/proxy 0.28.6 → 0.28.8

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.
Files changed (3) hide show
  1. package/dist/index.js +115 -49
  2. package/dist/init.js +115 -49
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -672,15 +672,29 @@ function installHooks(selectedTools = []) {
672
672
  unlockProtectedDirs();
673
673
  const hooksDir = resolve3(".solongate", "hooks");
674
674
  mkdirSync2(hooksDir, { recursive: true });
675
- const guardPath = join(hooksDir, "guard.mjs");
676
- writeFileSync2(guardPath, readHookScript("guard.mjs"));
677
- console.log(` Created ${guardPath}`);
678
- const auditPath = join(hooksDir, "audit.mjs");
679
- writeFileSync2(auditPath, readHookScript("audit.mjs"));
680
- console.log(` Created ${auditPath}`);
681
- const stopPath = join(hooksDir, "stop.mjs");
682
- writeFileSync2(stopPath, readHookScript("stop.mjs"));
683
- console.log(` Created ${stopPath}`);
675
+ const hookFiles = ["guard.mjs", "audit.mjs", "stop.mjs"];
676
+ let hooksUpdated = 0;
677
+ let hooksSkipped = 0;
678
+ for (const filename of hookFiles) {
679
+ const hookPath = join(hooksDir, filename);
680
+ const latest = readHookScript(filename);
681
+ let needsWrite = true;
682
+ if (existsSync4(hookPath)) {
683
+ const current = readFileSync4(hookPath, "utf-8");
684
+ if (current === latest) {
685
+ needsWrite = false;
686
+ hooksSkipped++;
687
+ }
688
+ }
689
+ if (needsWrite) {
690
+ writeFileSync2(hookPath, latest);
691
+ hooksUpdated++;
692
+ console.log(` ${existsSync4(hookPath) ? "Updated" : "Created"} ${hookPath}`);
693
+ }
694
+ }
695
+ if (hooksSkipped > 0 && hooksUpdated === 0) {
696
+ console.log(` Hook files already up to date`);
697
+ }
684
698
  const allClients = [
685
699
  { name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
686
700
  { name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
@@ -691,6 +705,7 @@ function installHooks(selectedTools = []) {
691
705
  ];
692
706
  const clients = selectedTools.length > 0 ? allClients.filter((c3) => selectedTools.includes(c3.key)) : allClients;
693
707
  const activatedNames = [];
708
+ const skippedNames = [];
694
709
  for (const client of clients) {
695
710
  const clientDir = resolve3(client.dir);
696
711
  mkdirSync2(clientDir, { recursive: true });
@@ -715,18 +730,31 @@ function installHooks(selectedTools = []) {
715
730
  } catch {
716
731
  }
717
732
  const merged = { ...existing, hooks: hookSettings };
718
- writeFileSync2(settingsPath, JSON.stringify(merged, null, 2) + "\n");
719
- console.log(` Created ${settingsPath}`);
720
- activatedNames.push(client.name);
733
+ const mergedStr = JSON.stringify(merged, null, 2) + "\n";
734
+ const existingStr = existsSync4(settingsPath) ? readFileSync4(settingsPath, "utf-8") : "";
735
+ if (mergedStr === existingStr) {
736
+ skippedNames.push(client.name);
737
+ } else {
738
+ writeFileSync2(settingsPath, mergedStr);
739
+ console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
740
+ activatedNames.push(client.name);
741
+ }
721
742
  }
722
743
  console.log("");
723
- console.log(" Hooks installed:");
724
- console.log(" guard.mjs \u2192 blocks policy-violating calls (pre-execution)");
725
- console.log(" audit.mjs \u2192 logs all calls to dashboard (post-execution)");
726
- console.log(" stop.mjs \u2192 tracks text-only responses (no tool calls)");
727
- console.log(` Activated for: ${activatedNames.join(", ")}`);
744
+ if (activatedNames.length > 0) {
745
+ console.log(" Hooks installed:");
746
+ console.log(" guard.mjs \u2192 blocks policy-violating calls (pre-execution)");
747
+ console.log(" audit.mjs \u2192 logs all calls to dashboard (post-execution)");
748
+ console.log(" stop.mjs \u2192 tracks text-only responses (no tool calls)");
749
+ console.log(` Activated for: ${activatedNames.join(", ")}`);
750
+ }
751
+ if (skippedNames.length > 0) {
752
+ console.log(` Already configured: ${skippedNames.join(", ")}`);
753
+ }
728
754
  }
729
755
  function ensureEnvFile() {
756
+ let envChanged = false;
757
+ let gitignoreChanged = false;
730
758
  const envPath = resolve3(".env");
731
759
  if (!existsSync4(envPath)) {
732
760
  const envContent = `# SolonGate Configuration
@@ -742,28 +770,50 @@ GROQ_API_KEY=gsk_your_groq_key_here
742
770
  writeFileSync2(envPath, envContent);
743
771
  console.log(` Created .env`);
744
772
  console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
745
- console.log("");
773
+ envChanged = true;
774
+ } else {
775
+ const existingEnv = readFileSync4(envPath, "utf-8");
776
+ if (!existingEnv.includes("SOLONGATE_API_KEY")) {
777
+ const separator = existingEnv.endsWith("\n") ? "" : "\n";
778
+ const appendContent = `${separator}
779
+ # SolonGate API key \u2014 get one at https://dashboard.solongate.com
780
+ SOLONGATE_API_KEY=sg_live_your_key_here
781
+ `;
782
+ writeFileSync2(envPath, existingEnv + appendContent);
783
+ console.log(` Updated .env (added SOLONGATE_API_KEY)`);
784
+ console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
785
+ envChanged = true;
786
+ }
746
787
  }
747
788
  const gitignorePath = resolve3(".gitignore");
789
+ const requiredEntries = [
790
+ { pattern: ".env", lines: ".env\n.env.local" },
791
+ { pattern: ".mcp.json", lines: ".mcp.json" },
792
+ { pattern: ".solongate", lines: ".solongate/" }
793
+ ];
748
794
  if (existsSync4(gitignorePath)) {
749
795
  let gitignore = readFileSync4(gitignorePath, "utf-8");
750
- let updated = false;
751
- if (!gitignore.includes(".env")) {
752
- gitignore = gitignore.trimEnd() + "\n.env\n.env.local\n";
753
- updated = true;
754
- }
755
- if (!gitignore.includes(".mcp.json")) {
756
- gitignore = gitignore.trimEnd() + "\n.mcp.json\n";
757
- updated = true;
796
+ const added = [];
797
+ for (const entry of requiredEntries) {
798
+ if (!gitignore.includes(entry.pattern)) {
799
+ gitignore = gitignore.trimEnd() + "\n" + entry.lines + "\n";
800
+ added.push(entry.pattern);
801
+ }
758
802
  }
759
- if (updated) {
803
+ if (added.length > 0) {
760
804
  writeFileSync2(gitignorePath, gitignore);
761
- console.log(` Updated .gitignore (added .env + .mcp.json)`);
805
+ console.log(` Updated .gitignore (added ${added.join(", ")})`);
806
+ gitignoreChanged = true;
762
807
  }
763
808
  } else {
764
- writeFileSync2(gitignorePath, ".env\n.env.local\n.mcp.json\nnode_modules/\n");
765
- console.log(` Created .gitignore (with .env and .mcp.json excluded)`);
809
+ writeFileSync2(gitignorePath, ".env\n.env.local\n.mcp.json\n.solongate/\nnode_modules/\n");
810
+ console.log(` Created .gitignore (with .env, .mcp.json, .solongate/ excluded)`);
811
+ gitignoreChanged = true;
812
+ }
813
+ if (!envChanged && !gitignoreChanged) {
814
+ console.log(` .env and .gitignore already up to date`);
766
815
  }
816
+ return { envChanged, gitignoreChanged };
767
817
  }
768
818
  async function main() {
769
819
  const options = parseInitArgs(process.argv);
@@ -924,21 +974,28 @@ async function main() {
924
974
  newConfig.mcpServers[name] = config.mcpServers[name];
925
975
  }
926
976
  }
927
- await sleep(400);
977
+ const currentContent = readFileSync4(configInfo.path, "utf-8");
978
+ let newContent;
928
979
  if (configInfo.type === "claude-desktop") {
929
- const original = JSON.parse(readFileSync4(configInfo.path, "utf-8"));
980
+ const original = JSON.parse(currentContent);
930
981
  original.mcpServers = newConfig.mcpServers;
931
- writeFileSync2(configInfo.path, JSON.stringify(original, null, 2) + "\n");
982
+ newContent = JSON.stringify(original, null, 2) + "\n";
932
983
  } else {
933
- writeFileSync2(configInfo.path, JSON.stringify(newConfig, null, 2) + "\n");
984
+ newContent = JSON.stringify(newConfig, null, 2) + "\n";
985
+ }
986
+ await sleep(400);
987
+ if (newContent === currentContent) {
988
+ console.log(" Config already up to date");
989
+ } else {
990
+ writeFileSync2(configInfo.path, newContent);
991
+ console.log(" Config updated!");
934
992
  }
935
- await sleep(300);
936
- console.log(" Config updated!");
937
993
  console.log("");
938
994
  await sleep(500);
939
995
  installHooks(options.tools);
940
996
  console.log("");
941
997
  await sleep(400);
998
+ const allUpToDate = toProtect.length === 0 && alreadyProtected.length === serverNames.length;
942
999
  console.log(" \u2500\u2500 Summary \u2500\u2500");
943
1000
  console.log("");
944
1001
  for (const name of toProtect) {
@@ -955,19 +1012,28 @@ async function main() {
955
1012
  }
956
1013
  console.log("");
957
1014
  await sleep(500);
958
- console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
959
- console.log(" \u2502 Setup complete! \u2502");
960
- console.log(" \u2502 \u2502");
961
- console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
962
- console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
963
- console.log(" \u2502 Claude, Cursor, Gemini, Antigravity, \u2502");
964
- console.log(" \u2502 OpenClaw, Perplexity \u2502");
965
- console.log(" \u2502 API key \u2192 Set in .env \u2502");
966
- console.log(" \u2502 \u2502");
967
- console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
968
- console.log(" \u2502 \u2502");
969
- console.log(" \u2502 Restart your MCP client to apply changes. \u2502");
970
- console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1015
+ if (allUpToDate) {
1016
+ console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1017
+ console.log(" \u2502 Everything is already up to date! \u2502");
1018
+ console.log(" \u2502 \u2502");
1019
+ console.log(" \u2502 All MCP servers protected, hooks configured. \u2502");
1020
+ console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
1021
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1022
+ } else {
1023
+ console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
1024
+ console.log(" \u2502 Setup complete! \u2502");
1025
+ console.log(" \u2502 \u2502");
1026
+ console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
1027
+ console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
1028
+ console.log(" \u2502 Claude, Cursor, Gemini, Antigravity, \u2502");
1029
+ console.log(" \u2502 OpenClaw, Perplexity \u2502");
1030
+ console.log(" \u2502 API key \u2192 Set in .env \u2502");
1031
+ console.log(" \u2502 \u2502");
1032
+ console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
1033
+ console.log(" \u2502 \u2502");
1034
+ console.log(" \u2502 Restart your MCP client to apply changes. \u2502");
1035
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
1036
+ }
971
1037
  console.log("");
972
1038
  }
973
1039
  var SEARCH_PATHS, CLAUDE_DESKTOP_PATHS, sleep, __dirname, HOOKS_DIR;
package/dist/init.js CHANGED
@@ -255,15 +255,29 @@ function installHooks(selectedTools = []) {
255
255
  unlockProtectedDirs();
256
256
  const hooksDir = resolve(".solongate", "hooks");
257
257
  mkdirSync(hooksDir, { recursive: true });
258
- const guardPath = join(hooksDir, "guard.mjs");
259
- writeFileSync(guardPath, readHookScript("guard.mjs"));
260
- console.log(` Created ${guardPath}`);
261
- const auditPath = join(hooksDir, "audit.mjs");
262
- writeFileSync(auditPath, readHookScript("audit.mjs"));
263
- console.log(` Created ${auditPath}`);
264
- const stopPath = join(hooksDir, "stop.mjs");
265
- writeFileSync(stopPath, readHookScript("stop.mjs"));
266
- console.log(` Created ${stopPath}`);
258
+ const hookFiles = ["guard.mjs", "audit.mjs", "stop.mjs"];
259
+ let hooksUpdated = 0;
260
+ let hooksSkipped = 0;
261
+ for (const filename of hookFiles) {
262
+ const hookPath = join(hooksDir, filename);
263
+ const latest = readHookScript(filename);
264
+ let needsWrite = true;
265
+ if (existsSync(hookPath)) {
266
+ const current = readFileSync(hookPath, "utf-8");
267
+ if (current === latest) {
268
+ needsWrite = false;
269
+ hooksSkipped++;
270
+ }
271
+ }
272
+ if (needsWrite) {
273
+ writeFileSync(hookPath, latest);
274
+ hooksUpdated++;
275
+ console.log(` ${existsSync(hookPath) ? "Updated" : "Created"} ${hookPath}`);
276
+ }
277
+ }
278
+ if (hooksSkipped > 0 && hooksUpdated === 0) {
279
+ console.log(` Hook files already up to date`);
280
+ }
267
281
  const allClients = [
268
282
  { name: "Claude Code", dir: ".claude", key: "claude", agentId: "claude-code", agentName: "Claude Code" },
269
283
  { name: "Cursor", dir: ".cursor", key: "cursor", agentId: "cursor", agentName: "Cursor" },
@@ -274,6 +288,7 @@ function installHooks(selectedTools = []) {
274
288
  ];
275
289
  const clients = selectedTools.length > 0 ? allClients.filter((c2) => selectedTools.includes(c2.key)) : allClients;
276
290
  const activatedNames = [];
291
+ const skippedNames = [];
277
292
  for (const client of clients) {
278
293
  const clientDir = resolve(client.dir);
279
294
  mkdirSync(clientDir, { recursive: true });
@@ -298,18 +313,31 @@ function installHooks(selectedTools = []) {
298
313
  } catch {
299
314
  }
300
315
  const merged = { ...existing, hooks: hookSettings };
301
- writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + "\n");
302
- console.log(` Created ${settingsPath}`);
303
- activatedNames.push(client.name);
316
+ const mergedStr = JSON.stringify(merged, null, 2) + "\n";
317
+ const existingStr = existsSync(settingsPath) ? readFileSync(settingsPath, "utf-8") : "";
318
+ if (mergedStr === existingStr) {
319
+ skippedNames.push(client.name);
320
+ } else {
321
+ writeFileSync(settingsPath, mergedStr);
322
+ console.log(` ${existingStr ? "Updated" : "Created"} ${settingsPath}`);
323
+ activatedNames.push(client.name);
324
+ }
304
325
  }
305
326
  console.log("");
306
- console.log(" Hooks installed:");
307
- console.log(" guard.mjs \u2192 blocks policy-violating calls (pre-execution)");
308
- console.log(" audit.mjs \u2192 logs all calls to dashboard (post-execution)");
309
- console.log(" stop.mjs \u2192 tracks text-only responses (no tool calls)");
310
- console.log(` Activated for: ${activatedNames.join(", ")}`);
327
+ if (activatedNames.length > 0) {
328
+ console.log(" Hooks installed:");
329
+ console.log(" guard.mjs \u2192 blocks policy-violating calls (pre-execution)");
330
+ console.log(" audit.mjs \u2192 logs all calls to dashboard (post-execution)");
331
+ console.log(" stop.mjs \u2192 tracks text-only responses (no tool calls)");
332
+ console.log(` Activated for: ${activatedNames.join(", ")}`);
333
+ }
334
+ if (skippedNames.length > 0) {
335
+ console.log(` Already configured: ${skippedNames.join(", ")}`);
336
+ }
311
337
  }
312
338
  function ensureEnvFile() {
339
+ let envChanged = false;
340
+ let gitignoreChanged = false;
313
341
  const envPath = resolve(".env");
314
342
  if (!existsSync(envPath)) {
315
343
  const envContent = `# SolonGate Configuration
@@ -325,28 +353,50 @@ GROQ_API_KEY=gsk_your_groq_key_here
325
353
  writeFileSync(envPath, envContent);
326
354
  console.log(` Created .env`);
327
355
  console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
328
- console.log("");
356
+ envChanged = true;
357
+ } else {
358
+ const existingEnv = readFileSync(envPath, "utf-8");
359
+ if (!existingEnv.includes("SOLONGATE_API_KEY")) {
360
+ const separator = existingEnv.endsWith("\n") ? "" : "\n";
361
+ const appendContent = `${separator}
362
+ # SolonGate API key \u2014 get one at https://dashboard.solongate.com
363
+ SOLONGATE_API_KEY=sg_live_your_key_here
364
+ `;
365
+ writeFileSync(envPath, existingEnv + appendContent);
366
+ console.log(` Updated .env (added SOLONGATE_API_KEY)`);
367
+ console.log(` \u2192 Set your API key in .env (get one at https://dashboard.solongate.com)`);
368
+ envChanged = true;
369
+ }
329
370
  }
330
371
  const gitignorePath = resolve(".gitignore");
372
+ const requiredEntries = [
373
+ { pattern: ".env", lines: ".env\n.env.local" },
374
+ { pattern: ".mcp.json", lines: ".mcp.json" },
375
+ { pattern: ".solongate", lines: ".solongate/" }
376
+ ];
331
377
  if (existsSync(gitignorePath)) {
332
378
  let gitignore = readFileSync(gitignorePath, "utf-8");
333
- let updated = false;
334
- if (!gitignore.includes(".env")) {
335
- gitignore = gitignore.trimEnd() + "\n.env\n.env.local\n";
336
- updated = true;
337
- }
338
- if (!gitignore.includes(".mcp.json")) {
339
- gitignore = gitignore.trimEnd() + "\n.mcp.json\n";
340
- updated = true;
379
+ const added = [];
380
+ for (const entry of requiredEntries) {
381
+ if (!gitignore.includes(entry.pattern)) {
382
+ gitignore = gitignore.trimEnd() + "\n" + entry.lines + "\n";
383
+ added.push(entry.pattern);
384
+ }
341
385
  }
342
- if (updated) {
386
+ if (added.length > 0) {
343
387
  writeFileSync(gitignorePath, gitignore);
344
- console.log(` Updated .gitignore (added .env + .mcp.json)`);
388
+ console.log(` Updated .gitignore (added ${added.join(", ")})`);
389
+ gitignoreChanged = true;
345
390
  }
346
391
  } else {
347
- writeFileSync(gitignorePath, ".env\n.env.local\n.mcp.json\nnode_modules/\n");
348
- console.log(` Created .gitignore (with .env and .mcp.json excluded)`);
392
+ writeFileSync(gitignorePath, ".env\n.env.local\n.mcp.json\n.solongate/\nnode_modules/\n");
393
+ console.log(` Created .gitignore (with .env, .mcp.json, .solongate/ excluded)`);
394
+ gitignoreChanged = true;
395
+ }
396
+ if (!envChanged && !gitignoreChanged) {
397
+ console.log(` .env and .gitignore already up to date`);
349
398
  }
399
+ return { envChanged, gitignoreChanged };
350
400
  }
351
401
  async function main() {
352
402
  const options = parseInitArgs(process.argv);
@@ -507,21 +557,28 @@ async function main() {
507
557
  newConfig.mcpServers[name] = config.mcpServers[name];
508
558
  }
509
559
  }
510
- await sleep(400);
560
+ const currentContent = readFileSync(configInfo.path, "utf-8");
561
+ let newContent;
511
562
  if (configInfo.type === "claude-desktop") {
512
- const original = JSON.parse(readFileSync(configInfo.path, "utf-8"));
563
+ const original = JSON.parse(currentContent);
513
564
  original.mcpServers = newConfig.mcpServers;
514
- writeFileSync(configInfo.path, JSON.stringify(original, null, 2) + "\n");
565
+ newContent = JSON.stringify(original, null, 2) + "\n";
515
566
  } else {
516
- writeFileSync(configInfo.path, JSON.stringify(newConfig, null, 2) + "\n");
567
+ newContent = JSON.stringify(newConfig, null, 2) + "\n";
568
+ }
569
+ await sleep(400);
570
+ if (newContent === currentContent) {
571
+ console.log(" Config already up to date");
572
+ } else {
573
+ writeFileSync(configInfo.path, newContent);
574
+ console.log(" Config updated!");
517
575
  }
518
- await sleep(300);
519
- console.log(" Config updated!");
520
576
  console.log("");
521
577
  await sleep(500);
522
578
  installHooks(options.tools);
523
579
  console.log("");
524
580
  await sleep(400);
581
+ const allUpToDate = toProtect.length === 0 && alreadyProtected.length === serverNames.length;
525
582
  console.log(" \u2500\u2500 Summary \u2500\u2500");
526
583
  console.log("");
527
584
  for (const name of toProtect) {
@@ -538,19 +595,28 @@ async function main() {
538
595
  }
539
596
  console.log("");
540
597
  await sleep(500);
541
- console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
542
- console.log(" \u2502 Setup complete! \u2502");
543
- console.log(" \u2502 \u2502");
544
- console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
545
- console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
546
- console.log(" \u2502 Claude, Cursor, Gemini, Antigravity, \u2502");
547
- console.log(" \u2502 OpenClaw, Perplexity \u2502");
548
- console.log(" \u2502 API key \u2192 Set in .env \u2502");
549
- console.log(" \u2502 \u2502");
550
- console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
551
- console.log(" \u2502 \u2502");
552
- console.log(" \u2502 Restart your MCP client to apply changes. \u2502");
553
- console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
598
+ if (allUpToDate) {
599
+ console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
600
+ console.log(" \u2502 Everything is already up to date! \u2502");
601
+ console.log(" \u2502 \u2502");
602
+ console.log(" \u2502 All MCP servers protected, hooks configured. \u2502");
603
+ console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
604
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
605
+ } else {
606
+ console.log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
607
+ console.log(" \u2502 Setup complete! \u2502");
608
+ console.log(" \u2502 \u2502");
609
+ console.log(" \u2502 MCP servers \u2192 Protected via proxy \u2502");
610
+ console.log(" \u2502 AI tools \u2192 Guarded via hooks \u2502");
611
+ console.log(" \u2502 Claude, Cursor, Gemini, Antigravity, \u2502");
612
+ console.log(" \u2502 OpenClaw, Perplexity \u2502");
613
+ console.log(" \u2502 API key \u2192 Set in .env \u2502");
614
+ console.log(" \u2502 \u2502");
615
+ console.log(" \u2502 View logs: https://dashboard.solongate.com \u2502");
616
+ console.log(" \u2502 \u2502");
617
+ console.log(" \u2502 Restart your MCP client to apply changes. \u2502");
618
+ console.log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
619
+ }
554
620
  console.log("");
555
621
  }
556
622
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.28.6",
3
+ "version": "0.28.8",
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": {