@pretense/cli 0.6.25 → 0.6.27
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-XYBJ63JG.js → chunk-6L7NU7KI.js} +1 -1
- package/dist/index.js +294 -64
- package/dist/postinstall.js +1 -1
- package/package.json +5 -5
|
@@ -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.27" : 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-6L7NU7KI.js";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__toESM,
|
|
@@ -7837,7 +7837,9 @@ import { execSync } from "child_process";
|
|
|
7837
7837
|
|
|
7838
7838
|
// ../apps/proxy/dist/server.js
|
|
7839
7839
|
init_esm_shims();
|
|
7840
|
-
import { resolve as resolvePath } from "path";
|
|
7840
|
+
import { resolve as resolvePath, join as joinPath } from "path";
|
|
7841
|
+
import { existsSync as existsSync24, readFileSync as readFileSync33 } from "fs";
|
|
7842
|
+
import { homedir as homedir3 } from "os";
|
|
7841
7843
|
|
|
7842
7844
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/index.js
|
|
7843
7845
|
init_esm_shims();
|
|
@@ -16657,11 +16659,11 @@ function versionFromCliPackageJson() {
|
|
|
16657
16659
|
return void 0;
|
|
16658
16660
|
}
|
|
16659
16661
|
function productVersion() {
|
|
16660
|
-
return override ?? (true ? "0.6.
|
|
16662
|
+
return override ?? (true ? "0.6.27" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
|
|
16661
16663
|
}
|
|
16662
16664
|
var UNKNOWN_COMMIT = "unknown";
|
|
16663
16665
|
function bakedCommitSha() {
|
|
16664
|
-
return "
|
|
16666
|
+
return "2899946100b26294eb8ef8dbde2d50e63a5247a9".length > 0 ? "2899946100b26294eb8ef8dbde2d50e63a5247a9" : UNKNOWN_COMMIT;
|
|
16665
16667
|
}
|
|
16666
16668
|
var FEATURE_TIERS = {
|
|
16667
16669
|
compliance_export: "pro",
|
|
@@ -17104,7 +17106,13 @@ async function streamWithRollingBuffer(upstreamResp, map, provider, requestId) {
|
|
|
17104
17106
|
if (provider === "anthropic" && line.includes("content_block_stop")) {
|
|
17105
17107
|
const stopIndex = blockStopIndex(line);
|
|
17106
17108
|
if (stopIndex !== null) {
|
|
17107
|
-
|
|
17109
|
+
const flushed = flushBlock(stopIndex);
|
|
17110
|
+
if (flushed.length > 0) {
|
|
17111
|
+
const header = outputLines.length > 0 && outputLines[outputLines.length - 1].startsWith("event:") ? outputLines.pop() : null;
|
|
17112
|
+
outputLines.push(...flushed);
|
|
17113
|
+
if (header !== null) outputLines.push(header);
|
|
17114
|
+
}
|
|
17115
|
+
outputLines.push(line);
|
|
17108
17116
|
continue;
|
|
17109
17117
|
}
|
|
17110
17118
|
}
|
|
@@ -17165,7 +17173,7 @@ async function streamWithRollingBuffer(upstreamResp, map, provider, requestId) {
|
|
|
17165
17173
|
function buildFlushEvent(text, provider, kind, index) {
|
|
17166
17174
|
if (provider === "anthropic") {
|
|
17167
17175
|
const delta2 = kind === "input_json" ? { type: "input_json_delta", partial_json: text } : kind === "thinking" ? { type: "thinking_delta", thinking: text } : { type: "text_delta", text };
|
|
17168
|
-
return "
|
|
17176
|
+
return "event: content_block_delta\ndata: " + JSON.stringify({ type: "content_block_delta", index, delta: delta2 });
|
|
17169
17177
|
}
|
|
17170
17178
|
if (provider === "google") {
|
|
17171
17179
|
const part = kind === "google_thought" ? { text, thought: true } : { text };
|
|
@@ -17357,6 +17365,37 @@ var _tierCache = /* @__PURE__ */ new Map();
|
|
|
17357
17365
|
var TIER_CACHE_OK_MS = 6e4;
|
|
17358
17366
|
var TIER_CACHE_FAIL_MS = 1e4;
|
|
17359
17367
|
var TIER_VALIDATE_TIMEOUT_MS = 3e3;
|
|
17368
|
+
var LOCAL_KEY_CACHE_MS = 3e4;
|
|
17369
|
+
var _localKeyCache = null;
|
|
17370
|
+
function underTestRunner() {
|
|
17371
|
+
return Boolean(process.env["VITEST"]) || process.env["NODE_ENV"] === "test";
|
|
17372
|
+
}
|
|
17373
|
+
function readLocalPretenseApiKey() {
|
|
17374
|
+
const now = Date.now();
|
|
17375
|
+
if (_localKeyCache && _localKeyCache.expiresAt > now) return _localKeyCache.key;
|
|
17376
|
+
let key = null;
|
|
17377
|
+
const fromEnv = process.env["PRETENSE_API_KEY"]?.trim();
|
|
17378
|
+
if (fromEnv) {
|
|
17379
|
+
key = fromEnv;
|
|
17380
|
+
} else if (!underTestRunner()) {
|
|
17381
|
+
const path2 = joinPath(homedir3(), ".pretense", "credentials.json");
|
|
17382
|
+
try {
|
|
17383
|
+
if (existsSync24(path2)) {
|
|
17384
|
+
const creds = JSON.parse(readFileSync33(path2, "utf-8"));
|
|
17385
|
+
const raw2 = creds["apiKey"] ?? creds["api_key"];
|
|
17386
|
+
if (typeof raw2 === "string" && raw2.trim().length > 0) key = raw2.trim();
|
|
17387
|
+
}
|
|
17388
|
+
} catch {
|
|
17389
|
+
}
|
|
17390
|
+
}
|
|
17391
|
+
_localKeyCache = { key, expiresAt: now + LOCAL_KEY_CACHE_MS };
|
|
17392
|
+
return key;
|
|
17393
|
+
}
|
|
17394
|
+
function resolvePretenseKeyForRequest(headerKey) {
|
|
17395
|
+
const explicit = headerKey?.trim();
|
|
17396
|
+
if (explicit) return explicit;
|
|
17397
|
+
return readLocalPretenseApiKey() ?? void 0;
|
|
17398
|
+
}
|
|
17360
17399
|
function tierApiRoot() {
|
|
17361
17400
|
const raw2 = (process.env["PRETENSE_API_URL"] ?? "https://api.pretense.ai").trim();
|
|
17362
17401
|
const normalized = /^https?:\/\//i.test(raw2) ? raw2 : `https://${raw2}`;
|
|
@@ -17832,7 +17871,7 @@ function createProxy(opts = {}) {
|
|
|
17832
17871
|
return c.json({ error: { type: "invalid_request", message: "Empty request body" } }, 400);
|
|
17833
17872
|
}
|
|
17834
17873
|
{
|
|
17835
|
-
const _apiKey = c.req.header("x-pretense-api-key")
|
|
17874
|
+
const _apiKey = resolvePretenseKeyForRequest(c.req.header("x-pretense-api-key"));
|
|
17836
17875
|
const _effectiveTier = await resolveKeyTier(_apiKey);
|
|
17837
17876
|
const _requestEnforcer = new PlanEnforcer(_effectiveTier, planCfg.tenantId);
|
|
17838
17877
|
const QUOTA_PERIOD_DAYS3 = 7;
|
|
@@ -18240,7 +18279,7 @@ ${_upgradeTier === "enterprise" ? "Enterprise offers unlimited mutations \u2014
|
|
|
18240
18279
|
sourceIp: c.req.header("x-forwarded-for") ?? c.req.header("x-real-ip")
|
|
18241
18280
|
}));
|
|
18242
18281
|
if (anyTokenized) {
|
|
18243
|
-
const usageKey = c.req.header("x-pretense-api-key")
|
|
18282
|
+
const usageKey = resolvePretenseKeyForRequest(c.req.header("x-pretense-api-key"));
|
|
18244
18283
|
uploadProxyUsage({
|
|
18245
18284
|
apiKey: usageKey,
|
|
18246
18285
|
identifiersMutated: mutationsApplied,
|
|
@@ -18369,8 +18408,8 @@ async function findFreePort(start, opts = {}) {
|
|
|
18369
18408
|
init_esm_shims();
|
|
18370
18409
|
import { existsSync as existsSync8, readFileSync as readFileSync6, unlinkSync } from "fs";
|
|
18371
18410
|
import { join as join7 } from "path";
|
|
18372
|
-
import { homedir as
|
|
18373
|
-
function pidFilePath(home =
|
|
18411
|
+
import { homedir as homedir4 } from "os";
|
|
18412
|
+
function pidFilePath(home = homedir4()) {
|
|
18374
18413
|
return join7(process.env.PRETENSE_PID_DIR ?? join7(home, ".pretense"), "proxy.pid");
|
|
18375
18414
|
}
|
|
18376
18415
|
function isProcessAlive(pid) {
|
|
@@ -18585,9 +18624,9 @@ import chalk3 from "chalk";
|
|
|
18585
18624
|
init_esm_shims();
|
|
18586
18625
|
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
18587
18626
|
import { join as join8 } from "path";
|
|
18588
|
-
import { homedir as
|
|
18627
|
+
import { homedir as homedir5 } from "os";
|
|
18589
18628
|
function credentialsPath() {
|
|
18590
|
-
return join8(
|
|
18629
|
+
return join8(homedir5(), ".pretense", "credentials.json");
|
|
18591
18630
|
}
|
|
18592
18631
|
function readApiKey() {
|
|
18593
18632
|
const fromEnv = process.env["PRETENSE_API_KEY"]?.trim();
|
|
@@ -18657,6 +18696,39 @@ function parseEntitlement(body) {
|
|
|
18657
18696
|
...subscriptionStatus !== void 0 ? { subscriptionStatus } : {}
|
|
18658
18697
|
};
|
|
18659
18698
|
}
|
|
18699
|
+
function parseCounter(raw2) {
|
|
18700
|
+
if (typeof raw2 !== "number" || !Number.isFinite(raw2)) return null;
|
|
18701
|
+
if (!Number.isInteger(raw2) || raw2 < 0) return null;
|
|
18702
|
+
return raw2;
|
|
18703
|
+
}
|
|
18704
|
+
function parseAllowance(raw2) {
|
|
18705
|
+
if (typeof raw2 !== "number" || !Number.isFinite(raw2) || !Number.isInteger(raw2)) return null;
|
|
18706
|
+
if (raw2 === -1) return { limit: null, unlimited: true };
|
|
18707
|
+
if (raw2 < 0) return null;
|
|
18708
|
+
return { limit: raw2, unlimited: false };
|
|
18709
|
+
}
|
|
18710
|
+
function parseResetInstant(raw2) {
|
|
18711
|
+
if (typeof raw2 !== "string" || raw2.trim().length === 0) return null;
|
|
18712
|
+
const ms = Date.parse(raw2.trim());
|
|
18713
|
+
if (!Number.isFinite(ms)) return null;
|
|
18714
|
+
try {
|
|
18715
|
+
return new Date(ms).toISOString();
|
|
18716
|
+
} catch {
|
|
18717
|
+
return null;
|
|
18718
|
+
}
|
|
18719
|
+
}
|
|
18720
|
+
function parseRemoteQuota(body) {
|
|
18721
|
+
const used = parseCounter(body["codeProtectionsUsed"]);
|
|
18722
|
+
const allowance = parseAllowance(body["monthlyCodeProtectionLimit"]);
|
|
18723
|
+
if (used === null || allowance === null) return void 0;
|
|
18724
|
+
const resetsAt = parseResetInstant(body["periodResetsAt"]);
|
|
18725
|
+
if (allowance.unlimited) {
|
|
18726
|
+
return { used, limit: null, remaining: null, unlimited: true, resetsAt };
|
|
18727
|
+
}
|
|
18728
|
+
const reported = parseCounter(body["codeProtectionsRemaining"]);
|
|
18729
|
+
const remaining2 = reported ?? Math.max(0, allowance.limit - used);
|
|
18730
|
+
return { used, limit: allowance.limit, remaining: remaining2, unlimited: false, resetsAt };
|
|
18731
|
+
}
|
|
18660
18732
|
async function tierFromBackend(apiKey) {
|
|
18661
18733
|
const url = `${getConfiguredApiRoot()}/api/cli/auth/validate`;
|
|
18662
18734
|
const controller = new AbortController();
|
|
@@ -18691,7 +18763,13 @@ async function tierFromBackend(apiKey) {
|
|
|
18691
18763
|
detail: "the plan service did not report a recognizable plan"
|
|
18692
18764
|
};
|
|
18693
18765
|
}
|
|
18694
|
-
|
|
18766
|
+
const quota2 = parseRemoteQuota(body);
|
|
18767
|
+
return {
|
|
18768
|
+
tier,
|
|
18769
|
+
source: "backend",
|
|
18770
|
+
entitlement: parseEntitlement(body),
|
|
18771
|
+
...quota2 ? { quota: quota2 } : {}
|
|
18772
|
+
};
|
|
18695
18773
|
} catch (err) {
|
|
18696
18774
|
const aborted = err?.name === "AbortError";
|
|
18697
18775
|
return {
|
|
@@ -18753,6 +18831,87 @@ function collectUsage(dbPath) {
|
|
|
18753
18831
|
function resetCadenceLabel() {
|
|
18754
18832
|
return `every ${QUOTA_PERIOD_DAYS2} days`;
|
|
18755
18833
|
}
|
|
18834
|
+
function formatResetInstant(iso) {
|
|
18835
|
+
const ms = Date.parse(iso);
|
|
18836
|
+
if (!Number.isFinite(ms)) return iso;
|
|
18837
|
+
return new Date(ms).toISOString().replace("T", " ").replace(/\.\d{3}Z$/, " UTC");
|
|
18838
|
+
}
|
|
18839
|
+
function resetLabel(quota2) {
|
|
18840
|
+
return quota2?.resetsAt ? formatResetInstant(quota2.resetsAt) : resetCadenceLabel();
|
|
18841
|
+
}
|
|
18842
|
+
function percentOf(used, limit) {
|
|
18843
|
+
if (limit <= 0) return used > 0 ? 100 : 0;
|
|
18844
|
+
return Math.round(used / limit * 100);
|
|
18845
|
+
}
|
|
18846
|
+
function resolveMutationBudget(resolution, localMutationsApplied) {
|
|
18847
|
+
const quota2 = resolution.quota;
|
|
18848
|
+
if (quota2) {
|
|
18849
|
+
return {
|
|
18850
|
+
source: "server",
|
|
18851
|
+
used: quota2.used,
|
|
18852
|
+
limit: quota2.limit,
|
|
18853
|
+
remaining: quota2.remaining,
|
|
18854
|
+
percent: quota2.unlimited ? null : percentOf(quota2.used, quota2.limit ?? 0),
|
|
18855
|
+
unlimited: quota2.unlimited,
|
|
18856
|
+
limitUnknown: false,
|
|
18857
|
+
resetsAt: quota2.resetsAt
|
|
18858
|
+
};
|
|
18859
|
+
}
|
|
18860
|
+
const tier = resolution.tier;
|
|
18861
|
+
if (!tier) {
|
|
18862
|
+
return {
|
|
18863
|
+
source: "local-audit",
|
|
18864
|
+
used: localMutationsApplied,
|
|
18865
|
+
limit: null,
|
|
18866
|
+
remaining: null,
|
|
18867
|
+
percent: null,
|
|
18868
|
+
unlimited: false,
|
|
18869
|
+
limitUnknown: true,
|
|
18870
|
+
resetsAt: null
|
|
18871
|
+
};
|
|
18872
|
+
}
|
|
18873
|
+
const planLimit = PLAN_CONFIGS[tier].mutationsPerPeriod;
|
|
18874
|
+
if (planLimit === null) {
|
|
18875
|
+
return {
|
|
18876
|
+
source: "local-audit",
|
|
18877
|
+
used: localMutationsApplied,
|
|
18878
|
+
limit: null,
|
|
18879
|
+
remaining: null,
|
|
18880
|
+
percent: null,
|
|
18881
|
+
unlimited: true,
|
|
18882
|
+
limitUnknown: false,
|
|
18883
|
+
resetsAt: null
|
|
18884
|
+
};
|
|
18885
|
+
}
|
|
18886
|
+
return {
|
|
18887
|
+
source: "local-audit",
|
|
18888
|
+
used: localMutationsApplied,
|
|
18889
|
+
limit: planLimit,
|
|
18890
|
+
remaining: Math.max(0, planLimit - localMutationsApplied),
|
|
18891
|
+
percent: percentOf(localMutationsApplied, planLimit),
|
|
18892
|
+
unlimited: false,
|
|
18893
|
+
limitUnknown: false,
|
|
18894
|
+
resetsAt: null
|
|
18895
|
+
};
|
|
18896
|
+
}
|
|
18897
|
+
function budgetSourceLines(budget, resolution, localMutationsApplied) {
|
|
18898
|
+
if (budget.source === "server") {
|
|
18899
|
+
const lines = [
|
|
18900
|
+
"Mutations: counted by the Pretense API \u2014 this is the figure your quota is enforced against."
|
|
18901
|
+
];
|
|
18902
|
+
if (localMutationsApplied !== budget.used) {
|
|
18903
|
+
lines.push(
|
|
18904
|
+
`This machine's local audit log records ${localMutationsApplied.toLocaleString("en-US")} \u2014 a different machine set and window, not your quota.`
|
|
18905
|
+
);
|
|
18906
|
+
}
|
|
18907
|
+
return lines;
|
|
18908
|
+
}
|
|
18909
|
+
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";
|
|
18910
|
+
return [
|
|
18911
|
+
"Mutations: counted LOCALLY on this machine (~/.pretense/audit.db) \u2014 this is NOT",
|
|
18912
|
+
`the usage your quota is enforced against, because ${why}.`
|
|
18913
|
+
];
|
|
18914
|
+
}
|
|
18756
18915
|
function priceLabel(tier) {
|
|
18757
18916
|
const cents = PLAN_CONFIGS[tier].pricePerSeatCents;
|
|
18758
18917
|
if (cents === null) return "custom \u2014 contact sales";
|
|
@@ -20174,7 +20333,7 @@ function configCommand() {
|
|
|
20174
20333
|
init_esm_shims();
|
|
20175
20334
|
import { Command as Command8 } from "commander";
|
|
20176
20335
|
import chalk8 from "chalk";
|
|
20177
|
-
import { homedir as
|
|
20336
|
+
import { homedir as homedir6 } from "os";
|
|
20178
20337
|
import { join as join12 } from "path";
|
|
20179
20338
|
function logsCommand() {
|
|
20180
20339
|
return new Command8("logs").description("Show recent audit log entries").option("-l, --limit <n>", "Number of entries to show", "50").option("--json", "Output as JSON", false).action((opts) => {
|
|
@@ -20182,7 +20341,7 @@ function logsCommand() {
|
|
|
20182
20341
|
let store;
|
|
20183
20342
|
let entries;
|
|
20184
20343
|
try {
|
|
20185
|
-
store = new AuditStore(join12(
|
|
20344
|
+
store = new AuditStore(join12(homedir6(), ".pretense", "audit.db"));
|
|
20186
20345
|
entries = store.getRecentEntries(limit);
|
|
20187
20346
|
store.close();
|
|
20188
20347
|
} catch {
|
|
@@ -20223,7 +20382,7 @@ init_esm_shims();
|
|
|
20223
20382
|
import { Command as Command9 } from "commander";
|
|
20224
20383
|
import chalk9 from "chalk";
|
|
20225
20384
|
import { join as join13 } from "path";
|
|
20226
|
-
import { homedir as
|
|
20385
|
+
import { homedir as homedir7 } from "os";
|
|
20227
20386
|
function renderBar(percent, width = 30) {
|
|
20228
20387
|
const filled = Math.min(Math.round(percent / 100 * width), width);
|
|
20229
20388
|
const empty = width - filled;
|
|
@@ -20242,27 +20401,43 @@ function percentLabel(percent) {
|
|
|
20242
20401
|
if (percent >= 80) return chalk9.yellow(`${percent}%`);
|
|
20243
20402
|
return chalk9.green(`${percent}%`);
|
|
20244
20403
|
}
|
|
20404
|
+
function mutationsPayload(budget) {
|
|
20405
|
+
return {
|
|
20406
|
+
source: budget.source,
|
|
20407
|
+
current: budget.used,
|
|
20408
|
+
limit: budget.limit,
|
|
20409
|
+
percent: budget.percent,
|
|
20410
|
+
remaining: budget.remaining,
|
|
20411
|
+
// `allowed` is only knowable with an allowance. `limitUnknown` must not
|
|
20412
|
+
// read as `true` — "we could not check" is not "you are fine".
|
|
20413
|
+
allowed: budget.limitUnknown ? null : budget.unlimited || (budget.remaining ?? 0) > 0,
|
|
20414
|
+
unlimited: budget.unlimited
|
|
20415
|
+
};
|
|
20416
|
+
}
|
|
20245
20417
|
function emptyUsagePayload(resolution) {
|
|
20246
20418
|
const tier = resolution.tier;
|
|
20247
20419
|
const planConfig = tier ? PLAN_CONFIGS[tier] : null;
|
|
20420
|
+
const budget = resolveMutationBudget(resolution, 0);
|
|
20248
20421
|
return {
|
|
20249
20422
|
tier,
|
|
20250
20423
|
tierSource: resolution.source,
|
|
20251
20424
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
20252
20425
|
periodStart: null,
|
|
20253
20426
|
periodEnd: null,
|
|
20254
|
-
resetDate:
|
|
20427
|
+
resetDate: budget.resetsAt,
|
|
20255
20428
|
resetCadenceDays: QUOTA_PERIOD_DAYS2,
|
|
20429
|
+
quotaSource: budget.source,
|
|
20256
20430
|
usage: {
|
|
20257
|
-
mutations:
|
|
20258
|
-
scans: { current: 0, limit: planConfig ? planConfig.scansPerPeriod : null, percent: 0, allowed: true }
|
|
20431
|
+
mutations: mutationsPayload(budget),
|
|
20432
|
+
scans: { source: "local-audit", current: 0, limit: planConfig ? planConfig.scansPerPeriod : null, percent: 0, allowed: true }
|
|
20259
20433
|
},
|
|
20260
|
-
|
|
20434
|
+
localAudit: { mutations: 0, scans: 0, secretsBlocked: 0 },
|
|
20435
|
+
overallPercent: budget.percent ?? 0,
|
|
20261
20436
|
recommendedUpgrade: null
|
|
20262
20437
|
};
|
|
20263
20438
|
}
|
|
20264
20439
|
function usageCommand() {
|
|
20265
|
-
return new Command9("usage").description("Show plan usage vs limits for the current billing period").option("--db <path>", "Path to audit database", join13(
|
|
20440
|
+
return new Command9("usage").description("Show plan usage vs limits for the current billing period").option("--db <path>", "Path to audit database", join13(homedir7(), ".pretense", "audit.db")).option("--json", "Output as JSON", false).option("--offline", "Do not contact the plan service to resolve the tier", false).action(async (opts) => {
|
|
20266
20441
|
const resolution = await resolvePlanTier({ offline: opts.offline });
|
|
20267
20442
|
const tier = resolution.tier;
|
|
20268
20443
|
const collected = collectUsage(opts.db);
|
|
@@ -20278,6 +20453,7 @@ function usageCommand() {
|
|
|
20278
20453
|
return;
|
|
20279
20454
|
}
|
|
20280
20455
|
const usageMetrics = collected.metrics;
|
|
20456
|
+
const budget = resolveMutationBudget(resolution, usageMetrics.mutationsApplied);
|
|
20281
20457
|
if (opts.json) {
|
|
20282
20458
|
const limits = tier ? checkAllLimits(usageMetrics, tier) : null;
|
|
20283
20459
|
const planConfig2 = tier ? PLAN_CONFIGS[tier] : null;
|
|
@@ -20289,23 +20465,33 @@ function usageCommand() {
|
|
|
20289
20465
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
20290
20466
|
periodStart: usageMetrics.periodStart,
|
|
20291
20467
|
periodEnd: usageMetrics.periodEnd,
|
|
20292
|
-
|
|
20468
|
+
// The server's own instant when it reported one. `null` means the
|
|
20469
|
+
// CLI was not told — it does NOT mean "no reset exists", and it is
|
|
20470
|
+
// not an invitation to compute one.
|
|
20471
|
+
resetDate: budget.resetsAt,
|
|
20293
20472
|
resetCadenceDays: QUOTA_PERIOD_DAYS2,
|
|
20473
|
+
quotaSource: budget.source,
|
|
20294
20474
|
usage: {
|
|
20295
|
-
mutations:
|
|
20296
|
-
|
|
20297
|
-
|
|
20298
|
-
percent: limits ? limits.mutations.usagePercent ?? 0 : null,
|
|
20299
|
-
allowed: limits ? limits.mutations.allowed : null
|
|
20300
|
-
},
|
|
20475
|
+
mutations: mutationsPayload(budget),
|
|
20476
|
+
// Scans have no server-side counterpart on the validate
|
|
20477
|
+
// response, so this half is local and says so.
|
|
20301
20478
|
scans: {
|
|
20479
|
+
source: "local-audit",
|
|
20302
20480
|
current: usageMetrics.totalScans,
|
|
20303
20481
|
limit: planConfig2 ? planConfig2.scansPerPeriod : null,
|
|
20304
20482
|
percent: limits ? limits.scans.usagePercent ?? 0 : null,
|
|
20305
20483
|
allowed: limits ? limits.scans.allowed : null
|
|
20306
20484
|
}
|
|
20307
20485
|
},
|
|
20308
|
-
|
|
20486
|
+
// The raw local counters, always under a key that names them as
|
|
20487
|
+
// local, so a consumer that wants this machine's view can have it
|
|
20488
|
+
// without it ever being mistaken for the quota.
|
|
20489
|
+
localAudit: {
|
|
20490
|
+
mutations: usageMetrics.mutationsApplied,
|
|
20491
|
+
scans: usageMetrics.totalScans,
|
|
20492
|
+
secretsBlocked: usageMetrics.secretsBlocked
|
|
20493
|
+
},
|
|
20494
|
+
overallPercent: budget.percent ?? (tier ? maxUsagePercent(usageMetrics, tier) : null),
|
|
20309
20495
|
recommendedUpgrade: tier ? recommendedTier(usageMetrics, tier) : null
|
|
20310
20496
|
},
|
|
20311
20497
|
null,
|
|
@@ -20314,11 +20500,11 @@ function usageCommand() {
|
|
|
20314
20500
|
);
|
|
20315
20501
|
return;
|
|
20316
20502
|
}
|
|
20317
|
-
const resetDate =
|
|
20503
|
+
const resetDate = resetLabel(resolution.quota);
|
|
20318
20504
|
console.log(
|
|
20319
20505
|
chalk9.cyan(
|
|
20320
|
-
"\n Pretense Usage \u2014 " + // Header shows today's date, NOT a billing month:
|
|
20321
|
-
//
|
|
20506
|
+
"\n Pretense Usage \u2014 " + // Header shows today's date, NOT a billing month: the quota window
|
|
20507
|
+
// trails the account's own activity, so a month name would imply a
|
|
20322
20508
|
// reset boundary that does not exist.
|
|
20323
20509
|
(/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
|
|
20324
20510
|
month: "long",
|
|
@@ -20337,35 +20523,60 @@ function usageCommand() {
|
|
|
20337
20523
|
console.log(chalk9.yellow(` ${line}`));
|
|
20338
20524
|
}
|
|
20339
20525
|
console.log();
|
|
20340
|
-
console.log(" " + "Mutations".padEnd(20) +
|
|
20526
|
+
console.log(" " + "Mutations".padEnd(20) + budget.used.toLocaleString("en-US"));
|
|
20341
20527
|
console.log(" " + "API Requests".padEnd(20) + usageMetrics.totalScans.toLocaleString("en-US"));
|
|
20342
20528
|
console.log(" " + "Secrets Blocked".padEnd(20) + usageMetrics.secretsBlocked.toLocaleString("en-US"));
|
|
20343
20529
|
console.log();
|
|
20530
|
+
for (const line of budgetSourceLines(budget, resolution, usageMetrics.mutationsApplied)) {
|
|
20531
|
+
console.log(chalk9.dim(` ${line}`));
|
|
20532
|
+
}
|
|
20533
|
+
console.log();
|
|
20344
20534
|
return;
|
|
20345
20535
|
}
|
|
20346
20536
|
const planConfig = PLAN_CONFIGS[tier];
|
|
20347
|
-
const overall = maxUsagePercent(usageMetrics, tier);
|
|
20537
|
+
const overall = budget.source === "server" ? budget.percent ?? 0 : maxUsagePercent(usageMetrics, tier);
|
|
20348
20538
|
const nextTier = recommendedTier(usageMetrics, tier);
|
|
20349
20539
|
console.log(
|
|
20350
20540
|
" " + chalk9.bold("Metric".padEnd(20)) + chalk9.bold("Used / Limit".padEnd(30)) + chalk9.bold("Progress")
|
|
20351
20541
|
);
|
|
20352
20542
|
console.log(" " + chalk9.dim("\u2500".repeat(72)));
|
|
20353
20543
|
const rows = [
|
|
20354
|
-
{
|
|
20355
|
-
|
|
20544
|
+
{
|
|
20545
|
+
label: "Mutations",
|
|
20546
|
+
value: budget.used,
|
|
20547
|
+
// `limitUnknown` must render as unknown, NOT as unlimited. That
|
|
20548
|
+
// conflation is the original defect: an org at 100% of its quota read
|
|
20549
|
+
// every missing field as "no limit" and was told it had none.
|
|
20550
|
+
limit: budget.limitUnknown ? null : budget.limit,
|
|
20551
|
+
percent: budget.percent
|
|
20552
|
+
},
|
|
20553
|
+
{
|
|
20554
|
+
label: "API Requests",
|
|
20555
|
+
value: usageMetrics.totalScans,
|
|
20556
|
+
limit: planConfig.scansPerPeriod,
|
|
20557
|
+
percent: null
|
|
20558
|
+
}
|
|
20356
20559
|
];
|
|
20357
20560
|
for (const row of rows) {
|
|
20358
|
-
const percent = row.limit === null ? 0 : Math.round(row.value / row.limit * 100);
|
|
20359
|
-
const
|
|
20561
|
+
const percent = row.percent ?? (row.limit === null ? 0 : Math.round(row.value / row.limit * 100));
|
|
20562
|
+
const unknown = row.label === "Mutations" && budget.limitUnknown;
|
|
20563
|
+
const bar2 = unknown ? chalk9.dim(" not reported ".padEnd(32)) : row.limit === null ? chalk9.dim(" unlimited ".padEnd(32)) : renderBar(percent);
|
|
20564
|
+
const used = unknown ? `${row.value.toLocaleString("en-US")} / not reported` : formatMetric(row.value, row.limit);
|
|
20360
20565
|
console.log(
|
|
20361
|
-
" " + row.label.padEnd(20) +
|
|
20566
|
+
" " + row.label.padEnd(20) + used.padEnd(30) + bar2 + " " + (row.limit === null || unknown ? "" : percentLabel(percent))
|
|
20362
20567
|
);
|
|
20363
20568
|
}
|
|
20364
20569
|
console.log(
|
|
20365
20570
|
" " + "Secrets Blocked".padEnd(20) + String(usageMetrics.secretsBlocked.toLocaleString("en-US")).padEnd(30) + chalk9.dim("(no limit)")
|
|
20366
20571
|
);
|
|
20367
20572
|
console.log(" " + chalk9.dim("\u2500".repeat(72)));
|
|
20368
|
-
|
|
20573
|
+
for (const line of budgetSourceLines(budget, resolution, usageMetrics.mutationsApplied)) {
|
|
20574
|
+
console.log(" " + chalk9.dim(line));
|
|
20575
|
+
}
|
|
20576
|
+
console.log(
|
|
20577
|
+
" " + chalk9.dim("API Requests / Secrets Blocked: counted locally on this machine.")
|
|
20578
|
+
);
|
|
20579
|
+
if (tier === "enterprise" && budget.unlimited) {
|
|
20369
20580
|
console.log(chalk9.green("\n Enterprise plan \u2014 all limits are unlimited.\n"));
|
|
20370
20581
|
} else if (overall >= 100) {
|
|
20371
20582
|
console.log(chalk9.red(`
|
|
@@ -20415,9 +20626,9 @@ import { Command as Command10 } from "commander";
|
|
|
20415
20626
|
import chalk10 from "chalk";
|
|
20416
20627
|
import { existsSync as existsSync12, readFileSync as readFileSync11, unlinkSync as unlinkSync2 } from "fs";
|
|
20417
20628
|
import { join as join14 } from "path";
|
|
20418
|
-
import { homedir as
|
|
20629
|
+
import { homedir as homedir8 } from "os";
|
|
20419
20630
|
import { execSync as execSync4 } from "child_process";
|
|
20420
|
-
var CREDENTIALS_DIR = join14(
|
|
20631
|
+
var CREDENTIALS_DIR = join14(homedir8(), ".pretense");
|
|
20421
20632
|
var CREDENTIALS_PATH = join14(CREDENTIALS_DIR, "credentials.json");
|
|
20422
20633
|
async function verifyApiKey(apiKey) {
|
|
20423
20634
|
const url = `${getConfiguredApiRoot()}/api/cli/auth/validate`;
|
|
@@ -21001,9 +21212,9 @@ import { Command as Command13 } from "commander";
|
|
|
21001
21212
|
import chalk13 from "chalk";
|
|
21002
21213
|
import { appendFileSync as appendFileSync3, readFileSync as readFileSync14, existsSync as existsSync14 } from "fs";
|
|
21003
21214
|
import { join as join17 } from "path";
|
|
21004
|
-
import { homedir as
|
|
21215
|
+
import { homedir as homedir9 } from "os";
|
|
21005
21216
|
var IGNORE_FILE = ".pretenseignore";
|
|
21006
|
-
var LAST_SCAN_PATH = join17(
|
|
21217
|
+
var LAST_SCAN_PATH = join17(homedir9(), ".pretense", "last-scan.json");
|
|
21007
21218
|
function ignorePath() {
|
|
21008
21219
|
return join17(process.cwd(), IGNORE_FILE);
|
|
21009
21220
|
}
|
|
@@ -21401,9 +21612,9 @@ import { resolve as resolve6, extname as extname4 } from "path";
|
|
|
21401
21612
|
// src/secret-crypto.ts
|
|
21402
21613
|
init_esm_shims();
|
|
21403
21614
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes3, hkdfSync as hkdfSync2 } from "crypto";
|
|
21404
|
-
import { homedir as
|
|
21615
|
+
import { homedir as homedir10 } from "os";
|
|
21405
21616
|
import { join as join19 } from "path";
|
|
21406
|
-
var KEYS_DIR = join19(
|
|
21617
|
+
var KEYS_DIR = join19(homedir10(), ".pretense", "keys");
|
|
21407
21618
|
var HKDF_SALT2 = Buffer.from("pretense-maps-v1", "utf-8");
|
|
21408
21619
|
var HKDF_INFO2 = Buffer.from("secret-mapping-aes-256-gcm", "utf-8");
|
|
21409
21620
|
var IV_LEN = 12;
|
|
@@ -21521,12 +21732,12 @@ function ensureDefaultMapPath(absFilePath, override2) {
|
|
|
21521
21732
|
|
|
21522
21733
|
// src/local-audit.ts
|
|
21523
21734
|
init_esm_shims();
|
|
21524
|
-
import { homedir as
|
|
21735
|
+
import { homedir as homedir11 } from "os";
|
|
21525
21736
|
import { join as join24 } from "path";
|
|
21526
21737
|
import { randomUUID } from "crypto";
|
|
21527
21738
|
import chalk15 from "chalk";
|
|
21528
21739
|
function localAuditDbPath() {
|
|
21529
|
-
return join24(
|
|
21740
|
+
return join24(homedir11(), ".pretense", "audit.db");
|
|
21530
21741
|
}
|
|
21531
21742
|
function recordLocalAudit(rec, dbPath = localAuditDbPath()) {
|
|
21532
21743
|
let store = null;
|
|
@@ -22524,7 +22735,7 @@ function policyCommand() {
|
|
|
22524
22735
|
init_esm_shims();
|
|
22525
22736
|
import { Command as Command20 } from "commander";
|
|
22526
22737
|
import chalk20 from "chalk";
|
|
22527
|
-
import { homedir as
|
|
22738
|
+
import { homedir as homedir12 } from "os";
|
|
22528
22739
|
import { join as join25 } from "path";
|
|
22529
22740
|
var VALID_FORMATS2 = ["table", "csv", "json", "jsonl"];
|
|
22530
22741
|
function toSafeAuditRow(e) {
|
|
@@ -22649,7 +22860,7 @@ function auditCommand() {
|
|
|
22649
22860
|
`));
|
|
22650
22861
|
process.exit(1);
|
|
22651
22862
|
}
|
|
22652
|
-
const dbPath = opts.db ?? join25(
|
|
22863
|
+
const dbPath = opts.db ?? join25(homedir12(), ".pretense", "audit.db");
|
|
22653
22864
|
let rows;
|
|
22654
22865
|
try {
|
|
22655
22866
|
const store = new AuditStore(dbPath);
|
|
@@ -22710,7 +22921,7 @@ init_esm_shims();
|
|
|
22710
22921
|
import { Command as Command21 } from "commander";
|
|
22711
22922
|
import chalk21 from "chalk";
|
|
22712
22923
|
import { join as join26 } from "path";
|
|
22713
|
-
import { homedir as
|
|
22924
|
+
import { homedir as homedir13 } from "os";
|
|
22714
22925
|
function remaining(used, limit) {
|
|
22715
22926
|
if (limit === null) return null;
|
|
22716
22927
|
return Math.max(0, limit - used);
|
|
@@ -22728,7 +22939,7 @@ function bar(used, limit, width = 24) {
|
|
|
22728
22939
|
return chalk21.green(s);
|
|
22729
22940
|
}
|
|
22730
22941
|
function creditsCommand() {
|
|
22731
|
-
return new Command21("credits").alias("tokens").description("Show remaining mutation budget for the current period").option("--db <path>", "Path to audit database", join26(
|
|
22942
|
+
return new Command21("credits").alias("tokens").description("Show remaining mutation budget for the current period").option("--db <path>", "Path to audit database", join26(homedir13(), ".pretense", "audit.db")).option("--json", "Output as JSON", false).option("--offline", "Do not contact the plan service to resolve the tier", false).action(async (opts) => {
|
|
22732
22943
|
const resolution = await resolvePlanTier({ offline: opts.offline });
|
|
22733
22944
|
const tier = resolution.tier;
|
|
22734
22945
|
const collected = collectUsage(opts.db);
|
|
@@ -22743,9 +22954,10 @@ function creditsCommand() {
|
|
|
22743
22954
|
if (!collected && !opts.json) {
|
|
22744
22955
|
console.log(chalk21.dim("\n No usage recorded yet \u2014 showing your full allowance.\n"));
|
|
22745
22956
|
}
|
|
22746
|
-
const
|
|
22957
|
+
const budget = resolveMutationBudget(resolution, m.mutationsApplied);
|
|
22958
|
+
const mutationLimit = budget.limitUnknown ? null : budget.limit;
|
|
22959
|
+
const mutationsLeft = budget.limitUnknown ? null : budget.remaining;
|
|
22747
22960
|
const scanLimit = tier ? PLAN_CONFIGS[tier].scansPerPeriod : null;
|
|
22748
|
-
const mutationsLeft = tier ? remaining(m.mutationsApplied, mutationLimit) : null;
|
|
22749
22961
|
const scansLeft = tier ? remaining(m.totalScans, scanLimit) : null;
|
|
22750
22962
|
if (opts.json) {
|
|
22751
22963
|
console.log(
|
|
@@ -22754,18 +22966,26 @@ function creditsCommand() {
|
|
|
22754
22966
|
tier,
|
|
22755
22967
|
tierSource: resolution.source,
|
|
22756
22968
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
22757
|
-
|
|
22969
|
+
// The server's instant when it sent one. It sends `periodResetsAt`
|
|
22970
|
+
// on every validation; this used to be hardcoded `null` while a
|
|
22971
|
+
// hardcoded cadence string was printed beside it.
|
|
22972
|
+
resetDate: budget.resetsAt,
|
|
22758
22973
|
resetCadenceDays: QUOTA_PERIOD_DAYS2,
|
|
22974
|
+
quotaSource: budget.source,
|
|
22759
22975
|
mutations: {
|
|
22760
|
-
|
|
22761
|
-
|
|
22762
|
-
|
|
22976
|
+
source: budget.source,
|
|
22977
|
+
used: budget.used,
|
|
22978
|
+
limit: mutationLimit,
|
|
22979
|
+
remaining: mutationsLeft,
|
|
22980
|
+
unlimited: budget.unlimited
|
|
22763
22981
|
},
|
|
22764
22982
|
scans: {
|
|
22983
|
+
source: "local-audit",
|
|
22765
22984
|
used: m.totalScans,
|
|
22766
22985
|
limit: tier ? scanLimit : null,
|
|
22767
22986
|
remaining: tier ? scansLeft : null
|
|
22768
|
-
}
|
|
22987
|
+
},
|
|
22988
|
+
localAudit: { mutations: m.mutationsApplied, scans: m.totalScans }
|
|
22769
22989
|
},
|
|
22770
22990
|
null,
|
|
22771
22991
|
2
|
|
@@ -22774,29 +22994,39 @@ function creditsCommand() {
|
|
|
22774
22994
|
return;
|
|
22775
22995
|
}
|
|
22776
22996
|
console.log(chalk21.cyan("\n Pretense Credits"));
|
|
22777
|
-
console.log(
|
|
22778
|
-
`))
|
|
22997
|
+
console.log(
|
|
22998
|
+
chalk21.dim(` Plan: ${tierLabel(tier)} | Resets: ${resetLabel(resolution.quota)}
|
|
22999
|
+
`)
|
|
23000
|
+
);
|
|
22779
23001
|
if (!tier) {
|
|
22780
23002
|
for (const line of unverifiedNote(resolution.detail)) {
|
|
22781
23003
|
console.log(chalk21.yellow(` ${line}`));
|
|
22782
23004
|
}
|
|
22783
23005
|
console.log();
|
|
22784
|
-
console.log(" " + "Mutations used".padEnd(20) +
|
|
23006
|
+
console.log(" " + "Mutations used".padEnd(20) + budget.used.toLocaleString("en-US"));
|
|
22785
23007
|
console.log(" " + "Requests used".padEnd(20) + m.totalScans.toLocaleString("en-US"));
|
|
22786
23008
|
console.log();
|
|
23009
|
+
for (const line of budgetSourceLines(budget, resolution, m.mutationsApplied)) {
|
|
23010
|
+
console.log(chalk21.dim(` ${line}`));
|
|
23011
|
+
}
|
|
23012
|
+
console.log();
|
|
22787
23013
|
return;
|
|
22788
23014
|
}
|
|
22789
23015
|
console.log(
|
|
22790
|
-
" " + "Mutations".padEnd(14) + bar(
|
|
23016
|
+
" " + "Mutations".padEnd(14) + bar(budget.used, mutationLimit) + " " + chalk21.bold(fmt(mutationsLeft)) + chalk21.dim(` left of ${fmt(mutationLimit)}`)
|
|
22791
23017
|
);
|
|
22792
23018
|
console.log(
|
|
22793
23019
|
" " + "Requests".padEnd(14) + bar(m.totalScans, scanLimit) + " " + chalk21.bold(fmt(scansLeft)) + chalk21.dim(` left of ${fmt(scanLimit)}`)
|
|
22794
23020
|
);
|
|
23021
|
+
console.log();
|
|
23022
|
+
for (const line of budgetSourceLines(budget, resolution, m.mutationsApplied)) {
|
|
23023
|
+
console.log(chalk21.dim(` ${line}`));
|
|
23024
|
+
}
|
|
22795
23025
|
if (tier !== "enterprise" && mutationLimit !== null && mutationsLeft === 0) {
|
|
22796
23026
|
console.log(
|
|
22797
23027
|
chalk21.red("\n Mutation budget exhausted for this period.") + chalk21.dim(" Run ") + chalk21.cyan("pretense upgrade") + chalk21.dim(" to compare plans.")
|
|
22798
23028
|
);
|
|
22799
|
-
} else if (tier !== "enterprise" && mutationLimit !== null &&
|
|
23029
|
+
} else if (tier !== "enterprise" && mutationLimit !== null && budget.used >= mutationLimit * 0.8) {
|
|
22800
23030
|
console.log(
|
|
22801
23031
|
chalk21.yellow("\n Running low.") + chalk21.dim(" Run ") + chalk21.cyan("pretense upgrade") + chalk21.dim(" to compare plans.")
|
|
22802
23032
|
);
|
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.27",
|
|
4
4
|
"description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
"typescript": "^5.4.0",
|
|
25
25
|
"vitest": "^1.0.0",
|
|
26
26
|
"@pretense/billing": "0.1.0",
|
|
27
|
-
"@pretense/learner": "0.2.0",
|
|
28
27
|
"@pretense/compliance-engine": "0.1.0",
|
|
29
|
-
"@pretense/
|
|
28
|
+
"@pretense/protocol": "0.1.0",
|
|
29
|
+
"@pretense/learner": "0.2.0",
|
|
30
30
|
"@pretense/proxy": "0.1.0",
|
|
31
|
+
"@pretense/mutator": "0.2.0",
|
|
31
32
|
"@pretense/scanner": "0.2.0",
|
|
32
33
|
"@pretense/scanner-rs": "0.2.0",
|
|
33
|
-
"@pretense/store": "0.2.0"
|
|
34
|
-
"@pretense/protocol": "0.1.0"
|
|
34
|
+
"@pretense/store": "0.2.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public",
|