@pretense/cli 0.6.21 → 0.6.23

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.21" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
20
+ var PRETENSE_VERSION = (true ? "0.6.23" : 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-2BMR5XBU.js";
4
+ } from "./chunk-Y7SXGTHU.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.21" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16660
+ return override ?? (true ? "0.6.23" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
16661
16661
  }
16662
16662
  var UNKNOWN_COMMIT = "unknown";
16663
16663
  function bakedCommitSha() {
16664
- return "7e80103647b573f455a73aecebeae1a0e2fa3ac9".length > 0 ? "7e80103647b573f455a73aecebeae1a0e2fa3ac9" : UNKNOWN_COMMIT;
16664
+ return "3bc1a6f92239a8ea27af2a6558e968baf4b94d71".length > 0 ? "3bc1a6f92239a8ea27af2a6558e968baf4b94d71" : UNKNOWN_COMMIT;
16665
16665
  }
16666
16666
  var FEATURE_TIERS = {
16667
16667
  compliance_export: "pro",
@@ -18089,7 +18089,12 @@ ${_upgradeTier === "enterprise" ? "Enterprise offers unlimited mutations \u2014
18089
18089
  action: "blocked",
18090
18090
  secretsBlocked: secretsTokenized,
18091
18091
  piiRedacted: piiTokenized,
18092
- mutationCount: tokensMutated,
18092
+ // TRUTHFUL COUNT: every span this proxy rewrote before egress, of any
18093
+ // kind (identifier tokens + tokenized secrets/PII) — the SAME number the
18094
+ // audit row logs as `mutationsApplied`. `tokensMutated` alone counted
18095
+ // only code identifiers, so a secret-only mutation pushed mutationCount:0
18096
+ // to the live dashboard even though a secret WAS mutated on the wire.
18097
+ mutationCount: mutationsApplied,
18093
18098
  bytesScanned: fullText.length,
18094
18099
  provider,
18095
18100
  findings: riskResult.factors.map((f) => f.name),
@@ -18171,7 +18176,12 @@ ${_upgradeTier === "enterprise" ? "Enterprise offers unlimited mutations \u2014
18171
18176
  action: "error",
18172
18177
  secretsBlocked: secretsTokenized,
18173
18178
  piiRedacted: piiTokenized,
18174
- mutationCount: tokensMutated,
18179
+ // TRUTHFUL COUNT: every span this proxy rewrote before egress, of any
18180
+ // kind (identifier tokens + tokenized secrets/PII) — the SAME number the
18181
+ // audit row logs as `mutationsApplied`. `tokensMutated` alone counted
18182
+ // only code identifiers, so a secret-only mutation pushed mutationCount:0
18183
+ // to the live dashboard even though a secret WAS mutated on the wire.
18184
+ mutationCount: mutationsApplied,
18175
18185
  bytesScanned: originalSize,
18176
18186
  provider,
18177
18187
  findings: ["upstream_unreachable"],
@@ -18210,12 +18220,23 @@ ${_upgradeTier === "enterprise" ? "Enterprise offers unlimited mutations \u2014
18210
18220
  action: anyTokenized ? "mutated" : "allowed",
18211
18221
  secretsBlocked: secretsTokenized,
18212
18222
  piiRedacted: piiTokenized,
18213
- mutationCount: tokensMutated,
18223
+ // TRUTHFUL COUNT: every span rewritten before egress (identifier tokens +
18224
+ // tokenized secrets/PII), matching the audit row's `mutationsApplied`. Using
18225
+ // `tokensMutated` here made the live dashboard show mutationCount:0 for a
18226
+ // request whose only mutation was a tokenized secret — the exact "meter logs
18227
+ // 0" defect. severity now reflects it too (mutationCount>0 -> 3, not 1).
18228
+ mutationCount: mutationsApplied,
18214
18229
  bytesScanned: originalSize,
18215
18230
  provider,
18216
- // Surface the skip in the telemetry stream too, so a dashboard/SIEM can
18217
- // alert on unscannable egress fields rather than assume full coverage.
18218
- ...skippedUnscannable > 0 ? { findings: ["skipped_unscannable_field"] } : {},
18231
+ // Detector KINDS that fired (e.g. "aws_access_key") metadata only, the same
18232
+ // kinds the audit row records as `detectorKinds`. NEVER secret VALUES or
18233
+ // identifier NAMES (the SSE bus carries the usage-upload privacy contract).
18234
+ // Plus the unscannable-skip marker so a dashboard/SIEM can alert on coverage
18235
+ // gaps rather than assume full coverage.
18236
+ findings: [
18237
+ ...foundTypes,
18238
+ ...skippedUnscannable > 0 ? ["skipped_unscannable_field"] : []
18239
+ ],
18219
18240
  sourceIp: c.req.header("x-forwarded-for") ?? c.req.header("x-real-ip")
18220
18241
  }));
18221
18242
  if (anyTokenized) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PRETENSE_VERSION
4
- } from "./chunk-2BMR5XBU.js";
4
+ } from "./chunk-Y7SXGTHU.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.21",
3
+ "version": "0.6.23",
4
4
  "description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,6 @@
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",
@@ -31,6 +30,7 @@
31
30
  "@pretense/proxy": "0.1.0",
32
31
  "@pretense/scanner": "0.2.0",
33
32
  "@pretense/scanner-rs": "0.2.0",
33
+ "@pretense/billing": "0.1.0",
34
34
  "@pretense/store": "0.2.0"
35
35
  },
36
36
  "publishConfig": {