@compaction/cli 0.1.0

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.
Files changed (143) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +319 -0
  3. package/dist/cli/commands/adapter.d.ts +2 -0
  4. package/dist/cli/commands/adapter.js +49 -0
  5. package/dist/cli/commands/aggregate.d.ts +2 -0
  6. package/dist/cli/commands/aggregate.js +60 -0
  7. package/dist/cli/commands/analyze.d.ts +2 -0
  8. package/dist/cli/commands/analyze.js +55 -0
  9. package/dist/cli/commands/apply-context.d.ts +12 -0
  10. package/dist/cli/commands/apply-context.js +80 -0
  11. package/dist/cli/commands/apply.d.ts +2 -0
  12. package/dist/cli/commands/apply.js +65 -0
  13. package/dist/cli/commands/approve.d.ts +2 -0
  14. package/dist/cli/commands/approve.js +55 -0
  15. package/dist/cli/commands/audit.d.ts +2 -0
  16. package/dist/cli/commands/audit.js +63 -0
  17. package/dist/cli/commands/billing-delta.d.ts +2 -0
  18. package/dist/cli/commands/billing-delta.js +246 -0
  19. package/dist/cli/commands/capture-claude-code.d.ts +19 -0
  20. package/dist/cli/commands/capture-claude-code.js +198 -0
  21. package/dist/cli/commands/capture-provider-usage.d.ts +35 -0
  22. package/dist/cli/commands/capture-provider-usage.js +113 -0
  23. package/dist/cli/commands/capture.d.ts +2 -0
  24. package/dist/cli/commands/capture.js +76 -0
  25. package/dist/cli/commands/compact.d.ts +2 -0
  26. package/dist/cli/commands/compact.js +206 -0
  27. package/dist/cli/commands/eval.d.ts +2 -0
  28. package/dist/cli/commands/eval.js +66 -0
  29. package/dist/cli/commands/export-session-seed.d.ts +11 -0
  30. package/dist/cli/commands/export-session-seed.js +42 -0
  31. package/dist/cli/commands/feedback.d.ts +2 -0
  32. package/dist/cli/commands/feedback.js +233 -0
  33. package/dist/cli/commands/import.d.ts +2 -0
  34. package/dist/cli/commands/import.js +60 -0
  35. package/dist/cli/commands/init.d.ts +2 -0
  36. package/dist/cli/commands/init.js +216 -0
  37. package/dist/cli/commands/integrations.d.ts +2 -0
  38. package/dist/cli/commands/integrations.js +29 -0
  39. package/dist/cli/commands/launch-treatment-session.d.ts +14 -0
  40. package/dist/cli/commands/launch-treatment-session.js +50 -0
  41. package/dist/cli/commands/optimize.d.ts +2 -0
  42. package/dist/cli/commands/optimize.js +33 -0
  43. package/dist/cli/commands/recommend.d.ts +4 -0
  44. package/dist/cli/commands/recommend.js +66 -0
  45. package/dist/cli/commands/review.d.ts +2 -0
  46. package/dist/cli/commands/review.js +60 -0
  47. package/dist/cli/commands/run.d.ts +2 -0
  48. package/dist/cli/commands/run.js +49 -0
  49. package/dist/cli/commands/spend.d.ts +2 -0
  50. package/dist/cli/commands/spend.js +24 -0
  51. package/dist/cli/commands/summary.d.ts +2 -0
  52. package/dist/cli/commands/summary.js +19 -0
  53. package/dist/cli/engine-degrade.d.ts +40 -0
  54. package/dist/cli/engine-degrade.js +59 -0
  55. package/dist/cli/index.d.ts +2 -0
  56. package/dist/cli/index.js +59 -0
  57. package/dist/core/adapter-validation.d.ts +32 -0
  58. package/dist/core/adapter-validation.js +185 -0
  59. package/dist/core/adapters/claude-code-adapter.d.ts +51 -0
  60. package/dist/core/adapters/claude-code-adapter.js +539 -0
  61. package/dist/core/adapters/claude-code-discovery.d.ts +40 -0
  62. package/dist/core/adapters/claude-code-discovery.js +100 -0
  63. package/dist/core/aggregate-format.d.ts +62 -0
  64. package/dist/core/aggregate-format.js +349 -0
  65. package/dist/core/api-client/client.d.ts +43 -0
  66. package/dist/core/api-client/client.js +143 -0
  67. package/dist/core/api-client/config.d.ts +36 -0
  68. package/dist/core/api-client/config.js +44 -0
  69. package/dist/core/api-client/index.d.ts +13 -0
  70. package/dist/core/api-client/index.js +14 -0
  71. package/dist/core/api-client/payload.d.ts +93 -0
  72. package/dist/core/api-client/payload.js +180 -0
  73. package/dist/core/api-client/types.d.ts +95 -0
  74. package/dist/core/api-client/types.js +21 -0
  75. package/dist/core/artifact-writer.d.ts +2 -0
  76. package/dist/core/artifact-writer.js +14 -0
  77. package/dist/core/audit-report.d.ts +91 -0
  78. package/dist/core/audit-report.js +422 -0
  79. package/dist/core/billing-delta/billing-delta-record.d.ts +290 -0
  80. package/dist/core/billing-delta/billing-delta-record.js +394 -0
  81. package/dist/core/capture-adapter.d.ts +74 -0
  82. package/dist/core/capture-adapter.js +2 -0
  83. package/dist/core/command-runner.d.ts +29 -0
  84. package/dist/core/command-runner.js +96 -0
  85. package/dist/core/content-hash.d.ts +1 -0
  86. package/dist/core/content-hash.js +5 -0
  87. package/dist/core/cost-calculator.d.ts +6 -0
  88. package/dist/core/cost-calculator.js +20 -0
  89. package/dist/core/feedback-bundle.d.ts +159 -0
  90. package/dist/core/feedback-bundle.js +406 -0
  91. package/dist/core/openai-agents-capture.d.ts +66 -0
  92. package/dist/core/openai-agents-capture.js +475 -0
  93. package/dist/core/policy-types.d.ts +85 -0
  94. package/dist/core/policy-types.js +29 -0
  95. package/dist/core/pricing.d.ts +23 -0
  96. package/dist/core/pricing.js +55 -0
  97. package/dist/core/provider-usage/credential-redaction.d.ts +23 -0
  98. package/dist/core/provider-usage/credential-redaction.js +60 -0
  99. package/dist/core/provider-usage/provider-usage-adapter.d.ts +65 -0
  100. package/dist/core/provider-usage/provider-usage-adapter.js +147 -0
  101. package/dist/core/provider-usage/provider-usage-client.d.ts +89 -0
  102. package/dist/core/provider-usage/provider-usage-client.js +96 -0
  103. package/dist/core/report-generator.d.ts +7 -0
  104. package/dist/core/report-generator.js +275 -0
  105. package/dist/core/run-aggregator.d.ts +50 -0
  106. package/dist/core/run-aggregator.js +251 -0
  107. package/dist/core/run-labels.d.ts +52 -0
  108. package/dist/core/run-labels.js +80 -0
  109. package/dist/core/run-trace-converter.d.ts +3 -0
  110. package/dist/core/run-trace-converter.js +94 -0
  111. package/dist/core/safety-report.d.ts +52 -0
  112. package/dist/core/safety-report.js +440 -0
  113. package/dist/core/savings.d.ts +22 -0
  114. package/dist/core/savings.js +36 -0
  115. package/dist/core/session-aggregate.d.ts +211 -0
  116. package/dist/core/session-aggregate.js +490 -0
  117. package/dist/core/skill-injection-detector.d.ts +51 -0
  118. package/dist/core/skill-injection-detector.js +146 -0
  119. package/dist/core/spend-attribution.d.ts +169 -0
  120. package/dist/core/spend-attribution.js +611 -0
  121. package/dist/core/standalone-capsule-provenance.d.ts +4 -0
  122. package/dist/core/standalone-capsule-provenance.js +62 -0
  123. package/dist/core/state-capsule.d.ts +3 -0
  124. package/dist/core/state-capsule.js +147 -0
  125. package/dist/core/token-accounting.d.ts +62 -0
  126. package/dist/core/token-accounting.js +81 -0
  127. package/dist/core/token-estimator.d.ts +3 -0
  128. package/dist/core/token-estimator.js +18 -0
  129. package/dist/core/trace-adapters.d.ts +53 -0
  130. package/dist/core/trace-adapters.js +714 -0
  131. package/dist/core/trace-fingerprint.d.ts +79 -0
  132. package/dist/core/trace-fingerprint.js +102 -0
  133. package/dist/core/trace-intake.d.ts +41 -0
  134. package/dist/core/trace-intake.js +164 -0
  135. package/dist/core/trace-parser.d.ts +203 -0
  136. package/dist/core/trace-parser.js +143 -0
  137. package/dist/core/types.d.ts +238 -0
  138. package/dist/core/types.js +2 -0
  139. package/dist/core/usage-metadata.d.ts +51 -0
  140. package/dist/core/usage-metadata.js +122 -0
  141. package/dist/core/waste-detector.d.ts +8 -0
  142. package/dist/core/waste-detector.js +58 -0
  143. package/package.json +90 -0
package/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # @compaction/cli
2
+
3
+ **The free, local-first CLI for capturing and measuring AI agent traces.** It
4
+ captures supported agent sessions on your own machine, shows input/output tokens
5
+ and estimated spend with honest labels, and writes local reports and redacted
6
+ share bundles — and, **when you opt in**, prepares those traces for optimization
7
+ and verification via the **Compaction API**.
8
+
9
+ > **The local CLI captures, measures, and prepares.** Optimization, advanced
10
+ > verification, apply guidance, and team reporting are **not** in the free CLI —
11
+ > they require the **Compaction API** (opt-in).
12
+
13
+ ## What the free CLI does (local, no account, no upload by default)
14
+
15
+ `@compaction/cli` is a local-first command-line tool. Everything below runs on your
16
+ machine and writes local files only:
17
+
18
+ - **Capture supported agent sessions.** **Claude Code is the primary supported
19
+ workflow** (`capture claude-code`, Integration Readiness **Level 2**
20
+ command-wrapper). Also supported: **OpenAI Agents SDK** (`capture openai-agents`,
21
+ Level 2 command-wrapper) and **Codex** local-file/trace **import** (`import`,
22
+ Level 1). These are local capture/import integrations — **not** native/Level 3
23
+ SDK instrumentation.
24
+ - **Show input/output tokens and estimated spend.** `analyze` and the local report
25
+ show input/output token counts and a per-run **estimated** cost. Token counts are
26
+ **provider-reported** only when the captured run carries provider usage metadata;
27
+ otherwise they are a **local estimate (chars/4)**. Cost is a **price-table
28
+ estimate** labeled `local estimate` / `token-estimated cost` — **never
29
+ billing-confirmed**.
30
+ - **Create local reports.** `analyze` / `compact` write local JSON + Markdown
31
+ reports under an operator-chosen output directory. Local files only.
32
+ - **Create redacted, content-free share bundles.** `feedback --redact` writes a
33
+ redacted, privacy-safe bundle as a **local file only — never uploaded**, and only
34
+ with an explicit write gesture (`--yes`).
35
+ - **No upload by default.** There is **no telemetry**. The **only** network call in
36
+ the free CLI is the explicitly operator-invoked, read-only `capture
37
+ provider-usage` (credential supplied via an environment variable only; aggregate
38
+ usage/cost figures only, no prompt/completion content).
39
+
40
+ The free CLI deliberately answers the first-value question — *"where is my context
41
+ being wasted, and roughly what does it cost?"* — entirely locally, with honest
42
+ labels.
43
+
44
+ ## What requires the Compaction API (opt-in — not in the free CLI)
45
+
46
+ The following are **not** part of the free local CLI. They are the **opt-in
47
+ Compaction API**:
48
+
49
+ - **Optimization** — producing a compacted context from a captured trace.
50
+ - **Advanced verification** — stronger checks on what a compacted context retains.
51
+ - **Apply guidance** — a readiness verdict and a review/approval path before any
52
+ context is applied.
53
+ - **Team reporting** — cross-run / cross-session reporting when enabled.
54
+
55
+ > **The Compaction API is not broadly hosted yet.** There is **no live hosted
56
+ > service today**. The API path is **designed to** optimize and verify **when you
57
+ > opt in** — this README does **not** claim those run as a live service. Until the
58
+ > API is available, these capabilities are **on the roadmap / opt-in**, not present
59
+ > in the free CLI.
60
+
61
+ When the API is available, the honesty rails carry over unchanged: cost stays an
62
+ **estimate** unless billing-confirmed (no figure carries that label today);
63
+ verification is **deterministic recoverability, NOT semantic/meaning preservation**;
64
+ integration stays **Level 1/2**; and there is **no auto-apply** — every application
65
+ is an explicit operator gesture.
66
+
67
+ ## The free local loop (recommended first run: your OWN workflow)
68
+
69
+ **capture → analyze / measure → (local report) → redact / share**
70
+
71
+ The recommended first run is on **your own** captured/imported workflow — **not a
72
+ demo**. Synthetic/demo traces exist only as illustration; they are never the
73
+ recommended first value.
74
+
75
+ 1. **Capture** a real workflow trace. **Claude Code is the primary supported
76
+ workflow** (`capture claude-code --session <path>`, Level 2 command-wrapper).
77
+ Also supported: OpenAI Agents SDK (`capture openai-agents`, Level 2) and Codex
78
+ local-file import (`import`, Level 1).
79
+ 2. **Analyze / measure** input/output tokens and estimated spend, and see where the
80
+ spend came from (`analyze`).
81
+ 3. **Local report** — read the local JSON / Markdown report written under your
82
+ chosen output directory.
83
+ 4. **Redact / share** — `feedback --redact` writes a redacted, content-free bundle
84
+ you can hand a teammate or founder. Local file only, never uploaded.
85
+
86
+ > **Optimization, advanced verification, apply guidance, and team reporting** are
87
+ > the **opt-in Compaction API**, not steps of the free local CLI (see the section
88
+ > above).
89
+
90
+ ## Evidence levels and claims
91
+
92
+ Every figure this tool produces carries one of these labels — and nothing stronger:
93
+
94
+ | Label | Meaning |
95
+ |---|---|
96
+ | **local estimate** | chars/4 token heuristics and price-table cost approximations computed locally |
97
+ | **provider-reported token delta** | token counts read from the provider's own API response/usage metadata (operator-entered or captured); input tokens are deterministic for a fixed context+prompt |
98
+ | **token-estimated cost** | a price-table estimate applied to provider-reported token counts (`price_table_estimate`) — an estimate, never a billed figure |
99
+ | **operator-entered billing record** | billed costs the operator read from their own provider console; recorded, not provider-verified by this tool |
100
+ | **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** |
101
+
102
+ **What is NOT claimed:** no billing-confirmed savings claim; no invoice savings claim; no general savings claim (all results are workflow-scoped and caveated); no auto-apply (every application is an explicit operator gesture); no hosted service or control plane (the free CLI is local-first, file-based); no universal "no context is lost" claim; no semantic/meaning preservation claim (it stays `not_evaluated`); no native/production/Level 3 integration claim.
103
+
104
+ ## Install
105
+
106
+ This is a local-first CLI. It makes no network calls by default; the only
107
+ command that reaches the network is the explicitly operator-invoked
108
+ `capture provider-usage`, and only when the operator supplies a credential via
109
+ an environment variable. There is no telemetry.
110
+
111
+ ### curl + npm / npx — AVAILABLE AT LAUNCH (pending publish; not live today)
112
+
113
+ **The public install path is not live yet.** The package is **not yet published**
114
+ to npm, and the installer is not yet hosted at `cli.compaction.dev`. The commands
115
+ below are the intended public install path and will work **only at launch**, once
116
+ the package is published **and** the script is hosted. Do not expect them to work
117
+ today.
118
+
119
+ ```bash
120
+ # AVAILABLE AT LAUNCH — not live today.
121
+ # One-line installer (hosted at cli.compaction.dev at launch):
122
+ curl -fsSL https://cli.compaction.dev/install | sh
123
+ # Inspect it first (recommended): pipe to `less`, or download and read, before sh.
124
+ curl -fsSL https://cli.compaction.dev/install | less
125
+
126
+ # or with npm / npx, once published:
127
+ npm install -g @compaction/cli # then: compaction init
128
+ npx @compaction/cli init # no global install
129
+ ```
130
+
131
+ The installer ([`scripts/install.sh`](scripts/install.sh)) is checked into the repo
132
+ and readable now: it uses **no `sudo` by default** (installs into a user-writable
133
+ prefix), makes **no network call except the npm install** (no telemetry), supports
134
+ macOS + Linux, and **fails clearly if the package is not yet published** rather than
135
+ faking success. Preview it without installing anything:
136
+
137
+ ```bash
138
+ sh scripts/install.sh --dry-run
139
+ ```
140
+
141
+ See [`docs/ops/install-readiness.md`](docs/ops/install-readiness.md) for the full
142
+ install-readiness contract (hosting, package name, version pinning, platforms, and
143
+ the pre-publish state).
144
+
145
+ This repository is licensed under **AGPL-3.0-only** (see [`LICENSE`](LICENSE)). The
146
+ npm **package name is `@compaction/cli`** (scoped, public; the installed binary
147
+ stays `compaction`). It is **not yet published** — the `npm install` / `npx`
148
+ commands above stay PENDING until the founder runs `npm publish`. Until publish,
149
+ use the from-source path (recommended) or the local-tarball fallback below.
150
+
151
+ ### From source — recommended today
152
+
153
+ ```bash
154
+ git clone <repo-url>
155
+ cd compaction-dev
156
+ npm ci
157
+ npm run build
158
+ # optional: expose the `compaction` binary on your PATH
159
+ npm link
160
+ ```
161
+
162
+ For reproducible local validation, use `npm ci` (not `npm install`).
163
+
164
+ ### Local tarball install (temporary internal/tester fallback)
165
+
166
+ Until the package is on npm, an external tester can install the packed tarball
167
+ directly. This is a **temporary fallback**, not the intended public path:
168
+
169
+ ```bash
170
+ npm pack
171
+ npm install -g ./compaction-cli-0.1.0.tgz
172
+ ```
173
+
174
+ The package layout is verified by `npm run smoke:package`, which packs the
175
+ tarball, installs it into a scratch prefix outside the repo, and runs
176
+ `compaction --help`, `compaction init`, and a capture → compact step from the
177
+ installed binary. The packed tarball ships the local CLI, `README.md`, and
178
+ `LICENSE` only.
179
+
180
+ ### Sanity check
181
+
182
+ ```bash
183
+ compaction --help
184
+ ```
185
+
186
+ ## CLI (free, local)
187
+
188
+ The free local commands:
189
+
190
+ ```bash
191
+ compaction init # scaffold local config
192
+ compaction capture claude-code --session <session.jsonl> [--include-subagents] --out <dir>
193
+ compaction capture claude-code --discover [--projects-dir <path>]
194
+ compaction capture openai-agents --out <dir> -- <command> [args...]
195
+ compaction capture openai-agents --out <dir> --export <local-jsonl-export>
196
+ compaction capture provider-usage --endpoint <url> [--credential-env-var <NAME>] [--out <dir>]
197
+ compaction import <trace-file> --source <source> --out <dir>
198
+ compaction import --list-sources
199
+ compaction analyze <trace-file>
200
+ compaction feedback --redact [--yes]
201
+ ```
202
+
203
+ ### `capture claude-code` (primary supported workflow)
204
+
205
+ Captures a real Claude Code session JSONL (optionally including subagent
206
+ transcripts) into the internal trace format, preserving provider-reported token
207
+ usage from the session's own API response metadata. `--discover` scans the local
208
+ Claude Code projects directory read-only and lists sessions with metadata (no
209
+ network, no upload). This is **Integration Readiness Level 2** (local
210
+ command-wrapper) — not Level 3 native SDK instrumentation. Captured traces may
211
+ contain local file content — review before sharing.
212
+
213
+ ### `capture openai-agents` (Level 2 command-wrapper)
214
+
215
+ Runs a local command or reads a local JSONL export containing OpenAI Agents
216
+ SDK-style trace/span events, normalizes the supported events into the internal
217
+ trace format, and writes capture evidence locally. It distinguishes
218
+ provider-reported usage from local estimates: when supported events carry provider
219
+ token fields, those values are labeled provider-reported; when absent, token
220
+ metadata is marked `missing`/`unknown` and **never invented**. This is local
221
+ capture only (Level 2) — it does **not** scrape the ChatGPT app, use undocumented
222
+ APIs, upload traces, proxy provider/model calls, switch providers/models, or add a
223
+ dashboard/auth/billing.
224
+
225
+ ### `capture provider-usage` (the only network call)
226
+
227
+ Explicitly operator-invoked, read-only read of aggregate usage/cost from a provider
228
+ usage API. The credential comes from an environment variable only (never a flag
229
+ value, never logged, never written into artifacts); absence is a clean refusal. It
230
+ captures aggregate token/cost figures only — no prompt/completion content. The
231
+ resulting record is classified as provider-usage evidence.
232
+
233
+ ### `import` (Codex / local-file traces — Level 1)
234
+
235
+ Reads a local trace-like JSON/JSONL file (including a `codex exec --json` export),
236
+ validates whether it can be converted into the internal trace format, and writes
237
+ normalized intake artifacts to an output directory. Import is local and file-based
238
+ only: it does not mutate the source file, upload data, call provider APIs, route
239
+ models, create a hosted service, use a database, add auth, or add billing. List
240
+ supported sources with `compaction import --list-sources`.
241
+
242
+ Codex token counts on the import path are **locally estimated (chars/4)**, not
243
+ provider-reported. Live provider/runtime integrations (native Claude Code/Cursor
244
+ instrumentation, live Codex launching, hosted provider APIs) remain future work; the
245
+ Codex support here is intentionally local/export-file based only (Level 1).
246
+
247
+ ### `analyze`
248
+
249
+ Reads a trace file and prints trace metadata, estimated input/output/total tokens,
250
+ an estimated local cost, conservative waste findings, and suggested
251
+ duplicate-output compaction opportunities (advisory only — the free CLI does **not**
252
+ apply them; optimization is the opt-in Compaction API).
253
+
254
+ ### `feedback --redact`
255
+
256
+ Builds a **redacted, privacy-safe feedback bundle** as a **local file only — never
257
+ uploaded**. Redaction is best-effort and the bundle's own README states what is
258
+ included/excluded; writing the bundle requires an explicit write gesture
259
+ (`--yes`/`--confirm`). There is no upload path.
260
+
261
+ ## Known limitations
262
+
263
+ - **The free CLI captures and measures; it does not optimize or verify.**
264
+ Optimization, advanced verification, apply guidance, and team reporting are the
265
+ **opt-in Compaction API** — not the free local CLI. The API is **not broadly
266
+ hosted yet**.
267
+ - **Cost figures are estimates or operator-entered records, not billing-confirmed.**
268
+ Locally computed cost figures are price-table estimates; provider-usage records
269
+ carry operator-entered/captured console figures (not provider-verified by this
270
+ tool). **No figure anywhere in this repository is billing-confirmed**; the accepted
271
+ criterion that could one day support such a label (N ≥ 3 per arm, ±2·SE interval
272
+ excluding zero, on real billed runs) has not been met.
273
+ - **Token counts are local estimates unless provider-reported usage is captured.**
274
+ The default is a chars/4 estimate, labeled as such; counts are provider-reported
275
+ only when the captured run carries provider usage metadata. Unknown stays unknown —
276
+ output tokens, provider, or cost the data does not carry are never inferred.
277
+ - **Integrations are Level 1/2, not native/production.** Claude Code and OpenAI
278
+ Agents capture are **Level 2** local command-wrappers; Codex/local-file import is
279
+ **Level 1**. There is **no** native/Level 3 SDK instrumentation, no production
280
+ proxy, no model routing, and no ChatGPT/Claude consumer-app support.
281
+ - **Advanced verification (API) is deterministic recoverability, not semantic
282
+ preservation.** Where the opt-in API verifies a compacted context, it checks
283
+ deterministic recoverability for a **supported** workflow; it does **not** evaluate
284
+ meaning or task equivalence, and it does **not** re-run your agent through a model.
285
+ SEMANTIC / meaning preservation remains **not evaluated**, and true model replay is
286
+ **future work**.
287
+ - **No universal "no context is lost" guarantee.** Any apply-guidance verdict from
288
+ the opt-in API is **fail-closed and scoped** to supported developer-agent
289
+ workflows — never a universal guarantee, and never a semantic/meaning claim.
290
+
291
+ ## Product constraints
292
+
293
+ - CLI-first, not web-app-first. No web framework, no database, no auth or billing, no
294
+ streaming.
295
+ - No provider integrations in the free CLI except the explicitly operator-invoked,
296
+ read-only `capture provider-usage` (env-only credential; aggregate usage/cost only).
297
+ No proxying, no model routing, no live-call interception.
298
+ - No hosted service or control plane in the free CLI; no full observability dashboard.
299
+
300
+ **On the roadmap / opt-in API (NOT in the free CLI; reads as future/opt-in anywhere
301
+ public):** the Compaction API's optimization and advanced verification, apply
302
+ guidance, and team reporting; a hosted dashboard / control plane; native (Level 3)
303
+ SDK instrumentation; model routing / provider switching / live-call interception; an
304
+ IDE plugin; true model replay; semantic / meaning preservation (today not
305
+ evaluated); and billing-confirmed savings (no figure in this repository carries that
306
+ label). **The Compaction API is not broadly hosted yet** — never imply a live hosted
307
+ service exists.
308
+
309
+ ## Contributing / internal docs
310
+
311
+ Repository development, the marketing/docs website (`apps/web`), and contributor
312
+ workflows live in the repo's internal documentation, **not** in this npm-facing
313
+ README:
314
+
315
+ - `AGENTS.md` — the agent operating contract.
316
+ - `ROADMAP.md` — canonical strategy and the long-term path.
317
+ - `docs/product/product-index.md` — the product-docs entry point (`mvp-plan.md`,
318
+ `decisions.md`).
319
+ - `docs/ops/install-readiness.md` — the install/publish readiness contract.
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerAdapterCommand(program: Command): void;
@@ -0,0 +1,49 @@
1
+ import chalk from "chalk";
2
+ import { validateAdapterFixtureFile } from "../../core/adapter-validation.js";
3
+ import { listTraceAdapters } from "../../core/trace-adapters.js";
4
+ function printSupportedAdapters() {
5
+ console.log(chalk.cyan("compaction adapter sources"));
6
+ for (const adapter of listTraceAdapters()) {
7
+ console.log(`- ${adapter.id}: ${adapter.displayName}`);
8
+ console.log(` ${adapter.description}`);
9
+ }
10
+ console.log("Adapter Fixture Harness v0 is local and file-based only; live provider/runtime integrations are future work.");
11
+ }
12
+ export function registerAdapterCommand(program) {
13
+ const adapter = program.command("adapter").description("Validate local adapter fixtures without live provider integrations.");
14
+ adapter.command("list").description("List local trace adapters available to the fixture harness.").action(() => {
15
+ printSupportedAdapters();
16
+ });
17
+ adapter
18
+ .command("validate")
19
+ .argument("<fixture-file>", "Path to a local adapter fixture JSON or JSONL file")
20
+ .requiredOption("--source <source>", "Input source from the local adapter registry")
21
+ .description("Validate a local fixture through adapter canHandle and normalize.")
22
+ .action(async (fixtureFile, options) => {
23
+ if (!options.source) {
24
+ throw new Error("Missing required option --source <source>.");
25
+ }
26
+ const artifacts = await validateAdapterFixtureFile(fixtureFile, options.source);
27
+ console.log(chalk.cyan("compaction adapter validate"));
28
+ console.log(`Status: ${artifacts.report.status}`);
29
+ console.log(`Validation ID: ${artifacts.report.validation_id}`);
30
+ console.log(`Source: ${artifacts.report.source}`);
31
+ console.log(`Adapter: ${artifacts.report.adapter_id}`);
32
+ console.log(`Supported format detected: ${artifacts.report.supported_format_detected ? "yes" : "no"}`);
33
+ console.log(`Messages: ${artifacts.report.message_count}`);
34
+ console.log(chalk.green(`Wrote ${artifacts.paths.validationReportJsonPath}`));
35
+ console.log(chalk.green(`Wrote ${artifacts.paths.validationReportMarkdownPath}`));
36
+ if (artifacts.normalizedTrace) {
37
+ console.log(chalk.green(`Wrote ${artifacts.paths.normalizedTracePath}`));
38
+ console.log(`Recommended next command: ${artifacts.report.recommended_next_command}`);
39
+ }
40
+ else {
41
+ console.log(chalk.red("No normalized trace was generated."));
42
+ for (const failure of artifacts.report.failures) {
43
+ console.log(chalk.red(`Failure: ${failure}`));
44
+ }
45
+ process.exitCode = 1;
46
+ }
47
+ });
48
+ }
49
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerAggregateCommand(program: Command): void;
@@ -0,0 +1,60 @@
1
+ import chalk from "chalk";
2
+ import { writeJsonArtifact, writeTextArtifact } from "../../core/artifact-writer.js";
3
+ import { createAggregateReport, AGGREGATE_ARTIFACT_DIRECTORY } from "../../core/session-aggregate.js";
4
+ import { buildAggregateShareBundle, formatAggregateMarkdown, formatAggregateReport, formatShareBundleMarkdown } from "../../core/aggregate-format.js";
5
+ import { normalizeRunLabels } from "../../core/run-labels.js";
6
+ /** Collect ONLY the label fields that were actually supplied, so absent ≡ no filter. */
7
+ function suppliedLabels(options) {
8
+ return normalizeRunLabels({
9
+ project: options.project,
10
+ workflow: options.workflow,
11
+ provider: options.provider,
12
+ user_label: options.userLabel,
13
+ session: options.session
14
+ });
15
+ }
16
+ export function registerAggregateCommand(program) {
17
+ program
18
+ .command("aggregate")
19
+ .description("Roll up local compaction runs into per-session + cross-session token / cost / estimated-savings " +
20
+ "and verification-outcome aggregates. LOCAL ONLY — reads .compaction/runs/*, makes NO network call, " +
21
+ "writes only local files. No hosted dashboard.")
22
+ .option("--runs <dir>", "Runs directory to aggregate", ".compaction/runs")
23
+ .option("--out <dir>", "Directory for the aggregate artifacts", AGGREGATE_ARTIFACT_DIRECTORY)
24
+ .option("--share", "Also write a redacted, content-free AGGREGATE share bundle (aggregate numbers + labels + evidence " +
25
+ "tiers, NOT raw traces) a developer can hand a founder/admin. Local file only — never uploaded.")
26
+ .option("--project <name>", "Local-only: roll up ONLY runs tagged with this project label")
27
+ .option("--workflow <name>", "Local-only: roll up ONLY runs tagged with this workflow label")
28
+ .option("--provider <name>", "Local-only: roll up ONLY runs tagged with this provider/runtime label (operator-asserted)")
29
+ .option("--user-label <text>", "Local-only: roll up ONLY runs tagged with this free-form user label")
30
+ .option("--session <id>", "Local-only: roll up ONLY runs tagged with this session id")
31
+ .action(async (options) => {
32
+ const filters = suppliedLabels(options);
33
+ const runsDir = options.runs ?? ".compaction/runs";
34
+ const outDir = options.out ?? AGGREGATE_ARTIFACT_DIRECTORY;
35
+ const report = await createAggregateReport(runsDir, {
36
+ filters,
37
+ rollupLabels: filters
38
+ });
39
+ const consoleReport = formatAggregateReport(report);
40
+ const markdown = formatAggregateMarkdown(report);
41
+ const aggregateDir = `${outDir}/${report.aggregate_id}`;
42
+ const jsonPath = await writeJsonArtifact(aggregateDir, "aggregate-report.json", report);
43
+ const markdownPath = await writeTextArtifact(aggregateDir, "aggregate-report.md", markdown);
44
+ console.log(chalk.cyan(consoleReport));
45
+ console.log("");
46
+ console.log(chalk.green(`Wrote ${jsonPath}`));
47
+ console.log(chalk.green(`Wrote ${markdownPath}`));
48
+ if (options.share === true) {
49
+ const shareBundle = buildAggregateShareBundle(report);
50
+ const shareJsonPath = await writeJsonArtifact(aggregateDir, "aggregate-share.json", shareBundle);
51
+ const shareMarkdownPath = await writeTextArtifact(aggregateDir, "aggregate-share.md", formatShareBundleMarkdown(shareBundle));
52
+ console.log("");
53
+ console.log(chalk.bold("Redacted aggregate share bundle (content-free): aggregate numbers + labels + evidence tiers only — " +
54
+ "NO raw traces, run ids, or paths. Local file only; never uploaded."));
55
+ console.log(chalk.green(`Wrote ${shareJsonPath}`));
56
+ console.log(chalk.green(`Wrote ${shareMarkdownPath}`));
57
+ }
58
+ });
59
+ }
60
+ //# sourceMappingURL=aggregate.js.map
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerAnalyzeCommand(program: Command): void;
@@ -0,0 +1,55 @@
1
+ import chalk from "chalk";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join, dirname } from "node:path";
4
+ import { calculateCost } from "../../core/cost-calculator.js";
5
+ import { formatAnalyzeReport } from "../../core/report-generator.js";
6
+ import { estimateTraceTokens } from "../../core/token-estimator.js";
7
+ import { detectWaste, buildSkillInjectionAdvisory } from "../../core/waste-detector.js";
8
+ import { parseTraceFile } from "../../core/trace-parser.js";
9
+ /**
10
+ * Try to load sibling capture-report.json from the same directory as the trace file.
11
+ * Returns the usage metadata if found and valid, otherwise undefined.
12
+ * Never throws — missing or malformed capture-report.json is silently ignored.
13
+ */
14
+ async function tryLoadCaptureUsage(traceFile) {
15
+ try {
16
+ const dir = dirname(traceFile);
17
+ const captureReportPath = join(dir, "capture-report.json");
18
+ const raw = await readFile(captureReportPath, "utf8");
19
+ const parsed = JSON.parse(raw);
20
+ if (parsed.usage && typeof parsed.usage === "object") {
21
+ return parsed.usage;
22
+ }
23
+ }
24
+ catch {
25
+ // No capture-report.json, or unreadable/malformed — silently ignore.
26
+ }
27
+ return undefined;
28
+ }
29
+ export function registerAnalyzeCommand(program) {
30
+ program
31
+ .command("analyze")
32
+ .argument("<trace-file>", "Path to a local agent trace JSON file")
33
+ .description("Analyze a trace and print token, cost, and waste estimates.")
34
+ .action(async (traceFile) => {
35
+ const trace = await parseTraceFile(traceFile);
36
+ const tokens = estimateTraceTokens(trace);
37
+ const findings = detectWaste(trace);
38
+ // Report-only skill-injection advisory. Built from a SEPARATE detector; nothing is
39
+ // compacted and it never affects `findings` / the tool-output compaction path.
40
+ const skillInjectionAdvisory = buildSkillInjectionAdvisory(trace);
41
+ // Load usage from sibling capture-report.json if available (provides cache token counts).
42
+ const captureUsage = await tryLoadCaptureUsage(traceFile);
43
+ const cost = calculateCost(trace.model, tokens, captureUsage
44
+ ? { cacheReadTokens: captureUsage.cache_read_input_tokens, cacheCreationTokens: captureUsage.cache_creation_input_tokens }
45
+ : undefined);
46
+ console.log(chalk.cyan("compaction analyze"));
47
+ console.log(formatAnalyzeReport(trace, tokens, cost, findings, captureUsage, skillInjectionAdvisory));
48
+ // Exact next command to continue the loop (chaining), with the trace path the user passed.
49
+ console.log("");
50
+ console.log(chalk.bold("Next: see the recommended policy and estimated delta:"));
51
+ console.log(` compaction recommend ${traceFile}`);
52
+ console.log(` compaction compact ${traceFile} --out <dir> # before/after delta + named policy + safety report`);
53
+ });
54
+ }
55
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1,12 @@
1
+ import { Command } from "commander";
2
+ /**
3
+ * `compaction apply-context <trace-file> --out <dir>` — LEVEL-5 IN-WORKFLOW APPLY, Form A.
4
+ *
5
+ * Operator-invoked, local-first. compaction.dev runs the existing compaction, the pre-apply safety
6
+ * checks, ALWAYS retains the un-compacted original, and produces the original-vs-compacted review.
7
+ * It emits the approved compacted context ONLY on the explicit per-application approval gesture
8
+ * `--approve-in-workflow-use`. It makes NO live provider call, holds NO credential, runs no proxy /
9
+ * hosted component, and performs no auto-apply. The unattended `apply` path is untouched and not
10
+ * reachable from here.
11
+ */
12
+ export declare function registerApplyContextCommand(program: Command): void;
@@ -0,0 +1,80 @@
1
+ import path from "node:path";
2
+ import chalk from "chalk";
3
+ import { Option } from "commander";
4
+ import { parseTraceFile } from "../../core/trace-parser.js";
5
+ import { runEngineCommand } from "../engine-degrade.js";
6
+ function defaultOutputDir(artifactRoot, traceId) {
7
+ return path.join(artifactRoot, traceId);
8
+ }
9
+ /**
10
+ * `compaction apply-context <trace-file> --out <dir>` — LEVEL-5 IN-WORKFLOW APPLY, Form A.
11
+ *
12
+ * Operator-invoked, local-first. compaction.dev runs the existing compaction, the pre-apply safety
13
+ * checks, ALWAYS retains the un-compacted original, and produces the original-vs-compacted review.
14
+ * It emits the approved compacted context ONLY on the explicit per-application approval gesture
15
+ * `--approve-in-workflow-use`. It makes NO live provider call, holds NO credential, runs no proxy /
16
+ * hosted component, and performs no auto-apply. The unattended `apply` path is untouched and not
17
+ * reachable from here.
18
+ */
19
+ export function registerApplyContextCommand(program) {
20
+ program
21
+ .command("apply-context")
22
+ .description("Form A in-workflow apply: review original-vs-compacted, run pre-apply safety checks, and (only with explicit per-application approval) emit an approved compacted context for YOUR OWN next provider call. compaction.dev makes no live call and holds no credential.")
23
+ .argument("<trace-file>", "Path to a local agent trace JSON file")
24
+ .option("--out <dir>", "Directory where in-workflow-apply artifacts should be written")
25
+ .addOption(new Option("--approve-in-workflow-use", "EXPLICIT per-application approval gesture. Without it: review artifacts are produced and NO approved context is emitted. This records 'approved for in-workflow use' (NOT 'applied')."))
26
+ .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
+ .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
+ .option("--attest-note <text>", "Optional free-text note recorded with the operator attestation")
29
+ .action(async (traceFile, options) => {
30
+ await runEngineCommand(async () => {
31
+ // Lazy-load the proprietary engine: present in-repo/API, excluded from the public package.
32
+ // When absent, runEngineCommand prints the boundary message and exits cleanly (no stack trace).
33
+ const { IN_WORKFLOW_APPLY_ARTIFACT_ROOT, recordOperatorAttestation, runInWorkflowApply } = await import("../../engine/in-workflow-apply.js");
34
+ const trace = await parseTraceFile(traceFile);
35
+ const outputDirectory = options.out ?? defaultOutputDir(IN_WORKFLOW_APPLY_ARTIFACT_ROOT, trace.id);
36
+ console.log(chalk.cyan("compaction apply-context (Form A)"));
37
+ console.log("Operator-invoked, local-first. compaction.dev makes NO live provider call and holds NO provider credential. No proxy, no hosted component, no auto-apply.");
38
+ const result = await runInWorkflowApply({
39
+ trace,
40
+ outputDirectory,
41
+ approveInWorkflowUse: options.approveInWorkflowUse === true,
42
+ approveSkillInjectionPolicy: options.approveSkillInjectionPolicy === true,
43
+ generatedAt: trace.generatedAt
44
+ });
45
+ console.log(result.consoleSummary);
46
+ console.log(chalk.green(`Wrote ${result.paths.preApplyReviewJsonPath}`));
47
+ console.log(chalk.green(`Wrote ${result.paths.preApplyReviewMarkdownPath}`));
48
+ console.log(chalk.green(`Wrote ${result.paths.retainedOriginalPath}`));
49
+ if (result.paths.approvedContextPath) {
50
+ console.log(chalk.green(`Wrote ${result.paths.approvedContextPath}`));
51
+ }
52
+ if (result.paths.applyApprovalRecordPath) {
53
+ console.log(chalk.green(`Wrote ${result.paths.applyApprovalRecordPath}`));
54
+ }
55
+ // Optional operator attestation (only meaningful once an approval record exists).
56
+ if (options.attestUsed === true) {
57
+ if (result.approvalRecord && result.paths.applyApprovalRecordPath) {
58
+ const { record, path: attestationPath } = await recordOperatorAttestation({
59
+ outputDirectory,
60
+ applyApprovalRecord: result.approvalRecord,
61
+ applyApprovalRecordPath: result.paths.applyApprovalRecordPath,
62
+ generatedAt: trace.generatedAt,
63
+ operatorNote: options.attestNote
64
+ });
65
+ console.log(chalk.yellow(`Operator attestation recorded (operator-attested, NOT observed): ${record.provenance_label}`));
66
+ console.log(chalk.green(`Wrote ${attestationPath}`));
67
+ }
68
+ else {
69
+ console.log(chalk.yellow("--attest-used ignored: there is no approval record to attest against (approve in-workflow use first)."));
70
+ }
71
+ }
72
+ console.log(chalk.green(`Output directory: ${result.outputDirectory}`));
73
+ // Exit non-zero when no approved context was emitted (refusal / review-only), mirroring apply/approve.
74
+ if (!result.approvedContextEmitted) {
75
+ process.exitCode = 1;
76
+ }
77
+ });
78
+ });
79
+ }
80
+ //# sourceMappingURL=apply-context.js.map
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerApplyCommand(program: Command): void;