@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.
- package/dist/{chunk-AWXABIHH.js → chunk-ZSQPYJVT.js} +1 -1
- package/dist/index.js +277 -42
- package/dist/postinstall.js +1 -1
- package/package.json +2 -2
|
@@ -17,7 +17,7 @@ function versionFromPackageJson() {
|
|
|
17
17
|
return void 0;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
var PRETENSE_VERSION = (true ? "0.6.
|
|
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-
|
|
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.
|
|
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 "
|
|
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
|
-
|
|
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
|
|
18766
|
-
"
|
|
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:
|
|
20388
|
+
resetDate: budget.resetsAt,
|
|
20211
20389
|
resetCadenceDays: QUOTA_PERIOD_DAYS2,
|
|
20390
|
+
quotaSource: budget.source,
|
|
20212
20391
|
usage: {
|
|
20213
|
-
mutations:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20253
|
-
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
20277
|
-
//
|
|
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) +
|
|
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
|
-
{
|
|
20311
|
-
|
|
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
|
|
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) +
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
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(
|
|
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) +
|
|
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(
|
|
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 &&
|
|
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
|
);
|
package/dist/postinstall.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pretense/cli",
|
|
3
|
-
"version": "0.6.
|
|
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",
|