@pretense/cli 0.6.22 → 0.6.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -324,6 +324,22 @@ provider automatically (`claude` → Anthropic, `cursor`/`code` → OpenAI-compa
324
324
  on your `PATH`, `run` prints an install hint and exits non-zero instead of
325
325
  crashing — and it never tears down a proxy it did not start.
326
326
 
327
+ ### Works with your LLM
328
+
329
+ `pretense run` sets the base-URL env var that each tool reads. The proxy mutates
330
+ all three provider request shapes (`/v1/messages`, `/v1/chat/completions`,
331
+ `/v1beta/…/generateContent`), so the same mutation engine covers every tool
332
+ below.
333
+
334
+ | Tool | Provider | Base-URL env var(s) `run` sets |
335
+ | --- | --- | --- |
336
+ | `claude`, `claude-code` | Anthropic | `ANTHROPIC_BASE_URL` |
337
+ | `cursor`, `codex` | OpenAI-compatible | `OPENAI_BASE_URL` (with a `/v1` suffix) |
338
+ | `gemini` | Google | `GEMINI_BASE_URL` **and** `GOOGLE_GEMINI_BASE_URL` |
339
+
340
+ For any other tool, pass `--provider anthropic|openai|google` to pick the
341
+ mapping.
342
+
327
343
  Read this before you rely on the proxy:
328
344
 
329
345
  - **npm install only.** `start` crashes on the `curl | sh` binary
@@ -543,10 +559,41 @@ of **36** compliance frameworks vendored from the `pretense-compliance-standards
543
559
  dataset (`pretense audit --list-frameworks` prints them). The two lists are not
544
560
  the same thing and should never be conflated.
545
561
 
562
+ ## Git hooks
563
+
564
+ `pretense install` writes Pretense Git hooks into the current repository so a
565
+ secret cannot reach a commit or a push:
566
+
567
+ ```bash
568
+ pretense install # installs both pre-commit and pre-push hooks
569
+ ```
570
+
571
+ <!-- docs-exec:expect "pretense install" 1 — the isolated session dir is deliberately not a git repo, so install has no .git to write into and exits 1 -->
572
+
573
+ Pass `--mode pre-commit` or `--mode pre-push` to install just one, and `--force`
574
+ to overwrite an existing hook. `pretense install` must be run from a repository
575
+ root; it exits `1` with a named error when there is no `.git` directory.
576
+
577
+ - The **pre-commit** hook runs `pretense scan pre-commit` over your staged files.
578
+ A commit that contains an AWS access key (`AKIA…`) is blocked with an
579
+ `aws-access-key` finding and never lands.
580
+ - The **pre-push** hook runs `pretense scan pre-push` over the commits being
581
+ pushed (it reads git's pre-push ref lines on stdin), catching anything that
582
+ slipped past pre-commit.
583
+
546
584
  ## Supported languages
547
585
 
548
586
  TypeScript, JavaScript, Python, Go, Java, C#, Ruby, Rust.
549
587
 
588
+ ## Supported platforms
589
+
590
+ The CLI runs on **macOS** (x64 and arm64), **Linux** (glibc and musl) and
591
+ **Windows**. L1 detection (regex, 98 patterns) runs on all of them with no native
592
+ dependencies. L2 detection needs the native `@pretense/scanner-rs` addon, which
593
+ is not published for every platform; where it is missing the CLI degrades to L1
594
+ in full and prints `L2 unavailable` rather than reporting less — see
595
+ [Detection levels](#detection-levels-l1-and-l2).
596
+
550
597
  ## Detection levels (L1 and L2)
551
598
 
552
599
  <!-- OBSERVED, not specified. Every output block below was produced on
@@ -17,7 +17,7 @@ function versionFromPackageJson() {
17
17
  return void 0;
18
18
  }
19
19
  }
20
- var PRETENSE_VERSION = (true ? "0.6.22" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
20
+ var PRETENSE_VERSION = (true ? "0.6.24" : 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-BWS6UMKL.js";
4
+ } from "./chunk-AWXABIHH.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.22" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16660
+ return override ?? (true ? "0.6.24" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16661
16661
  }
16662
16662
  var UNKNOWN_COMMIT = "unknown";
16663
16663
  function bakedCommitSha() {
16664
- return "6c0840ef4a9ecc06829215df3a27c5a1b1b603ab".length > 0 ? "6c0840ef4a9ecc06829215df3a27c5a1b1b603ab" : UNKNOWN_COMMIT;
16664
+ return "b258672fe5eb6d72b12faf92d12452d06dfa8ab2".length > 0 ? "b258672fe5eb6d72b12faf92d12452d06dfa8ab2" : UNKNOWN_COMMIT;
16665
16665
  }
16666
16666
  var FEATURE_TIERS = {
16667
16667
  compliance_export: "pro",
@@ -18634,6 +18634,20 @@ function planToTier(plan) {
18634
18634
  return null;
18635
18635
  }
18636
18636
  }
18637
+ function parseEntitlement(body) {
18638
+ const raw2 = body["entitlement"];
18639
+ if (!raw2 || typeof raw2 !== "object") return void 0;
18640
+ const e = raw2;
18641
+ const effectivePlan = planToTier(e["effectivePlan"]);
18642
+ const planOnRecord = planToTier(e["planOnRecord"]);
18643
+ if (effectivePlan === null && planOnRecord === null) return void 0;
18644
+ return {
18645
+ effectivePlan,
18646
+ planOnRecord,
18647
+ comped: e["comped"] === true,
18648
+ hasActiveSubscription: e["hasActiveSubscription"] === true
18649
+ };
18650
+ }
18637
18651
  async function tierFromBackend(apiKey) {
18638
18652
  const url = `${getConfiguredApiRoot()}/api/cli/auth/validate`;
18639
18653
  const controller = new AbortController();
@@ -18668,7 +18682,7 @@ async function tierFromBackend(apiKey) {
18668
18682
  detail: "the plan service did not report a recognizable plan"
18669
18683
  };
18670
18684
  }
18671
- return { tier, source: "backend" };
18685
+ return { tier, source: "backend", entitlement: parseEntitlement(body) };
18672
18686
  } catch (err) {
18673
18687
  const aborted = err?.name === "AbortError";
18674
18688
  return {
@@ -18743,8 +18757,21 @@ function tierLabel(tier) {
18743
18757
  if (tier === "free") return "Free";
18744
18758
  return `${tierName(tier)} (${priceLabel(tier)})`;
18745
18759
  }
18760
+ function entitlementMismatchLines(ent) {
18761
+ const paidOnRecord = ent.planOnRecord === "pro" || ent.planOnRecord === "enterprise";
18762
+ if (ent.effectivePlan !== "free" || !paidOnRecord) return [];
18763
+ const planName = ent.planOnRecord === "enterprise" ? "Enterprise" : "Pro";
18764
+ 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."
18767
+ ];
18768
+ }
18746
18769
  function planMismatchHint(resolution) {
18747
- if (resolution.tier !== "free" || resolution.source !== "backend") return [];
18770
+ if (resolution.source !== "backend") return [];
18771
+ if (resolution.entitlement) {
18772
+ return entitlementMismatchLines(resolution.entitlement);
18773
+ }
18774
+ if (resolution.tier !== "free") return [];
18748
18775
  return [
18749
18776
  "Not the plan you expected? An org flagged PRO without an active",
18750
18777
  "subscription/comp resolves to Free \u2014 see pretense.ai/dashboard/settings or contact support."
@@ -20376,7 +20403,7 @@ async function verifyApiKey(apiKey) {
20376
20403
  return { outcome: "rejected", url, detail: "the API reported the key as not valid" };
20377
20404
  }
20378
20405
  const plan = typeof body["plan"] === "string" ? body["plan"] : void 0;
20379
- return { outcome: "valid", url, plan };
20406
+ return { outcome: "valid", url, plan, entitlement: parseEntitlement(body) };
20380
20407
  } catch (err) {
20381
20408
  const aborted = err?.name === "AbortError";
20382
20409
  return {
@@ -20495,14 +20522,15 @@ function authCommand() {
20495
20522
  };
20496
20523
  writeCredentials(creds);
20497
20524
  if (verified) {
20498
- const planIsFree = String(verification.plan ?? "").trim().toLowerCase() === "free";
20525
+ const mismatchLines = verification.entitlement ? entitlementMismatchLines(verification.entitlement) : String(verification.plan ?? "").trim().toLowerCase() === "free" ? [
20526
+ "Not the plan you expected? A PRO-flagged org without an active",
20527
+ "subscription/comp resolves to Free \u2014 see pretense.ai/dashboard/settings."
20528
+ ] : [];
20499
20529
  console.log(
20500
20530
  chalk10.green("\n Authenticated. The key was verified by the Pretense API.") + chalk10.dim(`
20501
20531
  Key: ${maskApiKey(opts.apiKey)}`) + chalk10.dim(`
20502
20532
  Server: ${verification.url}`) + (verification.plan ? chalk10.dim(`
20503
- Plan: ${verification.plan}`) : "") + (planIsFree ? chalk10.dim(
20504
- "\n Not the plan you expected? A PRO-flagged org without an active\n subscription/comp resolves to Free \u2014 see pretense.ai/dashboard/settings."
20505
- ) : "") + "\n" + storageNotice()
20533
+ Plan: ${verification.plan}`) : "") + (mismatchLines.length > 0 ? chalk10.dim("\n " + mismatchLines.join("\n ")) : "") + "\n" + storageNotice()
20506
20534
  );
20507
20535
  return;
20508
20536
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PRETENSE_VERSION
4
- } from "./chunk-BWS6UMKL.js";
4
+ } from "./chunk-AWXABIHH.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.22",
3
+ "version": "0.6.24",
4
4
  "description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,13 +25,13 @@
25
25
  "vitest": "^1.0.0",
26
26
  "@pretense/billing": "0.1.0",
27
27
  "@pretense/compliance-engine": "0.1.0",
28
+ "@pretense/protocol": "0.1.0",
28
29
  "@pretense/learner": "0.2.0",
29
30
  "@pretense/mutator": "0.2.0",
30
31
  "@pretense/proxy": "0.1.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",