@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/src/index.ts CHANGED
@@ -158,7 +158,7 @@ function scanDirectory(dirPath: string, maxFiles = 500): DirectoryScanResult[] {
158
158
  // ─── Server Setup ──────────────────────────────────────────────────────────
159
159
 
160
160
  const server = new Server(
161
- { name: "streamblur-mcp", version: "1.5.5" },
161
+ { name: "streamblur-mcp", version: "1.5.7" },
162
162
  { capabilities: { tools: {} } }
163
163
  );
164
164
 
@@ -567,43 +567,126 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
567
567
 
568
568
  // ─── Pro Welcome TUI ───────────────────────────────────────────────────────
569
569
 
570
+ // Pull version live from package.json — never hardcode it
571
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
572
+ const MCP_VERSION: string = (require("../package.json") as { version: string }).version;
573
+
570
574
  function showProWelcome(email: string, configuredTools: string[], showRestartSection = true): void {
571
- const BLUE = "\x1b[34m";
572
- const CYAN = "\x1b[36m";
573
- const GREEN = "\x1b[32m";
575
+ // ── Core palette ──────────────────────────────────────────────────────────
576
+ const RESET = "\x1b[0m";
577
+ const BOLD = "\x1b[1m";
578
+ const DIM = "\x1b[2m";
579
+ const GREEN = "\x1b[32m";
574
580
  const YELLOW = "\x1b[33m";
575
- const BOLD = "\x1b[1m";
576
- const DIM = "\x1b[2m";
577
- const RESET = "\x1b[0m";
581
+ const CYAN = "\x1b[36m";
582
+
583
+ // Sticker gradient: purple → pink → blue (ANSI 256-color)
584
+ const P1 = "\x1b[38;5;129m"; // deep purple
585
+ const P2 = "\x1b[38;5;135m"; // mid purple
586
+ const P3 = "\x1b[38;5;205m"; // hot pink
587
+ const P4 = "\x1b[38;5;213m"; // light pink
588
+ const P5 = "\x1b[38;5;75m"; // sky blue
589
+ const P6 = "\x1b[38;5;69m"; // deep blue
590
+
591
+ // ── Detect terminal width — mobile gets compact layout ────────────────────
592
+ const cols = process.stdout.columns || 80;
593
+ const isMobile = cols < 62;
594
+
595
+ if (isMobile) {
596
+ // ── COMPACT MOBILE TUI ────────────────────────────────────────────────
597
+ const SEP = `${DIM} ──────────────────────────${RESET}`;
598
+ const BL = `${P1}${BOLD} ║${RESET}`;
599
+ const BR = `${P6}${BOLD}║${RESET}`;
600
+ const TOP = `${P1}${BOLD} ╔${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P6}╗${RESET}`;
601
+ const BOT = `${P1}${BOLD} ╚${P2}══${P3}══${P4}══${P3}══${P2}══${P1}══${P2}══${P3}══${P4}══${P3}══${P6}╝${RESET}`;
578
602
 
579
- const SEP = `${DIM} ------------------------------------------------------${RESET}`;
603
+ console.log("");
604
+ console.log(TOP);
605
+ 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}`);
606
+ 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}`);
607
+ console.log(`${BL}${DIM} v${MCP_VERSION} · Pro Edition ${RESET} ${BR}`);
608
+ console.log(BOT);
609
+ console.log("");
610
+ console.log(` ${GREEN}${BOLD}✓ Pro Active · 9/9 unlocked${RESET}`);
611
+ console.log(` ${DIM}${email}${RESET}`);
612
+ console.log("");
613
+ console.log(SEP);
614
+ console.log(` ${CYAN}${BOLD}FREE TOOLS${RESET}`);
615
+ console.log(SEP);
616
+ console.log(` ${GREEN}redact_text${RESET}`);
617
+ console.log(` ${DIM} Redact secrets from any text${RESET}`);
618
+ console.log("");
619
+ console.log(` ${GREEN}scan_text${RESET}`);
620
+ console.log(` ${DIM} Find secrets + show locations${RESET}`);
621
+ console.log("");
622
+ console.log(SEP);
623
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
624
+ console.log(SEP);
625
+ console.log(` ${YELLOW}redact_file${RESET}`);
626
+ console.log(` ${DIM} Redact secrets from any file${RESET}`);
627
+ console.log("");
628
+ console.log(` ${YELLOW}scan_directory${RESET}`);
629
+ console.log(` ${DIM} Scan a full project folder${RESET}`);
630
+ console.log("");
631
+ console.log(` ${YELLOW}scan_repo${RESET}`);
632
+ console.log(` ${DIM} Clone + audit any GitHub repo${RESET}`);
633
+ console.log("");
634
+ console.log(` ${YELLOW}audit_env_file${RESET}`);
635
+ console.log(` ${DIM} Full security report on .env${RESET}`);
636
+ console.log("");
637
+ console.log(` ${YELLOW}check_gitignore${RESET}`);
638
+ console.log(` ${DIM} Find .gitignore gaps${RESET}`);
639
+ console.log("");
640
+ console.log(` ${YELLOW}explain_detection${RESET}`);
641
+ console.log(` ${DIM} Plain-English secret explainer${RESET}`);
642
+ console.log("");
643
+ console.log(` ${YELLOW}generate_env_template${RESET}`);
644
+ console.log(` ${DIM} Generate safe .env.example${RESET}`);
645
+ console.log("");
646
+ console.log(SEP);
647
+ console.log(` ${CYAN}${BOLD}QUICK TEST${RESET}`);
648
+ console.log(SEP);
649
+ console.log(` ${DIM}Ask your AI:${RESET}`);
650
+ console.log(` "Scan this for secrets:`);
651
+ console.log(` OPENAI_API_KEY=sk-proj-test123"`);
652
+ console.log("");
653
+ console.log(` ${DIM}streamblur.com/mcp${RESET}`);
654
+ console.log("");
580
655
 
581
- const CYAN2 = "\x1b[36m";
582
- console.log("");
583
- console.log(`${BLUE}${BOLD} ╔══════════════════════════════════════════════════════╗${RESET}`);
584
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████╗████████╗██████╗ ███████╗ █████╗ ███╗ ███╗${BLUE}║${RESET}`);
585
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║${BLUE}║${RESET}`);
586
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║${BLUE}║${RESET}`);
587
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║${BLUE}║${RESET}`);
588
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ███████║ ██║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║${BLUE}║${RESET}`);
589
- console.log(`${BLUE}${BOLD} ║${RESET}${BOLD} ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝${BLUE}║${RESET}`);
590
- console.log(`${BLUE}${BOLD} ║${RESET}${CYAN2}${BOLD} B L U R ${BLUE}║${RESET}`);
591
- console.log(`${BLUE}${BOLD} ║${RESET}${DIM} Your AI Security Guard 🛡️ Pro Edition v1.5.5 ${BLUE}${BOLD}║${RESET}`);
592
- console.log(`${BLUE}${BOLD} ╚══════════════════════════════════════════════════════╝${RESET}`);
593
- console.log("");
594
- console.log(` ${GREEN}${BOLD}✓ Pro Active · ${email} · 9/9 tools unlocked${RESET}`);
595
- console.log("");
596
- console.log(SEP);
597
- console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
598
- console.log(SEP);
599
- console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
600
- console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
601
- console.log("");
602
- console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
603
- console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
604
- console.log("");
605
- console.log(SEP);
606
- console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
656
+ } else {
657
+ // ── FULL WIDE TUI (desktop) ───────────────────────────────────────────
658
+ const SEP = `${DIM} ──────────────────────────────────────────────────────${RESET}`;
659
+ const BL = `${P1}${BOLD} ║${RESET}`;
660
+ const BR = `${P6}${BOLD}║${RESET}`;
661
+ 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}`;
662
+ 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}`;
663
+
664
+ console.log("");
665
+ console.log(TOP);
666
+ console.log(`${BL}${P1}${BOLD} ███████╗████████╗██████╗ ███████╗ █████╗ ███╗ ███╗ ${BR}`);
667
+ console.log(`${BL}${P2}${BOLD} ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ ${BR}`);
668
+ console.log(`${BL}${P3}${BOLD} ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║ ${BR}`);
669
+ console.log(`${BL}${P4}${BOLD} ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ ${BR}`);
670
+ console.log(`${BL}${P5}${BOLD} ███████║ ██║ ██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ ${BR}`);
671
+ console.log(`${BL}${P6}${BOLD} ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ${BR}`);
672
+ 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}`);
673
+ console.log(`${BL}${DIM} ▶ Your AI-Native Secret Scanner · Pro Edition · v${MCP_VERSION} ${BR}`);
674
+ console.log(BOT);
675
+ console.log("");
676
+ console.log("");
677
+ console.log(` ${GREEN}${BOLD} Pro Active · ${email} · 9/9 tools unlocked${RESET}`);
678
+ console.log("");
679
+ console.log(SEP);
680
+ console.log(` ${CYAN}${BOLD}FREE TOOLS (always available)${RESET}`);
681
+ console.log(SEP);
682
+ console.log(` ${GREEN}redact_text${RESET} Replace secrets in any text with [REDACTED:type]`);
683
+ console.log(` ${DIM} Usage: "Redact this text: <paste anything>"${RESET}`);
684
+ console.log("");
685
+ console.log(` ${GREEN}scan_text${RESET} Find secrets and show exact locations`);
686
+ console.log(` ${DIM} Usage: "Scan this for secrets: <paste anything>"${RESET}`);
687
+ console.log("");
688
+ console.log(SEP);
689
+ console.log(` ${CYAN}${BOLD}PRO TOOLS · unlocked ✓${RESET}`);
607
690
  console.log(SEP);
608
691
  console.log(` ${YELLOW}redact_file${RESET} Redact secrets from any file without modifying it`);
609
692
  console.log(` ${DIM} Usage: "Redact the file at ~/.env"${RESET}`);
@@ -677,6 +760,7 @@ function showProWelcome(email: string, configuredTools: string[], showRestartSec
677
760
  console.log(` ${DIM}Docs: streamblur.com/mcp Support: streamblur.com/support${RESET}`);
678
761
  console.log(SEP);
679
762
  console.log("");
763
+ } // end wide TUI (desktop)
680
764
  }
681
765
 
682
766
  // ─── Free User TUI (after --setup, answered N) ────────────────────────────
@@ -966,7 +1050,7 @@ async function checkForUpdate(currentVersion: string): Promise<string | null> {
966
1050
  }
967
1051
 
968
1052
  async function showWelcome(): Promise<void> {
969
- const CURRENT_VERSION = "1.5.5";
1053
+ const CURRENT_VERSION = "1.5.7";
970
1054
 
971
1055
  const licenseKey = process.env.STREAMBLUR_LICENSE_KEY ?? "";
972
1056
  let proStatus = false;
@@ -1377,192 +1461,499 @@ async function runProActivation(): Promise<void> {
1377
1461
  <head>
1378
1462
  <meta charset="UTF-8">
1379
1463
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1380
- <title>StreamBlur Pro - Activated</title>
1464
+ <title>StreamBlur Pro Activated</title>
1465
+ <link rel="preconnect" href="https://fonts.googleapis.com">
1466
+ <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">
1381
1467
  <style>
1382
- * { margin: 0; padding: 0; box-sizing: border-box; }
1468
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
1469
+
1470
+ :root {
1471
+ --green: #10b981;
1472
+ --green-dim: rgba(16,185,129,0.12);
1473
+ --green-border: rgba(16,185,129,0.25);
1474
+ --blue: #3b82f6;
1475
+ --blue-dim: rgba(59,130,246,0.12);
1476
+ --slate: #0f172a;
1477
+ --slate-800: #1e293b;
1478
+ --slate-700: #334155;
1479
+ --slate-500: #64748b;
1480
+ --slate-400: #94a3b8;
1481
+ --slate-300: #cbd5e1;
1482
+ --white: #ffffff;
1483
+ --mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', monospace;
1484
+ }
1485
+
1486
+ html { scroll-behavior: smooth; }
1487
+
1383
1488
  body {
1384
- font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
1385
- background: #0f172a;
1386
- color: #e2e8f0;
1489
+ font-family: 'Inter', -apple-system, sans-serif;
1490
+ background: var(--slate);
1491
+ color: var(--slate-300);
1387
1492
  min-height: 100vh;
1388
1493
  display: flex;
1494
+ flex-direction: column;
1389
1495
  align-items: center;
1390
- justify-content: center;
1391
- overflow: hidden;
1496
+ justify-content: flex-start;
1497
+ padding: 3rem 1.5rem 4rem;
1498
+ overflow-x: hidden;
1392
1499
  position: relative;
1393
1500
  }
1501
+
1502
+ /* Background glow */
1394
1503
  .bg-glow {
1395
1504
  position: fixed;
1396
- top: -50%;
1505
+ top: -30%;
1397
1506
  left: 50%;
1398
1507
  transform: translateX(-50%);
1399
- width: 800px;
1400
- height: 600px;
1401
- background: radial-gradient(ellipse at center, rgba(16,185,129,0.12) 0%, transparent 70%);
1508
+ width: 900px;
1509
+ height: 700px;
1510
+ background: radial-gradient(ellipse at center, rgba(16,185,129,0.08) 0%, rgba(59,130,246,0.04) 40%, transparent 70%);
1402
1511
  pointer-events: none;
1512
+ z-index: 0;
1403
1513
  }
1404
- .card {
1514
+
1515
+ /* Floating dots */
1516
+ .dots-container {
1517
+ position: fixed;
1518
+ top: 0; left: 0; right: 0; bottom: 0;
1519
+ pointer-events: none;
1520
+ overflow: hidden;
1521
+ z-index: 0;
1522
+ }
1523
+ .dot-float {
1524
+ position: absolute;
1525
+ background: rgba(59,130,246,0.4);
1526
+ border-radius: 50%;
1527
+ animation: floatUp linear infinite;
1528
+ }
1529
+ @keyframes floatUp {
1530
+ 0% { transform: translateY(100vh) scale(0); opacity: 0; }
1531
+ 10% { opacity: 0.5; }
1532
+ 90% { opacity: 0.5; }
1533
+ 100% { transform: translateY(-10vh) scale(1); opacity: 0; }
1534
+ }
1535
+
1536
+ /* Main wrapper */
1537
+ .wrap {
1405
1538
  position: relative;
1406
1539
  z-index: 1;
1407
- text-align: center;
1408
- padding: 3rem 2.5rem;
1409
- max-width: 480px;
1410
- width: 90%;
1540
+ width: 100%;
1541
+ max-width: 640px;
1542
+ display: flex;
1543
+ flex-direction: column;
1544
+ align-items: center;
1545
+ gap: 0;
1411
1546
  }
1547
+
1548
+ /* Logo */
1412
1549
  .logo {
1413
1550
  display: flex;
1414
1551
  align-items: center;
1415
- justify-content: center;
1416
1552
  gap: 10px;
1417
1553
  margin-bottom: 2.5rem;
1554
+ animation: fadeDown 0.5s ease both;
1418
1555
  }
1556
+ .logo img { border-radius: 10px; }
1557
+ .logo-text { font-size: 1.5rem; font-weight: 900; letter-spacing: -0.02em; }
1558
+ .logo-stream { color: var(--white); }
1559
+ .logo-blur { color: var(--blue); }
1419
1560
 
1420
- .logo-text {
1421
- font-size: 1.5rem;
1422
- font-weight: 900;
1423
- letter-spacing: -0.02em;
1561
+ /* Hero checkmark + headline */
1562
+ .hero {
1563
+ text-align: center;
1564
+ margin-bottom: 2.5rem;
1565
+ animation: fadeDown 0.55s 0.05s ease both;
1424
1566
  }
1425
- .logo-stream { color: #ffffff; }
1426
- .logo-blur { color: #3b82f6; }
1427
1567
  .checkmark-wrap {
1428
- width: 80px;
1429
- height: 80px;
1430
- background: rgba(16,185,129,0.12);
1431
- border: 2px solid rgba(16,185,129,0.3);
1568
+ width: 76px; height: 76px;
1569
+ background: var(--green-dim);
1570
+ border: 2px solid var(--green-border);
1432
1571
  border-radius: 50%;
1433
- display: flex;
1434
- align-items: center;
1435
- justify-content: center;
1436
- margin: 0 auto 1.75rem;
1437
- animation: pop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
1572
+ display: flex; align-items: center; justify-content: center;
1573
+ margin: 0 auto 1.5rem;
1574
+ animation: pop 0.45s 0.1s cubic-bezier(0.175,0.885,0.32,1.275) both;
1438
1575
  }
1439
1576
  @keyframes pop {
1440
- 0% { transform: scale(0); opacity: 0; }
1577
+ 0% { transform: scale(0); opacity: 0; }
1441
1578
  100% { transform: scale(1); opacity: 1; }
1442
1579
  }
1443
- .checkmark-wrap svg { width: 36px; height: 36px; }
1580
+ .checkmark-wrap svg { width: 34px; height: 34px; }
1581
+
1444
1582
  h1 {
1445
- font-size: 1.75rem;
1446
- font-weight: 800;
1447
- color: #ffffff;
1448
- margin-bottom: 0.75rem;
1449
- letter-spacing: -0.02em;
1450
- }
1451
- .subtitle {
1452
- color: #94a3b8;
1583
+ font-size: clamp(1.6rem, 4vw, 2rem);
1584
+ font-weight: 900;
1585
+ color: var(--white);
1586
+ letter-spacing: -0.03em;
1587
+ margin-bottom: 0.6rem;
1588
+ line-height: 1.15;
1589
+ }
1590
+ .tagline {
1591
+ color: var(--slate-400);
1453
1592
  font-size: 1rem;
1454
- line-height: 1.6;
1593
+ line-height: 1.65;
1594
+ }
1595
+ .tagline strong { color: var(--green); font-weight: 600; }
1596
+
1597
+ /* ── TUI Terminal Card ─────────────────────────────────── */
1598
+ .tui-card {
1599
+ width: 100%;
1600
+ background: #0a0f1a;
1601
+ border: 1px solid rgba(255,255,255,0.08);
1602
+ border-radius: 14px;
1603
+ overflow: hidden;
1455
1604
  margin-bottom: 2rem;
1605
+ box-shadow: 0 24px 64px rgba(0,0,0,0.4);
1606
+ animation: fadeUp 0.6s 0.15s ease both;
1456
1607
  }
1457
- .tools-unlocked {
1458
- background: rgba(16,185,129,0.08);
1459
- border: 1px solid rgba(16,185,129,0.2);
1460
- border-radius: 12px;
1461
- padding: 1.25rem 1.5rem;
1608
+
1609
+ /* Title bar */
1610
+ .tui-bar {
1611
+ display: flex;
1612
+ align-items: center;
1613
+ gap: 0.5rem;
1614
+ padding: 0.75rem 1rem;
1615
+ background: rgba(255,255,255,0.04);
1616
+ border-bottom: 1px solid rgba(255,255,255,0.06);
1617
+ }
1618
+ .tui-dot {
1619
+ width: 12px; height: 12px;
1620
+ border-radius: 50%;
1621
+ flex-shrink: 0;
1622
+ }
1623
+ .tui-dot.red { background: #ff5f57; }
1624
+ .tui-dot.yellow { background: #febc2e; }
1625
+ .tui-dot.green { background: #28c840; }
1626
+ .tui-title {
1627
+ flex: 1;
1628
+ text-align: center;
1629
+ font-size: 0.75rem;
1630
+ color: var(--slate-500);
1631
+ font-family: var(--mono);
1632
+ letter-spacing: 0.03em;
1633
+ }
1634
+
1635
+ /* Terminal body */
1636
+ .tui-body {
1637
+ padding: 1.25rem 1.5rem 1.5rem;
1638
+ font-family: var(--mono);
1639
+ font-size: 0.82rem;
1640
+ line-height: 1.7;
1641
+ min-height: 320px;
1642
+ }
1643
+
1644
+ /* ASCII art banner */
1645
+ .ascii-art {
1646
+ color: var(--blue);
1647
+ font-size: 0.6rem;
1648
+ line-height: 1.2;
1649
+ margin-bottom: 1rem;
1650
+ white-space: pre;
1651
+ opacity: 0;
1652
+ animation: fadeIn 0.3s 0.4s ease forwards;
1653
+ user-select: none;
1654
+ }
1655
+
1656
+ /* Terminal line types */
1657
+ .t-line { display: flex; gap: 0.5rem; margin-bottom: 0.1rem; opacity: 0; }
1658
+ .t-prompt { color: var(--green); flex-shrink: 0; }
1659
+ .t-cmd { color: var(--white); }
1660
+ .t-out { color: var(--slate-400); padding-left: 1.1rem; }
1661
+ .t-hit { color: #f87171; padding-left: 1.1rem; }
1662
+ .t-redact { color: var(--green); padding-left: 1.1rem; font-weight: 700; }
1663
+ .t-ok { color: var(--green); padding-left: 1.1rem; }
1664
+ .t-info { color: #60a5fa; padding-left: 1.1rem; }
1665
+ .t-blank { height: 0.5rem; opacity: 1 !important; }
1666
+ .t-cursor {
1667
+ display: inline-block;
1668
+ width: 8px; height: 1em;
1669
+ background: var(--green);
1670
+ vertical-align: text-bottom;
1671
+ animation: blink 1s step-end infinite;
1672
+ opacity: 0;
1673
+ }
1674
+ @keyframes blink { 0%,100% { opacity:1; } 50% { opacity:0; } }
1675
+
1676
+ /* ── Tools unlocked grid ─────────────────────────────── */
1677
+ .tools-section {
1678
+ width: 100%;
1462
1679
  margin-bottom: 2rem;
1463
- text-align: left;
1680
+ animation: fadeUp 0.6s 0.2s ease both;
1464
1681
  }
1465
- .tools-unlocked p {
1466
- font-size: 0.8rem;
1682
+ .tools-label {
1683
+ font-size: 0.7rem;
1467
1684
  font-weight: 700;
1468
1685
  text-transform: uppercase;
1469
- letter-spacing: 0.08em;
1470
- color: #10b981;
1471
- margin-bottom: 0.75rem;
1686
+ letter-spacing: 0.1em;
1687
+ color: var(--green);
1688
+ margin-bottom: 0.85rem;
1689
+ }
1690
+ .tools-grid {
1691
+ display: grid;
1692
+ grid-template-columns: 1fr 1fr;
1693
+ gap: 0.5rem;
1472
1694
  }
1473
- .tool-row {
1695
+ .tool-chip {
1474
1696
  display: flex;
1475
1697
  align-items: center;
1476
1698
  gap: 0.5rem;
1477
- font-size: 0.875rem;
1478
- color: #cbd5e1;
1479
- margin-bottom: 0.4rem;
1699
+ background: rgba(16,185,129,0.06);
1700
+ border: 1px solid rgba(16,185,129,0.15);
1701
+ border-radius: 8px;
1702
+ padding: 0.55rem 0.75rem;
1703
+ font-family: var(--mono);
1704
+ font-size: 0.78rem;
1705
+ color: var(--slate-300);
1480
1706
  }
1481
- .tool-row:last-child { margin-bottom: 0; }
1482
- .dot { width: 6px; height: 6px; background: #10b981; border-radius: 50%; flex-shrink: 0; }
1483
- .terminal-note {
1484
- background: rgba(255,255,255,0.04);
1485
- border: 1px solid rgba(255,255,255,0.08);
1486
- border-radius: 10px;
1487
- padding: 1rem 1.25rem;
1488
- font-size: 0.875rem;
1489
- color: #64748b;
1490
- margin-bottom: 1.5rem;
1491
- }
1492
- .terminal-note strong { color: #94a3b8; }
1493
- .countdown {
1494
- font-size: 0.8rem;
1495
- color: #475569;
1496
- }
1497
- .countdown span { color: #3b82f6; font-weight: 600; }
1498
- .dots-container {
1499
- position: fixed;
1500
- top: 0; left: 0; right: 0; bottom: 0;
1501
- pointer-events: none;
1502
- overflow: hidden;
1707
+ .tool-chip.pro { background: rgba(16,185,129,0.1); border-color: rgba(16,185,129,0.25); }
1708
+ .chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; background: var(--green); }
1709
+ .chip-badge {
1710
+ margin-left: auto;
1711
+ font-size: 0.58rem;
1712
+ font-weight: 700;
1713
+ text-transform: uppercase;
1714
+ letter-spacing: 0.06em;
1715
+ background: var(--blue);
1716
+ color: #fff;
1717
+ padding: 1px 5px;
1718
+ border-radius: 3px;
1503
1719
  }
1504
- .dot-float {
1505
- position: absolute;
1506
- width: 3px;
1507
- height: 3px;
1508
- background: rgba(59,130,246,0.5);
1720
+
1721
+ /* ── Next steps ──────────────────────────────────────── */
1722
+ .steps-section {
1723
+ width: 100%;
1724
+ margin-bottom: 2rem;
1725
+ animation: fadeUp 0.6s 0.25s ease both;
1726
+ }
1727
+ .steps-label {
1728
+ font-size: 0.7rem;
1729
+ font-weight: 700;
1730
+ text-transform: uppercase;
1731
+ letter-spacing: 0.1em;
1732
+ color: var(--slate-400);
1733
+ margin-bottom: 0.85rem;
1734
+ }
1735
+ .step-row {
1736
+ display: flex;
1737
+ align-items: flex-start;
1738
+ gap: 0.85rem;
1739
+ padding: 0.75rem 0;
1740
+ border-bottom: 1px solid rgba(255,255,255,0.05);
1741
+ }
1742
+ .step-row:last-child { border-bottom: none; }
1743
+ .step-num {
1744
+ width: 22px; height: 22px;
1509
1745
  border-radius: 50%;
1510
- animation: floatUp linear infinite;
1746
+ background: rgba(255,255,255,0.06);
1747
+ border: 1px solid rgba(255,255,255,0.1);
1748
+ display: flex; align-items: center; justify-content: center;
1749
+ font-size: 0.7rem;
1750
+ font-weight: 700;
1751
+ color: var(--slate-400);
1752
+ flex-shrink: 0;
1753
+ margin-top: 1px;
1511
1754
  }
1512
- @keyframes floatUp {
1513
- 0% { transform: translateY(100vh) scale(0); opacity: 0; }
1514
- 10% { opacity: 0.6; }
1515
- 90% { opacity: 0.6; }
1516
- 100% { transform: translateY(-10vh) scale(1); opacity: 0; }
1755
+ .step-content { flex: 1; }
1756
+ .step-title { font-size: 0.875rem; font-weight: 600; color: var(--white); margin-bottom: 0.2rem; }
1757
+ .step-desc { font-size: 0.8rem; color: var(--slate-500); line-height: 1.5; }
1758
+ .step-code {
1759
+ display: inline-block;
1760
+ background: rgba(255,255,255,0.06);
1761
+ border: 1px solid rgba(255,255,255,0.08);
1762
+ border-radius: 5px;
1763
+ padding: 1px 7px;
1764
+ font-family: var(--mono);
1765
+ font-size: 0.78rem;
1766
+ color: var(--slate-300);
1767
+ margin-top: 0.35rem;
1768
+ }
1769
+
1770
+ /* Countdown */
1771
+ .footer-note {
1772
+ text-align: center;
1773
+ font-size: 0.78rem;
1774
+ color: var(--slate-500);
1775
+ animation: fadeUp 0.6s 0.3s ease both;
1776
+ }
1777
+ .footer-note span { color: var(--blue); font-weight: 600; }
1778
+
1779
+ /* Keyframes */
1780
+ @keyframes fadeDown {
1781
+ from { opacity: 0; transform: translateY(-12px); }
1782
+ to { opacity: 1; transform: translateY(0); }
1783
+ }
1784
+ @keyframes fadeUp {
1785
+ from { opacity: 0; transform: translateY(14px); }
1786
+ to { opacity: 1; transform: translateY(0); }
1787
+ }
1788
+ @keyframes fadeIn {
1789
+ to { opacity: 1; }
1790
+ }
1791
+
1792
+ @media (max-width: 520px) {
1793
+ body { padding: 2rem 1rem 3rem; }
1794
+ .tools-grid { grid-template-columns: 1fr; }
1795
+ .ascii-art { display: none; }
1796
+ .tui-body { font-size: 0.78rem; }
1517
1797
  }
1518
1798
  </style>
1519
1799
  </head>
1520
1800
  <body>
1521
1801
  <div class="bg-glow"></div>
1522
1802
  <div class="dots-container" id="dots"></div>
1523
- <div class="card">
1803
+
1804
+ <div class="wrap">
1805
+
1806
+ <!-- Logo -->
1524
1807
  <div class="logo">
1525
- <img src="https://streamblur.com/assets/logo.png" alt="StreamBlur" width="40" height="40" style="border-radius:10px;">
1808
+ <img src="https://streamblur.com/assets/logo.png" alt="StreamBlur" width="36" height="36">
1526
1809
  <span class="logo-text"><span class="logo-stream">Stream</span><span class="logo-blur">Blur</span></span>
1527
1810
  </div>
1528
1811
 
1529
- <div class="checkmark-wrap">
1530
- <svg viewBox="0 0 36 36" fill="none" stroke="#10b981" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
1531
- <path d="M7 18l7 7L29 11"/>
1532
- </svg>
1812
+ <!-- Hero -->
1813
+ <div class="hero">
1814
+ <div class="checkmark-wrap">
1815
+ <svg viewBox="0 0 36 36" fill="none" stroke="#10b981" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round">
1816
+ <path d="M7 18l7 7L29 11"/>
1817
+ </svg>
1818
+ </div>
1819
+ <h1>You're in. Pro is active.</h1>
1820
+ <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>
1533
1821
  </div>
1534
1822
 
1535
- <h1>You're in. Pro is active.</h1>
1536
- <p class="subtitle">Your AI security toolkit is fully unlocked.<br>All 9 tools are ready to use.</p>
1823
+ <!-- TUI Terminal Demo -->
1824
+ <div class="tui-card">
1825
+ <div class="tui-bar">
1826
+ <div class="tui-dot red"></div>
1827
+ <div class="tui-dot yellow"></div>
1828
+ <div class="tui-dot green"></div>
1829
+ <span class="tui-title">streamblur — zsh — 80x24</span>
1830
+ </div>
1831
+ <div class="tui-body" id="tuiBody">
1832
+ <pre class="ascii-art"> ____ _ ____ _
1833
+ / ___|| |_ _ __ ___ __ _ _ __ ___ | __ )| |_ _ _ __
1834
+ \\___ \\| __| '__/ _ \\/ _\` | '_ \` _ \\| _ \\| | | | | '__|
1835
+ ___) | |_| | | __/ (_| | | | | | | |_) | | |_| | |
1836
+ |____/ \\__|_| \\___|\\__,_|_| |_| |_|____/|_|\\__,_|_| v1.5.6</pre>
1837
+ <div id="tLines"></div>
1838
+ </div>
1839
+ </div>
1537
1840
 
1538
- <div class="tools-unlocked">
1539
- <p>9 tools unlocked</p>
1540
- <div class="tool-row"><div class="dot"></div>redact_text · scan_text (free)</div>
1541
- <div class="tool-row"><div class="dot"></div>redact_file · scan_directory · scan_repo</div>
1542
- <div class="tool-row"><div class="dot"></div>audit_env_file · check_gitignore</div>
1543
- <div class="tool-row"><div class="dot"></div>explain_detection · generate_env_template</div>
1841
+ <!-- Tools grid -->
1842
+ <div class="tools-section">
1843
+ <div class="tools-label">9 tools unlocked</div>
1844
+ <div class="tools-grid">
1845
+ <div class="tool-chip"><div class="chip-dot"></div>scan_text</div>
1846
+ <div class="tool-chip"><div class="chip-dot"></div>redact_text</div>
1847
+ <div class="tool-chip pro"><div class="chip-dot"></div>redact_file <span class="chip-badge">Pro</span></div>
1848
+ <div class="tool-chip pro"><div class="chip-dot"></div>scan_directory <span class="chip-badge">Pro</span></div>
1849
+ <div class="tool-chip pro"><div class="chip-dot"></div>scan_repo <span class="chip-badge">Pro</span></div>
1850
+ <div class="tool-chip pro"><div class="chip-dot"></div>audit_env_file <span class="chip-badge">Pro</span></div>
1851
+ <div class="tool-chip pro"><div class="chip-dot"></div>check_gitignore <span class="chip-badge">Pro</span></div>
1852
+ <div class="tool-chip pro"><div class="chip-dot"></div>explain_detection <span class="chip-badge">Pro</span></div>
1853
+ <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>
1854
+ </div>
1544
1855
  </div>
1545
1856
 
1546
- <div class="terminal-note">
1547
- <strong>Return to your terminal</strong> to see your full tool list and next steps.
1857
+ <!-- Next steps -->
1858
+ <div class="steps-section">
1859
+ <div class="steps-label">What happens next</div>
1860
+ <div class="step-row">
1861
+ <div class="step-num">1</div>
1862
+ <div class="step-content">
1863
+ <div class="step-title">Return to your terminal</div>
1864
+ <div class="step-desc">Pro is now active on this machine. Your terminal will confirm with a green checkmark.</div>
1865
+ </div>
1866
+ </div>
1867
+ <div class="step-row">
1868
+ <div class="step-num">2</div>
1869
+ <div class="step-content">
1870
+ <div class="step-title">Restart your AI tool</div>
1871
+ <div class="step-desc">Restart Claude Code, Claude Desktop, Cursor, or Windsurf to load all 9 tools.</div>
1872
+ </div>
1873
+ </div>
1874
+ <div class="step-row">
1875
+ <div class="step-num">3</div>
1876
+ <div class="step-content">
1877
+ <div class="step-title">Try a directory scan</div>
1878
+ <div class="step-desc">Ask your AI: <em>"scan my project for leaked secrets"</em></div>
1879
+ <code class="step-code">use streamblur to scan_directory /your/project</code>
1880
+ </div>
1881
+ </div>
1882
+ <div class="step-row">
1883
+ <div class="step-num">4</div>
1884
+ <div class="step-content">
1885
+ <div class="step-title">Other machines</div>
1886
+ <div class="step-desc">Run setup on any other machine and sign in with the same email to activate Pro there too.</div>
1887
+ <code class="step-code">npx @streamblur/mcp --setup</code>
1888
+ </div>
1889
+ </div>
1548
1890
  </div>
1549
1891
 
1550
- <p class="countdown">This window closes in <span id="sec">30</span>s</p>
1551
- <p class="countdown" id="close-msg" style="margin-top:0.5rem;"></p>
1552
- </div>
1892
+ <!-- Countdown -->
1893
+ <div class="footer-note">
1894
+ <p>This window closes in <span id="sec">30</span>s &mdash; or you can close it now.</p>
1895
+ <p id="close-msg" style="margin-top:0.35rem;"></p>
1896
+ </div>
1897
+
1898
+ </div><!-- /wrap -->
1553
1899
 
1554
1900
  <script>
1555
- // Floating dots
1556
- const c = document.getElementById('dots');
1557
- for (let i = 0; i < 12; i++) {
1901
+ (function() {
1902
+ // ── Floating dots
1903
+ const dc = document.getElementById('dots');
1904
+ for (let i = 0; i < 14; i++) {
1558
1905
  const d = document.createElement('div');
1559
1906
  d.className = 'dot-float';
1560
1907
  d.style.left = Math.random() * 100 + '%';
1561
- d.style.animationDuration = (6 + Math.random() * 8) + 's';
1562
- d.style.animationDelay = Math.random() * 6 + 's';
1563
- d.style.width = d.style.height = (2 + Math.random() * 3) + 'px';
1564
- c.appendChild(d);
1908
+ d.style.animationDuration = (7 + Math.random() * 9) + 's';
1909
+ d.style.animationDelay = Math.random() * 7 + 's';
1910
+ const sz = (2 + Math.random() * 3) + 'px';
1911
+ d.style.width = sz; d.style.height = sz;
1912
+ dc.appendChild(d);
1913
+ }
1914
+
1915
+ // ── TUI terminal animation
1916
+ const lines = [
1917
+ { cls: 't-blank' },
1918
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur scan_text "OPENAI_API_KEY=sk-proj-abc123XYZdef456"</span>' },
1919
+ { cls: 't-blank' },
1920
+ { cls: 't-line t-hit', html: ' ⚠ 1 secret detected' },
1921
+ { cls: 't-line t-hit', html: ' ↳ openai_project_key chars 0–38' },
1922
+ { cls: 't-blank' },
1923
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur redact_text "OPENAI_API_KEY=sk-proj-abc123XYZdef456"</span>' },
1924
+ { cls: 't-blank' },
1925
+ { cls: 't-line t-redact', html: ' OPENAI_API_KEY=[REDACTED:openai_project_key]' },
1926
+ { cls: 't-blank' },
1927
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> streamblur scan_directory ./my-project</span>' },
1928
+ { cls: 't-blank' },
1929
+ { cls: 't-line t-info', html: ' Scanning 143 files...' },
1930
+ { cls: 't-line t-hit', html: ' ⚠ .env line 3 → env_stripe_key' },
1931
+ { cls: 't-line t-hit', html: ' ⚠ config/db.js line 12 → postgres_url' },
1932
+ { cls: 't-line t-ok', html: ' ✓ 141 files clean' },
1933
+ { cls: 't-blank' },
1934
+ { cls: 't-line', html: '<span class="t-prompt">$</span><span class="t-cmd"> <span class="t-cursor" id="cur"></span></span>' },
1935
+ ];
1936
+
1937
+ const container = document.getElementById('tLines');
1938
+ let i = 0;
1939
+ function nextLine() {
1940
+ if (i >= lines.length) return;
1941
+ const ln = lines[i++];
1942
+ const el = document.createElement('div');
1943
+ el.className = ln.cls;
1944
+ if (ln.html) el.innerHTML = ln.html;
1945
+ container.appendChild(el);
1946
+ // Reveal with tiny delay
1947
+ requestAnimationFrame(() => {
1948
+ requestAnimationFrame(() => { el.style.opacity = '1'; });
1949
+ });
1950
+ const delay = ln.cls === 't-blank' ? 80 :
1951
+ ln.cls.includes('t-line') && ln.html && ln.html.includes('t-cmd') ? 320 : 180;
1952
+ setTimeout(nextLine, delay);
1565
1953
  }
1954
+ // Start after ASCII art fades in
1955
+ setTimeout(nextLine, 900);
1956
+
1566
1957
  // Countdown
1567
1958
  let s = 30;
1568
1959
  const el = document.getElementById('sec');
@@ -1576,6 +1967,7 @@ async function runProActivation(): Promise<void> {
1576
1967
  if (el && el.parentElement) el.parentElement.style.display = 'none';
1577
1968
  }
1578
1969
  }, 1000);
1970
+ })();
1579
1971
  </script>
1580
1972
  </body>
1581
1973
  </html>`;
@@ -1704,7 +2096,7 @@ async function main(): Promise<void> {
1704
2096
 
1705
2097
  // --version flag
1706
2098
  if (args.includes("--version")) {
1707
- const CURRENT_VERSION = "1.5.5";
2099
+ const CURRENT_VERSION = "1.5.7";
1708
2100
  const GREEN = "\x1b[32m";
1709
2101
  const DIM = "\x1b[2m";
1710
2102
  const RESET = "\x1b[0m";