@syke1/mcp-server 1.8.7 → 1.8.9

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.
@@ -1,5 +1,6 @@
1
1
  export interface LicenseStatus {
2
2
  plan: "free" | "pro" | "pro_trial" | "cortex";
3
+ billingPeriod?: "monthly" | "annual";
3
4
  email?: string;
4
5
  expiresAt?: string;
5
6
  source: "online" | "cache" | "default";
@@ -256,6 +256,13 @@ function mapPlan(serverPlan) {
256
256
  return "cortex";
257
257
  return "pro"; // pro_monthly, pro_annual, pro_founding, master, etc.
258
258
  }
259
+ function extractBillingPeriod(serverPlan) {
260
+ if (serverPlan.endsWith("_annual"))
261
+ return "annual";
262
+ if (serverPlan.endsWith("_monthly"))
263
+ return "monthly";
264
+ return undefined;
265
+ }
259
266
  /**
260
267
  * Main license validation — called on MCP server startup
261
268
  */
@@ -274,6 +281,7 @@ async function checkLicense() {
274
281
  const cachedPlan = mapPlan(cache.plan || "");
275
282
  return {
276
283
  plan: cachedPlan,
284
+ billingPeriod: extractBillingPeriod(cache.plan || ""),
277
285
  email: cache.email,
278
286
  expiresAt: cache.expiresAt,
279
287
  source: "cache",
@@ -299,6 +307,7 @@ async function checkLicense() {
299
307
  const foundingPlan = mapPlan(result.plan || "");
300
308
  return {
301
309
  plan: foundingPlan,
310
+ billingPeriod: extractBillingPeriod(result.plan || ""),
302
311
  email: result.email,
303
312
  expiresAt: result.expiresAt,
304
313
  source: "online",
@@ -323,6 +332,7 @@ async function checkLicense() {
323
332
  const onlinePlan = mapPlan(result.plan || "");
324
333
  return {
325
334
  plan: onlinePlan,
335
+ billingPeriod: extractBillingPeriod(result.plan || ""),
326
336
  email: result.email,
327
337
  expiresAt: result.expiresAt,
328
338
  source: "online",
@@ -344,6 +354,7 @@ async function checkLicense() {
344
354
  const gracePlan = mapPlan(cache.plan || "");
345
355
  return {
346
356
  plan: gracePlan,
357
+ billingPeriod: extractBillingPeriod(cache.plan || ""),
347
358
  email: cache.email,
348
359
  expiresAt: cache.expiresAt,
349
360
  source: "cache",
@@ -464,6 +464,7 @@ document.addEventListener("DOMContentLoaded", async () => {
464
464
  setupSettings();
465
465
  setupProjectModal();
466
466
  setupLicenseModal();
467
+ setupUpgradeModal();
467
468
  setupAIKeysModal();
468
469
  setupAIProviderSelector();
469
470
  setupFileTree();
@@ -2099,21 +2100,33 @@ function setupEventListeners() {
2099
2100
  const modal = document.getElementById("cortex-modal");
2100
2101
  const planInfo = document.getElementById("cortex-plan-info");
2101
2102
  const upgradeLink = document.getElementById("cortex-upgrade-link");
2103
+ const priceNote = document.querySelector(".cortex-price-note");
2102
2104
  const plan = _currentPlan.toLowerCase();
2105
+ const billing = _billingPeriod; // "monthly" | "annual" | null
2103
2106
 
2104
2107
  if (plan === "cortex" || plan === "cortex_trial") {
2105
- // Already on Cortex — trigger scan_project via MCP (show coming-soon notice for now)
2106
2108
  alert("Onboarding document generation is coming in the next update. Stay tuned!");
2107
2109
  return;
2108
2110
  }
2109
2111
 
2110
- // Show modal with plan-specific messaging
2112
+ // Show modal with plan-specific pricing
2111
2113
  if (plan === "pro" || plan === "pro_trial") {
2112
- planInfo.textContent = "You're on Pro ($9/mo). Upgrade to Cortex for just $20/mo more.";
2113
- upgradeLink.textContent = "UPGRADE TO CORTEX (+$20/mo)";
2114
+ if (billing === "annual") {
2115
+ // Pro Annual $99/yr Cortex Annual $249/yr = +$150/yr
2116
+ planInfo.textContent = "You're on Pro ($99/yr). Upgrade to Cortex for just $150/yr more.";
2117
+ upgradeLink.textContent = "UPGRADE TO CORTEX (+$150/yr)";
2118
+ if (priceNote) priceNote.textContent = "$249/yr · 14-day money-back guarantee";
2119
+ } else {
2120
+ // Pro Monthly $9/mo → Cortex Monthly $29/mo = +$20/mo
2121
+ planInfo.textContent = "You're on Pro ($9/mo). Upgrade to Cortex for just $20/mo more.";
2122
+ upgradeLink.textContent = "UPGRADE TO CORTEX (+$20/mo)";
2123
+ if (priceNote) priceNote.textContent = "$29/mo · $249/yr · 14-day money-back guarantee";
2124
+ }
2114
2125
  } else {
2126
+ // Free → Cortex (full price)
2115
2127
  planInfo.textContent = "You're on the Free plan. Upgrade to Cortex to unlock AI-powered analysis.";
2116
2128
  upgradeLink.textContent = "UPGRADE TO CORTEX";
2129
+ if (priceNote) priceNote.textContent = "$29/mo · $249/yr · 14-day money-back guarantee";
2117
2130
  }
2118
2131
  modal.classList.remove("hidden");
2119
2132
  });
@@ -3646,7 +3659,10 @@ function updateLicenseBadge(plan, expiresAt) {
3646
3659
 
3647
3660
  badge.className = "license-badge";
3648
3661
 
3649
- if (plan === "pro" || plan === "pro_trial") {
3662
+ if (plan === "cortex") {
3663
+ badge.classList.add("cortex");
3664
+ badge.textContent = "CORTEX";
3665
+ } else if (plan === "pro" || plan === "pro_trial") {
3650
3666
  if (expiresAt && new Date(expiresAt) < new Date()) {
3651
3667
  badge.classList.add("expired");
3652
3668
  badge.textContent = "EXPIRED";
@@ -3703,12 +3719,16 @@ function hideServerOffline() {
3703
3719
  }
3704
3720
 
3705
3721
  let _currentPlan = "free"; // track current plan for Cortex modal
3722
+ let _billingPeriod = null; // "monthly" | "annual" | null
3723
+ let _expiresAt = null; // ISO date string for trial/subscription expiry
3706
3724
 
3707
3725
  async function loadProjectInfo() {
3708
3726
  try {
3709
3727
  const res = await fetch("/api/project-info");
3710
3728
  const info = await res.json();
3711
3729
  _currentPlan = info.plan || "free";
3730
+ _billingPeriod = info.billingPeriod || null;
3731
+ _expiresAt = info.expiresAt || null;
3712
3732
  const el = document.getElementById("current-project");
3713
3733
  if (el) {
3714
3734
  const short = info.projectRoot.length > 50
@@ -3727,6 +3747,7 @@ async function loadProjectInfo() {
3727
3747
  hideServerOffline();
3728
3748
  updateLicenseBadge(info.plan, info.expiresAt);
3729
3749
  updateLicenseButton(info.plan);
3750
+ updateUpgradeButton(info.plan);
3730
3751
  // Bottom bar: fetch version from npm registry
3731
3752
  updateBottomBar();
3732
3753
  } catch (e) {
@@ -3963,6 +3984,7 @@ function setupLicenseModal() {
3963
3984
  statusEl.textContent = data.plan === "pro_trial" ? "TRIAL-PRO ACTIVATED" : "PRO ACTIVATED";
3964
3985
  updateLicenseBadge(data.plan, data.expiresAt);
3965
3986
  updateLicenseButton(data.plan);
3987
+ updateUpgradeButton(data.plan);
3966
3988
  setTimeout(closeModal, 1200);
3967
3989
  } else {
3968
3990
  statusEl.className = "error";
@@ -3992,6 +4014,7 @@ function setupLicenseModal() {
3992
4014
  statusEl.textContent = "KEY REMOVED";
3993
4015
  updateLicenseBadge("free", null);
3994
4016
  updateLicenseButton("free");
4017
+ updateUpgradeButton("free");
3995
4018
  setTimeout(closeModal, 800);
3996
4019
  }
3997
4020
  } catch {
@@ -4012,6 +4035,192 @@ function updateLicenseButton(plan) {
4012
4035
  btn.textContent = (plan === "pro" || plan === "pro_trial") ? "LICENSED" : "LICENSE";
4013
4036
  }
4014
4037
 
4038
+ // ══════════════════════════════════════════════════════════════
4039
+ // UPGRADE BUTTON + MODAL
4040
+ // ══════════════════════════════════════════════════════════════
4041
+ function updateUpgradeButton(plan) {
4042
+ const btn = document.getElementById("btn-upgrade");
4043
+ if (!btn) return;
4044
+
4045
+ const p = (plan || "free").toLowerCase();
4046
+
4047
+ if (p === "cortex" || p === "cortex_trial") {
4048
+ // Cortex users: hide upgrade button
4049
+ btn.classList.add("hidden");
4050
+ btn.className = "top-btn upgrade-btn hidden";
4051
+ } else if (p === "pro" || p === "pro_trial") {
4052
+ // Pro users: show "CORTEX" button (magenta)
4053
+ btn.classList.remove("hidden");
4054
+ btn.className = "top-btn upgrade-btn upgrade-cortex";
4055
+ btn.innerHTML = "&#8594; CORTEX";
4056
+ } else {
4057
+ // Free / Trial: show "UPGRADE" with pulse
4058
+ btn.classList.remove("hidden");
4059
+ btn.className = "top-btn upgrade-btn upgrade-pulse";
4060
+ btn.innerHTML = "UPGRADE &#8593;";
4061
+ }
4062
+
4063
+ // Update trial badge with days left
4064
+ updateTrialBadge(p);
4065
+ }
4066
+
4067
+ function updateTrialBadge(plan) {
4068
+ const badge = document.getElementById("license-badge");
4069
+ if (!badge) return;
4070
+
4071
+ if ((plan === "pro_trial" || plan === "trial") && _expiresAt) {
4072
+ const now = new Date();
4073
+ const exp = new Date(_expiresAt);
4074
+ const daysLeft = Math.max(0, Math.ceil((exp - now) / (1000 * 60 * 60 * 24)));
4075
+ badge.textContent = "TRIAL \u00B7 " + daysLeft + "d left";
4076
+ badge.className = "license-badge trial-days";
4077
+ }
4078
+ }
4079
+
4080
+ function openUpgradeModal() {
4081
+ const modal = document.getElementById("upgrade-modal");
4082
+ const title = document.getElementById("upgrade-modal-title");
4083
+ const proCard = document.getElementById("upgrade-card-pro");
4084
+ const cortexCard = document.getElementById("upgrade-card-cortex");
4085
+ const cardsContainer = document.getElementById("upgrade-cards");
4086
+ const currentPlanEl = document.getElementById("upgrade-current-plan");
4087
+ const cortexPrice = document.getElementById("cortex-monthly-price");
4088
+
4089
+ if (!modal) return;
4090
+
4091
+ const plan = (_currentPlan || "free").toLowerCase();
4092
+ const billing = _billingPeriod;
4093
+
4094
+ // Reset layout
4095
+ cardsContainer.classList.remove("cortex-only");
4096
+
4097
+ if (plan === "pro" || plan === "pro_trial") {
4098
+ // Pro user -> show only Cortex card with upgrade pricing
4099
+ title.textContent = "UPGRADE TO CORTEX";
4100
+ proCard.style.display = "none";
4101
+ cortexCard.style.display = "";
4102
+ cardsContainer.classList.add("cortex-only");
4103
+
4104
+ // Show upgrade price note
4105
+ if (billing === "annual") {
4106
+ cortexPrice.innerHTML = '$29<span class="upgrade-price-unit">/mo</span> <span class="upgrade-pro-note">(+$150/yr upgrade)</span>';
4107
+ } else {
4108
+ cortexPrice.innerHTML = '$29<span class="upgrade-price-unit">/mo</span> <span class="upgrade-pro-note">(+$20/mo upgrade)</span>';
4109
+ }
4110
+
4111
+ const planLabel = plan === "pro_trial" ? "TRIAL-PRO" : "PRO";
4112
+ currentPlanEl.textContent = "Current: " + planLabel;
4113
+
4114
+ // Update subscribe button labels for Pro users
4115
+ cortexCard.querySelectorAll(".cortex-subscribe").forEach(function(btn) {
4116
+ if (btn.dataset.plan === "cortex_monthly") {
4117
+ btn.textContent = "UPGRADE MONTHLY";
4118
+ } else if (btn.dataset.plan === "cortex_annual") {
4119
+ btn.textContent = "UPGRADE ANNUAL";
4120
+ }
4121
+ });
4122
+ } else {
4123
+ // Free / Trial -> show both cards
4124
+ title.textContent = "UPGRADE YOUR PLAN";
4125
+ proCard.style.display = "";
4126
+ cortexCard.style.display = "";
4127
+
4128
+ // Reset cortex price (no upgrade note)
4129
+ cortexPrice.innerHTML = '$29<span class="upgrade-price-unit">/mo</span>';
4130
+
4131
+ currentPlanEl.textContent = "Current: FREE";
4132
+
4133
+ // Reset subscribe button labels
4134
+ cortexCard.querySelectorAll(".cortex-subscribe").forEach(function(btn) {
4135
+ if (btn.dataset.plan === "cortex_monthly") {
4136
+ btn.textContent = "SUBSCRIBE";
4137
+ } else if (btn.dataset.plan === "cortex_annual") {
4138
+ btn.textContent = "SUBSCRIBE ANNUAL";
4139
+ }
4140
+ });
4141
+ }
4142
+
4143
+ modal.classList.remove("hidden");
4144
+ }
4145
+
4146
+ function closeUpgradeModal() {
4147
+ var modal = document.getElementById("upgrade-modal");
4148
+ if (modal) modal.classList.add("hidden");
4149
+ }
4150
+
4151
+ function setupUpgradeModal() {
4152
+ var upgradeBtn = document.getElementById("btn-upgrade");
4153
+ var closeBtn = document.getElementById("btn-close-upgrade");
4154
+ var footerClose = document.getElementById("btn-upgrade-close");
4155
+ var modal = document.getElementById("upgrade-modal");
4156
+
4157
+ if (!upgradeBtn || !modal) return;
4158
+
4159
+ // Open modal
4160
+ upgradeBtn.addEventListener("click", openUpgradeModal);
4161
+
4162
+ // Close handlers
4163
+ if (closeBtn) closeBtn.addEventListener("click", closeUpgradeModal);
4164
+ if (footerClose) footerClose.addEventListener("click", closeUpgradeModal);
4165
+
4166
+ // Close on backdrop click
4167
+ modal.addEventListener("click", function(e) {
4168
+ if (e.target === modal) closeUpgradeModal();
4169
+ });
4170
+
4171
+ // Subscribe button handlers
4172
+ modal.querySelectorAll(".upgrade-subscribe-btn").forEach(function(btn) {
4173
+ btn.addEventListener("click", function() {
4174
+ var planId = btn.dataset.plan;
4175
+ handleUpgradeSubscribe(planId, btn);
4176
+ });
4177
+ });
4178
+ }
4179
+
4180
+ async function handleUpgradeSubscribe(planId, btn) {
4181
+ var originalText = btn.textContent;
4182
+ btn.textContent = "LOADING...";
4183
+ btn.disabled = true;
4184
+
4185
+ try {
4186
+ var res = await fetch("/api/createPaddleCheckout", {
4187
+ method: "POST",
4188
+ headers: { "Content-Type": "application/json" },
4189
+ body: JSON.stringify({ plan: planId }),
4190
+ });
4191
+
4192
+ var data = await res.json();
4193
+
4194
+ if (data.checkoutUrl) {
4195
+ // Redirect to Paddle checkout
4196
+ window.open(data.checkoutUrl, "_blank");
4197
+ btn.textContent = "OPENED";
4198
+ setTimeout(function() {
4199
+ btn.textContent = originalText;
4200
+ btn.disabled = false;
4201
+ }, 3000);
4202
+ } else if (data.error) {
4203
+ btn.textContent = "ERROR";
4204
+ console.error("[SYKE] Checkout error:", data.error);
4205
+ setTimeout(function() {
4206
+ btn.textContent = originalText;
4207
+ btn.disabled = false;
4208
+ }, 2000);
4209
+ } else {
4210
+ // Fallback: redirect to syke.cloud/dashboard
4211
+ window.open("https://syke.cloud/dashboard/?plan=" + encodeURIComponent(planId), "_blank");
4212
+ btn.textContent = originalText;
4213
+ btn.disabled = false;
4214
+ }
4215
+ } catch (err) {
4216
+ console.warn("[SYKE] Checkout fetch failed, redirecting to dashboard:", err);
4217
+ // Fallback to syke.cloud dashboard
4218
+ window.open("https://syke.cloud/dashboard/?plan=" + encodeURIComponent(planId), "_blank");
4219
+ btn.textContent = originalText;
4220
+ btn.disabled = false;
4221
+ }
4222
+ }
4223
+
4015
4224
  function setupProjectModal() {
4016
4225
  const openBtn = document.getElementById("btn-change-project");
4017
4226
  const modal = document.getElementById("project-modal");
@@ -29,6 +29,7 @@
29
29
  <option value="anthropic">ANTHROPIC</option>
30
30
  </select>
31
31
  <button id="btn-ai-apply" class="top-btn ai-apply-btn">APPLY</button>
32
+ <button id="btn-upgrade" class="top-btn upgrade-btn hidden">UPGRADE &#8593;</button>
32
33
  </div>
33
34
  <div class="project-selector">
34
35
  <span id="current-project" class="project-path">Loading...</span>
@@ -519,6 +520,62 @@
519
520
  </div>
520
521
  </div>
521
522
 
523
+ <!-- Upgrade Modal -->
524
+ <div id="upgrade-modal" class="hidden">
525
+ <div class="upgrade-modal-panel">
526
+ <button id="btn-close-upgrade" class="upgrade-close">&times;</button>
527
+ <h3 class="upgrade-modal-title" id="upgrade-modal-title">UPGRADE YOUR PLAN</h3>
528
+ <div class="upgrade-cards" id="upgrade-cards">
529
+ <!-- PRO Card (shown for free/trial users) -->
530
+ <div class="upgrade-card pro-card" id="upgrade-card-pro">
531
+ <div class="upgrade-card-header pro-header">
532
+ <span class="upgrade-card-name">PRO</span>
533
+ </div>
534
+ <ul class="upgrade-features">
535
+ <li>Unlimited files</li>
536
+ <li>Cycle detection</li>
537
+ <li>Hub file analysis</li>
538
+ <li>Real-time monitoring</li>
539
+ <li>Project switching</li>
540
+ </ul>
541
+ <div class="upgrade-price-row">
542
+ <span class="upgrade-price">$9<span class="upgrade-price-unit">/mo</span></span>
543
+ <button class="upgrade-subscribe-btn pro-subscribe" data-plan="monthly">SUBSCRIBE</button>
544
+ </div>
545
+ <div class="upgrade-price-row annual-row">
546
+ <span class="upgrade-price-annual">$99<span class="upgrade-price-unit">/yr</span> <span class="upgrade-save">Save $9</span></span>
547
+ <button class="upgrade-subscribe-btn pro-subscribe" data-plan="annual">SUBSCRIBE ANNUAL</button>
548
+ </div>
549
+ </div>
550
+ <!-- CORTEX Card (always shown in upgrade modal) -->
551
+ <div class="upgrade-card cortex-card" id="upgrade-card-cortex">
552
+ <div class="upgrade-best-ribbon">BEST</div>
553
+ <div class="upgrade-card-header cortex-header">
554
+ <span class="upgrade-card-name">CORTEX</span>
555
+ </div>
556
+ <ul class="upgrade-features">
557
+ <li>Everything in Pro</li>
558
+ <li>AI-powered analysis</li>
559
+ <li>Onboarding doc generator</li>
560
+ <li>Smart recommendations</li>
561
+ </ul>
562
+ <div class="upgrade-price-row">
563
+ <span class="upgrade-price" id="cortex-monthly-price">$29<span class="upgrade-price-unit">/mo</span></span>
564
+ <button class="upgrade-subscribe-btn cortex-subscribe" data-plan="cortex_monthly">SUBSCRIBE</button>
565
+ </div>
566
+ <div class="upgrade-price-row annual-row">
567
+ <span class="upgrade-price-annual">$249<span class="upgrade-price-unit">/yr</span> <span class="upgrade-save">Save $99</span></span>
568
+ <button class="upgrade-subscribe-btn cortex-subscribe" data-plan="cortex_annual">SUBSCRIBE ANNUAL</button>
569
+ </div>
570
+ </div>
571
+ </div>
572
+ <div class="upgrade-modal-footer">
573
+ <span class="upgrade-current-plan" id="upgrade-current-plan">Current: FREE</span>
574
+ <button id="btn-upgrade-close" class="upgrade-footer-close">CLOSE</button>
575
+ </div>
576
+ </div>
577
+ </div>
578
+
522
579
  <!-- Bottom status bar -->
523
580
  <div id="bottom-bar">
524
581
  <span id="bottom-info">SYKE v--- · ---</span>
@@ -147,6 +147,12 @@ body {
147
147
  text-shadow: 0 0 8px rgba(255,215,0,0.3);
148
148
  }
149
149
 
150
+ .license-badge.cortex {
151
+ color: #e040fb;
152
+ border-color: rgba(224,64,251,0.4);
153
+ text-shadow: 0 0 8px rgba(224,64,251,0.3);
154
+ }
155
+
150
156
  .license-badge.trial {
151
157
  color: var(--risk-medium);
152
158
  border-color: rgba(255,159,10,0.4);
@@ -3555,3 +3561,320 @@ main {
3555
3561
  .set-row-checkbox .set-val {
3556
3562
  display: none;
3557
3563
  }
3564
+
3565
+ /* ═══════════════════════════════════════════ */
3566
+ /* Upgrade Button (Topbar) */
3567
+ /* ═══════════════════════════════════════════ */
3568
+ .upgrade-btn {
3569
+ padding: 4px 14px;
3570
+ font-size: 10px;
3571
+ font-family: inherit;
3572
+ font-weight: 700;
3573
+ letter-spacing: 2px;
3574
+ border-radius: 3px;
3575
+ cursor: pointer;
3576
+ transition: all 0.2s;
3577
+ margin-left: 4px;
3578
+ }
3579
+
3580
+ .upgrade-btn.hidden { display: none; }
3581
+
3582
+ .upgrade-btn.upgrade-pulse {
3583
+ color: #f0c040;
3584
+ border: 1px solid rgba(240,192,64,0.5);
3585
+ background: rgba(240,192,64,0.08);
3586
+ animation: upgrade-pulse-anim 2s ease-in-out infinite;
3587
+ }
3588
+
3589
+ .upgrade-btn.upgrade-pulse:hover {
3590
+ color: #fff;
3591
+ background: rgba(240,192,64,0.2);
3592
+ border-color: #f0c040;
3593
+ box-shadow: 0 0 16px rgba(240,192,64,0.35);
3594
+ }
3595
+
3596
+ .upgrade-btn.upgrade-cortex {
3597
+ color: #e040fb;
3598
+ border: 1px solid rgba(224,64,251,0.5);
3599
+ background: rgba(224,64,251,0.08);
3600
+ }
3601
+
3602
+ .upgrade-btn.upgrade-cortex:hover {
3603
+ color: #fff;
3604
+ background: rgba(224,64,251,0.2);
3605
+ border-color: #e040fb;
3606
+ box-shadow: 0 0 16px rgba(224,64,251,0.35);
3607
+ }
3608
+
3609
+ @keyframes upgrade-pulse-anim {
3610
+ 0%, 100% { box-shadow: 0 0 4px rgba(240,192,64,0.15); }
3611
+ 50% { box-shadow: 0 0 14px rgba(240,192,64,0.4); }
3612
+ }
3613
+
3614
+ /* ═══════════════════════════════════════════ */
3615
+ /* Upgrade Modal */
3616
+ /* ═══════════════════════════════════════════ */
3617
+ #upgrade-modal {
3618
+ position: fixed;
3619
+ inset: 0;
3620
+ z-index: 9000;
3621
+ background: rgba(0, 0, 0, 0.75);
3622
+ backdrop-filter: blur(6px);
3623
+ display: flex;
3624
+ align-items: center;
3625
+ justify-content: center;
3626
+ }
3627
+ #upgrade-modal.hidden { display: none; }
3628
+
3629
+ .upgrade-modal-panel {
3630
+ background: linear-gradient(160deg, #0d1b2a, #0f1d32);
3631
+ border: 1px solid rgba(0,212,255,0.15);
3632
+ border-radius: 12px;
3633
+ padding: 32px 36px 24px;
3634
+ max-width: 700px;
3635
+ width: 94%;
3636
+ position: relative;
3637
+ box-shadow: 0 0 60px rgba(0,0,0,0.6), 0 0 30px rgba(0,212,255,0.08);
3638
+ }
3639
+
3640
+ .upgrade-close {
3641
+ position: absolute;
3642
+ top: 12px;
3643
+ right: 16px;
3644
+ background: none;
3645
+ border: none;
3646
+ color: #556677;
3647
+ font-size: 22px;
3648
+ cursor: pointer;
3649
+ z-index: 1;
3650
+ }
3651
+ .upgrade-close:hover { color: #fff; }
3652
+
3653
+ .upgrade-modal-title {
3654
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3655
+ font-size: 14px;
3656
+ color: var(--accent);
3657
+ letter-spacing: 3px;
3658
+ text-align: center;
3659
+ margin-bottom: 28px;
3660
+ }
3661
+
3662
+ /* Card container */
3663
+ .upgrade-cards {
3664
+ display: flex;
3665
+ gap: 20px;
3666
+ justify-content: center;
3667
+ }
3668
+
3669
+ /* Individual card */
3670
+ .upgrade-card {
3671
+ flex: 1;
3672
+ max-width: 300px;
3673
+ border-radius: 8px;
3674
+ padding: 24px 22px 20px;
3675
+ position: relative;
3676
+ overflow: hidden;
3677
+ }
3678
+
3679
+ .upgrade-card.pro-card {
3680
+ background: rgba(240,192,64,0.04);
3681
+ border: 1px solid rgba(240,192,64,0.2);
3682
+ }
3683
+
3684
+ .upgrade-card.cortex-card {
3685
+ background: rgba(224,64,251,0.04);
3686
+ border: 1px solid rgba(224,64,251,0.25);
3687
+ }
3688
+
3689
+ /* BEST ribbon */
3690
+ .upgrade-best-ribbon {
3691
+ position: absolute;
3692
+ top: 12px;
3693
+ right: -28px;
3694
+ background: linear-gradient(135deg, #e040fb, #7c3aed);
3695
+ color: #fff;
3696
+ font-size: 9px;
3697
+ font-weight: 700;
3698
+ letter-spacing: 2px;
3699
+ padding: 3px 36px;
3700
+ transform: rotate(45deg);
3701
+ box-shadow: 0 2px 8px rgba(224,64,251,0.3);
3702
+ }
3703
+
3704
+ /* Card header */
3705
+ .upgrade-card-header {
3706
+ margin-bottom: 16px;
3707
+ }
3708
+
3709
+ .upgrade-card-name {
3710
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3711
+ font-size: 16px;
3712
+ font-weight: 700;
3713
+ letter-spacing: 3px;
3714
+ }
3715
+
3716
+ .pro-header .upgrade-card-name {
3717
+ color: #f0c040;
3718
+ text-shadow: 0 0 10px rgba(240,192,64,0.3);
3719
+ }
3720
+
3721
+ .cortex-header .upgrade-card-name {
3722
+ color: #e040fb;
3723
+ text-shadow: 0 0 10px rgba(224,64,251,0.3);
3724
+ }
3725
+
3726
+ /* Feature list */
3727
+ .upgrade-features {
3728
+ list-style: none;
3729
+ margin-bottom: 20px;
3730
+ }
3731
+
3732
+ .upgrade-features li {
3733
+ font-size: 11px;
3734
+ color: #8899aa;
3735
+ padding: 4px 0;
3736
+ padding-left: 16px;
3737
+ position: relative;
3738
+ }
3739
+
3740
+ .upgrade-features li::before {
3741
+ content: '\2713';
3742
+ position: absolute;
3743
+ left: 0;
3744
+ color: #30d158;
3745
+ font-size: 10px;
3746
+ }
3747
+
3748
+ /* Price row */
3749
+ .upgrade-price-row {
3750
+ display: flex;
3751
+ align-items: center;
3752
+ justify-content: space-between;
3753
+ margin-bottom: 10px;
3754
+ }
3755
+
3756
+ .upgrade-price-row.annual-row {
3757
+ margin-bottom: 0;
3758
+ }
3759
+
3760
+ .upgrade-price {
3761
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3762
+ font-size: 18px;
3763
+ color: #c8d6e5;
3764
+ font-weight: 700;
3765
+ }
3766
+
3767
+ .upgrade-price-unit {
3768
+ font-size: 11px;
3769
+ color: #5a7599;
3770
+ font-weight: 400;
3771
+ }
3772
+
3773
+ .upgrade-price-annual {
3774
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3775
+ font-size: 13px;
3776
+ color: #8899aa;
3777
+ }
3778
+
3779
+ .upgrade-save {
3780
+ font-size: 10px;
3781
+ color: #30d158;
3782
+ font-weight: 700;
3783
+ margin-left: 4px;
3784
+ }
3785
+
3786
+ /* Subscribe buttons */
3787
+ .upgrade-subscribe-btn {
3788
+ padding: 6px 16px;
3789
+ border-radius: 4px;
3790
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3791
+ font-size: 10px;
3792
+ font-weight: 600;
3793
+ letter-spacing: 1px;
3794
+ cursor: pointer;
3795
+ transition: all 0.2s;
3796
+ white-space: nowrap;
3797
+ }
3798
+
3799
+ .upgrade-subscribe-btn.pro-subscribe {
3800
+ background: rgba(240,192,64,0.12);
3801
+ border: 1px solid rgba(240,192,64,0.4);
3802
+ color: #f0c040;
3803
+ }
3804
+
3805
+ .upgrade-subscribe-btn.pro-subscribe:hover {
3806
+ background: rgba(240,192,64,0.25);
3807
+ border-color: #f0c040;
3808
+ box-shadow: 0 0 12px rgba(240,192,64,0.3);
3809
+ transform: translateY(-1px);
3810
+ }
3811
+
3812
+ .upgrade-subscribe-btn.cortex-subscribe {
3813
+ background: rgba(224,64,251,0.12);
3814
+ border: 1px solid rgba(224,64,251,0.4);
3815
+ color: #e040fb;
3816
+ }
3817
+
3818
+ .upgrade-subscribe-btn.cortex-subscribe:hover {
3819
+ background: rgba(224,64,251,0.25);
3820
+ border-color: #e040fb;
3821
+ box-shadow: 0 0 12px rgba(224,64,251,0.3);
3822
+ transform: translateY(-1px);
3823
+ }
3824
+
3825
+ /* Footer */
3826
+ .upgrade-modal-footer {
3827
+ display: flex;
3828
+ align-items: center;
3829
+ justify-content: space-between;
3830
+ margin-top: 24px;
3831
+ padding-top: 16px;
3832
+ border-top: 1px solid rgba(255,255,255,0.06);
3833
+ }
3834
+
3835
+ .upgrade-current-plan {
3836
+ font-family: 'Consolas', 'JetBrains Mono', monospace;
3837
+ font-size: 11px;
3838
+ color: #5a7599;
3839
+ letter-spacing: 1px;
3840
+ }
3841
+
3842
+ .upgrade-footer-close {
3843
+ padding: 6px 20px;
3844
+ background: transparent;
3845
+ border: 1px solid var(--border);
3846
+ border-radius: 3px;
3847
+ color: var(--text-secondary);
3848
+ font-family: inherit;
3849
+ font-size: 10px;
3850
+ letter-spacing: 2px;
3851
+ cursor: pointer;
3852
+ transition: all 0.2s;
3853
+ }
3854
+
3855
+ .upgrade-footer-close:hover {
3856
+ color: var(--accent);
3857
+ border-color: var(--accent);
3858
+ }
3859
+
3860
+ /* Cortex-only layout (single card, wider) */
3861
+ .upgrade-cards.cortex-only {
3862
+ justify-content: center;
3863
+ }
3864
+
3865
+ .upgrade-cards.cortex-only .upgrade-card {
3866
+ max-width: 380px;
3867
+ }
3868
+
3869
+ /* Pro upgrade note (shown inside cortex card for pro users) */
3870
+ .upgrade-pro-note {
3871
+ font-size: 10px;
3872
+ color: #5a7599;
3873
+ margin-left: 6px;
3874
+ }
3875
+
3876
+ /* Trial badge with days left */
3877
+ .license-badge.trial-days {
3878
+ color: var(--risk-medium);
3879
+ border-color: rgba(255,159,10,0.4);
3880
+ }
@@ -32,6 +32,7 @@ export interface WebServerHandle {
32
32
  }
33
33
  export declare function createWebServer(getGraphFn: () => DependencyGraph, initialFileCache?: FileCache, switchProjectFn?: (newRoot: string) => SwitchProjectResult, getProjectRoot?: () => string, getPackageName?: () => string, getLicenseStatus?: () => {
34
34
  plan: string;
35
+ billingPeriod?: string;
35
36
  expiresAt?: string;
36
37
  error?: string;
37
38
  source?: string;
@@ -833,6 +833,7 @@ function createWebServer(getGraphFn, initialFileCache, switchProjectFn, getProje
833
833
  fileCount: graph.files.size,
834
834
  edgeCount,
835
835
  plan: license?.plan || "free",
836
+ billingPeriod: license?.billingPeriod || null,
836
837
  planSource: license?.source || "default",
837
838
  expiresAt: license?.expiresAt || null,
838
839
  licenseKey: maskedKey,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syke1/mcp-server",
3
- "version": "1.8.7",
3
+ "version": "1.8.9",
4
4
  "mcpName": "io.github.khalomsky/syke",
5
5
  "description": "AI code impact analysis MCP server — dependency graphs, cascade detection, and a mandatory build gate for AI coding agents",
6
6
  "main": "dist/index.js",