prism-mcp-server 20.21.12 → 20.21.13

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/README.md CHANGED
@@ -70,6 +70,13 @@ Prism works locally without an account, API key, or cloud subscription. Add a
70
70
  Synalux subscription when you want cloud memory, paid-tier skills, or team
71
71
  features.
72
72
 
73
+ To check your plan, open **⚙ Account & Settings → Account** in the dashboard.
74
+ Free users see **Start 14-day trial**; paid users see **Manage subscription**.
75
+ During a trial, the same panel shows the paid tier and exact end date. No card
76
+ is required to start. Add payment details before the end date to continue; if
77
+ you do not, the subscription cancels and local Prism Free remains available.
78
+ You can also compare plans directly at [synalux.ai/pricing#prism-plans](https://synalux.ai/pricing#prism-plans).
79
+
73
80
  After a few sessions, ask what it's been worth:
74
81
 
75
82
  ```bash
@@ -151,6 +158,17 @@ or by re-enabling after each run.
151
158
  <details>
152
159
  <summary>Release history (optional)</summary>
153
160
 
161
+ ## What's New in v20.21.13
162
+
163
+ ### Paid plans and trials are clear in Account & Settings
164
+
165
+ - Free users can open the Prism plan comparison and start a 14-day trial.
166
+ - Trial users see their paid tier, exact end date, and the action to add payment
167
+ details before automatic cancellation.
168
+ - Active and payment-recovery states lead to the correct hosted billing action;
169
+ an unavailable verification is labeled instead of being presented as paid.
170
+ - Local Prism Free remains available without an account or subscription.
171
+
154
172
  ## What's New in v20.21.12
155
173
 
156
174
  ### Multiple MCP hosts keep a working dashboard link
@@ -1311,7 +1329,11 @@ All on-device models are free to run locally via Ollama on every tier. A subscri
1311
1329
  | Analytics dashboard | -- | ✅ | ✅ | ✅ |
1312
1330
  | HIPAA BAA | -- | -- | -- | ✅ |
1313
1331
 
1314
- 14-day free trial on paid plans. 25+ seats: [contact sales](https://synalux.ai/support)
1332
+ Paid plans start with a 14-day trial. No card is required to start; add payment
1333
+ details before the trial ends to continue, or the subscription cancels
1334
+ automatically and local Prism Free remains available. View the exact deadline
1335
+ under **⚙ Account & Settings → Account** in `prism dashboard`. 25+ seats:
1336
+ [contact sales](https://synalux.ai/support)
1315
1337
 
1316
1338
  ---
1317
1339
 
@@ -6,6 +6,11 @@ import { upgradeInsecureCloudUrl } from "../utils/secureUrl.js";
6
6
  const DEFAULT_PORTAL_URL = "https://synalux.ai";
7
7
  const MAX_BODY_BYTES = 16 * 1024;
8
8
  const VALID_PLANS = new Set(["free", "standard", "advanced", "enterprise"]);
9
+ const VALID_BILLING_STATUSES = new Set([
10
+ "free", "trialing", "active", "past_due", "unpaid", "canceled",
11
+ "incomplete", "incomplete_expired", "paused", "managed", "unknown", "sync_pending",
12
+ ]);
13
+ const VALID_PAID_PLANS = new Set(["standard", "advanced", "enterprise"]);
9
14
  let accountMutationQueue = Promise.resolve();
10
15
  async function serializeAccountMutation(operation) {
11
16
  const previous = accountMutationQueue;
@@ -94,7 +99,10 @@ function signedOutAccount(origin) {
94
99
  name: null,
95
100
  role_key: null,
96
101
  plan: "free",
97
- billing: { action: "upgrade", url: `${origin}/pricing` },
102
+ subscription_plan: null,
103
+ billing_status: "free",
104
+ trial_ends_at: null,
105
+ billing: { action: "upgrade", url: `${origin}/pricing#prism-plans` },
98
106
  auth_url: authUrl(origin),
99
107
  };
100
108
  }
@@ -112,13 +120,28 @@ function normalizeAccount(value, origin) {
112
120
  const url = typeof billingRaw.url === "string" && isAllowedBillingUrl(billingRaw.url, origin)
113
121
  ? billingRaw.url
114
122
  : null;
123
+ const rawBillingStatus = typeof raw.billing_status === "string" && VALID_BILLING_STATUSES.has(raw.billing_status)
124
+ ? raw.billing_status
125
+ : plan === "free" ? "free" : "unknown";
126
+ const subscriptionPlan = typeof raw.subscription_plan === "string" && VALID_PAID_PLANS.has(raw.subscription_plan)
127
+ ? raw.subscription_plan
128
+ : null;
129
+ const billingStatus = rawBillingStatus === "sync_pending" && subscriptionPlan === null
130
+ ? "unknown"
131
+ : rawBillingStatus;
132
+ const trialEndsAt = typeof raw.trial_ends_at === "string" && Number.isFinite(Date.parse(raw.trial_ends_at))
133
+ ? new Date(raw.trial_ends_at).toISOString()
134
+ : null;
115
135
  return {
116
136
  signed_in: raw.signed_in === true,
117
137
  configured: true,
118
138
  name: typeof raw.name === "string" ? raw.name.slice(0, 160) : null,
119
139
  role_key: typeof raw.role_key === "string" ? raw.role_key.slice(0, 80) : null,
120
140
  plan: plan,
141
+ subscription_plan: subscriptionPlan,
121
142
  plan_source: raw.plan_source === "managed" ? "managed" : "stripe",
143
+ billing_status: billingStatus,
144
+ trial_ends_at: billingStatus === "trialing" || billingStatus === "sync_pending" ? trialEndsAt : null,
122
145
  billing: { action, url },
123
146
  auth_url: authUrl(origin),
124
147
  };
@@ -230,7 +253,7 @@ export async function openDashboardBilling(overrides = {}) {
230
253
  const deps = { ...defaultDeps, ...overrides };
231
254
  const origin = await portalOrigin(deps);
232
255
  if (await applyStoredSignOut(deps) || !deps.usablePortalKey()) {
233
- return { url: `${origin}/pricing`, action: "upgrade" };
256
+ return { url: `${origin}/pricing#prism-plans`, action: "upgrade" };
234
257
  }
235
258
  let jwt = await deps.getJwt();
236
259
  if (!jwt || isSynaluxSignedOut())
@@ -449,6 +449,8 @@ export function renderDashboardHTML(version) {
449
449
  .identity-chip .role-icon { font-size: 0.9rem; }
450
450
  .identity-chip .identity-label { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
451
451
  .identity-chip .plan-mini { font-size: 0.58rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-green); }
452
+ .identity-chip .plan-mini.trial { color: var(--accent-amber); }
453
+ .identity-chip .plan-mini.attention { color: #fb7185; }
452
454
  .main-tabs { overflow-x: auto; scrollbar-width: thin; }
453
455
  .main-tabs .s-tab { flex: 0 0 auto; }
454
456
  /* Settings modal tab bar */
@@ -549,6 +551,8 @@ export function renderDashboardHTML(version) {
549
551
  }
550
552
  .account-badge.role { color: var(--accent-cyan); background: rgba(6,182,212,0.1); border-color: rgba(6,182,212,0.22); }
551
553
  .account-badge.managed { color: var(--accent-amber); background: rgba(245,158,11,0.1); border-color: rgba(245,158,11,0.22); }
554
+ .account-badge.trial { color: var(--accent-green); background: rgba(34,197,94,0.1); border-color: rgba(34,197,94,0.3); }
555
+ .account-badge.attention { color: #fb7185; background: rgba(244,63,94,0.1); border-color: rgba(244,63,94,0.3); }
552
556
  .account-name { font-size: 1.35rem; line-height: 1.2; font-weight: 700; color: var(--text-primary); }
553
557
  .account-summary { margin-top: 0.45rem; color: var(--text-secondary); font-size: 0.82rem; line-height: 1.55; max-width: 540px; }
554
558
  .account-actions { display: flex; flex-wrap: wrap; gap: 0.65rem; margin-top: 1rem; }
@@ -2118,6 +2122,49 @@ function accountPlanSummary(plan) {
2118
2122
  };
2119
2123
  return summaries[plan] || summaries.free;
2120
2124
  }
2125
+ function accountTrialEndLabel(value) {
2126
+ if (!value) return '';
2127
+ var date = new Date(value);
2128
+ if (isNaN(date.getTime())) return '';
2129
+ return date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
2130
+ }
2131
+ function accountBillingBadge(account) {
2132
+ if (account.billing_status === 'trialing') return '<span class="account-badge trial">Trial active</span>';
2133
+ if (account.billing_status === 'sync_pending') return '<span class="account-badge attention">Access update pending</span>';
2134
+ if (['past_due', 'unpaid', 'incomplete', 'paused'].indexOf(account.billing_status) >= 0) {
2135
+ return '<span class="account-badge attention">Payment needs attention</span>';
2136
+ }
2137
+ if (account.billing_status === 'unknown') return '<span class="account-badge attention">Billing status unavailable</span>';
2138
+ if (account.billing_status === 'active') return '<span class="account-badge trial">Paid</span>';
2139
+ return '';
2140
+ }
2141
+ function accountSubscriptionSummary(account) {
2142
+ if (account.billing_status === 'trialing') {
2143
+ var end = accountTrialEndLabel(account.trial_ends_at);
2144
+ return accountPlanLabel(account.plan) + ' trial is active' + (end ? ' through ' + end : '') +
2145
+ '. Add payment details before the trial ends to continue; otherwise it cancels automatically.';
2146
+ }
2147
+ if (['past_due', 'unpaid', 'incomplete', 'paused'].indexOf(account.billing_status) >= 0) {
2148
+ var billedPlan = account.subscription_plan
2149
+ ? accountPlanLabel(account.subscription_plan) + ' plan'
2150
+ : account.plan === 'free' ? 'paid subscription' : accountPlanLabel(account.plan) + ' plan';
2151
+ return 'Your ' + billedPlan + ' needs billing attention. Update payment details to restore or keep cloud features active.';
2152
+ }
2153
+ if (account.billing_status === 'sync_pending') {
2154
+ var syncingPlan = accountPlanLabel(account.subscription_plan || account.plan);
2155
+ var syncTrialEnd = accountTrialEndLabel(account.trial_ends_at);
2156
+ return 'Stripe confirms your ' + syncingPlan + ' subscription' +
2157
+ (syncTrialEnd ? ' with a trial through ' + syncTrialEnd : '') +
2158
+ '. Synalux is updating access; current access remains ' + accountPlanLabel(account.plan) + '. Retry shortly or manage the subscription.';
2159
+ }
2160
+ if (account.billing_status === 'canceled' || account.billing_status === 'incomplete_expired') {
2161
+ return 'This paid subscription is no longer active. Local Prism Free remains available.';
2162
+ }
2163
+ if (account.billing_status === 'unknown') {
2164
+ return 'Prism could not verify the current trial or payment status. Open billing to review the subscription; local features remain available.';
2165
+ }
2166
+ return accountPlanSummary(account.plan);
2167
+ }
2121
2168
  function renderPlanLadder(plan) {
2122
2169
  var tiers = [
2123
2170
  ['free', 'Free', 'Local'],
@@ -2132,14 +2179,29 @@ function renderPlanLadder(plan) {
2132
2179
  }
2133
2180
  function renderAccountChip(account, error) {
2134
2181
  var chip = document.getElementById('identityChip');
2182
+ var planStatus;
2183
+ var planStatusClass;
2135
2184
  if (!chip)
2136
2185
  return;
2137
2186
  if (error) {
2138
2187
  chip.innerHTML = '<span class="role-icon">⚠️</span><span class="identity-label">Account</span>';
2139
2188
  }
2140
2189
  else if (account && account.signed_in) {
2190
+ planStatus = account.billing_status === 'sync_pending'
2191
+ ? accountPlanLabel(account.subscription_plan || account.plan) + ' syncing'
2192
+ : account.billing_status === 'trialing' ? ' trial' :
2193
+ ['past_due', 'unpaid', 'incomplete', 'paused'].indexOf(account.billing_status) >= 0
2194
+ ? (account.plan === 'free' ? 'Payment due' : ' payment due') :
2195
+ account.billing_status === 'unknown' ? ' status unavailable' : '';
2196
+ planStatusClass = account.billing_status === 'trialing' ? ' trial' :
2197
+ ['past_due', 'unpaid', 'incomplete', 'paused', 'unknown', 'sync_pending'].indexOf(account.billing_status) >= 0 ? ' attention' : '';
2198
+ var chipPlanLabel = account.billing_status === 'sync_pending'
2199
+ ? planStatus
2200
+ : account.plan === 'free' && planStatus === 'Payment due'
2201
+ ? planStatus
2202
+ : accountPlanLabel(account.plan) + planStatus;
2141
2203
  chip.innerHTML = '<span class="role-icon">🤖</span><span class="identity-label">' + escapeHtml(account.name || 'Synalux user') + '</span>' +
2142
- '<span class="plan-mini">' + escapeHtml(accountPlanLabel(account.plan)) + '</span>';
2204
+ '<span class="plan-mini' + planStatusClass + '">' + escapeHtml(chipPlanLabel) + '</span>';
2143
2205
  }
2144
2206
  else {
2145
2207
  chip.innerHTML = '<span class="role-icon">🆓</span><span class="identity-label">Free</span>';
@@ -2180,14 +2242,17 @@ function renderAccountPanel(account, error) {
2180
2242
  return;
2181
2243
  }
2182
2244
  role = account.role_key || 'user';
2183
- billingLabel = account.billing && account.billing.action === 'manage' ? 'Manage subscription' :
2184
- account.billing && account.billing.action === 'included' ? 'View plans' : 'Upgrade plan';
2245
+ billingLabel = account.billing_status === 'trialing' ? 'Add payment details' :
2246
+ account.billing_status === 'sync_pending' ? 'Manage subscription' :
2247
+ ['past_due', 'unpaid', 'incomplete', 'paused'].indexOf(account.billing_status) >= 0 ? 'Update payment details' :
2248
+ account.billing && account.billing.action === 'manage' ? 'Manage subscription' :
2249
+ account.billing && account.billing.action === 'included' ? 'View plans' : 'Start 14-day trial';
2185
2250
  managedBadge = account.plan_source === 'managed' ? '<span class="account-badge managed">Managed</span>' : '';
2186
2251
  panel.innerHTML = '<div class="account-card"><div class="account-card-head"><div>' +
2187
2252
  '<div class="account-badges"><span class="account-badge">' + escapeHtml(accountPlanLabel(account.plan)) + '</span>' +
2188
- '<span class="account-badge role">' + escapeHtml(role) + '</span>' + managedBadge + '</div>' +
2253
+ '<span class="account-badge role">' + escapeHtml(role) + '</span>' + managedBadge + accountBillingBadge(account) + '</div>' +
2189
2254
  '<div class="account-name">' + escapeHtml(account.name || 'Synalux user') + '</div>' +
2190
- '<div class="account-summary">' + accountPlanSummary(account.plan) + '</div></div></div>' +
2255
+ '<div class="account-summary">' + escapeHtml(accountSubscriptionSummary(account)) + '</div></div></div>' +
2191
2256
  '<div class="account-actions"><button class="account-action" id="accountBillingButton" onclick="openAccountBilling()">' + billingLabel + '</button>' +
2192
2257
  '<button class="account-action danger" id="accountSignOutButton" onclick="signOutAccount()">Sign out</button></div>' +
2193
2258
  '<div class="account-status" id="accountStatus"></div></div>' + renderPlanLadder(account.plan);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "20.21.12",
3
+ "version": "20.21.13",
4
4
  "mcpName": "io.github.dcostenco/prism-coder",
5
5
  "description": "Persistent session memory for AI coding agents that never leaves your machine — including the on-device model that reasons over it. Restores your prior decisions, open TODOs, and changed files across sessions; adds associative recall of related past work, semantic drift detection, and local inference. Local-first by default. Works with Claude Code, Cursor, and Codex.",
6
6
  "module": "index.ts",