@streamblur/mcp 1.5.6 → 1.5.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.
package/dist/src/index.js CHANGED
@@ -152,7 +152,7 @@ function scanDirectory(dirPath, maxFiles = 500) {
152
152
  return results;
153
153
  }
154
154
  // ─── Server Setup ──────────────────────────────────────────────────────────
155
- const server = new index_js_1.Server({ name: "streamblur-mcp", version: "1.5.5" }, { capabilities: { tools: {} } });
155
+ const server = new index_js_1.Server({ name: "streamblur-mcp", version: "1.5.7" }, { capabilities: { tools: {} } });
156
156
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
157
157
  const proActive = await isPro();
158
158
  const tools = [
@@ -549,111 +549,191 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
549
549
  }
550
550
  });
551
551
  // ─── Pro Welcome TUI ───────────────────────────────────────────────────────
552
+ // Pull version live from package.json — never hardcode it
553
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
554
+ const MCP_VERSION = require("../package.json").version;
552
555
  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";
556
+ // ── Core palette ──────────────────────────────────────────────────────────
557
+ const RESET = "\x1b[0m";
557
558
  const BOLD = "\x1b[1m";
558
559
  const DIM = "\x1b[2m";
559
- const RESET = "\x1b[0m";
560
- const SEP = `${DIM} ------------------------------------------------------${RESET}`;
561
- const CYAN2 = "\x1b[36m";
562
- console.log("");
563
- console.log(`${BLUE}${BOLD} ╔══════════════════════════════════════════════════════╗${RESET}`);
564
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████╗████████╗██████╗ ███████╗ █████╗ ███╗ ███╗${BLUE}║${RESET}`);
565
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║${BLUE}║${RESET}`);
566
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║${BLUE}║${RESET}`);
567
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║${BLUE}║${RESET}`);
568
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████║ ██║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║${BLUE}║${RESET}`);
569
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝${BLUE}║${RESET}`);
570
- console.log(`${BLUE}${BOLD} ║${RESET}${CYAN2}${BOLD} B L U R ${BLUE}║${RESET}`);
571
- console.log(`${BLUE}${BOLD} ║${RESET}${DIM} Your AI Security Guard 🛡️ Pro Edition v1.5.5 ${BLUE}${BOLD}║${RESET}`);
572
- console.log(`${BLUE}${BOLD} ╚══════════════════════════════════════════════════════╝${RESET}`);
573
- console.log("");
574
- console.log(` ${GREEN}${BOLD}✓ Pro Active · ${email} · 9/9 tools unlocked${RESET}`);
575
- console.log("");
576
- console.log(SEP);
577
- console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
578
- console.log(SEP);
579
- console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
580
- console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
581
- console.log("");
582
- console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
583
- console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
584
- console.log("");
585
- console.log(SEP);
586
- console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
587
- console.log(SEP);
588
- console.log(` ${YELLOW}redact_file${RESET} Redact secrets from any file without modifying it`);
589
- console.log(` ${DIM} Usage: "Redact the file at ~/.env"${RESET}`);
590
- console.log("");
591
- console.log(` ${YELLOW}scan_directory${RESET} Scan an entire project folder for leaked secrets`);
592
- console.log(` ${DIM} Usage: "Scan my project at ~/myapp for secrets"${RESET}`);
593
- console.log("");
594
- console.log(` ${YELLOW}scan_repo${RESET} Clone + audit any GitHub repo, then delete the clone`);
595
- console.log(` ${DIM} Usage: "Scan github.com/user/repo for leaked keys"${RESET}`);
596
- console.log("");
597
- console.log(` ${YELLOW}audit_env_file${RESET} Full security report on any .env file`);
598
- console.log(` ${DIM} Usage: "Audit my .env at ~/myapp/.env"${RESET}`);
599
- console.log("");
600
- console.log(` ${YELLOW}check_gitignore${RESET} Find gaps in your .gitignore before you commit`);
601
- console.log(` ${DIM} Usage: "Check my .gitignore at ~/myapp"${RESET}`);
602
- console.log("");
603
- console.log(` ${YELLOW}explain_detection${RESET} Plain-English explanation of any detected secret type`);
604
- console.log(` ${DIM} Usage: "Explain this detection: stripe_secret_live"${RESET}`);
605
- console.log("");
606
- console.log(` ${YELLOW}generate_env_template${RESET} Generate a safe .env.example for your stack`);
607
- console.log(` ${DIM} Usage: "Generate an env template for Next.js + Stripe"${RESET}`);
608
- console.log("");
609
- console.log(SEP);
610
- console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
611
- console.log(SEP);
612
- console.log(` --setup Auto-configure all your AI tools`);
613
- console.log(` --pro Verify Pro or activate on a new machine`);
614
- console.log(` --remove Remove StreamBlur from all configs`);
615
- console.log(` --version Show version and update status`);
616
- console.log("");
617
- console.log(SEP);
618
- console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
619
- console.log(SEP);
620
- console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
621
- console.log(` Your AI sees the tools and uses them automatically when relevant.`);
622
- console.log("");
623
- console.log(` Try asking:`);
624
- console.log(` "Redact my clipboard before I paste it anywhere"`);
625
- console.log(` "Scan my whole project for any leaked API keys"`);
626
- console.log(` "Audit my .env file and tell me what to rotate"`);
627
- console.log("");
628
- if (showRestartSection) {
560
+ const GREEN = "\x1b[32m";
561
+ const YELLOW = "\x1b[33m";
562
+ const CYAN = "\x1b[36m";
563
+ // Sticker gradient: purple → pink → blue (ANSI 256-color)
564
+ const P1 = "\x1b[38;5;129m"; // deep purple
565
+ const P2 = "\x1b[38;5;135m"; // mid purple
566
+ const P3 = "\x1b[38;5;205m"; // hot pink
567
+ const P4 = "\x1b[38;5;213m"; // light pink
568
+ const P5 = "\x1b[38;5;75m"; // sky blue
569
+ const P6 = "\x1b[38;5;69m"; // deep blue
570
+ // ── Detect terminal width — mobile gets compact layout ────────────────────
571
+ const cols = process.stdout.columns || 80;
572
+ const isMobile = cols < 62;
573
+ if (isMobile) {
574
+ // ── COMPACT MOBILE TUI ────────────────────────────────────────────────
575
+ const SEP = `${DIM} ──────────────────────────${RESET}`;
576
+ const BL = `${P1}${BOLD} ║${RESET}`;
577
+ const BR = `${P6}${BOLD}║${RESET}`;
578
+ const TOP = `${P1}${BOLD} ╔${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P6}╗${RESET}`;
579
+ const BOT = `${P1}${BOLD} ╚${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P6}╝${RESET}`;
580
+ console.log("");
581
+ console.log(TOP);
582
+ console.log(`${BL}${P1}${BOLD} ▶ ${P2}S${P3}T${P4}R${P3}E${P2}A${P1}M${P2}B${P3}L${P4}U${P3}R${P2} ${P4}P${P3}R${P2}O${P5} ${P6}◀${RESET} ${BR}`);
583
+ console.log(`${BL}${P1}░${P2}▒${P3}▓${P4}█${P3}▶${P2} ${P1}A${P2}I ${P3}S${P4}e${P3}c${P2}r${P1}e${P2}t${P3} ${P4}S${P3}c${P2}a${P1}n${P2}n${P3}e${P4}r ${P3}▶${P2}█${P5}▓${P6}▒${P5}░${RESET} ${BR}`);
584
+ console.log(`${BL}${DIM} v${MCP_VERSION} · Pro Edition ${RESET} ${BR}`);
585
+ console.log(BOT);
586
+ console.log("");
587
+ console.log(` ${GREEN}${BOLD} Pro Active · 9/9 unlocked${RESET}`);
588
+ console.log(` ${DIM}${email}${RESET}`);
589
+ console.log("");
629
590
  console.log(SEP);
630
- console.log(` ${CYAN}${BOLD}TO FINISH - restart your AI tool:${RESET}`);
591
+ console.log(` ${CYAN}${BOLD}FREE TOOLS${RESET}`);
631
592
  console.log(SEP);
632
- const restartInstructions = {
633
- "Claude Code": ` ${CYAN}Claude Code:${RESET} /exit then run: claude (or open a new session)`,
634
- "Cursor": ` ${CYAN}Cursor:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
635
- "Claude Desktop": ` ${CYAN}Claude Desktop:${RESET} Quit from the menu bar, then reopen`,
636
- "Windsurf": ` ${CYAN}Windsurf:${RESET} Close and reopen the window`,
637
- "Zed": ` ${CYAN}Zed:${RESET} Cmd+Q then reopen`,
638
- "VS Code (experimental)": ` ${CYAN}VS Code:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
639
- };
640
- for (const tool of configuredTools) {
641
- const line = restartInstructions[tool];
642
- if (line)
643
- console.log(line);
644
- }
593
+ console.log(` ${GREEN}redact_text${RESET}`);
594
+ console.log(` ${DIM} Redact secrets from any text${RESET}`);
595
+ console.log("");
596
+ console.log(` ${GREEN}scan_text${RESET}`);
597
+ console.log(` ${DIM} Find secrets + show locations${RESET}`);
598
+ console.log("");
599
+ console.log(SEP);
600
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
601
+ console.log(SEP);
602
+ console.log(` ${YELLOW}redact_file${RESET}`);
603
+ console.log(` ${DIM} Redact secrets from any file${RESET}`);
604
+ console.log("");
605
+ console.log(` ${YELLOW}scan_directory${RESET}`);
606
+ console.log(` ${DIM} Scan a full project folder${RESET}`);
607
+ console.log("");
608
+ console.log(` ${YELLOW}scan_repo${RESET}`);
609
+ console.log(` ${DIM} Clone + audit any GitHub repo${RESET}`);
610
+ console.log("");
611
+ console.log(` ${YELLOW}audit_env_file${RESET}`);
612
+ console.log(` ${DIM} Full security report on .env${RESET}`);
613
+ console.log("");
614
+ console.log(` ${YELLOW}check_gitignore${RESET}`);
615
+ console.log(` ${DIM} Find .gitignore gaps${RESET}`);
616
+ console.log("");
617
+ console.log(` ${YELLOW}explain_detection${RESET}`);
618
+ console.log(` ${DIM} Plain-English secret explainer${RESET}`);
619
+ console.log("");
620
+ console.log(` ${YELLOW}generate_env_template${RESET}`);
621
+ console.log(` ${DIM} Generate safe .env.example${RESET}`);
622
+ console.log("");
623
+ console.log(SEP);
624
+ console.log(` ${CYAN}${BOLD}QUICK TEST${RESET}`);
625
+ console.log(SEP);
626
+ console.log(` ${DIM}Ask your AI:${RESET}`);
627
+ console.log(` "Scan this for secrets:`);
628
+ console.log(` OPENAI_API_KEY=sk-proj-test123"`);
629
+ console.log("");
630
+ console.log(` ${DIM}streamblur.com/mcp${RESET}`);
631
+ console.log("");
645
632
  }
646
- console.log("");
647
- console.log(` Then ask your AI: "List your available MCP tools"`);
648
- console.log(` You should see all 9 StreamBlur tools listed.`);
649
- console.log("");
650
- console.log(` Quick test - paste this to your AI:`);
651
- console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
652
- console.log("");
653
- console.log(SEP);
654
- console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
655
- console.log(SEP);
656
- console.log("");
633
+ else {
634
+ // ── FULL WIDE TUI (desktop) ───────────────────────────────────────────
635
+ const SEP = `${DIM} ──────────────────────────────────────────────────────${RESET}`;
636
+ const BL = `${P1}${BOLD} ║${RESET}`;
637
+ const BR = `${P6}${BOLD}║${RESET}`;
638
+ const TOP = `${P1}${BOLD} ╔${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P6}╗${RESET}`;
639
+ const BOT = `${P1}${BOLD} ╚${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P6}╝${RESET}`;
640
+ console.log("");
641
+ console.log(TOP);
642
+ console.log(`${BL}${P1}${BOLD} ███████╗████████╗██████╗ ███████╗ █████╗ ███╗ ███╗ ${BR}`);
643
+ console.log(`${BL}${P2}${BOLD} ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ ${BR}`);
644
+ console.log(`${BL}${P3}${BOLD} ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║ ${BR}`);
645
+ console.log(`${BL}${P4}${BOLD} ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ ${BR}`);
646
+ console.log(`${BL}${P5}${BOLD} ███████║ ██║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ ${BR}`);
647
+ console.log(`${BL}${P6}${BOLD} ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ${BR}`);
648
+ console.log(`${BL}${P1}░${P2}░${P3}▒${P4}▒${P3}▓${P2}▓${P1}█${P2}▶${P3} ${P4}B ${P3}L ${P2}U ${P1}R ${P2} ${P3}▶${P2}█${P1}▓${P2}▓${P3}▒${P4}▒${P3}░${P2}░${P5}░${P6}░${P5}▒${P6}▒${P5}▓${P6}▓${P5}█${P6}▶${P5} ${P6}P${P5}R${P6}O${P5} ${P6}▶${P5}█${P6}▓${P5}▓${P6}▒${P5}▒${P6}░${P5}░ ${BR}`);
649
+ console.log(`${BL}${DIM} ▶ Your AI-Native Secret Scanner · Pro Edition · v${MCP_VERSION} ${BR}`);
650
+ console.log(BOT);
651
+ console.log("");
652
+ console.log("");
653
+ console.log(` ${GREEN}${BOLD}✓ Pro Active · ${email} · 9/9 tools unlocked${RESET}`);
654
+ console.log("");
655
+ console.log(SEP);
656
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
657
+ console.log(SEP);
658
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
659
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
660
+ console.log("");
661
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
662
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
663
+ console.log("");
664
+ console.log(SEP);
665
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
666
+ console.log(SEP);
667
+ console.log(` ${YELLOW}redact_file${RESET} Redact secrets from any file without modifying it`);
668
+ console.log(` ${DIM} Usage: "Redact the file at ~/.env"${RESET}`);
669
+ console.log("");
670
+ console.log(` ${YELLOW}scan_directory${RESET} Scan an entire project folder for leaked secrets`);
671
+ console.log(` ${DIM} Usage: "Scan my project at ~/myapp for secrets"${RESET}`);
672
+ console.log("");
673
+ console.log(` ${YELLOW}scan_repo${RESET} Clone + audit any GitHub repo, then delete the clone`);
674
+ console.log(` ${DIM} Usage: "Scan github.com/user/repo for leaked keys"${RESET}`);
675
+ console.log("");
676
+ console.log(` ${YELLOW}audit_env_file${RESET} Full security report on any .env file`);
677
+ console.log(` ${DIM} Usage: "Audit my .env at ~/myapp/.env"${RESET}`);
678
+ console.log("");
679
+ console.log(` ${YELLOW}check_gitignore${RESET} Find gaps in your .gitignore before you commit`);
680
+ console.log(` ${DIM} Usage: "Check my .gitignore at ~/myapp"${RESET}`);
681
+ console.log("");
682
+ console.log(` ${YELLOW}explain_detection${RESET} Plain-English explanation of any detected secret type`);
683
+ console.log(` ${DIM} Usage: "Explain this detection: stripe_secret_live"${RESET}`);
684
+ console.log("");
685
+ console.log(` ${YELLOW}generate_env_template${RESET} Generate a safe .env.example for your stack`);
686
+ console.log(` ${DIM} Usage: "Generate an env template for Next.js + Stripe"${RESET}`);
687
+ console.log("");
688
+ console.log(SEP);
689
+ console.log(` ${CYAN}${BOLD}COMMANDS${RESET}`);
690
+ console.log(SEP);
691
+ console.log(` --setup Auto-configure all your AI tools`);
692
+ console.log(` --pro Verify Pro or activate on a new machine`);
693
+ console.log(` --remove Remove StreamBlur from all configs`);
694
+ console.log(` --version Show version and update status`);
695
+ console.log("");
696
+ console.log(SEP);
697
+ console.log(` ${CYAN}${BOLD}HOW TO USE${RESET}`);
698
+ console.log(SEP);
699
+ console.log(` Just talk to your AI naturally. StreamBlur works in the background.`);
700
+ console.log(` Your AI sees the tools and uses them automatically when relevant.`);
701
+ console.log("");
702
+ console.log(` Try asking:`);
703
+ console.log(` "Redact my clipboard before I paste it anywhere"`);
704
+ console.log(` "Scan my whole project for any leaked API keys"`);
705
+ console.log(` "Audit my .env file and tell me what to rotate"`);
706
+ console.log("");
707
+ if (showRestartSection) {
708
+ console.log(SEP);
709
+ console.log(` ${CYAN}${BOLD}TO FINISH - restart your AI tool:${RESET}`);
710
+ console.log(SEP);
711
+ const restartInstructions = {
712
+ "Claude Code": ` ${CYAN}Claude Code:${RESET} /exit then run: claude (or open a new session)`,
713
+ "Cursor": ` ${CYAN}Cursor:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
714
+ "Claude Desktop": ` ${CYAN}Claude Desktop:${RESET} Quit from the menu bar, then reopen`,
715
+ "Windsurf": ` ${CYAN}Windsurf:${RESET} Close and reopen the window`,
716
+ "Zed": ` ${CYAN}Zed:${RESET} Cmd+Q then reopen`,
717
+ "VS Code (experimental)": ` ${CYAN}VS Code:${RESET} Cmd+Shift+P - "Developer: Reload Window"`,
718
+ };
719
+ for (const tool of configuredTools) {
720
+ const line = restartInstructions[tool];
721
+ if (line)
722
+ console.log(line);
723
+ }
724
+ }
725
+ console.log("");
726
+ console.log(` Then ask your AI: "List your available MCP tools"`);
727
+ console.log(` You should see all 9 StreamBlur tools listed.`);
728
+ console.log("");
729
+ console.log(` Quick test - paste this to your AI:`);
730
+ console.log(` "Use StreamBlur to scan this for secrets: OPENAI_API_KEY=sk-proj-test123"`);
731
+ console.log("");
732
+ console.log(SEP);
733
+ console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
734
+ console.log(SEP);
735
+ console.log("");
736
+ } // end wide TUI (desktop)
657
737
  }
658
738
  // ─── Free User TUI (after --setup, answered N) ────────────────────────────
659
739
  function showFreeSetupComplete() {
@@ -931,7 +1011,7 @@ async function checkForUpdate(currentVersion) {
931
1011
  }
932
1012
  }
933
1013
  async function showWelcome() {
934
- const CURRENT_VERSION = "1.5.5";
1014
+ const CURRENT_VERSION = "1.5.7";
935
1015
  const licenseKey = process.env.STREAMBLUR_LICENSE_KEY ?? "";
936
1016
  let proStatus = false;
937
1017
  let proCheckFailed = false;
@@ -1331,192 +1411,499 @@ async function runProActivation() {
1331
1411
  <head>
1332
1412
  <meta charset="UTF-8">
1333
1413
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1334
- <title>StreamBlur Pro - Activated</title>
1414
+ <title>StreamBlur Pro Activated</title>
1415
+ <link rel="preconnect" href="https://fonts.googleapis.com">
1416
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
1335
1417
  <style>
1336
- * { margin: 0; padding: 0; box-sizing: border-box; }
1418
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
1419
+
1420
+ :root {
1421
+ --green: #10b981;
1422
+ --green-dim: rgba(16,185,129,0.12);
1423
+ --green-border: rgba(16,185,129,0.25);
1424
+ --blue: #3b82f6;
1425
+ --blue-dim: rgba(59,130,246,0.12);
1426
+ --slate: #0f172a;
1427
+ --slate-800: #1e293b;
1428
+ --slate-700: #334155;
1429
+ --slate-500: #64748b;
1430
+ --slate-400: #94a3b8;
1431
+ --slate-300: #cbd5e1;
1432
+ --white: #ffffff;
1433
+ --mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
1434
+ }
1435
+
1436
+ html { scroll-behavior: smooth; }
1437
+
1337
1438
  body {
1338
- font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
1339
- background: #0f172a;
1340
- color: #e2e8f0;
1439
+ font-family: 'Inter', -apple-system, sans-serif;
1440
+ background: var(--slate);
1441
+ color: var(--slate-300);
1341
1442
  min-height: 100vh;
1342
1443
  display: flex;
1444
+ flex-direction: column;
1343
1445
  align-items: center;
1344
- justify-content: center;
1345
- overflow: hidden;
1446
+ justify-content: flex-start;
1447
+ padding: 3rem 1.5rem 4rem;
1448
+ overflow-x: hidden;
1346
1449
  position: relative;
1347
1450
  }
1451
+
1452
+ /* Background glow */
1348
1453
  .bg-glow {
1349
1454
  position: fixed;
1350
- top: -50%;
1455
+ top: -30%;
1351
1456
  left: 50%;
1352
1457
  transform: translateX(-50%);
1353
- width: 800px;
1354
- height: 600px;
1355
- background: radial-gradient(ellipse at center, rgba(16,185,129,0.12) 0%, transparent 70%);
1458
+ width: 900px;
1459
+ height: 700px;
1460
+ background: radial-gradient(ellipse at center, rgba(16,185,129,0.08) 0%, rgba(59,130,246,0.04) 40%, transparent 70%);
1356
1461
  pointer-events: none;
1462
+ z-index: 0;
1357
1463
  }
1358
- .card {
1464
+
1465
+ /* Floating dots */
1466
+ .dots-container {
1467
+ position: fixed;
1468
+ top: 0; left: 0; right: 0; bottom: 0;
1469
+ pointer-events: none;
1470
+ overflow: hidden;
1471
+ z-index: 0;
1472
+ }
1473
+ .dot-float {
1474
+ position: absolute;
1475
+ background: rgba(59,130,246,0.4);
1476
+ border-radius: 50%;
1477
+ animation: floatUp linear infinite;
1478
+ }
1479
+ @keyframes floatUp {
1480
+ 0% { transform: translateY(100vh) scale(0); opacity: 0; }
1481
+ 10% { opacity: 0.5; }
1482
+ 90% { opacity: 0.5; }
1483
+ 100% { transform: translateY(-10vh) scale(1); opacity: 0; }
1484
+ }
1485
+
1486
+ /* Main wrapper */
1487
+ .wrap {
1359
1488
  position: relative;
1360
1489
  z-index: 1;
1361
- text-align: center;
1362
- padding: 3rem 2.5rem;
1363
- max-width: 480px;
1364
- width: 90%;
1490
+ width: 100%;
1491
+ max-width: 640px;
1492
+ display: flex;
1493
+ flex-direction: column;
1494
+ align-items: center;
1495
+ gap: 0;
1365
1496
  }
1497
+
1498
+ /* Logo */
1366
1499
  .logo {
1367
1500
  display: flex;
1368
1501
  align-items: center;
1369
- justify-content: center;
1370
1502
  gap: 10px;
1371
1503
  margin-bottom: 2.5rem;
1504
+ animation: fadeDown 0.5s ease both;
1372
1505
  }
1506
+ .logo img { border-radius: 10px; }
1507
+ .logo-text { font-size: 1.5rem; font-weight: 900; letter-spacing: -0.02em; }
1508
+ .logo-stream { color: var(--white); }
1509
+ .logo-blur { color: var(--blue); }
1373
1510
 
1374
- .logo-text {
1375
- font-size: 1.5rem;
1376
- font-weight: 900;
1377
- letter-spacing: -0.02em;
1511
+ /* Hero checkmark + headline */
1512
+ .hero {
1513
+ text-align: center;
1514
+ margin-bottom: 2.5rem;
1515
+ animation: fadeDown 0.55s 0.05s ease both;
1378
1516
  }
1379
- .logo-stream { color: #ffffff; }
1380
- .logo-blur { color: #3b82f6; }
1381
1517
  .checkmark-wrap {
1382
- width: 80px;
1383
- height: 80px;
1384
- background: rgba(16,185,129,0.12);
1385
- border: 2px solid rgba(16,185,129,0.3);
1518
+ width: 76px; height: 76px;
1519
+ background: var(--green-dim);
1520
+ border: 2px solid var(--green-border);
1386
1521
  border-radius: 50%;
1387
- display: flex;
1388
- align-items: center;
1389
- justify-content: center;
1390
- margin: 0 auto 1.75rem;
1391
- animation: pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
1522
+ display: flex; align-items: center; justify-content: center;
1523
+ margin: 0 auto 1.5rem;
1524
+ animation: pop 0.45s 0.1s cubic-bezier(0.175,0.885,0.32,1.275) both;
1392
1525
  }
1393
1526
  @keyframes pop {
1394
- 0% { transform: scale(0); opacity: 0; }
1527
+ 0% { transform: scale(0); opacity: 0; }
1395
1528
  100% { transform: scale(1); opacity: 1; }
1396
1529
  }
1397
- .checkmark-wrap svg { width: 36px; height: 36px; }
1530
+ .checkmark-wrap svg { width: 34px; height: 34px; }
1531
+
1398
1532
  h1 {
1399
- font-size: 1.75rem;
1400
- font-weight: 800;
1401
- color: #ffffff;
1402
- margin-bottom: 0.75rem;
1403
- letter-spacing: -0.02em;
1533
+ font-size: clamp(1.6rem, 4vw, 2rem);
1534
+ font-weight: 900;
1535
+ color: var(--white);
1536
+ letter-spacing: -0.03em;
1537
+ margin-bottom: 0.6rem;
1538
+ line-height: 1.15;
1404
1539
  }
1405
- .subtitle {
1406
- color: #94a3b8;
1540
+ .tagline {
1541
+ color: var(--slate-400);
1407
1542
  font-size: 1rem;
1408
- line-height: 1.6;
1543
+ line-height: 1.65;
1544
+ }
1545
+ .tagline strong { color: var(--green); font-weight: 600; }
1546
+
1547
+ /* ── TUI Terminal Card ─────────────────────────────────── */
1548
+ .tui-card {
1549
+ width: 100%;
1550
+ background: #0a0f1a;
1551
+ border: 1px solid rgba(255,255,255,0.08);
1552
+ border-radius: 14px;
1553
+ overflow: hidden;
1409
1554
  margin-bottom: 2rem;
1555
+ box-shadow: 0 24px 64px rgba(0,0,0,0.4);
1556
+ animation: fadeUp 0.6s 0.15s ease both;
1410
1557
  }
1411
- .tools-unlocked {
1412
- background: rgba(16,185,129,0.08);
1413
- border: 1px solid rgba(16,185,129,0.2);
1414
- border-radius: 12px;
1415
- padding: 1.25rem 1.5rem;
1558
+
1559
+ /* Title bar */
1560
+ .tui-bar {
1561
+ display: flex;
1562
+ align-items: center;
1563
+ gap: 0.5rem;
1564
+ padding: 0.75rem 1rem;
1565
+ background: rgba(255,255,255,0.04);
1566
+ border-bottom: 1px solid rgba(255,255,255,0.06);
1567
+ }
1568
+ .tui-dot {
1569
+ width: 12px; height: 12px;
1570
+ border-radius: 50%;
1571
+ flex-shrink: 0;
1572
+ }
1573
+ .tui-dot.red { background: #ff5f57; }
1574
+ .tui-dot.yellow { background: #febc2e; }
1575
+ .tui-dot.green { background: #28c840; }
1576
+ .tui-title {
1577
+ flex: 1;
1578
+ text-align: center;
1579
+ font-size: 0.75rem;
1580
+ color: var(--slate-500);
1581
+ font-family: var(--mono);
1582
+ letter-spacing: 0.03em;
1583
+ }
1584
+
1585
+ /* Terminal body */
1586
+ .tui-body {
1587
+ padding: 1.25rem 1.5rem 1.5rem;
1588
+ font-family: var(--mono);
1589
+ font-size: 0.82rem;
1590
+ line-height: 1.7;
1591
+ min-height: 320px;
1592
+ }
1593
+
1594
+ /* ASCII art banner */
1595
+ .ascii-art {
1596
+ color: var(--blue);
1597
+ font-size: 0.6rem;
1598
+ line-height: 1.2;
1599
+ margin-bottom: 1rem;
1600
+ white-space: pre;
1601
+ opacity: 0;
1602
+ animation: fadeIn 0.3s 0.4s ease forwards;
1603
+ user-select: none;
1604
+ }
1605
+
1606
+ /* Terminal line types */
1607
+ .t-line { display: flex; gap: 0.5rem; margin-bottom: 0.1rem; opacity: 0; }
1608
+ .t-prompt { color: var(--green); flex-shrink: 0; }
1609
+ .t-cmd { color: var(--white); }
1610
+ .t-out { color: var(--slate-400); padding-left: 1.1rem; }
1611
+ .t-hit { color: #f87171; padding-left: 1.1rem; }
1612
+ .t-redact { color: var(--green); padding-left: 1.1rem; font-weight: 700; }
1613
+ .t-ok { color: var(--green); padding-left: 1.1rem; }
1614
+ .t-info { color: #60a5fa; padding-left: 1.1rem; }
1615
+ .t-blank { height: 0.5rem; opacity: 1 !important; }
1616
+ .t-cursor {
1617
+ display: inline-block;
1618
+ width: 8px; height: 1em;
1619
+ background: var(--green);
1620
+ vertical-align: text-bottom;
1621
+ animation: blink 1s step-end infinite;
1622
+ opacity: 0;
1623
+ }
1624
+ @keyframes blink { 0%,100% { opacity:1; } 50% { opacity:0; } }
1625
+
1626
+ /* ── Tools unlocked grid ─────────────────────────────── */
1627
+ .tools-section {
1628
+ width: 100%;
1416
1629
  margin-bottom: 2rem;
1417
- text-align: left;
1630
+ animation: fadeUp 0.6s 0.2s ease both;
1418
1631
  }
1419
- .tools-unlocked p {
1420
- font-size: 0.8rem;
1632
+ .tools-label {
1633
+ font-size: 0.7rem;
1421
1634
  font-weight: 700;
1422
1635
  text-transform: uppercase;
1423
- letter-spacing: 0.08em;
1424
- color: #10b981;
1425
- margin-bottom: 0.75rem;
1636
+ letter-spacing: 0.1em;
1637
+ color: var(--green);
1638
+ margin-bottom: 0.85rem;
1639
+ }
1640
+ .tools-grid {
1641
+ display: grid;
1642
+ grid-template-columns: 1fr 1fr;
1643
+ gap: 0.5rem;
1426
1644
  }
1427
- .tool-row {
1645
+ .tool-chip {
1428
1646
  display: flex;
1429
1647
  align-items: center;
1430
1648
  gap: 0.5rem;
1431
- font-size: 0.875rem;
1432
- color: #cbd5e1;
1433
- margin-bottom: 0.4rem;
1649
+ background: rgba(16,185,129,0.06);
1650
+ border: 1px solid rgba(16,185,129,0.15);
1651
+ border-radius: 8px;
1652
+ padding: 0.55rem 0.75rem;
1653
+ font-family: var(--mono);
1654
+ font-size: 0.78rem;
1655
+ color: var(--slate-300);
1434
1656
  }
1435
- .tool-row:last-child { margin-bottom: 0; }
1436
- .dot { width: 6px; height: 6px; background: #10b981; border-radius: 50%; flex-shrink: 0; }
1437
- .terminal-note {
1438
- background: rgba(255,255,255,0.04);
1439
- border: 1px solid rgba(255,255,255,0.08);
1440
- border-radius: 10px;
1441
- padding: 1rem 1.25rem;
1442
- font-size: 0.875rem;
1443
- color: #64748b;
1444
- margin-bottom: 1.5rem;
1657
+ .tool-chip.pro { background: rgba(16,185,129,0.1); border-color: rgba(16,185,129,0.25); }
1658
+ .chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--green); }
1659
+ .chip-badge {
1660
+ margin-left: auto;
1661
+ font-size: 0.58rem;
1662
+ font-weight: 700;
1663
+ text-transform: uppercase;
1664
+ letter-spacing: 0.06em;
1665
+ background: var(--blue);
1666
+ color: #fff;
1667
+ padding: 1px 5px;
1668
+ border-radius: 3px;
1445
1669
  }
1446
- .terminal-note strong { color: #94a3b8; }
1447
- .countdown {
1448
- font-size: 0.8rem;
1449
- color: #475569;
1670
+
1671
+ /* ── Next steps ──────────────────────────────────────── */
1672
+ .steps-section {
1673
+ width: 100%;
1674
+ margin-bottom: 2rem;
1675
+ animation: fadeUp 0.6s 0.25s ease both;
1450
1676
  }
1451
- .countdown span { color: #3b82f6; font-weight: 600; }
1452
- .dots-container {
1453
- position: fixed;
1454
- top: 0; left: 0; right: 0; bottom: 0;
1455
- pointer-events: none;
1456
- overflow: hidden;
1677
+ .steps-label {
1678
+ font-size: 0.7rem;
1679
+ font-weight: 700;
1680
+ text-transform: uppercase;
1681
+ letter-spacing: 0.1em;
1682
+ color: var(--slate-400);
1683
+ margin-bottom: 0.85rem;
1457
1684
  }
1458
- .dot-float {
1459
- position: absolute;
1460
- width: 3px;
1461
- height: 3px;
1462
- background: rgba(59,130,246,0.5);
1685
+ .step-row {
1686
+ display: flex;
1687
+ align-items: flex-start;
1688
+ gap: 0.85rem;
1689
+ padding: 0.75rem 0;
1690
+ border-bottom: 1px solid rgba(255,255,255,0.05);
1691
+ }
1692
+ .step-row:last-child { border-bottom: none; }
1693
+ .step-num {
1694
+ width: 22px; height: 22px;
1463
1695
  border-radius: 50%;
1464
- animation: floatUp linear infinite;
1696
+ background: rgba(255,255,255,0.06);
1697
+ border: 1px solid rgba(255,255,255,0.1);
1698
+ display: flex; align-items: center; justify-content: center;
1699
+ font-size: 0.7rem;
1700
+ font-weight: 700;
1701
+ color: var(--slate-400);
1702
+ flex-shrink: 0;
1703
+ margin-top: 1px;
1465
1704
  }
1466
- @keyframes floatUp {
1467
- 0% { transform: translateY(100vh) scale(0); opacity: 0; }
1468
- 10% { opacity: 0.6; }
1469
- 90% { opacity: 0.6; }
1470
- 100% { transform: translateY(-10vh) scale(1); opacity: 0; }
1705
+ .step-content { flex: 1; }
1706
+ .step-title { font-size: 0.875rem; font-weight: 600; color: var(--white); margin-bottom: 0.2rem; }
1707
+ .step-desc { font-size: 0.8rem; color: var(--slate-500); line-height: 1.5; }
1708
+ .step-code {
1709
+ display: inline-block;
1710
+ background: rgba(255,255,255,0.06);
1711
+ border: 1px solid rgba(255,255,255,0.08);
1712
+ border-radius: 5px;
1713
+ padding: 1px 7px;
1714
+ font-family: var(--mono);
1715
+ font-size: 0.78rem;
1716
+ color: var(--slate-300);
1717
+ margin-top: 0.35rem;
1718
+ }
1719
+
1720
+ /* Countdown */
1721
+ .footer-note {
1722
+ text-align: center;
1723
+ font-size: 0.78rem;
1724
+ color: var(--slate-500);
1725
+ animation: fadeUp 0.6s 0.3s ease both;
1726
+ }
1727
+ .footer-note span { color: var(--blue); font-weight: 600; }
1728
+
1729
+ /* Keyframes */
1730
+ @keyframes fadeDown {
1731
+ from { opacity: 0; transform: translateY(-12px); }
1732
+ to { opacity: 1; transform: translateY(0); }
1733
+ }
1734
+ @keyframes fadeUp {
1735
+ from { opacity: 0; transform: translateY(14px); }
1736
+ to { opacity: 1; transform: translateY(0); }
1737
+ }
1738
+ @keyframes fadeIn {
1739
+ to { opacity: 1; }
1740
+ }
1741
+
1742
+ @media (max-width: 520px) {
1743
+ body { padding: 2rem 1rem 3rem; }
1744
+ .tools-grid { grid-template-columns: 1fr; }
1745
+ .ascii-art { display: none; }
1746
+ .tui-body { font-size: 0.78rem; }
1471
1747
  }
1472
1748
  </style>
1473
1749
  </head>
1474
1750
  <body>
1475
1751
  <div class="bg-glow"></div>
1476
1752
  <div class="dots-container" id="dots"></div>
1477
- <div class="card">
1753
+
1754
+ <div class="wrap">
1755
+
1756
+ <!-- Logo -->
1478
1757
  <div class="logo">
1479
- <img src="https://streamblur.com/assets/logo.png" alt="StreamBlur" width="40" height="40" style="border-radius:10px;">
1758
+ <img src="https://streamblur.com/assets/logo.png" alt="StreamBlur" width="36" height="36">
1480
1759
  <span class="logo-text"><span class="logo-stream">Stream</span><span class="logo-blur">Blur</span></span>
1481
1760
  </div>
1482
1761
 
1483
- <div class="checkmark-wrap">
1484
- <svg viewBox="0 0 36 36" fill="none" stroke="#10b981" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
1485
- <path d="M7 18l7 7L29 11"/>
1486
- </svg>
1762
+ <!-- Hero -->
1763
+ <div class="hero">
1764
+ <div class="checkmark-wrap">
1765
+ <svg viewBox="0 0 36 36" fill="none" stroke="#10b981" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round">
1766
+ <path d="M7 18l7 7L29 11"/>
1767
+ </svg>
1768
+ </div>
1769
+ <h1>You're in. Pro is active.</h1>
1770
+ <p class="tagline">Your AI security toolkit is fully unlocked.<br><strong>9 tools</strong> are now ready in Claude, Cursor, Windsurf, and Zed.</p>
1771
+ </div>
1772
+
1773
+ <!-- TUI Terminal Demo -->
1774
+ <div class="tui-card">
1775
+ <div class="tui-bar">
1776
+ <div class="tui-dot red"></div>
1777
+ <div class="tui-dot yellow"></div>
1778
+ <div class="tui-dot green"></div>
1779
+ <span class="tui-title">streamblur — zsh — 80x24</span>
1780
+ </div>
1781
+ <div class="tui-body" id="tuiBody">
1782
+ <pre class="ascii-art"> ____ _ ____ _
1783
+ / ___|| |_ _ __ ___ __ _ _ __ ___ | __ )| |_ _ _ __
1784
+ \\___ \\| __| '__/ _ \\/ _\` | '_ \` _ \\| _ \\| | | | | '__|
1785
+ ___) | |_| | | __/ (_| | | | | | | |_) | | |_| | |
1786
+ |____/ \\__|_| \\___|\\__,_|_| |_| |_|____/|_|\\__,_|_| v1.5.6</pre>
1787
+ <div id="tLines"></div>
1788
+ </div>
1487
1789
  </div>
1488
1790
 
1489
- <h1>You're in. Pro is active.</h1>
1490
- <p class="subtitle">Your AI security toolkit is fully unlocked.<br>All 9 tools are ready to use.</p>
1791
+ <!-- Tools grid -->
1792
+ <div class="tools-section">
1793
+ <div class="tools-label">9 tools unlocked</div>
1794
+ <div class="tools-grid">
1795
+ <div class="tool-chip"><div class="chip-dot"></div>scan_text</div>
1796
+ <div class="tool-chip"><div class="chip-dot"></div>redact_text</div>
1797
+ <div class="tool-chip pro"><div class="chip-dot"></div>redact_file <span class="chip-badge">Pro</span></div>
1798
+ <div class="tool-chip pro"><div class="chip-dot"></div>scan_directory <span class="chip-badge">Pro</span></div>
1799
+ <div class="tool-chip pro"><div class="chip-dot"></div>scan_repo <span class="chip-badge">Pro</span></div>
1800
+ <div class="tool-chip pro"><div class="chip-dot"></div>audit_env_file <span class="chip-badge">Pro</span></div>
1801
+ <div class="tool-chip pro"><div class="chip-dot"></div>check_gitignore <span class="chip-badge">Pro</span></div>
1802
+ <div class="tool-chip pro"><div class="chip-dot"></div>explain_detection <span class="chip-badge">Pro</span></div>
1803
+ <div class="tool-chip pro" style="grid-column:1/-1;"><div class="chip-dot"></div>generate_env_template <span class="chip-badge">Pro</span></div>
1804
+ </div>
1805
+ </div>
1491
1806
 
1492
- <div class="tools-unlocked">
1493
- <p>9 tools unlocked</p>
1494
- <div class="tool-row"><div class="dot"></div>redact_text · scan_text (free)</div>
1495
- <div class="tool-row"><div class="dot"></div>redact_file · scan_directory · scan_repo</div>
1496
- <div class="tool-row"><div class="dot"></div>audit_env_file · check_gitignore</div>
1497
- <div class="tool-row"><div class="dot"></div>explain_detection · generate_env_template</div>
1807
+ <!-- Next steps -->
1808
+ <div class="steps-section">
1809
+ <div class="steps-label">What happens next</div>
1810
+ <div class="step-row">
1811
+ <div class="step-num">1</div>
1812
+ <div class="step-content">
1813
+ <div class="step-title">Return to your terminal</div>
1814
+ <div class="step-desc">Pro is now active on this machine. Your terminal will confirm with a green checkmark.</div>
1815
+ </div>
1816
+ </div>
1817
+ <div class="step-row">
1818
+ <div class="step-num">2</div>
1819
+ <div class="step-content">
1820
+ <div class="step-title">Restart your AI tool</div>
1821
+ <div class="step-desc">Restart Claude Code, Claude Desktop, Cursor, or Windsurf to load all 9 tools.</div>
1822
+ </div>
1823
+ </div>
1824
+ <div class="step-row">
1825
+ <div class="step-num">3</div>
1826
+ <div class="step-content">
1827
+ <div class="step-title">Try a directory scan</div>
1828
+ <div class="step-desc">Ask your AI: <em>"scan my project for leaked secrets"</em></div>
1829
+ <code class="step-code">use streamblur to scan_directory /your/project</code>
1830
+ </div>
1831
+ </div>
1832
+ <div class="step-row">
1833
+ <div class="step-num">4</div>
1834
+ <div class="step-content">
1835
+ <div class="step-title">Other machines</div>
1836
+ <div class="step-desc">Run setup on any other machine and sign in with the same email to activate Pro there too.</div>
1837
+ <code class="step-code">npx @streamblur/mcp --setup</code>
1838
+ </div>
1839
+ </div>
1498
1840
  </div>
1499
1841
 
1500
- <div class="terminal-note">
1501
- <strong>Return to your terminal</strong> to see your full tool list and next steps.
1842
+ <!-- Countdown -->
1843
+ <div class="footer-note">
1844
+ <p>This window closes in <span id="sec">30</span>s &mdash; or you can close it now.</p>
1845
+ <p id="close-msg" style="margin-top:0.35rem;"></p>
1502
1846
  </div>
1503
1847
 
1504
- <p class="countdown">This window closes in <span id="sec">30</span>s</p>
1505
- <p class="countdown" id="close-msg" style="margin-top:0.5rem;"></p>
1506
- </div>
1848
+ </div><!-- /wrap -->
1507
1849
 
1508
1850
  <script>
1509
- // Floating dots
1510
- const c = document.getElementById('dots');
1511
- for (let i = 0; i < 12; i++) {
1851
+ (function() {
1852
+ // ── Floating dots
1853
+ const dc = document.getElementById('dots');
1854
+ for (let i = 0; i < 14; i++) {
1512
1855
  const d = document.createElement('div');
1513
1856
  d.className = 'dot-float';
1514
1857
  d.style.left = Math.random() * 100 + '%';
1515
- d.style.animationDuration = (6 + Math.random() * 8) + 's';
1516
- d.style.animationDelay = Math.random() * 6 + 's';
1517
- d.style.width = d.style.height = (2 + Math.random() * 3) + 'px';
1518
- c.appendChild(d);
1858
+ d.style.animationDuration = (7 + Math.random() * 9) + 's';
1859
+ d.style.animationDelay = Math.random() * 7 + 's';
1860
+ const sz = (2 + Math.random() * 3) + 'px';
1861
+ d.style.width = sz; d.style.height = sz;
1862
+ dc.appendChild(d);
1863
+ }
1864
+
1865
+ // ── TUI terminal animation
1866
+ const lines = [
1867
+ { cls: 't-blank' },
1868
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur scan_text "OPENAI_API_KEY=sk-proj-abc123XYZdef456"</span>' },
1869
+ { cls: 't-blank' },
1870
+ { cls: 't-line t-hit', html: ' ⚠ 1 secret detected' },
1871
+ { cls: 't-line t-hit', html: ' ↳ openai_project_key chars 0–38' },
1872
+ { cls: 't-blank' },
1873
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur redact_text "OPENAI_API_KEY=sk-proj-abc123XYZdef456"</span>' },
1874
+ { cls: 't-blank' },
1875
+ { cls: 't-line t-redact', html: ' OPENAI_API_KEY=[REDACTED:openai_project_key]' },
1876
+ { cls: 't-blank' },
1877
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur scan_directory ./my-project</span>' },
1878
+ { cls: 't-blank' },
1879
+ { cls: 't-line t-info', html: ' Scanning 143 files...' },
1880
+ { cls: 't-line t-hit', html: ' ⚠ .env line 3 → env_stripe_key' },
1881
+ { cls: 't-line t-hit', html: ' ⚠ config/db.js line 12 → postgres_url' },
1882
+ { cls: 't-line t-ok', html: ' ✓ 141 files clean' },
1883
+ { cls: 't-blank' },
1884
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> <span class="t-cursor" id="cur"></span></span>' },
1885
+ ];
1886
+
1887
+ const container = document.getElementById('tLines');
1888
+ let i = 0;
1889
+ function nextLine() {
1890
+ if (i >= lines.length) return;
1891
+ const ln = lines[i++];
1892
+ const el = document.createElement('div');
1893
+ el.className = ln.cls;
1894
+ if (ln.html) el.innerHTML = ln.html;
1895
+ container.appendChild(el);
1896
+ // Reveal with tiny delay
1897
+ requestAnimationFrame(() => {
1898
+ requestAnimationFrame(() => { el.style.opacity = '1'; });
1899
+ });
1900
+ const delay = ln.cls === 't-blank' ? 80 :
1901
+ ln.cls.includes('t-line') && ln.html && ln.html.includes('t-cmd') ? 320 : 180;
1902
+ setTimeout(nextLine, delay);
1519
1903
  }
1904
+ // Start after ASCII art fades in
1905
+ setTimeout(nextLine, 900);
1906
+
1520
1907
  // Countdown
1521
1908
  let s = 30;
1522
1909
  const el = document.getElementById('sec');
@@ -1530,6 +1917,7 @@ async function runProActivation() {
1530
1917
  if (el && el.parentElement) el.parentElement.style.display = 'none';
1531
1918
  }
1532
1919
  }, 1000);
1920
+ })();
1533
1921
  </script>
1534
1922
  </body>
1535
1923
  </html>`;
@@ -1651,7 +2039,7 @@ async function main() {
1651
2039
  const args = process.argv.slice(2);
1652
2040
  // --version flag
1653
2041
  if (args.includes("--version")) {
1654
- const CURRENT_VERSION = "1.5.5";
2042
+ const CURRENT_VERSION = "1.5.7";
1655
2043
  const GREEN = "\x1b[32m";
1656
2044
  const DIM = "\x1b[2m";
1657
2045
  const RESET = "\x1b[0m";