@streamblur/mcp 1.4.0 → 1.5.1

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/src/index.js CHANGED
@@ -7,8 +7,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = require("node:path");
9
9
  const node_child_process_1 = require("node:child_process");
10
+ const node_child_process_2 = require("node:child_process");
11
+ const node_util_1 = require("node:util");
12
+ const node_http_1 = require("node:http");
10
13
  const node_os_1 = require("node:os");
11
14
  const node_readline_1 = __importDefault(require("node:readline"));
15
+ const execAsync = (0, node_util_1.promisify)(node_child_process_2.exec);
12
16
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
13
17
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
14
18
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
@@ -148,7 +152,7 @@ function scanDirectory(dirPath, maxFiles = 500) {
148
152
  return results;
149
153
  }
150
154
  // ─── Server Setup ──────────────────────────────────────────────────────────
151
- const server = new index_js_1.Server({ name: "streamblur-mcp", version: "1.4.0" }, { capabilities: { tools: {} } });
155
+ const server = new index_js_1.Server({ name: "streamblur-mcp", version: "1.5.1" }, { capabilities: { tools: {} } });
152
156
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
153
157
  const proActive = await isPro();
154
158
  const tools = [
@@ -544,6 +548,169 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
544
548
  throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
545
549
  }
546
550
  });
551
+ // ─── Pro Welcome TUI ───────────────────────────────────────────────────────
552
+ function showProWelcome(email, configuredTools, showRestartSection = true) {
553
+ const BLUE = "\x1b[34m";
554
+ const CYAN = "\x1b[36m";
555
+ const GREEN = "\x1b[32m";
556
+ const YELLOW = "\x1b[33m";
557
+ const BOLD = "\x1b[1m";
558
+ const DIM = "\x1b[2m";
559
+ const RESET = "\x1b[0m";
560
+ const SEP = `${DIM} ------------------------------------------------------${RESET}`;
561
+ console.log("");
562
+ console.log(`${BLUE}${BOLD} ╔══════════════════════════════════════════════════════╗${RESET}`);
563
+ console.log(`${BLUE}${BOLD} ║ STREAM B L U R · Pro Edition v1.5.1 ║${RESET}`);
564
+ console.log(`${BLUE}${BOLD} ╚══════════════════════════════════════════════════════╝${RESET}`);
565
+ console.log("");
566
+ console.log(` ${GREEN}${BOLD}✓ Pro Active · ${email} · 9/9 tools unlocked${RESET}`);
567
+ console.log("");
568
+ console.log(SEP);
569
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
570
+ console.log(SEP);
571
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
572
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
573
+ console.log("");
574
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
575
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
576
+ console.log("");
577
+ console.log(SEP);
578
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
579
+ console.log(SEP);
580
+ console.log(` ${YELLOW}redact_file${RESET} Redact secrets from any file without modifying it`);
581
+ console.log(` ${DIM} Usage: "Redact the file at ~/.env"${RESET}`);
582
+ console.log("");
583
+ console.log(` ${YELLOW}scan_directory${RESET} Scan an entire project folder for leaked secrets`);
584
+ console.log(` ${DIM} Usage: "Scan my project at ~/myapp for secrets"${RESET}`);
585
+ console.log("");
586
+ console.log(` ${YELLOW}scan_repo${RESET} Clone + audit any GitHub repo, then delete the clone`);
587
+ console.log(` ${DIM} Usage: "Scan github.com/user/repo for leaked keys"${RESET}`);
588
+ console.log("");
589
+ console.log(` ${YELLOW}audit_env_file${RESET} Full security report on any .env file`);
590
+ console.log(` ${DIM} Usage: "Audit my .env at ~/myapp/.env"${RESET}`);
591
+ console.log("");
592
+ console.log(` ${YELLOW}check_gitignore${RESET} Find gaps in your .gitignore before you commit`);
593
+ console.log(` ${DIM} Usage: "Check my .gitignore at ~/myapp"${RESET}`);
594
+ console.log("");
595
+ console.log(` ${YELLOW}explain_detection${RESET} Plain-English explanation of any detected secret type`);
596
+ console.log(` ${DIM} Usage: "Explain this detection: stripe_secret_live"${RESET}`);
597
+ console.log("");
598
+ console.log(` ${YELLOW}generate_env_template${RESET} Generate a safe .env.example for your stack`);
599
+ console.log(` ${DIM} Usage: "Generate an env template for Next.js + Stripe"${RESET}`);
600
+ console.log("");
601
+ console.log(SEP);
602
+ console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
603
+ console.log(SEP);
604
+ console.log(` --setup Auto-configure all your AI tools`);
605
+ console.log(` --pro Verify Pro or activate on a new machine`);
606
+ console.log(` --remove Remove StreamBlur from all configs`);
607
+ console.log(` --version Show version and update status`);
608
+ console.log("");
609
+ console.log(SEP);
610
+ console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
611
+ console.log(SEP);
612
+ console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
613
+ console.log(` Your AI sees the tools and uses them automatically when relevant.`);
614
+ console.log("");
615
+ console.log(` Try asking:`);
616
+ console.log(` "Redact my clipboard before I paste it anywhere"`);
617
+ console.log(` "Scan my whole project for any leaked API keys"`);
618
+ console.log(` "Audit my .env file and tell me what to rotate"`);
619
+ console.log("");
620
+ if (showRestartSection) {
621
+ console.log(SEP);
622
+ console.log(` ${CYAN}${BOLD}TO FINISH - restart your AI tool:${RESET}`);
623
+ console.log(SEP);
624
+ const restartInstructions = {
625
+ "Claude Code": ` ${CYAN}Claude Code:${RESET} /exit then run: claude (or open a new session)`,
626
+ "Cursor": ` ${CYAN}Cursor:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
627
+ "Claude Desktop": ` ${CYAN}Claude Desktop:${RESET} Quit from the menu bar, then reopen`,
628
+ "Windsurf": ` ${CYAN}Windsurf:${RESET} Close and reopen the window`,
629
+ "Zed": ` ${CYAN}Zed:${RESET} Cmd+Q then reopen`,
630
+ "VS Code (experimental)": ` ${CYAN}VS Code:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
631
+ };
632
+ for (const tool of configuredTools) {
633
+ const line = restartInstructions[tool];
634
+ if (line)
635
+ console.log(line);
636
+ }
637
+ }
638
+ console.log("");
639
+ console.log(` Then ask your AI: "List your available MCP tools"`);
640
+ console.log(` You should see all 9 StreamBlur tools listed.`);
641
+ console.log("");
642
+ console.log(` Quick test - paste this to your AI:`);
643
+ console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
644
+ console.log("");
645
+ console.log(SEP);
646
+ console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
647
+ console.log(SEP);
648
+ console.log("");
649
+ }
650
+ // ─── Free User TUI (after --setup, answered N) ────────────────────────────
651
+ function showFreeSetupComplete() {
652
+ const CYAN = "\x1b[36m";
653
+ const GREEN = "\x1b[32m";
654
+ const BOLD = "\x1b[1m";
655
+ const DIM = "\x1b[2m";
656
+ const RESET = "\x1b[0m";
657
+ const SEP = `${DIM} ------------------------------------------------------${RESET}`;
658
+ console.log("");
659
+ console.log(SEP);
660
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
661
+ console.log(SEP);
662
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
663
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
664
+ console.log("");
665
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
666
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
667
+ console.log("");
668
+ console.log(SEP);
669
+ console.log(` ${DIM}PRO TOOLS · locked${RESET}`);
670
+ console.log(SEP);
671
+ console.log(` ${DIM}redact_file Redact secrets from any file without modifying it${RESET}`);
672
+ console.log("");
673
+ console.log(` ${DIM}scan_directory Scan an entire project folder for leaked secrets${RESET}`);
674
+ console.log("");
675
+ console.log(` ${DIM}scan_repo Clone + audit any GitHub repo, then delete the clone${RESET}`);
676
+ console.log("");
677
+ console.log(` ${DIM}audit_env_file Full security report on any .env file${RESET}`);
678
+ console.log("");
679
+ console.log(` ${DIM}check_gitignore Find gaps in your .gitignore before you commit${RESET}`);
680
+ console.log("");
681
+ console.log(` ${DIM}explain_detection Plain-English explanation of any detected secret type${RESET}`);
682
+ console.log("");
683
+ console.log(` ${DIM}generate_env_template Generate a safe .env.example for your stack${RESET}`);
684
+ console.log("");
685
+ console.log(` 🔒 Unlock 7 more tools · $2.99 one-time · streamblur.com/pricing`);
686
+ console.log("");
687
+ console.log(SEP);
688
+ console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
689
+ console.log(SEP);
690
+ console.log(` --setup Auto-configure all your AI tools`);
691
+ console.log(` --pro Verify Pro or activate on a new machine`);
692
+ console.log(` --remove Remove StreamBlur from all configs`);
693
+ console.log(` --version Show version and update status`);
694
+ console.log("");
695
+ console.log(SEP);
696
+ console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
697
+ console.log(SEP);
698
+ console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
699
+ console.log(` Your AI sees the tools and uses them automatically when relevant.`);
700
+ console.log("");
701
+ console.log(` Try asking:`);
702
+ console.log(` "Redact my clipboard before I paste it anywhere"`);
703
+ console.log(` "Scan my whole project for any leaked API keys"`);
704
+ console.log(` "Audit my .env file and tell me what to rotate"`);
705
+ console.log("");
706
+ console.log(` Quick test - paste this to your AI:`);
707
+ console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
708
+ console.log("");
709
+ console.log(SEP);
710
+ console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
711
+ console.log(SEP);
712
+ console.log("");
713
+ }
547
714
  async function runSetup() {
548
715
  const os = process.platform;
549
716
  const home = process.env.HOME || process.env.USERPROFILE || "";
@@ -704,11 +871,6 @@ async function runSetup() {
704
871
  console.log(` ${GREEN}${BOLD}Setup complete!${configured > 0 ? ` ${configured} tool(s) configured.` : ""}${RESET}`);
705
872
  console.log(` ${DIM}Restart your AI tool and StreamBlur will be active.${RESET}`);
706
873
  console.log("");
707
- console.log(` ${DIM}To unlock Pro tools (7 more tools, $2.99 one-time):${RESET}`);
708
- console.log(` ${DIM}1. Buy at: https://streamblur.com/pricing${RESET}`);
709
- console.log(` ${DIM}2. Run: npx @streamblur/mcp --pro${RESET}`);
710
- console.log(` ${DIM}3. Follow the instructions to add your email to your config${RESET}`);
711
- console.log("");
712
874
  console.log(` ${DIM}To remove StreamBlur at any time:${RESET}`);
713
875
  console.log(` ${DIM}npx @streamblur/mcp --remove${RESET}`);
714
876
  }
@@ -717,18 +879,30 @@ async function runSetup() {
717
879
  console.log(` ${DIM}Either your AI tools were not found or are already set up.${RESET}`);
718
880
  console.log("");
719
881
  console.log(` ${BOLD} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${RESET}`);
720
- console.log(` ${BOLD} Manual setup \u2014 copy the block for your tool:${RESET}`);
882
+ console.log(` ${BOLD} Manual setup - copy the block for your tool:${RESET}`);
721
883
  console.log("");
722
884
  console.log(` ${CYAN} Claude Code CLI:${RESET}`);
723
885
  console.log(` claude mcp add --transport stdio --scope user streamblur -- npx -y @streamblur/mcp`);
724
886
  console.log("");
725
- console.log(` ${CYAN} Claude Desktop / Cursor / Windsurf / Zed \u2014 add to mcpServers:${RESET}`);
887
+ console.log(` ${CYAN} Claude Desktop / Cursor / Windsurf / Zed - add to mcpServers:${RESET}`);
726
888
  console.log(` "streamblur": { "command": "npx", "args": ["-y", "@streamblur/mcp"] }`);
727
889
  console.log("");
728
890
  console.log(` ${DIM} Full docs: https://streamblur.com/mcp${RESET}`);
729
891
  console.log(` ${BOLD} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${RESET}`);
730
892
  }
731
893
  console.log("");
894
+ // Ask about Pro
895
+ console.log("");
896
+ const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
897
+ const answer = await new Promise(resolve => {
898
+ rl.question(` Are you a StreamBlur Pro user? (y/n) `, (ans) => { rl.close(); resolve(ans.trim().toLowerCase()); });
899
+ });
900
+ if (answer === "y" || answer === "yes") {
901
+ await runProActivation();
902
+ }
903
+ else {
904
+ showFreeSetupComplete();
905
+ }
732
906
  }
733
907
  // ─── Version Check ────────────────────────────────────────────────────────
734
908
  async function checkForUpdate(currentVersion) {
@@ -749,7 +923,7 @@ async function checkForUpdate(currentVersion) {
749
923
  }
750
924
  }
751
925
  async function showWelcome() {
752
- const CURRENT_VERSION = "1.4.0";
926
+ const CURRENT_VERSION = "1.5.1";
753
927
  const licenseKey = process.env.STREAMBLUR_LICENSE_KEY ?? "";
754
928
  let proStatus = false;
755
929
  let proCheckFailed = false;
@@ -769,9 +943,8 @@ async function showWelcome() {
769
943
  const BOLD = "\x1b[1m";
770
944
  const DIM = "\x1b[2m";
771
945
  const RESET = "\x1b[0m";
772
- const w = 56;
773
- const line = "\u2500".repeat(w);
774
- // ASCII Art logo
946
+ const SEP = `${DIM} ------------------------------------------------------${RESET}`;
947
+ // ASCII Art logo box
775
948
  console.log("");
776
949
  console.log(`${BLUE}${BOLD} \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${RESET}`);
777
950
  console.log(`${BLUE}${BOLD} \u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u255c\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u255c\u2588\u2588\u2588\u2588\u2588\u2588\u255c \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u255c \u2588\u2588\u2588\u2588\u2588\u255c \u2588\u2588\u2588\u255c \u2588\u2588\u2588\u255c\u2551${RESET}`);
@@ -790,97 +963,136 @@ async function showWelcome() {
790
963
  console.log(` ${YELLOW}\u26A1 Update available: v${CURRENT_VERSION} -> v${latestVersion} Run: npx @streamblur/mcp@latest --setup${RESET}`);
791
964
  console.log("");
792
965
  }
793
- // Pro status line
794
966
  if (proStatus) {
795
- console.log(` ${GREEN}${BOLD}\u2713 Pro - Authenticated${RESET} ${DIM}All 9 tools unlocked${RESET}`);
967
+ // Pro status line
968
+ console.log(` ${GREEN}${BOLD}✓ Pro Active · ${licenseKey} · 9/9 tools unlocked${RESET}`);
969
+ console.log("");
970
+ console.log(SEP);
971
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
972
+ console.log(SEP);
973
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
974
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
975
+ console.log("");
976
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
977
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
978
+ console.log("");
979
+ console.log(SEP);
980
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
981
+ console.log(SEP);
982
+ console.log(` ${YELLOW}redact_file${RESET} Redact secrets from any file without modifying it`);
983
+ console.log(` ${DIM} Usage: "Redact the file at ~/.env"${RESET}`);
984
+ console.log("");
985
+ console.log(` ${YELLOW}scan_directory${RESET} Scan an entire project folder for leaked secrets`);
986
+ console.log(` ${DIM} Usage: "Scan my project at ~/myapp for secrets"${RESET}`);
987
+ console.log("");
988
+ console.log(` ${YELLOW}scan_repo${RESET} Clone + audit any GitHub repo, then delete the clone`);
989
+ console.log(` ${DIM} Usage: "Scan github.com/user/repo for leaked keys"${RESET}`);
990
+ console.log("");
991
+ console.log(` ${YELLOW}audit_env_file${RESET} Full security report on any .env file`);
992
+ console.log(` ${DIM} Usage: "Audit my .env at ~/myapp/.env"${RESET}`);
993
+ console.log("");
994
+ console.log(` ${YELLOW}check_gitignore${RESET} Find gaps in your .gitignore before you commit`);
995
+ console.log(` ${DIM} Usage: "Check my .gitignore at ~/myapp"${RESET}`);
996
+ console.log("");
997
+ console.log(` ${YELLOW}explain_detection${RESET} Plain-English explanation of any detected secret type`);
998
+ console.log(` ${DIM} Usage: "Explain this detection: stripe_secret_live"${RESET}`);
999
+ console.log("");
1000
+ console.log(` ${YELLOW}generate_env_template${RESET} Generate a safe .env.example for your stack`);
1001
+ console.log(` ${DIM} Usage: "Generate an env template for Next.js + Stripe"${RESET}`);
1002
+ console.log("");
1003
+ console.log(SEP);
1004
+ console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
1005
+ console.log(SEP);
1006
+ console.log(` --setup Auto-configure all your AI tools`);
1007
+ console.log(` --pro Verify Pro or activate on a new machine`);
1008
+ console.log(` --remove Remove StreamBlur from all configs`);
1009
+ console.log(` --version Show version and update status`);
1010
+ console.log("");
1011
+ console.log(SEP);
1012
+ console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
1013
+ console.log(SEP);
1014
+ console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
1015
+ console.log(` Your AI sees the tools and uses them automatically when relevant.`);
1016
+ console.log("");
1017
+ console.log(` Try asking:`);
1018
+ console.log(` "Redact my clipboard before I paste it anywhere"`);
1019
+ console.log(` "Scan my whole project for any leaked API keys"`);
1020
+ console.log(` "Audit my .env file and tell me what to rotate"`);
1021
+ console.log("");
1022
+ console.log(` Quick test - paste this to your AI:`);
1023
+ console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
1024
+ console.log("");
1025
+ console.log(SEP);
1026
+ console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
1027
+ console.log(SEP);
1028
+ console.log("");
796
1029
  }
797
1030
  else if (licenseKey && proCheckFailed) {
798
1031
  console.log(` ${YELLOW}\u26A0 Could not validate your license key.${RESET}`);
799
1032
  console.log(` ${DIM}Make sure STREAMBLUR_LICENSE_KEY matches your purchase email.${RESET}`);
800
1033
  console.log(` ${DIM}Run: npx @streamblur/mcp --pro to verify.${RESET}`);
1034
+ console.log("");
801
1035
  }
802
1036
  else {
803
- console.log(` ${GREEN}\u2713 Free tools active${RESET} ${DIM}2 of 9 tools available${RESET}`);
804
- console.log(` ${DIM}Have Pro? Run: npx @streamblur/mcp --pro${RESET}`);
805
- console.log(` ${DIM}Get Pro: streamblur.com/pricing ($2.99 one-time)${RESET}`);
806
- }
807
- console.log("");
808
- console.log(` ${DIM}Thanks for installing StreamBlur MCP!${RESET}`);
809
- console.log(` ${DIM}You are protected against accidental API key${RESET}`);
810
- console.log(` ${DIM}exposure in your AI coding workflow.${RESET}`);
811
- console.log("");
812
- console.log(` ${BOLD}${line}${RESET}`);
813
- console.log(` ${CYAN}${BOLD}FREE TOOLS${RESET}${DIM} (active now, no setup needed)${RESET}`);
814
- console.log(` ${BOLD}${line}${RESET}`);
815
- console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text`);
816
- console.log(` ${GREEN}scan_text${RESET} Detect secrets and their locations`);
817
- console.log("");
818
- if (proStatus) {
819
- console.log(` ${BOLD}${line}${RESET}`);
820
- console.log(` ${YELLOW}${BOLD}PRO TOOLS${RESET}${DIM} (all unlocked)${RESET}`);
821
- console.log(` ${BOLD}${line}${RESET}`);
822
- console.log(` ${YELLOW}redact_file${RESET} Redact any file on your system`);
823
- console.log(` ${YELLOW}scan_directory${RESET} Scan an entire project folder`);
824
- console.log(` ${YELLOW}scan_repo${RESET} Audit any GitHub repository`);
825
- console.log(` ${YELLOW}audit_env_file${RESET} Full .env file health report`);
826
- console.log(` ${YELLOW}check_gitignore${RESET} Catch missing .gitignore rules`);
827
- console.log(` ${YELLOW}explain_detection${RESET} Know exactly what to do when`);
828
- console.log(` ${" ".repeat(9)}a secret is found`);
829
- console.log(` ${YELLOW}generate_env_template${RESET}`);
830
- console.log(` ${" ".repeat(9)}Safe starter templates for any stack`);
831
- }
832
- else {
833
- console.log(` ${BOLD}${line}${RESET}`);
834
- console.log(` ${YELLOW}${BOLD}PRO TOOLS${RESET} ${YELLOW}\u26A1${RESET}${DIM} (7 additional tools)${RESET}`);
835
- console.log(` ${BOLD}${line}${RESET}`);
836
- console.log(` ${DIM}redact_file Redact any file on your system${RESET}`);
837
- console.log(` ${DIM}scan_directory Scan an entire project folder${RESET}`);
838
- console.log(` ${DIM}scan_repo Audit any GitHub repository${RESET}`);
839
- console.log(` ${DIM}audit_env_file Full .env file health report${RESET}`);
840
- console.log(` ${DIM}check_gitignore Catch missing .gitignore rules${RESET}`);
841
- console.log(` ${DIM}explain_detection Know exactly what to do when${RESET}`);
842
- console.log(` ${DIM} a secret is found${RESET}`);
843
- console.log(` ${DIM}generate_env_template${RESET}`);
844
- console.log(` ${DIM} Safe starter templates for any stack${RESET}`);
1037
+ // Free user
1038
+ console.log(SEP);
1039
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
1040
+ console.log(SEP);
1041
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
1042
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
845
1043
  console.log("");
846
- console.log(` ${YELLOW}${BOLD}Unlock all 7 Pro tools for $2.99 one-time${RESET}`);
847
- console.log(` ${DIM}Same license as the Chrome extension.${RESET}`);
848
- console.log(` ${DIM}Buy once, use both.${RESET}`);
1044
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
1045
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
849
1046
  console.log("");
850
- console.log(` ${BOLD}Get Pro -> ${CYAN}https://streamblur.com/pricing${RESET}`);
851
- }
852
- console.log("");
853
- console.log(` ${BOLD}${line}${RESET}`);
854
- console.log(` ${BOLD}QUICK SETUP${RESET}`);
855
- console.log(` ${BOLD}${line}${RESET}`);
856
- console.log(` Auto-configure Claude Desktop, Cursor, Windsurf:`);
857
- console.log("");
858
- console.log(` ${CYAN} npx @streamblur/mcp --setup${RESET}`);
859
- console.log("");
860
- if (proStatus) {
861
- // already pro, no extra block needed
862
- }
863
- else if (licenseKey && proCheckFailed) {
864
- // already shown warning above
865
- }
866
- else {
867
- console.log(` ${BOLD}${line}${RESET}`);
868
- console.log(` ${BOLD}ALREADY A PRO USER?${RESET}`);
869
- console.log(` ${BOLD}${line}${RESET}`);
870
- console.log(` Add to your AI tool config under mcpServers:`);
1047
+ console.log(SEP);
1048
+ console.log(` ${DIM}PRO TOOLS · locked${RESET}`);
1049
+ console.log(SEP);
1050
+ console.log(` ${DIM}redact_file Redact secrets from any file without modifying it${RESET}`);
1051
+ console.log("");
1052
+ console.log(` ${DIM}scan_directory Scan an entire project folder for leaked secrets${RESET}`);
871
1053
  console.log("");
872
- console.log(` ${DIM} "env": {${RESET}`);
873
- console.log(` ${DIM} "STREAMBLUR_LICENSE_KEY": "you@example.com"${RESET}`);
874
- console.log(` ${DIM} }${RESET}`);
1054
+ console.log(` ${DIM}scan_repo Clone + audit any GitHub repo, then delete the clone${RESET}`);
1055
+ console.log("");
1056
+ console.log(` ${DIM}audit_env_file Full security report on any .env file${RESET}`);
1057
+ console.log("");
1058
+ console.log(` ${DIM}check_gitignore Find gaps in your .gitignore before you commit${RESET}`);
1059
+ console.log("");
1060
+ console.log(` ${DIM}explain_detection Plain-English explanation of any detected secret type${RESET}`);
1061
+ console.log("");
1062
+ console.log(` ${DIM}generate_env_template Generate a safe .env.example for your stack${RESET}`);
1063
+ console.log("");
1064
+ console.log(` 🔒 Unlock 7 more tools · $2.99 one-time · streamblur.com/pricing`);
1065
+ console.log("");
1066
+ console.log(SEP);
1067
+ console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
1068
+ console.log(SEP);
1069
+ console.log(` --setup Auto-configure all your AI tools`);
1070
+ console.log(` --pro Verify Pro or activate on a new machine`);
1071
+ console.log(` --remove Remove StreamBlur from all configs`);
1072
+ console.log(` --version Show version and update status`);
1073
+ console.log("");
1074
+ console.log(SEP);
1075
+ console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
1076
+ console.log(SEP);
1077
+ console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
1078
+ console.log(` Your AI sees the tools and uses them automatically when relevant.`);
1079
+ console.log("");
1080
+ console.log(` Try asking:`);
1081
+ console.log(` "Redact my clipboard before I paste it anywhere"`);
1082
+ console.log(` "Scan my whole project for any leaked API keys"`);
1083
+ console.log(` "Audit my .env file and tell me what to rotate"`);
1084
+ console.log("");
1085
+ console.log(` Have Pro? Run: npx @streamblur/mcp --pro`);
1086
+ console.log(` Get Pro: streamblur.com/pricing ($2.99 one-time)`);
1087
+ console.log("");
1088
+ console.log(` Quick test - paste this to your AI:`);
1089
+ console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
1090
+ console.log("");
1091
+ console.log(SEP);
1092
+ console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
1093
+ console.log(SEP);
875
1094
  console.log("");
876
1095
  }
877
- console.log(` ${BOLD}${line}${RESET}`);
878
- console.log(` ${DIM}Docs -> https://streamblur.com/mcp${RESET}`);
879
- console.log(` ${DIM}npm -> https://npmjs.com/package/@streamblur/mcp${RESET}`);
880
- console.log("");
881
- console.log(` ${DIM}Running as MCP server? Your AI tool launches this${RESET}`);
882
- console.log(` ${DIM}automatically. No need to run it manually.${RESET}`);
883
- console.log("");
884
1096
  }
885
1097
  async function runRemove() {
886
1098
  const os = process.platform;
@@ -950,54 +1162,227 @@ async function runRemove() {
950
1162
  console.log(` ${DIM}Your data was never stored anywhere. All detection ran locally.${RESET}`);
951
1163
  console.log("");
952
1164
  }
1165
+ async function activateProInConfigs(email) {
1166
+ const os = process.platform;
1167
+ const home = process.env.HOME || process.env.USERPROFILE || "";
1168
+ const appData = process.env.APPDATA || "";
1169
+ const GREEN = "\x1b[32m";
1170
+ const YELLOW = "\x1b[33m";
1171
+ const DIM = "\x1b[2m";
1172
+ const RESET = "\x1b[0m";
1173
+ const configuredTools = [];
1174
+ // Claude Code CLI
1175
+ let claudeCodeFound = false;
1176
+ try {
1177
+ if (os === "win32") {
1178
+ (0, node_child_process_1.execSync)("where claude", { stdio: "pipe" });
1179
+ }
1180
+ else {
1181
+ (0, node_child_process_1.execSync)("which claude", { stdio: "pipe" });
1182
+ }
1183
+ claudeCodeFound = true;
1184
+ }
1185
+ catch {
1186
+ claudeCodeFound = false;
1187
+ }
1188
+ if (claudeCodeFound) {
1189
+ try {
1190
+ (0, node_child_process_1.execSync)("claude mcp remove streamblur", { stdio: "pipe" });
1191
+ }
1192
+ catch { /* may not exist yet */ }
1193
+ try {
1194
+ (0, node_child_process_1.execSync)(`claude mcp add --transport stdio --scope user --env STREAMBLUR_LICENSE_KEY=${email} streamblur -- npx -y @streamblur/mcp`, { stdio: "pipe" });
1195
+ console.log(` ${GREEN}✓ Claude Code: Pro activated${RESET}`);
1196
+ configuredTools.push("Claude Code");
1197
+ }
1198
+ catch (err) {
1199
+ const msg = err instanceof Error ? err.message : String(err);
1200
+ console.log(` ${YELLOW}⚠ Claude Code: could not update - ${msg}${RESET}`);
1201
+ }
1202
+ }
1203
+ // Config file locations
1204
+ const tools = [];
1205
+ if (os === "darwin") {
1206
+ tools.push({ name: "Claude Desktop", configPath: `${home}/Library/Application Support/Claude/claude_desktop_config.json` });
1207
+ tools.push({ name: "Cursor", configPath: `${home}/.cursor/mcp.json` });
1208
+ tools.push({ name: "Windsurf", configPath: `${home}/.codeium/windsurf/mcp_config.json` });
1209
+ tools.push({ name: "Zed", configPath: `${home}/Library/Application Support/Zed/settings.json` });
1210
+ }
1211
+ else if (os === "win32") {
1212
+ tools.push({ name: "Claude Desktop", configPath: `${appData}\\Claude\\claude_desktop_config.json` });
1213
+ tools.push({ name: "Cursor", configPath: `${home}\\.cursor\\mcp.json` });
1214
+ tools.push({ name: "Windsurf", configPath: `${appData}\\Codeium\\Windsurf\\mcp_config.json` });
1215
+ }
1216
+ else {
1217
+ tools.push({ name: "Claude Desktop", configPath: `${home}/.config/Claude/claude_desktop_config.json` });
1218
+ tools.push({ name: "Cursor", configPath: `${home}/.cursor/mcp.json` });
1219
+ tools.push({ name: "Windsurf", configPath: `${home}/.codeium/windsurf/mcp_config.json` });
1220
+ tools.push({ name: "Zed", configPath: `${home}/.config/zed/settings.json` });
1221
+ }
1222
+ tools.push({ name: "VS Code (experimental)", configPath: `${home}/.vscode/mcp.json` });
1223
+ for (const tool of tools) {
1224
+ if (!(0, node_fs_1.existsSync)(tool.configPath))
1225
+ continue;
1226
+ try {
1227
+ const raw = (0, node_fs_1.readFileSync)(tool.configPath, "utf8");
1228
+ let config = {};
1229
+ try {
1230
+ config = JSON.parse(raw);
1231
+ }
1232
+ catch {
1233
+ continue;
1234
+ }
1235
+ const servers = config.mcpServers;
1236
+ if (!servers || !servers.streamblur)
1237
+ continue;
1238
+ const entry = servers.streamblur;
1239
+ entry.env = { STREAMBLUR_LICENSE_KEY: email };
1240
+ (0, node_fs_1.writeFileSync)(tool.configPath, JSON.stringify(config, null, 2));
1241
+ console.log(` ${GREEN}✓ ${tool.name}: Pro activated${RESET}`);
1242
+ configuredTools.push(tool.name);
1243
+ }
1244
+ catch (err) {
1245
+ const msg = err instanceof Error ? err.message : String(err);
1246
+ console.log(` ${YELLOW}⚠ ${tool.name}: could not update - ${msg}${RESET}`);
1247
+ }
1248
+ }
1249
+ if (!claudeCodeFound) {
1250
+ console.log(` ${DIM}Claude Code CLI: not installed, skipped${RESET}`);
1251
+ }
1252
+ return configuredTools;
1253
+ }
953
1254
  async function runProActivation() {
954
- const CYAN = "\x1b[36m";
955
1255
  const GREEN = "\x1b[32m";
1256
+ const CYAN = "\x1b[36m";
956
1257
  const YELLOW = "\x1b[33m";
957
1258
  const BOLD = "\x1b[1m";
958
1259
  const DIM = "\x1b[2m";
959
1260
  const RESET = "\x1b[0m";
1261
+ const CLIENT_ID = "189216007668-dfn12966rn5u36rs2h7nk14hvlmcb0su.apps.googleusercontent.com";
1262
+ // Check if already activated
1263
+ const existingKey = process.env.STREAMBLUR_LICENSE_KEY;
1264
+ if (existingKey) {
1265
+ console.log("");
1266
+ console.log(` Checking existing activation...`);
1267
+ const verified = existingKey.includes("@") ? await checkProLicense(existingKey) : false;
1268
+ if (verified) {
1269
+ console.log(` ${GREEN}${BOLD}✓ Pro is active on this machine.${RESET}`);
1270
+ console.log(` ${DIM}License: ${existingKey}${RESET}`);
1271
+ console.log(` ${DIM}Tools unlocked: 9/9${RESET}`);
1272
+ console.log("");
1273
+ return;
1274
+ }
1275
+ // Key invalid, fall through to re-auth
1276
+ console.log(` ${YELLOW}Existing key could not be verified. Re-authenticating...${RESET}`);
1277
+ }
960
1278
  console.log("");
961
- console.log(` ${BOLD}StreamBlur Pro Activation${RESET}`);
962
- console.log(` ${"\u2500".repeat(25)}`);
1279
+ console.log(`${BOLD} StreamBlur Pro - Google Sign-In${RESET}`);
1280
+ console.log(` ${DIM}We'll verify your purchase by signing in with Google.${RESET}`);
1281
+ console.log(` ${DIM}We only read your email address. Nothing else.${RESET}`);
963
1282
  console.log("");
964
- console.log(` Enter the email you used to purchase StreamBlur Pro:`);
965
- const email = await new Promise((resolve) => {
966
- const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
967
- rl.question(" > ", (answer) => {
968
- rl.close();
969
- resolve(answer.trim());
1283
+ // Find a free port
1284
+ const port = await new Promise((resolve, reject) => {
1285
+ const s = (0, node_http_1.createServer)();
1286
+ s.listen(0, "127.0.0.1", () => {
1287
+ const p = s.address().port;
1288
+ s.close(() => resolve(p));
970
1289
  });
1290
+ s.on("error", reject);
971
1291
  });
972
- if (!email || !email.includes("@")) {
973
- console.log(` ${YELLOW}Invalid email. Please enter a valid email address.${RESET}`);
974
- console.log("");
975
- return;
976
- }
977
- console.log("");
978
- console.log(` ${DIM}Checking license for ${email}...${RESET}`);
979
- const verified = await checkProLicense(email);
980
- if (verified) {
981
- console.log(` ${GREEN}${BOLD}✓ Pro verified! Here's your config snippet:${RESET}`);
982
- console.log("");
983
- console.log(` ${DIM}{${RESET}`);
984
- console.log(` ${DIM} "env": {${RESET}`);
985
- console.log(` ${DIM} "STREAMBLUR_LICENSE_KEY": "${email}"${RESET}`);
986
- console.log(` ${DIM} }${RESET}`);
987
- console.log(` ${DIM}}${RESET}`);
1292
+ const redirectUri = `http://localhost:${port}/callback`;
1293
+ const scope = "openid email";
1294
+ const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
1295
+ `client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(redirectUri)}&` +
1296
+ `response_type=code&scope=${encodeURIComponent(scope)}&prompt=select_account`;
1297
+ // Wait for callback
1298
+ const code = await new Promise((resolve, reject) => {
1299
+ const server = (0, node_http_1.createServer)((req, res) => {
1300
+ const url = new URL(req.url || "/", `http://localhost:${port}`);
1301
+ const code = url.searchParams.get("code");
1302
+ const error = url.searchParams.get("error");
1303
+ res.writeHead(200, { "Content-Type": "text/html" });
1304
+ if (code) {
1305
+ res.end(`<html><body style="font-family:sans-serif;text-align:center;padding:3rem;background:#0f172a;color:#e2e8f0"><h2 style="color:#10b981">Authenticated!</h2><p>Return to your terminal.</p><script>window.close()</script></body></html>`);
1306
+ server.close();
1307
+ resolve(code);
1308
+ }
1309
+ else {
1310
+ res.end(`<html><body style="font-family:sans-serif;text-align:center;padding:3rem;background:#0f172a;color:#e2e8f0"><h2 style="color:#ef4444">Authentication cancelled.</h2><p>Return to your terminal.</p></body></html>`);
1311
+ server.close();
1312
+ reject(new Error(error || "Authentication cancelled"));
1313
+ }
1314
+ });
1315
+ server.listen(port, "127.0.0.1", async () => {
1316
+ console.log(` ${CYAN}Opening your browser for Google sign-in...${RESET}`);
1317
+ console.log(` ${DIM}If it doesn't open, visit:${RESET}`);
1318
+ console.log(` ${DIM}${authUrl}${RESET}`);
1319
+ console.log("");
1320
+ // Open browser cross-platform
1321
+ const open = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
1322
+ try {
1323
+ await execAsync(`${open} "${authUrl}"`);
1324
+ }
1325
+ catch { /* browser open failed, user has URL */ }
1326
+ });
1327
+ server.on("error", reject);
1328
+ // Timeout after 3 minutes
1329
+ setTimeout(() => { server.close(); reject(new Error("Timed out waiting for Google sign-in")); }, 180000);
1330
+ });
1331
+ console.log(` ${DIM}Verifying with StreamBlur...${RESET}`);
1332
+ // Exchange code for email + pro status via our Netlify function
1333
+ try {
1334
+ const res = await fetch("https://streamblur.com/.netlify/functions/oauth-exchange", {
1335
+ method: "POST",
1336
+ headers: { "Content-Type": "application/json" },
1337
+ body: JSON.stringify({ code, redirectUri }),
1338
+ signal: AbortSignal.timeout(15000)
1339
+ });
1340
+ const data = await res.json();
1341
+ if (data.error) {
1342
+ console.log(` ${YELLOW}⚠ Verification failed: ${data.error}${RESET}`);
1343
+ return;
1344
+ }
1345
+ const email = data.email || "";
988
1346
  console.log("");
989
- console.log(` Add the env block above to your AI tool config and restart.`);
990
- console.log(` ${DIM}Or re-run --setup and add your email when prompted.${RESET}`);
1347
+ if (data.isPro) {
1348
+ console.log(` ${GREEN}${BOLD}✓ Pro verified! Welcome back.${RESET}`);
1349
+ console.log(` ${DIM}Activating for: ${email}${RESET}`);
1350
+ console.log("");
1351
+ // Write license key to all detected config files
1352
+ const configuredTools = await activateProInConfigs(email);
1353
+ showProWelcome(email, configuredTools, true);
1354
+ }
1355
+ else {
1356
+ console.log(` ${YELLOW}No Pro license found for ${email}.${RESET}`);
1357
+ console.log(` ${DIM}If you just purchased, wait 1-2 minutes and try again.${RESET}`);
1358
+ console.log(` ${CYAN} Get Pro: https://streamblur.com/pricing ($2.99 one-time)${RESET}`);
1359
+ }
991
1360
  }
992
- else {
993
- console.log(` ${YELLOW}No Pro license found for that email.${RESET}`);
994
- console.log(` ${DIM}If you just purchased, wait 1-2 minutes and try again.${RESET}`);
995
- console.log(` ${DIM}Get Pro at: ${CYAN}https://streamblur.com/pricing${RESET}`);
1361
+ catch (err) {
1362
+ const msg = err instanceof Error ? err.message : String(err);
1363
+ console.log(` ${YELLOW} Could not connect to StreamBlur: ${msg}${RESET}`);
996
1364
  }
997
1365
  console.log("");
998
1366
  }
999
1367
  async function main() {
1000
1368
  const args = process.argv.slice(2);
1369
+ // --version flag
1370
+ if (args.includes("--version")) {
1371
+ const CURRENT_VERSION = "1.5.1";
1372
+ const GREEN = "\x1b[32m";
1373
+ const DIM = "\x1b[2m";
1374
+ const RESET = "\x1b[0m";
1375
+ const licenseKey = process.env.STREAMBLUR_LICENSE_KEY ?? "";
1376
+ let proActive = false;
1377
+ if (licenseKey) {
1378
+ proActive = await isPro();
1379
+ }
1380
+ console.log(` @streamblur/mcp v${CURRENT_VERSION}`);
1381
+ console.log(` Pro: ${proActive ? `${GREEN}active · ${licenseKey}${RESET}` : `${DIM}not activated${RESET}`}`);
1382
+ console.log(` Tools: ${proActive ? "9/9" : "2/9"} unlocked`);
1383
+ console.log(` npm: https://www.npmjs.com/package/@streamblur/mcp`);
1384
+ return;
1385
+ }
1001
1386
  // --remove flag: uninstall from all AI tools
1002
1387
  if (args.includes("--remove")) {
1003
1388
  await runRemove();