snow-flow 10.0.80 → 10.0.82

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.80",
3
+ "version": "10.0.82",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -271,12 +271,22 @@ export namespace Agent {
271
271
  item.permission = PermissionNext.merge(item.permission, PermissionNext.fromConfig(value.permission ?? {}))
272
272
  }
273
273
 
274
- // Unhide review agent for enterprise users
274
+ // Unhide review agent for enterprise users with the code-review module
275
275
  const enterpriseAuth = await Auth.all().then((all) =>
276
276
  Object.values(all).find((e) => e.type === "enterprise" && (e.licenseKey || e.token)),
277
277
  )
278
- if (enterpriseAuth && result.review) {
279
- result.review.hidden = false
278
+ if (enterpriseAuth && result.review && enterpriseAuth.type === "enterprise") {
279
+ const jwt = enterpriseAuth.token
280
+ if (jwt) {
281
+ try {
282
+ const payload = JSON.parse(Buffer.from(jwt.split(".")[1], "base64").toString())
283
+ if (Array.isArray(payload.features) && payload.features.includes("code-review")) {
284
+ result.review.hidden = false
285
+ }
286
+ } catch {
287
+ // malformed token — keep review agent hidden
288
+ }
289
+ }
280
290
  }
281
291
 
282
292
  // Ensure Truncate.DIR is allowed unless explicitly configured
package/src/auth/index.ts CHANGED
@@ -82,6 +82,10 @@ export namespace Auth {
82
82
  azureOrg: z.string().optional(),
83
83
  azureProject: z.string().optional(),
84
84
  azurePat: z.string().optional(),
85
+ // Subscription & feature gating (set after device/verify)
86
+ features: z.array(z.string()).optional(),
87
+ subscriptionStatus: z.string().optional(),
88
+ trialEndsAt: z.number().optional(),
85
89
  })
86
90
  .meta({ ref: "Enterprise" })
87
91
 
@@ -1054,6 +1054,9 @@ function DialogAuthEnterprise() {
1054
1054
  username: data.user?.username || data.user?.email,
1055
1055
  email: data.user?.email,
1056
1056
  role: data.user?.role,
1057
+ features: data.features || [],
1058
+ subscriptionStatus: data.subscription?.status,
1059
+ trialEndsAt: data.subscription?.trialEndsAt,
1057
1060
  })
1058
1061
 
1059
1062
  // Also save to ~/.snow-code/enterprise.json for the enterprise proxy
@@ -1185,6 +1188,50 @@ function DialogAuthEnterprise() {
1185
1188
  console.error('[Enterprise] Failed to update documentation:', docError)
1186
1189
  }
1187
1190
 
1191
+ // Show trial/subscription status toast
1192
+ try {
1193
+ const subStatus = data.subscription?.status
1194
+ const trialEnd = data.subscription?.trialEndsAt
1195
+ const featureCount = (data.features || []).length
1196
+
1197
+ if (subStatus === "trialing" && trialEnd) {
1198
+ const daysLeft = Math.max(0, Math.ceil((trialEnd - Date.now()) / (24 * 60 * 60 * 1000)))
1199
+ if (daysLeft <= 0) {
1200
+ toast.show({
1201
+ variant: "error",
1202
+ message: "Trial ended — visit portal.snow-flow.dev/portal/billing to activate features",
1203
+ duration: 8000,
1204
+ })
1205
+ } else if (daysLeft <= 3) {
1206
+ toast.show({
1207
+ variant: "warning",
1208
+ message: `Trial ends in ${daysLeft} day${daysLeft === 1 ? "" : "s"} — all features enabled`,
1209
+ duration: 6000,
1210
+ })
1211
+ } else {
1212
+ toast.show({
1213
+ variant: "info",
1214
+ message: `Trial active — all features enabled (${daysLeft} days remaining)`,
1215
+ duration: 4000,
1216
+ })
1217
+ }
1218
+ } else if (subStatus === "past_due") {
1219
+ toast.show({
1220
+ variant: "error",
1221
+ message: "Trial ended — visit portal.snow-flow.dev/portal/billing to activate features",
1222
+ duration: 8000,
1223
+ })
1224
+ } else if (subStatus === "active" && featureCount > 0) {
1225
+ toast.show({
1226
+ variant: "info",
1227
+ message: `Enterprise connected — ${featureCount} feature${featureCount === 1 ? "" : "s"} enabled`,
1228
+ duration: 4000,
1229
+ })
1230
+ }
1231
+ } catch {
1232
+ // Non-critical, skip toast on error
1233
+ }
1234
+
1188
1235
  dialog.clear()
1189
1236
  } catch (e) {
1190
1237
  toast.show({ variant: "error", message: e instanceof Error ? e.message : "Verification failed" })
@@ -393,4 +393,45 @@ export function registerEnterpriseCommands(program: Command): void {
393
393
  });
394
394
  }
395
395
 
396
+ /**
397
+ * Get subscription status and features from the portal auth store.
398
+ * Falls back to the legacy ~/.snow-flow/auth.json if portal auth is not available.
399
+ */
400
+ export async function getSubscriptionStatus(): Promise<{
401
+ status?: string;
402
+ trialEndsAt?: number;
403
+ features: string[];
404
+ } | null> {
405
+ // Try portal auth store first (new device auth flow)
406
+ try {
407
+ const { Auth } = await import('../../auth/index.js');
408
+ const enterprise = await Auth.get('enterprise');
409
+ if (enterprise?.type === 'enterprise') {
410
+ return {
411
+ status: enterprise.subscriptionStatus,
412
+ trialEndsAt: enterprise.trialEndsAt,
413
+ features: enterprise.features || [],
414
+ };
415
+ }
416
+ } catch {
417
+ // Fall through to legacy auth
418
+ }
419
+
420
+ // Fallback: legacy auth.json
421
+ const auth = await loadAuth();
422
+ if (auth?.customer) {
423
+ return {
424
+ features: auth.customer.features || [],
425
+ };
426
+ }
427
+ return null;
428
+ }
429
+
430
+ /**
431
+ * Check if a specific feature is enabled in the user's subscription.
432
+ */
433
+ export function isFeatureEnabled(features: string[], feature: string): boolean {
434
+ return features.includes(feature);
435
+ }
436
+
396
437
  export const ENTERPRISE_MCP_SERVER_URL = MCP_SERVER_URL;