@compaction/cli 0.2.0 → 0.3.1
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 +142 -64
- package/dist/cli/commands/activity.d.ts +8 -0
- package/dist/cli/commands/activity.js +35 -0
- package/dist/cli/commands/apply-context.js +68 -0
- package/dist/cli/commands/billing-delta.js +12 -1
- package/dist/cli/commands/capture-claude-code.d.ts +44 -0
- package/dist/cli/commands/capture-claude-code.js +206 -0
- package/dist/cli/commands/capture.js +283 -1
- package/dist/cli/commands/compact.js +9 -5
- package/dist/cli/commands/dev.d.ts +17 -0
- package/dist/cli/commands/dev.js +131 -0
- package/dist/cli/commands/gateway.d.ts +31 -0
- package/dist/cli/commands/gateway.js +312 -0
- package/dist/cli/commands/hooks.d.ts +5 -0
- package/dist/cli/commands/hooks.js +181 -0
- package/dist/cli/commands/init.js +422 -17
- package/dist/cli/commands/input-compaction-ab.d.ts +2 -0
- package/dist/cli/commands/input-compaction-ab.js +125 -0
- package/dist/cli/commands/optimize-hosted.d.ts +54 -0
- package/dist/cli/commands/optimize-hosted.js +123 -0
- package/dist/cli/commands/optimize.js +8 -0
- package/dist/cli/commands/output-shaping-ab.d.ts +2 -0
- package/dist/cli/commands/output-shaping-ab.js +132 -0
- package/dist/cli/commands/output-shaping.d.ts +7 -0
- package/dist/cli/commands/output-shaping.js +43 -0
- package/dist/cli/commands/policies.d.ts +2 -0
- package/dist/cli/commands/policies.js +80 -0
- package/dist/cli/commands/precall.d.ts +19 -0
- package/dist/cli/commands/precall.js +436 -0
- package/dist/cli/commands/recommend.js +1 -1
- package/dist/cli/commands/run.js +297 -12
- package/dist/cli/commands/upgrade-status.d.ts +42 -0
- package/dist/cli/commands/upgrade-status.js +152 -0
- package/dist/cli/cursor-export-read.d.ts +13 -0
- package/dist/cli/cursor-export-read.js +53 -0
- package/dist/cli/cursor-live-preflight.d.ts +19 -0
- package/dist/cli/cursor-live-preflight.js +46 -0
- package/dist/cli/index.js +36 -2
- package/dist/cli/onboarding/GatewayTui.d.ts +33 -0
- package/dist/cli/onboarding/GatewayTui.js +113 -0
- package/dist/cli/onboarding/model.d.ts +32 -1
- package/dist/cli/onboarding/model.js +27 -2
- package/dist/cli/terminal-logo.d.ts +27 -0
- package/dist/cli/terminal-logo.js +49 -0
- package/dist/core/activity-event.d.ts +107 -0
- package/dist/core/activity-event.js +182 -0
- package/dist/core/activity-store.d.ts +63 -0
- package/dist/core/activity-store.js +254 -0
- package/dist/core/activity-view.d.ts +76 -0
- package/dist/core/activity-view.js +120 -0
- package/dist/core/api-client/index.d.ts +3 -1
- package/dist/core/api-client/index.js +4 -0
- package/dist/core/api-client/payload.d.ts +5 -1
- package/dist/core/api-client/payload.js +8 -6
- package/dist/core/api-client/persisted-config.d.ts +57 -0
- package/dist/core/api-client/persisted-config.js +156 -0
- package/dist/core/api-client/tool.d.ts +29 -0
- package/dist/core/api-client/tool.js +50 -0
- package/dist/core/api-client/types.d.ts +15 -4
- package/dist/core/auto-apply-ask.d.ts +58 -0
- package/dist/core/auto-apply-ask.js +105 -0
- package/dist/core/auto-apply-gates.d.ts +76 -0
- package/dist/core/auto-apply-gates.js +113 -0
- package/dist/core/before-call-activity.d.ts +35 -0
- package/dist/core/before-call-activity.js +103 -0
- package/dist/core/before-call-recovery.d.ts +19 -0
- package/dist/core/before-call-recovery.js +46 -0
- package/dist/core/before-call-stdin.d.ts +59 -0
- package/dist/core/before-call-stdin.js +78 -0
- package/dist/core/before-call.d.ts +149 -0
- package/dist/core/before-call.js +358 -0
- package/dist/core/billing-delta/billing-delta-record.d.ts +28 -0
- package/dist/core/billing-delta/billing-delta-record.js +26 -0
- package/dist/core/capture-record.d.ts +40 -0
- package/dist/core/capture-record.js +55 -0
- package/dist/core/claude-code-before-call.d.ts +37 -0
- package/dist/core/claude-code-before-call.js +120 -0
- package/dist/core/claude-code-connect.d.ts +31 -0
- package/dist/core/claude-code-connect.js +87 -0
- package/dist/core/claude-code-hook-record.d.ts +71 -0
- package/dist/core/claude-code-hook-record.js +0 -0
- package/dist/core/claude-code-hooks.d.ts +77 -0
- package/dist/core/claude-code-hooks.js +141 -0
- package/dist/core/codex-capture.d.ts +45 -0
- package/dist/core/codex-capture.js +204 -0
- package/dist/core/command-runner.js +5 -1
- package/dist/core/compaction-artifacts.d.ts +51 -0
- package/dist/core/compaction-artifacts.js +242 -0
- package/dist/core/compactor.d.ts +9 -0
- package/dist/core/compactor.js +95 -0
- package/dist/core/cross-surface-event.d.ts +306 -0
- package/dist/core/cross-surface-event.js +330 -0
- package/dist/core/cursor-capture.d.ts +54 -0
- package/dist/core/cursor-capture.js +215 -0
- package/dist/core/cursor-preflight-probe.d.ts +8 -0
- package/dist/core/cursor-preflight-probe.js +88 -0
- package/dist/core/cursor-preflight.d.ts +86 -0
- package/dist/core/cursor-preflight.js +126 -0
- package/dist/core/gateway/apply-activation.d.ts +39 -0
- package/dist/core/gateway/apply-activation.js +84 -0
- package/dist/core/gateway/apply-policy.d.ts +64 -0
- package/dist/core/gateway/apply-policy.js +221 -0
- package/dist/core/gateway/apply-receipt.d.ts +36 -0
- package/dist/core/gateway/apply-receipt.js +75 -0
- package/dist/core/gateway/cache-proof.d.ts +45 -0
- package/dist/core/gateway/cache-proof.js +65 -0
- package/dist/core/gateway/configure.d.ts +50 -0
- package/dist/core/gateway/configure.js +169 -0
- package/dist/core/gateway/openai-usage.d.ts +56 -0
- package/dist/core/gateway/openai-usage.js +128 -0
- package/dist/core/gateway/receipt.d.ts +138 -0
- package/dist/core/gateway/receipt.js +120 -0
- package/dist/core/gateway/recovery.d.ts +23 -0
- package/dist/core/gateway/recovery.js +68 -0
- package/dist/core/gateway/server.d.ts +51 -0
- package/dist/core/gateway/server.js +276 -0
- package/dist/core/gateway/status.d.ts +45 -0
- package/dist/core/gateway/status.js +109 -0
- package/dist/core/hook-usage-aggregate.d.ts +47 -0
- package/dist/core/hook-usage-aggregate.js +161 -0
- package/dist/core/input-compaction-ab.d.ts +111 -0
- package/dist/core/input-compaction-ab.js +158 -0
- package/dist/core/local-run-record.d.ts +109 -0
- package/dist/core/local-run-record.js +223 -0
- package/dist/core/output-shaping-ab.d.ts +140 -0
- package/dist/core/output-shaping-ab.js +146 -0
- package/dist/core/output-shaping-attach.d.ts +31 -0
- package/dist/core/output-shaping-attach.js +57 -0
- package/dist/core/output-shaping.d.ts +56 -0
- package/dist/core/output-shaping.js +89 -0
- package/dist/core/policy-middleware.d.ts +121 -0
- package/dist/core/policy-middleware.js +919 -0
- package/dist/core/policy-preferences.d.ts +99 -0
- package/dist/core/policy-preferences.js +232 -0
- package/dist/core/run-aggregator.d.ts +11 -1
- package/dist/core/run-aggregator.js +29 -2
- package/dist/core/run-flow-report.d.ts +82 -0
- package/dist/core/run-flow-report.js +71 -0
- package/dist/core/safety-report.js +8 -1
- package/dist/core/shim-capture-bridge.d.ts +32 -0
- package/dist/core/shim-capture-bridge.js +88 -0
- package/dist/core/skill-injection-policy.d.ts +72 -0
- package/dist/core/skill-injection-policy.js +183 -0
- package/dist/core/spend-attribution.js +1 -1
- package/dist/core/token-accounting.d.ts +1 -1
- package/dist/core/tool-shim.d.ts +129 -0
- package/dist/core/tool-shim.js +447 -0
- package/dist/core/trace-parser.d.ts +13 -13
- package/dist/core/trace-parser.js +6 -6
- package/dist/core/types.d.ts +12 -2
- package/dist/core/waste-detector.d.ts +20 -0
- package/dist/core/waste-detector.js +160 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,53 @@
|
|
|
1
1
|
# @compaction/cli
|
|
2
2
|
|
|
3
|
-
**The free, local-first CLI for
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
**The free, local-first CLI for the Compaction Gateway — a local, OpenAI-compatible proxy that
|
|
4
|
+
measures your AI traffic without changing it.** Point your OpenAI-compatible client's base URL at
|
|
5
|
+
the local gateway (or launch your workflow through it) and it forwards traffic to your provider and
|
|
6
|
+
records **content-free** token/cache receipts — counts and labels only, never prompt/response
|
|
7
|
+
content. Your provider key stays on the client. The CLI also captures and measures agent traces
|
|
8
|
+
locally. Everything runs on your machine — **no account, no telemetry, no upload to Compaction.**
|
|
9
|
+
|
|
10
|
+
> The free CLI runs the **local Gateway** (byte-safe **record** mode + content-free receipts, plus
|
|
11
|
+
> an **explicit, experimental deterministic apply/recovery**), captures and measures agent traces,
|
|
12
|
+
> and performs deterministic local compaction with the basic policies (`compact`) — writing honest
|
|
13
|
+
> before/after artifacts. The **learned context model (LCM), learned optimization engine, hosted /
|
|
14
|
+
> team control plane, verified-savings logic, and advanced proprietary evals are NOT in the npm /
|
|
15
|
+
> free CLI** — they are the **opt-in Compaction API**, which is **not a live hosted service yet**.
|
|
16
|
+
|
|
17
|
+
## The Gateway (local, byte-safe)
|
|
18
|
+
|
|
19
|
+
The Compaction **Gateway** is a **local, OpenAI-compatible reverse proxy for OpenAI-compatible
|
|
20
|
+
clients**. Point your client's base URL at it, or launch your workflow through it, and it forwards
|
|
21
|
+
traffic to your provider and records **content-free** token/cache receipts (counts / structure /
|
|
22
|
+
labels only — never prompt/response content). Your provider key rides straight through to the
|
|
23
|
+
provider and is **never read, stored, or logged**. Set it up from onboarding (`compaction` →
|
|
24
|
+
**Gateway setup**), or directly:
|
|
7
25
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
26
|
+
```bash
|
|
27
|
+
compaction gateway start # start the local gateway (RECORD mode: byte-safe, no mutation)
|
|
28
|
+
compaction gateway run -- npm run dev # run a command through the gateway (no baseURL copy-paste)
|
|
29
|
+
compaction gateway status # requests observed + a content-free receipts rollup
|
|
30
|
+
compaction gateway activate # print env exports: eval "$(compaction gateway activate)"
|
|
31
|
+
```
|
|
13
32
|
|
|
14
|
-
|
|
33
|
+
- **Record mode is byte-safe** — it forwards your request and the provider's response
|
|
34
|
+
**byte-for-byte** and never changes either. Receipts are content-free and local-only (gitignored).
|
|
35
|
+
- **Explicit, experimental deterministic apply** (`--mode apply --policy deterministic-dedupe`) can
|
|
36
|
+
remove **exact-duplicate large blocks** from known-safe requests. It is **off by default**,
|
|
37
|
+
opt-in, and **retains the original locally** (`compaction gateway recover <id>`). Unknown/complex
|
|
38
|
+
shapes **fail closed** (forwarded unchanged); system/developer instructions and tool schemas are
|
|
39
|
+
never touched; the **response is never changed**.
|
|
40
|
+
- **No hosted/managed proxy or model routing.** The local Gateway is an OpenAI-compatible reverse
|
|
41
|
+
proxy for compatible clients — it runs on your machine.
|
|
42
|
+
- **Claim boundary.** The gateway reports **provider-reported** token/cache counts (or
|
|
43
|
+
`unavailable`) — it makes **no cost-savings, no output-token-savings, and no billing-confirmed
|
|
44
|
+
claim**. A model-visible **input** reduction is stated only when apply actually changed the
|
|
45
|
+
request (a **local-estimate** before/after; the original is retained) — never a cost or
|
|
46
|
+
output-token figure, and never a "no context lost" claim.
|
|
47
|
+
|
|
48
|
+
## Trace / capture utilities (other local tools)
|
|
49
|
+
|
|
50
|
+
Beyond the Gateway, the free CLI captures and measures agent traces locally — local files only:
|
|
15
51
|
|
|
16
52
|
- **Capture supported agent sessions.** Claude Code is the primary supported workflow
|
|
17
53
|
(`capture claude-code`); OpenAI Agents SDK (`capture openai-agents`) and Codex / local-file
|
|
@@ -22,59 +58,64 @@ Everything below runs on your machine and writes local files only:
|
|
|
22
58
|
run carries provider usage metadata; otherwise they are a **local estimate (chars/4)**. Cost is
|
|
23
59
|
a **price-table estimate** labeled `local estimate` / `token-estimated cost` — **never
|
|
24
60
|
billing-confirmed**.
|
|
61
|
+
- **Compact deterministically, locally.** `compact` applies the basic deterministic policies
|
|
62
|
+
(e.g. `stale_tool_output_to_state_capsule`) to a captured/imported trace and writes honest
|
|
63
|
+
before/after artifacts locally (report, safety/recoverability report, state capsules). The
|
|
64
|
+
original trace is retained, token figures stay **local estimates** unless provider-reported,
|
|
65
|
+
and **nothing is applied to your workflow automatically**.
|
|
25
66
|
- **Inspect spend and roll up runs.** `spend`, `summary`, and `aggregate` summarize where context
|
|
26
67
|
spend came from and roll up local runs — local files only, no hosted dashboard.
|
|
27
68
|
- **Build a local context store and retrieve from it.** `context add` accumulates source-pointed
|
|
28
69
|
items from a captured/imported trace into a local, size-capped store; `context get`
|
|
29
70
|
deterministically retrieves and assembles the active context for a query under a token budget,
|
|
30
|
-
printing it **with source pointers** plus local retrieval **diagnostics
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- **Write local reports.** `analyze` writes local JSON + Markdown reports under an
|
|
36
|
-
operator-chosen output directory. Local files only.
|
|
71
|
+
printing it **with source pointers** plus local retrieval **diagnostics**. Local-only and
|
|
72
|
+
deterministic — **no model, no embeddings, no network**. It reports **diagnostics only** and
|
|
73
|
+
makes **no savings claim**.
|
|
74
|
+
- **Write local reports.** `analyze` writes local JSON + Markdown reports under an operator-chosen
|
|
75
|
+
output directory. Local files only.
|
|
37
76
|
- **Create redacted, content-free share bundles.** `feedback --redact` writes a redacted,
|
|
38
77
|
privacy-safe bundle as a **local file only — never uploaded**, and only with an explicit write
|
|
39
78
|
gesture (`--yes`).
|
|
40
|
-
- **No upload by default.** There is **no telemetry**. The **only** network call in the free CLI
|
|
41
|
-
is the explicitly operator-invoked, read-only `capture provider-usage` (credential supplied via
|
|
42
|
-
an environment variable only; aggregate usage/cost figures only, no prompt/completion content).
|
|
43
79
|
|
|
44
|
-
|
|
45
|
-
and roughly what does it cost?"* — entirely locally, with honest labels.
|
|
80
|
+
## Free (npm) vs. private (opt-in API)
|
|
46
81
|
|
|
47
|
-
|
|
82
|
+
**In the free / local CLI (npm):**
|
|
48
83
|
|
|
49
|
-
|
|
84
|
+
- the **local Gateway** — record mode, `status`, content-free receipts, `gateway run`,
|
|
85
|
+
- **explicit deterministic apply / dry-run / recover** (experimental, opt-in),
|
|
86
|
+
- **capture / import / analyze / spend / compact / context / feedback** (local trace utilities).
|
|
50
87
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- **Apply guidance** — a readiness verdict and a review/approval path before any context is applied.
|
|
54
|
-
- **Policies & team reporting** — configurable behavior controls and cross-run / team reporting.
|
|
88
|
+
**NOT in the npm / free CLI** (these are the opt-in Compaction API — **not a live hosted service
|
|
89
|
+
yet**):
|
|
55
90
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
91
|
+
- the **LCM / learned context model**,
|
|
92
|
+
- the **learned optimization engine**,
|
|
93
|
+
- the **hosted / team control plane**,
|
|
94
|
+
- **verified-savings** logic,
|
|
95
|
+
- **advanced proprietary evals** (and recommendation / advanced verification / apply-guidance / advanced policies).
|
|
96
|
+
|
|
97
|
+
> **The Compaction API is not broadly hosted yet.** There is **no live hosted service today**. The
|
|
98
|
+
> honesty rails carry over unchanged: cost stays an **estimate** unless billing-confirmed (no figure
|
|
99
|
+
> carries that label today); verification is **deterministic recoverability, NOT semantic/meaning
|
|
100
|
+
> preservation**; and there is **no auto-apply** — every application is an explicit operator gesture.
|
|
62
101
|
|
|
63
102
|
## Install
|
|
64
103
|
|
|
65
|
-
A local-first CLI.
|
|
66
|
-
|
|
104
|
+
A local-first CLI. **No telemetry and no upload to Compaction.** Network happens only when you
|
|
105
|
+
explicitly call provider-usage (`capture provider-usage`) or route your own provider traffic through
|
|
106
|
+
the local gateway (which forwards it to your provider). Nothing else reaches the network.
|
|
67
107
|
|
|
68
108
|
### npm / npx
|
|
69
109
|
|
|
70
110
|
```bash
|
|
71
|
-
npm install -g @compaction/cli # then: compaction
|
|
111
|
+
npm install -g @compaction/cli # then: compaction
|
|
72
112
|
npx @compaction/cli init # no global install
|
|
73
113
|
npx @compaction/cli --help # no install at all
|
|
74
114
|
```
|
|
75
115
|
|
|
76
116
|
The installed binary is `compaction`. After a global install, sanity-check with
|
|
77
|
-
`compaction --version` (→ `0.
|
|
117
|
+
`compaction --version` (→ `0.3.1`) and `compaction --help`. Run `compaction` (no args) to open
|
|
118
|
+
onboarding, including **Gateway setup**.
|
|
78
119
|
|
|
79
120
|
### curl one-liner
|
|
80
121
|
|
|
@@ -94,23 +135,29 @@ curl -fsSL https://cli.compaction.dev/install | sh -s -- --dry-run
|
|
|
94
135
|
|
|
95
136
|
## Quick start
|
|
96
137
|
|
|
97
|
-
|
|
98
|
-
|
|
138
|
+
Two local loops, both on **your own** workflow — not a demo.
|
|
139
|
+
|
|
140
|
+
**Route your traffic through the local Gateway** (byte-safe; content-free receipts):
|
|
99
141
|
|
|
100
142
|
```bash
|
|
101
|
-
compaction
|
|
102
|
-
#
|
|
103
|
-
compaction
|
|
143
|
+
compaction gateway start # start the local gateway (RECORD mode)
|
|
144
|
+
compaction gateway run -- npm run dev # or point your OpenAI client's baseURL at the listen address + /v1
|
|
145
|
+
compaction gateway status # see requests observed + the content-free receipts rollup
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Capture + measure an agent trace** (local files only):
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
compaction init # one-time local scaffold (writes nothing until you capture)
|
|
152
|
+
compaction capture claude-code --discover # list local Claude Code sessions
|
|
104
153
|
compaction capture claude-code --session <session.jsonl> --out ./my-trace
|
|
105
|
-
|
|
106
|
-
compaction
|
|
107
|
-
compaction spend ./my-trace/captured-trace.json
|
|
108
|
-
# 3. Share a redacted, content-free bundle (local file only, never uploaded):
|
|
109
|
-
compaction feedback --redact --yes
|
|
154
|
+
compaction analyze ./my-trace/captured-trace.json # tokens + estimated spend, honestly labeled
|
|
155
|
+
compaction feedback --redact --yes # redacted, content-free bundle (local file only, never uploaded)
|
|
110
156
|
```
|
|
111
157
|
|
|
112
|
-
|
|
113
|
-
|
|
158
|
+
Deterministic basic compaction (`compaction compact <trace> --out <dir>`) also runs locally.
|
|
159
|
+
Advanced verification, recommendation, and apply guidance are the opt-in Compaction API — not steps
|
|
160
|
+
of the free local CLI.
|
|
114
161
|
|
|
115
162
|
## Supported local workflows
|
|
116
163
|
|
|
@@ -126,14 +173,29 @@ free local CLI.
|
|
|
126
173
|
`codex exec --json` export) and normalizes it. **Level 1.** Codex token counts on this path are
|
|
127
174
|
**locally estimated (chars/4)**, not provider-reported. `compaction import --list-sources` lists
|
|
128
175
|
supported sources.
|
|
176
|
+
- **OpenAI-compatible clients via the local Gateway** — any OpenAI-compatible client can route
|
|
177
|
+
through `compaction gateway` for content-free receipts (and, opt-in, explicit deterministic apply).
|
|
129
178
|
|
|
130
|
-
There is **no** native/Level 3 SDK instrumentation, no
|
|
179
|
+
There is **no** native/Level 3 SDK instrumentation, **no hosted/managed proxy or model routing**
|
|
180
|
+
(the local Gateway is an OpenAI-compatible reverse proxy for compatible clients), and no
|
|
131
181
|
consumer-app (ChatGPT/Claude desktop) support.
|
|
132
182
|
|
|
133
183
|
## Commands
|
|
134
184
|
|
|
135
185
|
```bash
|
|
186
|
+
compaction # onboarding (workflow chooser + Gateway setup)
|
|
136
187
|
compaction init # one-time local scaffold
|
|
188
|
+
|
|
189
|
+
# Gateway (local, byte-safe):
|
|
190
|
+
compaction gateway start # start the local gateway (RECORD mode)
|
|
191
|
+
compaction gateway run -- <command> # run a command through the gateway
|
|
192
|
+
compaction gateway status # requests observed + content-free receipts rollup
|
|
193
|
+
compaction gateway activate # print env exports (eval-able); prints only, no mutation
|
|
194
|
+
compaction gateway configure # approval-gated: propose a project baseURL (diff, no write without --apply)
|
|
195
|
+
compaction gateway recover <recovery_id> # recover the original request retained by apply mode
|
|
196
|
+
compaction gateway stop # stop a running local gateway
|
|
197
|
+
|
|
198
|
+
# Trace / capture utilities:
|
|
137
199
|
compaction capture claude-code --session <session.jsonl> [--include-subagents] --out <dir>
|
|
138
200
|
compaction capture claude-code --discover [--projects-dir <path>]
|
|
139
201
|
compaction capture openai-agents --out <dir> -- <command> [args...]
|
|
@@ -141,6 +203,7 @@ compaction capture provider-usage --endpoint <url> [--credential-env-var <NAME>]
|
|
|
141
203
|
compaction import <trace-file> --source <source> --out <dir>
|
|
142
204
|
compaction import --list-sources
|
|
143
205
|
compaction analyze <trace-file>
|
|
206
|
+
compaction compact <trace-file> --out <dir> # deterministic local compaction (basic policies) + honest artifacts
|
|
144
207
|
compaction context add <trace-file> # build a local context store from a captured/imported trace
|
|
145
208
|
compaction context get "<query>" # retrieve + assemble the active context (with source pointers)
|
|
146
209
|
compaction spend <trace-or-optimization-path> # context-spend attribution
|
|
@@ -149,15 +212,20 @@ compaction aggregate # per-session / cross-session l
|
|
|
149
212
|
compaction feedback --redact [--yes] # redacted, local-only share bundle
|
|
150
213
|
```
|
|
151
214
|
|
|
152
|
-
`compaction --help` lists the free local commands.
|
|
215
|
+
`compaction --help` lists the free local commands; `compaction gateway --help` lists the gateway commands.
|
|
153
216
|
|
|
154
217
|
## Privacy and security
|
|
155
218
|
|
|
156
|
-
- **No telemetry; no upload
|
|
157
|
-
- **
|
|
158
|
-
|
|
159
|
-
never written into artifacts
|
|
160
|
-
prompt/completion content
|
|
219
|
+
- **No telemetry; no upload to Compaction.** The free CLI is local-first and file-based.
|
|
220
|
+
- **Network only on explicit action.** Network happens only when you explicitly call
|
|
221
|
+
`capture provider-usage` (read-only; credential via an **environment variable only**, never a flag
|
|
222
|
+
value, never logged, never written into artifacts; **aggregate** usage/cost figures only — no
|
|
223
|
+
prompt/completion content) **or** route your own provider traffic through the local gateway (which
|
|
224
|
+
forwards it to your provider; your provider key stays on the client and is never read or stored).
|
|
225
|
+
- **Content-free gateway receipts.** Gateway receipts record token/cache counts and labels only —
|
|
226
|
+
never prompt/response content; they are local-only (gitignored). Apply mode retains the original
|
|
227
|
+
request **locally** (restrictive permissions) so it is recoverable; that original is referenced
|
|
228
|
+
from receipts by id only.
|
|
161
229
|
- **Captured traces can contain local content.** Capturing a session may include local file
|
|
162
230
|
content — review a trace before sharing it.
|
|
163
231
|
- **Redacted sharing.** `feedback --redact` produces a redacted, content-free bundle as a local
|
|
@@ -171,17 +239,24 @@ Every figure this tool produces carries one of these labels — and nothing stro
|
|
|
171
239
|
| Label | Meaning |
|
|
172
240
|
|---|---|
|
|
173
241
|
| **local estimate** | chars/4 token heuristics and price-table cost approximations computed locally |
|
|
174
|
-
| **provider-reported token delta** | token counts read from the provider's own API response/usage metadata (operator-entered or
|
|
242
|
+
| **provider-reported token delta** | token counts read from the provider's own API response/usage metadata (operator-entered, captured, or via the gateway); input tokens are deterministic for a fixed context+prompt |
|
|
175
243
|
| **token-estimated cost** | a price-table estimate applied to provider-reported token counts (`price_table_estimate`) — an estimate, never a billed figure |
|
|
176
244
|
| **operator-entered billing record** | billed costs the operator read from their own provider console; recorded, not provider-verified by this tool |
|
|
177
245
|
| **billing-confirmed** | only with real provider billing/invoice evidence **AND** the accepted measurement criterion met on those billed runs (N ≥ 3 runs per arm AND the delta-of-means ±2·SE interval excludes zero) — the statistical criterion alone is a bar on operator-entered figures, not proof of billing, so it is never sufficient by itself — **no figure in this repository currently carries this label** |
|
|
178
246
|
|
|
179
|
-
**What is NOT claimed:** no billing-confirmed savings claim; no invoice savings claim; no
|
|
247
|
+
**What is NOT claimed:** no billing-confirmed savings claim; no invoice savings claim; no
|
|
248
|
+
output-token savings claim unless measured before/after **and** eval-confirmed; no general savings
|
|
249
|
+
claim (all results are workflow-scoped and caveated); no auto-apply (every application is an explicit
|
|
250
|
+
operator gesture); no hosted service or control plane, and **no hosted-live claim** (the free CLI +
|
|
251
|
+
Gateway are local-first, file-based); no universal "no context is lost" claim; no semantic/meaning
|
|
252
|
+
preservation claim (it stays `not_evaluated`); no native/production/Level 3 integration claim.
|
|
180
253
|
|
|
181
254
|
## Known limitations
|
|
182
255
|
|
|
183
|
-
- **The free CLI
|
|
184
|
-
|
|
256
|
+
- **The free CLI runs the local Gateway, captures/measures traces, and compacts deterministically;
|
|
257
|
+
it does not perform advanced verification.** The LCM / learned optimization engine, hosted/team
|
|
258
|
+
control plane, verified savings, advanced proprietary evals, recommendation, advanced verification
|
|
259
|
+
(incl. `compact --eval`), apply guidance, and advanced policies are the **opt-in Compaction API** —
|
|
185
260
|
not the free local CLI. The API is **not broadly hosted yet**.
|
|
186
261
|
- **Cost figures are estimates or operator-entered records, not billing-confirmed.** Locally
|
|
187
262
|
computed cost figures are price-table estimates; provider-usage records carry operator-entered/
|
|
@@ -189,14 +264,17 @@ Every figure this tool produces carries one of these labels — and nothing stro
|
|
|
189
264
|
- **Token counts are local estimates unless provider-reported usage is captured.** The default is a
|
|
190
265
|
chars/4 estimate, labeled as such. Unknown stays unknown — output tokens, provider, or cost the
|
|
191
266
|
data does not carry are never inferred.
|
|
267
|
+
- **Gateway apply is experimental, deterministic, and opt-in.** It removes only exact-duplicate large
|
|
268
|
+
blocks from known-safe request shapes, retains the original locally, and fails closed on anything
|
|
269
|
+
else; it makes no output-token or cost claim, and never claims meaning preservation or "no context
|
|
270
|
+
lost". Record mode is the byte-safe default.
|
|
192
271
|
- **Integrations are Level 1/2, not native/production.** Claude Code and OpenAI Agents capture are
|
|
193
272
|
Level 2 local command-wrappers; Codex/local-file import is Level 1. There is **no** native/Level 3
|
|
194
|
-
SDK instrumentation, no
|
|
273
|
+
SDK instrumentation, **no hosted/managed proxy or model routing**, and no consumer-app support.
|
|
195
274
|
- **Verification (opt-in API) is deterministic recoverability, not semantic preservation.** Where
|
|
196
275
|
the opt-in API verifies a compacted context, it checks deterministic recoverability for a
|
|
197
276
|
supported workflow; it does **not** evaluate meaning or task equivalence and does **not** re-run
|
|
198
|
-
your agent through a model. Semantic / meaning preservation remains **not evaluated
|
|
199
|
-
replay is future work.
|
|
277
|
+
your agent through a model. Semantic / meaning preservation remains **not evaluated**.
|
|
200
278
|
- **No universal "no context is lost" guarantee.** Any apply-guidance verdict from the opt-in API
|
|
201
279
|
is **fail-closed and scoped** to supported developer-agent workflows — never a universal
|
|
202
280
|
guarantee, and never a semantic/meaning claim.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* `compaction activity` — READ-ONLY, metrics-only view of recent runs from the local activity
|
|
4
|
+
* store (`.compaction/activity/activity.jsonl`). Content-free: it renders only the counts/labels
|
|
5
|
+
* the events already carry; it never reads or prints prompt/response content, and it writes
|
|
6
|
+
* NOTHING. Empty store → a friendly message, exit 0.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerActivityCommand(program: Command): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { readActivityEvents } from "../../core/activity-store.js";
|
|
3
|
+
import { DEFAULT_ACTIVITY_LIMIT, buildActivityJson, buildActivityRows, formatActivityTable } from "../../core/activity-view.js";
|
|
4
|
+
/**
|
|
5
|
+
* `compaction activity` — READ-ONLY, metrics-only view of recent runs from the local activity
|
|
6
|
+
* store (`.compaction/activity/activity.jsonl`). Content-free: it renders only the counts/labels
|
|
7
|
+
* the events already carry; it never reads or prints prompt/response content, and it writes
|
|
8
|
+
* NOTHING. Empty store → a friendly message, exit 0.
|
|
9
|
+
*/
|
|
10
|
+
export function registerActivityCommand(program) {
|
|
11
|
+
program
|
|
12
|
+
.command("activity")
|
|
13
|
+
.description("Show recent runs recorded in the local metrics-only activity store (read-only, content-free).")
|
|
14
|
+
.option("--limit <n>", `Max runs to show, most recent first (default ${DEFAULT_ACTIVITY_LIMIT})`)
|
|
15
|
+
.option("--surface <surface>", "Only show runs from this surface (e.g. cursor, codex, cli, claude_code)")
|
|
16
|
+
.option("--json", "Machine-readable JSON output")
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const limit = options.limit !== undefined ? Number.parseInt(options.limit, 10) : DEFAULT_ACTIVITY_LIMIT;
|
|
19
|
+
if (Number.isNaN(limit) || limit < 0) {
|
|
20
|
+
console.error(`Invalid --limit "${options.limit}": expected a non-negative integer.`);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const { events, skipped } = await readActivityEvents();
|
|
25
|
+
const rows = buildActivityRows(events, { limit, surface: options.surface });
|
|
26
|
+
const meta = { totalEvents: events.length, limit, surface: options.surface, skippedCount: skipped.length };
|
|
27
|
+
if (options.json) {
|
|
28
|
+
console.log(JSON.stringify(buildActivityJson(rows, meta), null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const table = formatActivityTable(rows, meta);
|
|
32
|
+
console.log(rows.length === 0 ? chalk.yellow(table) : chalk.cyan(table));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { Option } from "commander";
|
|
4
|
+
import { AUTO_APPLY_QUESTION_LINES, formatSavedPreferenceConfirmation, resolveAutoApplyOffer } from "../../core/auto-apply-ask.js";
|
|
5
|
+
import { savePolicyPreference } from "../../core/policy-preferences.js";
|
|
4
6
|
import { parseTraceFile } from "../../core/trace-parser.js";
|
|
5
7
|
import { runEngineCommand } from "../engine-degrade.js";
|
|
6
8
|
function defaultOutputDir(artifactRoot, traceId) {
|
|
7
9
|
return path.join(artifactRoot, traceId);
|
|
8
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Infer the SAFEST workflow tool for the auto-apply preference scope. Prefers the explicit
|
|
13
|
+
* `--workflow-tool` flag; otherwise maps an unambiguous trace source to its tool. Returns undefined
|
|
14
|
+
* when it cannot infer safely (then the offer fails closed and saves nothing — never guesses global).
|
|
15
|
+
*/
|
|
16
|
+
function inferWorkflowTool(explicit, traceSource) {
|
|
17
|
+
if (explicit && explicit.trim() !== "")
|
|
18
|
+
return explicit.trim();
|
|
19
|
+
if (traceSource === "codex_import")
|
|
20
|
+
return "codex";
|
|
21
|
+
if (traceSource === "cursor_import")
|
|
22
|
+
return "cursor";
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
9
25
|
/**
|
|
10
26
|
* `compaction apply-context <trace-file> --out <dir>` — LEVEL-5 IN-WORKFLOW APPLY, Form A.
|
|
11
27
|
*
|
|
@@ -26,6 +42,12 @@ export function registerApplyContextCommand(program) {
|
|
|
26
42
|
.addOption(new Option("--approve-skill-injection-policy", "EXPLICITLY also authorize the approval-required repeated_skill_injection_to_state_capsule policy. Default off; no auto-apply."))
|
|
27
43
|
.addOption(new Option("--attest-used", "OPTIONAL operator attestation: AFTER an approval, the operator records that they used the approved context in a live call. Stored as operator-ATTESTED provenance (the operator's own claim), never observed by compaction.dev."))
|
|
28
44
|
.option("--attest-note <text>", "Optional free-text note recorded with the operator attestation")
|
|
45
|
+
.addOption(new Option("--offer-auto-apply", "OPT-IN. AFTER an explicit approval, offer the ONE binary question 'apply this automatically next time when safety gates pass?' (default no). Saving a preference records intent only — it NEVER applies anything (no auto-apply engine exists)."))
|
|
46
|
+
.addOption(new Option("--remember-auto-apply", "Non-interactive answer YES to the auto-apply offer (requires --offer-auto-apply and a prior approval). Saves a preference for the inferred safest scope; applies nothing now."))
|
|
47
|
+
.addOption(new Option("--no-remember", "Non-interactive answer NO to the auto-apply offer (the default): save nothing, keep asking each time."))
|
|
48
|
+
.option("--workflow-tool <tool>", "Tool/workflow to scope a saved auto-apply preference to (never global/cross-tool). Inferred from the trace source when omitted.")
|
|
49
|
+
.option("--workflow-repo <repo>", "Optional content-free repo identifier to narrow a saved auto-apply preference's scope.")
|
|
50
|
+
.option("--policy-type <type>", "Policy type a saved auto-apply preference concerns (defaults to the approved policy name).")
|
|
29
51
|
.action(async (traceFile, options) => {
|
|
30
52
|
await runEngineCommand(async () => {
|
|
31
53
|
// Lazy-load the proprietary engine: present in-repo/API, excluded from the public package.
|
|
@@ -70,6 +92,52 @@ export function registerApplyContextCommand(program) {
|
|
|
70
92
|
}
|
|
71
93
|
}
|
|
72
94
|
console.log(chalk.green(`Output directory: ${result.outputDirectory}`));
|
|
95
|
+
// OPT-IN post-approval auto-apply OFFER (§11a block 4/5). This offer is made ONLY after an
|
|
96
|
+
// explicit in-workflow approval already emitted an approved context. It APPLIES NOTHING: on
|
|
97
|
+
// yes it records a PREFERENCE (intent for the future gated slice) via the #598 store; on
|
|
98
|
+
// no/default it saves nothing. It never touches apply execution semantics.
|
|
99
|
+
if (options.offerAutoApply === true && result.approvedContextEmitted) {
|
|
100
|
+
console.log("");
|
|
101
|
+
for (const line of AUTO_APPLY_QUESTION_LINES)
|
|
102
|
+
console.log(chalk.cyan(line));
|
|
103
|
+
const answer = options.rememberAutoApply === true ? "yes" : "no";
|
|
104
|
+
const decision = resolveAutoApplyOffer({
|
|
105
|
+
approvedInWorkflow: true,
|
|
106
|
+
answer,
|
|
107
|
+
scope: {
|
|
108
|
+
tool: inferWorkflowTool(options.workflowTool, trace.source),
|
|
109
|
+
repo: options.workflowRepo,
|
|
110
|
+
policyType: options.policyType ?? result.review.policies_applied[0]
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
if (decision.action === "save") {
|
|
114
|
+
const saved = await savePolicyPreference({
|
|
115
|
+
scope: decision.scope,
|
|
116
|
+
preference: decision.preference,
|
|
117
|
+
gates_required: decision.gatesRequired
|
|
118
|
+
});
|
|
119
|
+
if (saved.saved) {
|
|
120
|
+
console.log("");
|
|
121
|
+
console.log(chalk.green(formatSavedPreferenceConfirmation(saved.preference)));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log("");
|
|
125
|
+
console.log(chalk.yellow("Preference NOT saved (fail-closed) — nothing was applied:"));
|
|
126
|
+
for (const problem of saved.problems)
|
|
127
|
+
console.log(chalk.yellow(` - ${problem}`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (decision.action === "blocked") {
|
|
131
|
+
console.log("");
|
|
132
|
+
console.log(chalk.yellow("Preference NOT saved — could not infer a safe (non-global, non-cross-tool) scope. Nothing applied:"));
|
|
133
|
+
for (const problem of decision.problems)
|
|
134
|
+
console.log(chalk.yellow(` - ${problem}`));
|
|
135
|
+
console.log(chalk.dim(" Pass --workflow-tool <tool> (and optionally --policy-type / --workflow-repo) to record a preference."));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
console.log(chalk.dim("No auto-apply preference saved — Compaction will keep asking each time (the default)."));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
73
141
|
// Exit non-zero when no approved context was emitted (refusal / review-only), mirroring apply/approve.
|
|
74
142
|
if (!result.approvedContextEmitted) {
|
|
75
143
|
process.exitCode = 1;
|
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { writeJsonArtifact, writeTextArtifact } from "../../core/artifact-writer.js";
|
|
5
|
-
import { addRun, computeReport, initMeasurementRecord, BILLING_DELTA_CRITERION, BILLING_DELTA_RECORD_ROOT } from "../../core/billing-delta/billing-delta-record.js";
|
|
5
|
+
import { addRun, computeReport, initMeasurementRecord, API_METERED_BILLING_CONFIRMED_CRITERIA, BILLING_DELTA_CRITERION, BILLING_DELTA_FIXED_PLAN_NOTE, BILLING_DELTA_RECORD_ROOT } from "../../core/billing-delta/billing-delta-record.js";
|
|
6
6
|
const PRIVACY_NOTE = "Operator-run, local-first. compaction.dev makes NO provider call, reads NO credential, and has NO network access. " +
|
|
7
7
|
"All billing figures are operator-entered (read from YOUR provider console/billing export) and are NOT provider-verified by this tool. " +
|
|
8
8
|
"Aggregate cost only — no prompt/completion content is stored.";
|
|
@@ -81,6 +81,17 @@ function buildReportMarkdown(report) {
|
|
|
81
81
|
"",
|
|
82
82
|
`- ${report.criterion}`,
|
|
83
83
|
"",
|
|
84
|
+
"## API-metered billing-confirmed criteria (cross-surface contract §5, D6 — checklist only)",
|
|
85
|
+
"",
|
|
86
|
+
"> A billing-confirmed figure is possible ONLY on api_metered workflows, ONLY through this",
|
|
87
|
+
"> billing-delta flow, and ONLY when ALL of the criteria below hold. This report does NOT verify",
|
|
88
|
+
"> them and NEVER carries billing_confirmed: true. Even when all criteria hold, the claim is",
|
|
89
|
+
"> workflow-scoped only — generalized billing-confirmed = future only.",
|
|
90
|
+
">",
|
|
91
|
+
`> ${BILLING_DELTA_FIXED_PLAN_NOTE}`,
|
|
92
|
+
"",
|
|
93
|
+
...API_METERED_BILLING_CONFIRMED_CRITERIA.map((c, i) => `${i + 1}. ${c}`),
|
|
94
|
+
"",
|
|
84
95
|
"## Verdict notes",
|
|
85
96
|
"",
|
|
86
97
|
...report.verdict_notes.map((n) => `- ${n}`),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UsageMetadata } from "../../core/usage-metadata.js";
|
|
1
2
|
interface DiscoverClaudeCodeOptions {
|
|
2
3
|
projectsDir?: string;
|
|
3
4
|
}
|
|
@@ -8,6 +9,49 @@ interface CaptureClaudeCodeOptions {
|
|
|
8
9
|
includeSubagents?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export declare function captureClaudeCodeCommand(options: CaptureClaudeCodeOptions): Promise<void>;
|
|
12
|
+
/** A normalized usage summary for the hook path — usage + a content-free fingerprint + message count. */
|
|
13
|
+
interface HookNormalizeResult {
|
|
14
|
+
usage: UsageMetadata;
|
|
15
|
+
messageCount: number;
|
|
16
|
+
fingerprint?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface FromHookDeps {
|
|
19
|
+
readStdin?: () => Promise<string>;
|
|
20
|
+
normalize?: (transcriptPath: string) => Promise<HookNormalizeResult>;
|
|
21
|
+
cwd?: string;
|
|
22
|
+
now?: () => string;
|
|
23
|
+
hostedConfigured?: () => boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface FromHookOptions {
|
|
26
|
+
dryRun?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `compaction capture claude-code --from-hook`. Reads the Stop payload from stdin, resolves the session
|
|
30
|
+
* JSONL via `transcript_path`, and records CONTENT-FREE usage only — never message content, never
|
|
31
|
+
* `last_assistant_message`. Idempotent via a content-free dedup ledger. FAIL-OPEN by contract: any error is
|
|
32
|
+
* swallowed and the process exits 0 so the hook can never break Claude Code.
|
|
33
|
+
*/
|
|
34
|
+
export declare function captureClaudeCodeFromHook(options?: FromHookOptions, deps?: FromHookDeps): Promise<void>;
|
|
35
|
+
export interface FromPromptHookDeps {
|
|
36
|
+
readStdin?: () => Promise<string>;
|
|
37
|
+
cwd?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* `compaction capture claude-code --from-prompt-hook` — the BEFORE-CALL recommendation path (charter
|
|
41
|
+
* 2026-07-04-run-13). The Claude Code **UserPromptSubmit** hook runs this BEFORE the model processes the
|
|
42
|
+
* prompt (a genuine pre-call event — NOT the post-session Stop hook). It reads the UserPromptSubmit
|
|
43
|
+
* payload from stdin, analyzes the pending PROMPT for avoidable duplicated context IN-PROCESS
|
|
44
|
+
* (content-free), and — when present — records ONE metrics-only `claude_code` before-call RECOMMENDATION
|
|
45
|
+
* activity event so it appears in `compaction activity`. Apply is a PROVEN BLOCKER on this surface (no
|
|
46
|
+
* hook can reduce the model's context; hooks are non-interactive) → recommendation-only; the original
|
|
47
|
+
* prompt ALWAYS runs UNCHANGED.
|
|
48
|
+
*
|
|
49
|
+
* CRITICAL: this path writes NOTHING to stdout — on UserPromptSubmit, a hook's stdout is ADDED to the
|
|
50
|
+
* model's context, so injecting anything would be both intrusive and self-defeating for a compaction
|
|
51
|
+
* tool. It is silent and transparent; the recommendation lives in `compaction activity`. FAIL-OPEN +
|
|
52
|
+
* CONTENT-FREE: any error is swallowed and the process exits 0; the prompt text is never persisted.
|
|
53
|
+
*/
|
|
54
|
+
export declare function captureClaudeCodeFromPromptHook(deps?: FromPromptHookDeps): Promise<void>;
|
|
11
55
|
/**
|
|
12
56
|
* Discover local Claude Code sessions (metadata only) and print, for each, the
|
|
13
57
|
* ready-to-run `capture claude-code --session <path>` command (guided capture).
|