@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 +506 -121
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +528 -125
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
773
|
-
|
|
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
|
-
|
|
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
|
-
|
|
804
|
-
console.log(
|
|
805
|
-
console.log(` ${
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
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(` ${
|
|
847
|
-
console.log(` ${DIM}
|
|
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(
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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}
|
|
873
|
-
console.log(
|
|
874
|
-
console.log(` ${DIM}
|
|
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(
|
|
962
|
-
console.log(` ${
|
|
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
|
-
|
|
965
|
-
const
|
|
966
|
-
const
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
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
|
-
|
|
990
|
-
|
|
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
|
-
|
|
993
|
-
|
|
994
|
-
console.log(` ${
|
|
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();
|