@pretense/cli 0.6.24 → 0.6.26

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.
@@ -17,7 +17,7 @@ function versionFromPackageJson() {
17
17
  return void 0;
18
18
  }
19
19
  }
20
- var PRETENSE_VERSION = (true ? "0.6.24" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
20
+ var PRETENSE_VERSION = (true ? "0.6.26" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
21
21
 
22
22
  export {
23
23
  PRETENSE_VERSION
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PRETENSE_VERSION
4
- } from "./chunk-AWXABIHH.js";
4
+ } from "./chunk-ZSQPYJVT.js";
5
5
  import {
6
6
  __commonJS,
7
7
  __toESM,
@@ -16657,11 +16657,11 @@ function versionFromCliPackageJson() {
16657
16657
  return void 0;
16658
16658
  }
16659
16659
  function productVersion() {
16660
- return override ?? (true ? "0.6.24" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16660
+ return override ?? (true ? "0.6.26" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16661
16661
  }
16662
16662
  var UNKNOWN_COMMIT = "unknown";
16663
16663
  function bakedCommitSha() {
16664
- return "b258672fe5eb6d72b12faf92d12452d06dfa8ab2".length > 0 ? "b258672fe5eb6d72b12faf92d12452d06dfa8ab2" : UNKNOWN_COMMIT;
16664
+ return "91077fab39006ac43c0256257c895b5534640e17".length > 0 ? "91077fab39006ac43c0256257c895b5534640e17" : UNKNOWN_COMMIT;
16665
16665
  }
16666
16666
  var FEATURE_TIERS = {
16667
16667
  compliance_export: "pro",
@@ -18634,6 +18634,13 @@ function planToTier(plan) {
18634
18634
  return null;
18635
18635
  }
18636
18636
  }
18637
+ var SUBSCRIPTION_STATUS_SHAPE = /^[A-Za-z][A-Za-z0-9_-]{0,31}$/;
18638
+ function parseSubscriptionStatus(raw2) {
18639
+ if (raw2 === null) return null;
18640
+ if (typeof raw2 !== "string") return void 0;
18641
+ const trimmed = raw2.trim();
18642
+ return SUBSCRIPTION_STATUS_SHAPE.test(trimmed) ? trimmed : void 0;
18643
+ }
18637
18644
  function parseEntitlement(body) {
18638
18645
  const raw2 = body["entitlement"];
18639
18646
  if (!raw2 || typeof raw2 !== "object") return void 0;
@@ -18641,13 +18648,48 @@ function parseEntitlement(body) {
18641
18648
  const effectivePlan = planToTier(e["effectivePlan"]);
18642
18649
  const planOnRecord = planToTier(e["planOnRecord"]);
18643
18650
  if (effectivePlan === null && planOnRecord === null) return void 0;
18651
+ const subscriptionStatus = parseSubscriptionStatus(e["subscriptionStatus"]);
18644
18652
  return {
18645
18653
  effectivePlan,
18646
18654
  planOnRecord,
18647
18655
  comped: e["comped"] === true,
18648
- hasActiveSubscription: e["hasActiveSubscription"] === true
18656
+ hasActiveSubscription: e["hasActiveSubscription"] === true,
18657
+ ...subscriptionStatus !== void 0 ? { subscriptionStatus } : {}
18649
18658
  };
18650
18659
  }
18660
+ function parseCounter(raw2) {
18661
+ if (typeof raw2 !== "number" || !Number.isFinite(raw2)) return null;
18662
+ if (!Number.isInteger(raw2) || raw2 < 0) return null;
18663
+ return raw2;
18664
+ }
18665
+ function parseAllowance(raw2) {
18666
+ if (typeof raw2 !== "number" || !Number.isFinite(raw2) || !Number.isInteger(raw2)) return null;
18667
+ if (raw2 === -1) return { limit: null, unlimited: true };
18668
+ if (raw2 < 0) return null;
18669
+ return { limit: raw2, unlimited: false };
18670
+ }
18671
+ function parseResetInstant(raw2) {
18672
+ if (typeof raw2 !== "string" || raw2.trim().length === 0) return null;
18673
+ const ms = Date.parse(raw2.trim());
18674
+ if (!Number.isFinite(ms)) return null;
18675
+ try {
18676
+ return new Date(ms).toISOString();
18677
+ } catch {
18678
+ return null;
18679
+ }
18680
+ }
18681
+ function parseRemoteQuota(body) {
18682
+ const used = parseCounter(body["codeProtectionsUsed"]);
18683
+ const allowance = parseAllowance(body["monthlyCodeProtectionLimit"]);
18684
+ if (used === null || allowance === null) return void 0;
18685
+ const resetsAt = parseResetInstant(body["periodResetsAt"]);
18686
+ if (allowance.unlimited) {
18687
+ return { used, limit: null, remaining: null, unlimited: true, resetsAt };
18688
+ }
18689
+ const reported = parseCounter(body["codeProtectionsRemaining"]);
18690
+ const remaining2 = reported ?? Math.max(0, allowance.limit - used);
18691
+ return { used, limit: allowance.limit, remaining: remaining2, unlimited: false, resetsAt };
18692
+ }
18651
18693
  async function tierFromBackend(apiKey) {
18652
18694
  const url = `${getConfiguredApiRoot()}/api/cli/auth/validate`;
18653
18695
  const controller = new AbortController();
@@ -18682,7 +18724,13 @@ async function tierFromBackend(apiKey) {
18682
18724
  detail: "the plan service did not report a recognizable plan"
18683
18725
  };
18684
18726
  }
18685
- return { tier, source: "backend", entitlement: parseEntitlement(body) };
18727
+ const quota2 = parseRemoteQuota(body);
18728
+ return {
18729
+ tier,
18730
+ source: "backend",
18731
+ entitlement: parseEntitlement(body),
18732
+ ...quota2 ? { quota: quota2 } : {}
18733
+ };
18686
18734
  } catch (err) {
18687
18735
  const aborted = err?.name === "AbortError";
18688
18736
  return {
@@ -18744,6 +18792,87 @@ function collectUsage(dbPath) {
18744
18792
  function resetCadenceLabel() {
18745
18793
  return `every ${QUOTA_PERIOD_DAYS2} days`;
18746
18794
  }
18795
+ function formatResetInstant(iso) {
18796
+ const ms = Date.parse(iso);
18797
+ if (!Number.isFinite(ms)) return iso;
18798
+ return new Date(ms).toISOString().replace("T", " ").replace(/\.\d{3}Z$/, " UTC");
18799
+ }
18800
+ function resetLabel(quota2) {
18801
+ return quota2?.resetsAt ? formatResetInstant(quota2.resetsAt) : resetCadenceLabel();
18802
+ }
18803
+ function percentOf(used, limit) {
18804
+ if (limit <= 0) return used > 0 ? 100 : 0;
18805
+ return Math.round(used / limit * 100);
18806
+ }
18807
+ function resolveMutationBudget(resolution, localMutationsApplied) {
18808
+ const quota2 = resolution.quota;
18809
+ if (quota2) {
18810
+ return {
18811
+ source: "server",
18812
+ used: quota2.used,
18813
+ limit: quota2.limit,
18814
+ remaining: quota2.remaining,
18815
+ percent: quota2.unlimited ? null : percentOf(quota2.used, quota2.limit ?? 0),
18816
+ unlimited: quota2.unlimited,
18817
+ limitUnknown: false,
18818
+ resetsAt: quota2.resetsAt
18819
+ };
18820
+ }
18821
+ const tier = resolution.tier;
18822
+ if (!tier) {
18823
+ return {
18824
+ source: "local-audit",
18825
+ used: localMutationsApplied,
18826
+ limit: null,
18827
+ remaining: null,
18828
+ percent: null,
18829
+ unlimited: false,
18830
+ limitUnknown: true,
18831
+ resetsAt: null
18832
+ };
18833
+ }
18834
+ const planLimit = PLAN_CONFIGS[tier].mutationsPerPeriod;
18835
+ if (planLimit === null) {
18836
+ return {
18837
+ source: "local-audit",
18838
+ used: localMutationsApplied,
18839
+ limit: null,
18840
+ remaining: null,
18841
+ percent: null,
18842
+ unlimited: true,
18843
+ limitUnknown: false,
18844
+ resetsAt: null
18845
+ };
18846
+ }
18847
+ return {
18848
+ source: "local-audit",
18849
+ used: localMutationsApplied,
18850
+ limit: planLimit,
18851
+ remaining: Math.max(0, planLimit - localMutationsApplied),
18852
+ percent: percentOf(localMutationsApplied, planLimit),
18853
+ unlimited: false,
18854
+ limitUnknown: false,
18855
+ resetsAt: null
18856
+ };
18857
+ }
18858
+ function budgetSourceLines(budget, resolution, localMutationsApplied) {
18859
+ if (budget.source === "server") {
18860
+ const lines = [
18861
+ "Mutations: counted by the Pretense API \u2014 this is the figure your quota is enforced against."
18862
+ ];
18863
+ if (localMutationsApplied !== budget.used) {
18864
+ lines.push(
18865
+ `This machine's local audit log records ${localMutationsApplied.toLocaleString("en-US")} \u2014 a different machine set and window, not your quota.`
18866
+ );
18867
+ }
18868
+ return lines;
18869
+ }
18870
+ const why = resolution.source === "no-credentials" ? "you are not signed in, so no server was asked" : resolution.source === "key-prefix" ? "a legacy pt- key names its plan offline, so no server was asked for your usage" : resolution.source === "unverified" ? resolution.detail ?? "the plan service could not be reached" : "the plan service did not report usage figures";
18871
+ return [
18872
+ "Mutations: counted LOCALLY on this machine (~/.pretense/audit.db) \u2014 this is NOT",
18873
+ `the usage your quota is enforced against, because ${why}.`
18874
+ ];
18875
+ }
18747
18876
  function priceLabel(tier) {
18748
18877
  const cents = PLAN_CONFIGS[tier].pricePerSeatCents;
18749
18878
  if (cents === null) return "custom \u2014 contact sales";
@@ -18761,9 +18890,44 @@ function entitlementMismatchLines(ent) {
18761
18890
  const paidOnRecord = ent.planOnRecord === "pro" || ent.planOnRecord === "enterprise";
18762
18891
  if (ent.effectivePlan !== "free" || !paidOnRecord) return [];
18763
18892
  const planName = ent.planOnRecord === "enterprise" ? "Enterprise" : "Pro";
18893
+ const status = ent.subscriptionStatus;
18894
+ if (status === void 0) {
18895
+ return [
18896
+ `${planName} plan on record, but this key resolves to Free.`,
18897
+ "This server did not report the reason \u2014 a paid org without an entitling",
18898
+ "subscription or comp resolves to Free; see pretense.ai/dashboard/settings."
18899
+ ];
18900
+ }
18901
+ if (status === null) {
18902
+ if (ent.comped) {
18903
+ return [
18904
+ `${planName} plan on record and the org is comped with no subscription record,`,
18905
+ "yet this key resolves to Free \u2014 that combination is unexpected.",
18906
+ "Please contact support with this output \u2014 pretense.ai/dashboard/settings."
18907
+ ];
18908
+ }
18909
+ return [
18910
+ `${planName} plan present, but no active subscription or comp \u2014 running as Free.`,
18911
+ "Attach a Stripe subscription or set the org comp flag \u2014 pretense.ai/dashboard/settings."
18912
+ ];
18913
+ }
18914
+ if (ent.hasActiveSubscription) {
18915
+ return [
18916
+ `${planName} plan on record with a ${status} subscription the server reports as`,
18917
+ "active, yet this key resolves to Free \u2014 that combination is unexpected.",
18918
+ "Please contact support with this output \u2014 pretense.ai/dashboard/settings."
18919
+ ];
18920
+ }
18921
+ if (ent.comped) {
18922
+ return [
18923
+ `${planName} plan on record and the org IS comped, but a ${status} subscription`,
18924
+ "record is overriding the comp \u2014 running as Free.",
18925
+ `Remove or replace that ${status} subscription record \u2014 pretense.ai/dashboard/settings.`
18926
+ ];
18927
+ }
18764
18928
  return [
18765
- `${planName} plan present, but no active subscription or comp \u2014 running as Free.`,
18766
- "Attach a Stripe subscription or set the org comp flag \u2014 pretense.ai/dashboard/settings."
18929
+ `${planName} plan on record, but its subscription is ${status} \u2014 running as Free.`,
18930
+ "Replace it with a live subscription \u2014 pretense.ai/dashboard/settings."
18767
18931
  ];
18768
18932
  }
18769
18933
  function planMismatchHint(resolution) {
@@ -20198,22 +20362,38 @@ function percentLabel(percent) {
20198
20362
  if (percent >= 80) return chalk9.yellow(`${percent}%`);
20199
20363
  return chalk9.green(`${percent}%`);
20200
20364
  }
20365
+ function mutationsPayload(budget) {
20366
+ return {
20367
+ source: budget.source,
20368
+ current: budget.used,
20369
+ limit: budget.limit,
20370
+ percent: budget.percent,
20371
+ remaining: budget.remaining,
20372
+ // `allowed` is only knowable with an allowance. `limitUnknown` must not
20373
+ // read as `true` — "we could not check" is not "you are fine".
20374
+ allowed: budget.limitUnknown ? null : budget.unlimited || (budget.remaining ?? 0) > 0,
20375
+ unlimited: budget.unlimited
20376
+ };
20377
+ }
20201
20378
  function emptyUsagePayload(resolution) {
20202
20379
  const tier = resolution.tier;
20203
20380
  const planConfig = tier ? PLAN_CONFIGS[tier] : null;
20381
+ const budget = resolveMutationBudget(resolution, 0);
20204
20382
  return {
20205
20383
  tier,
20206
20384
  tierSource: resolution.source,
20207
20385
  ...resolution.detail ? { tierDetail: resolution.detail } : {},
20208
20386
  periodStart: null,
20209
20387
  periodEnd: null,
20210
- resetDate: null,
20388
+ resetDate: budget.resetsAt,
20211
20389
  resetCadenceDays: QUOTA_PERIOD_DAYS2,
20390
+ quotaSource: budget.source,
20212
20391
  usage: {
20213
- mutations: { current: 0, limit: planConfig ? planConfig.mutationsPerPeriod : null, percent: 0, allowed: true },
20214
- scans: { current: 0, limit: planConfig ? planConfig.scansPerPeriod : null, percent: 0, allowed: true }
20392
+ mutations: mutationsPayload(budget),
20393
+ scans: { source: "local-audit", current: 0, limit: planConfig ? planConfig.scansPerPeriod : null, percent: 0, allowed: true }
20215
20394
  },
20216
- overallPercent: 0,
20395
+ localAudit: { mutations: 0, scans: 0, secretsBlocked: 0 },
20396
+ overallPercent: budget.percent ?? 0,
20217
20397
  recommendedUpgrade: null
20218
20398
  };
20219
20399
  }
@@ -20234,6 +20414,7 @@ function usageCommand() {
20234
20414
  return;
20235
20415
  }
20236
20416
  const usageMetrics = collected.metrics;
20417
+ const budget = resolveMutationBudget(resolution, usageMetrics.mutationsApplied);
20237
20418
  if (opts.json) {
20238
20419
  const limits = tier ? checkAllLimits(usageMetrics, tier) : null;
20239
20420
  const planConfig2 = tier ? PLAN_CONFIGS[tier] : null;
@@ -20245,23 +20426,33 @@ function usageCommand() {
20245
20426
  ...resolution.detail ? { tierDetail: resolution.detail } : {},
20246
20427
  periodStart: usageMetrics.periodStart,
20247
20428
  periodEnd: usageMetrics.periodEnd,
20248
- resetDate: null,
20429
+ // The server's own instant when it reported one. `null` means the
20430
+ // CLI was not told — it does NOT mean "no reset exists", and it is
20431
+ // not an invitation to compute one.
20432
+ resetDate: budget.resetsAt,
20249
20433
  resetCadenceDays: QUOTA_PERIOD_DAYS2,
20434
+ quotaSource: budget.source,
20250
20435
  usage: {
20251
- mutations: {
20252
- current: usageMetrics.mutationsApplied,
20253
- limit: planConfig2 ? planConfig2.mutationsPerPeriod : null,
20254
- percent: limits ? limits.mutations.usagePercent ?? 0 : null,
20255
- allowed: limits ? limits.mutations.allowed : null
20256
- },
20436
+ mutations: mutationsPayload(budget),
20437
+ // Scans have no server-side counterpart on the validate
20438
+ // response, so this half is local and says so.
20257
20439
  scans: {
20440
+ source: "local-audit",
20258
20441
  current: usageMetrics.totalScans,
20259
20442
  limit: planConfig2 ? planConfig2.scansPerPeriod : null,
20260
20443
  percent: limits ? limits.scans.usagePercent ?? 0 : null,
20261
20444
  allowed: limits ? limits.scans.allowed : null
20262
20445
  }
20263
20446
  },
20264
- overallPercent: tier ? maxUsagePercent(usageMetrics, tier) : null,
20447
+ // The raw local counters, always under a key that names them as
20448
+ // local, so a consumer that wants this machine's view can have it
20449
+ // without it ever being mistaken for the quota.
20450
+ localAudit: {
20451
+ mutations: usageMetrics.mutationsApplied,
20452
+ scans: usageMetrics.totalScans,
20453
+ secretsBlocked: usageMetrics.secretsBlocked
20454
+ },
20455
+ overallPercent: budget.percent ?? (tier ? maxUsagePercent(usageMetrics, tier) : null),
20265
20456
  recommendedUpgrade: tier ? recommendedTier(usageMetrics, tier) : null
20266
20457
  },
20267
20458
  null,
@@ -20270,11 +20461,11 @@ function usageCommand() {
20270
20461
  );
20271
20462
  return;
20272
20463
  }
20273
- const resetDate = resetCadenceLabel();
20464
+ const resetDate = resetLabel(resolution.quota);
20274
20465
  console.log(
20275
20466
  chalk9.cyan(
20276
- "\n Pretense Usage \u2014 " + // Header shows today's date, NOT a billing month: quotas roll on a
20277
- // 7-day window anchored to signup, so a month name would imply a
20467
+ "\n Pretense Usage \u2014 " + // Header shows today's date, NOT a billing month: the quota window
20468
+ // trails the account's own activity, so a month name would imply a
20278
20469
  // reset boundary that does not exist.
20279
20470
  (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
20280
20471
  month: "long",
@@ -20293,35 +20484,60 @@ function usageCommand() {
20293
20484
  console.log(chalk9.yellow(` ${line}`));
20294
20485
  }
20295
20486
  console.log();
20296
- console.log(" " + "Mutations".padEnd(20) + usageMetrics.mutationsApplied.toLocaleString("en-US"));
20487
+ console.log(" " + "Mutations".padEnd(20) + budget.used.toLocaleString("en-US"));
20297
20488
  console.log(" " + "API Requests".padEnd(20) + usageMetrics.totalScans.toLocaleString("en-US"));
20298
20489
  console.log(" " + "Secrets Blocked".padEnd(20) + usageMetrics.secretsBlocked.toLocaleString("en-US"));
20299
20490
  console.log();
20491
+ for (const line of budgetSourceLines(budget, resolution, usageMetrics.mutationsApplied)) {
20492
+ console.log(chalk9.dim(` ${line}`));
20493
+ }
20494
+ console.log();
20300
20495
  return;
20301
20496
  }
20302
20497
  const planConfig = PLAN_CONFIGS[tier];
20303
- const overall = maxUsagePercent(usageMetrics, tier);
20498
+ const overall = budget.source === "server" ? budget.percent ?? 0 : maxUsagePercent(usageMetrics, tier);
20304
20499
  const nextTier = recommendedTier(usageMetrics, tier);
20305
20500
  console.log(
20306
20501
  " " + chalk9.bold("Metric".padEnd(20)) + chalk9.bold("Used / Limit".padEnd(30)) + chalk9.bold("Progress")
20307
20502
  );
20308
20503
  console.log(" " + chalk9.dim("\u2500".repeat(72)));
20309
20504
  const rows = [
20310
- { label: "Mutations", value: usageMetrics.mutationsApplied, limit: planConfig.mutationsPerPeriod },
20311
- { label: "API Requests", value: usageMetrics.totalScans, limit: planConfig.scansPerPeriod }
20505
+ {
20506
+ label: "Mutations",
20507
+ value: budget.used,
20508
+ // `limitUnknown` must render as unknown, NOT as unlimited. That
20509
+ // conflation is the original defect: an org at 100% of its quota read
20510
+ // every missing field as "no limit" and was told it had none.
20511
+ limit: budget.limitUnknown ? null : budget.limit,
20512
+ percent: budget.percent
20513
+ },
20514
+ {
20515
+ label: "API Requests",
20516
+ value: usageMetrics.totalScans,
20517
+ limit: planConfig.scansPerPeriod,
20518
+ percent: null
20519
+ }
20312
20520
  ];
20313
20521
  for (const row of rows) {
20314
- const percent = row.limit === null ? 0 : Math.round(row.value / row.limit * 100);
20315
- const bar2 = row.limit === null ? chalk9.dim(" unlimited ".padEnd(32)) : renderBar(percent);
20522
+ const percent = row.percent ?? (row.limit === null ? 0 : Math.round(row.value / row.limit * 100));
20523
+ const unknown = row.label === "Mutations" && budget.limitUnknown;
20524
+ const bar2 = unknown ? chalk9.dim(" not reported ".padEnd(32)) : row.limit === null ? chalk9.dim(" unlimited ".padEnd(32)) : renderBar(percent);
20525
+ const used = unknown ? `${row.value.toLocaleString("en-US")} / not reported` : formatMetric(row.value, row.limit);
20316
20526
  console.log(
20317
- " " + row.label.padEnd(20) + formatMetric(row.value, row.limit).padEnd(30) + bar2 + " " + (row.limit === null ? "" : percentLabel(percent))
20527
+ " " + row.label.padEnd(20) + used.padEnd(30) + bar2 + " " + (row.limit === null || unknown ? "" : percentLabel(percent))
20318
20528
  );
20319
20529
  }
20320
20530
  console.log(
20321
20531
  " " + "Secrets Blocked".padEnd(20) + String(usageMetrics.secretsBlocked.toLocaleString("en-US")).padEnd(30) + chalk9.dim("(no limit)")
20322
20532
  );
20323
20533
  console.log(" " + chalk9.dim("\u2500".repeat(72)));
20324
- if (tier === "enterprise") {
20534
+ for (const line of budgetSourceLines(budget, resolution, usageMetrics.mutationsApplied)) {
20535
+ console.log(" " + chalk9.dim(line));
20536
+ }
20537
+ console.log(
20538
+ " " + chalk9.dim("API Requests / Secrets Blocked: counted locally on this machine.")
20539
+ );
20540
+ if (tier === "enterprise" && budget.unlimited) {
20325
20541
  console.log(chalk9.green("\n Enterprise plan \u2014 all limits are unlimited.\n"));
20326
20542
  } else if (overall >= 100) {
20327
20543
  console.log(chalk9.red(`
@@ -22699,9 +22915,10 @@ function creditsCommand() {
22699
22915
  if (!collected && !opts.json) {
22700
22916
  console.log(chalk21.dim("\n No usage recorded yet \u2014 showing your full allowance.\n"));
22701
22917
  }
22702
- const mutationLimit = tier ? PLAN_CONFIGS[tier].mutationsPerPeriod : null;
22918
+ const budget = resolveMutationBudget(resolution, m.mutationsApplied);
22919
+ const mutationLimit = budget.limitUnknown ? null : budget.limit;
22920
+ const mutationsLeft = budget.limitUnknown ? null : budget.remaining;
22703
22921
  const scanLimit = tier ? PLAN_CONFIGS[tier].scansPerPeriod : null;
22704
- const mutationsLeft = tier ? remaining(m.mutationsApplied, mutationLimit) : null;
22705
22922
  const scansLeft = tier ? remaining(m.totalScans, scanLimit) : null;
22706
22923
  if (opts.json) {
22707
22924
  console.log(
@@ -22710,18 +22927,26 @@ function creditsCommand() {
22710
22927
  tier,
22711
22928
  tierSource: resolution.source,
22712
22929
  ...resolution.detail ? { tierDetail: resolution.detail } : {},
22713
- resetDate: null,
22930
+ // The server's instant when it sent one. It sends `periodResetsAt`
22931
+ // on every validation; this used to be hardcoded `null` while a
22932
+ // hardcoded cadence string was printed beside it.
22933
+ resetDate: budget.resetsAt,
22714
22934
  resetCadenceDays: QUOTA_PERIOD_DAYS2,
22935
+ quotaSource: budget.source,
22715
22936
  mutations: {
22716
- used: m.mutationsApplied,
22717
- limit: tier ? mutationLimit : null,
22718
- remaining: tier ? mutationsLeft : null
22937
+ source: budget.source,
22938
+ used: budget.used,
22939
+ limit: mutationLimit,
22940
+ remaining: mutationsLeft,
22941
+ unlimited: budget.unlimited
22719
22942
  },
22720
22943
  scans: {
22944
+ source: "local-audit",
22721
22945
  used: m.totalScans,
22722
22946
  limit: tier ? scanLimit : null,
22723
22947
  remaining: tier ? scansLeft : null
22724
- }
22948
+ },
22949
+ localAudit: { mutations: m.mutationsApplied, scans: m.totalScans }
22725
22950
  },
22726
22951
  null,
22727
22952
  2
@@ -22730,29 +22955,39 @@ function creditsCommand() {
22730
22955
  return;
22731
22956
  }
22732
22957
  console.log(chalk21.cyan("\n Pretense Credits"));
22733
- console.log(chalk21.dim(` Plan: ${tierLabel(tier)} | Resets: ${resetCadenceLabel()}
22734
- `));
22958
+ console.log(
22959
+ chalk21.dim(` Plan: ${tierLabel(tier)} | Resets: ${resetLabel(resolution.quota)}
22960
+ `)
22961
+ );
22735
22962
  if (!tier) {
22736
22963
  for (const line of unverifiedNote(resolution.detail)) {
22737
22964
  console.log(chalk21.yellow(` ${line}`));
22738
22965
  }
22739
22966
  console.log();
22740
- console.log(" " + "Mutations used".padEnd(20) + m.mutationsApplied.toLocaleString("en-US"));
22967
+ console.log(" " + "Mutations used".padEnd(20) + budget.used.toLocaleString("en-US"));
22741
22968
  console.log(" " + "Requests used".padEnd(20) + m.totalScans.toLocaleString("en-US"));
22742
22969
  console.log();
22970
+ for (const line of budgetSourceLines(budget, resolution, m.mutationsApplied)) {
22971
+ console.log(chalk21.dim(` ${line}`));
22972
+ }
22973
+ console.log();
22743
22974
  return;
22744
22975
  }
22745
22976
  console.log(
22746
- " " + "Mutations".padEnd(14) + bar(m.mutationsApplied, mutationLimit) + " " + chalk21.bold(fmt(mutationsLeft)) + chalk21.dim(` left of ${fmt(mutationLimit)}`)
22977
+ " " + "Mutations".padEnd(14) + bar(budget.used, mutationLimit) + " " + chalk21.bold(fmt(mutationsLeft)) + chalk21.dim(` left of ${fmt(mutationLimit)}`)
22747
22978
  );
22748
22979
  console.log(
22749
22980
  " " + "Requests".padEnd(14) + bar(m.totalScans, scanLimit) + " " + chalk21.bold(fmt(scansLeft)) + chalk21.dim(` left of ${fmt(scanLimit)}`)
22750
22981
  );
22982
+ console.log();
22983
+ for (const line of budgetSourceLines(budget, resolution, m.mutationsApplied)) {
22984
+ console.log(chalk21.dim(` ${line}`));
22985
+ }
22751
22986
  if (tier !== "enterprise" && mutationLimit !== null && mutationsLeft === 0) {
22752
22987
  console.log(
22753
22988
  chalk21.red("\n Mutation budget exhausted for this period.") + chalk21.dim(" Run ") + chalk21.cyan("pretense upgrade") + chalk21.dim(" to compare plans.")
22754
22989
  );
22755
- } else if (tier !== "enterprise" && mutationLimit !== null && m.mutationsApplied >= mutationLimit * 0.8) {
22990
+ } else if (tier !== "enterprise" && mutationLimit !== null && budget.used >= mutationLimit * 0.8) {
22756
22991
  console.log(
22757
22992
  chalk21.yellow("\n Running low.") + chalk21.dim(" Run ") + chalk21.cyan("pretense upgrade") + chalk21.dim(" to compare plans.")
22758
22993
  );
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PRETENSE_VERSION
4
- } from "./chunk-AWXABIHH.js";
4
+ } from "./chunk-ZSQPYJVT.js";
5
5
  import {
6
6
  init_esm_shims
7
7
  } from "./chunk-TWMRHZGM.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pretense/cli",
3
- "version": "0.6.24",
3
+ "version": "0.6.26",
4
4
  "description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,10 +23,10 @@
23
23
  "tsx": "^4.0.0",
24
24
  "typescript": "^5.4.0",
25
25
  "vitest": "^1.0.0",
26
- "@pretense/billing": "0.1.0",
27
26
  "@pretense/compliance-engine": "0.1.0",
28
27
  "@pretense/protocol": "0.1.0",
29
28
  "@pretense/learner": "0.2.0",
29
+ "@pretense/billing": "0.1.0",
30
30
  "@pretense/mutator": "0.2.0",
31
31
  "@pretense/proxy": "0.1.0",
32
32
  "@pretense/scanner": "0.2.0",