kompactor 0.8.1__tar.gz → 0.8.2__tar.gz

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 (43) hide show
  1. {kompactor-0.8.1 → kompactor-0.8.2}/PKG-INFO +15 -10
  2. {kompactor-0.8.1 → kompactor-0.8.2}/README.md +14 -9
  3. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/__init__.py +1 -1
  4. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/cli.py +27 -8
  5. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/installer.py +62 -0
  6. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/usage.html +1 -1
  7. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/store.py +43 -0
  8. kompactor-0.8.2/kompactor/vsix/kompactor-0.8.2.vsix +0 -0
  9. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/PKG-INFO +15 -10
  10. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/SOURCES.txt +1 -0
  11. {kompactor-0.8.1 → kompactor-0.8.2}/pyproject.toml +3 -2
  12. {kompactor-0.8.1 → kompactor-0.8.2}/tests/test_graph.py +1 -0
  13. {kompactor-0.8.1 → kompactor-0.8.2}/tests/test_kompactor.py +24 -0
  14. {kompactor-0.8.1 → kompactor-0.8.2}/tests/test_shell.py +1 -0
  15. {kompactor-0.8.1 → kompactor-0.8.2}/LICENSE +0 -0
  16. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/__main__.py +0 -0
  17. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/_launch.py +0 -0
  18. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/config.py +0 -0
  19. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/estimate.py +0 -0
  20. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/filters.py +0 -0
  21. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/graph.py +0 -0
  22. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/hooks.py +0 -0
  23. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/langs.py +0 -0
  24. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/outline.py +0 -0
  25. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/prove.py +0 -0
  26. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/rules.py +0 -0
  27. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/samples.py +0 -0
  28. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/server.py +0 -0
  29. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/shellwrap.py +0 -0
  30. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/OFL.txt +0 -0
  31. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/plex-mono-400.woff2 +0 -0
  32. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/plex-mono-500.woff2 +0 -0
  33. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/plex-sans-400.woff2 +0 -0
  34. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/plex-sans-500.woff2 +0 -0
  35. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/fonts/plex-sans-600.woff2 +0 -0
  36. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/static/logo-mark.svg +0 -0
  37. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/tokens.py +0 -0
  38. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor/ui.html +0 -0
  39. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/dependency_links.txt +0 -0
  40. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/entry_points.txt +0 -0
  41. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/requires.txt +0 -0
  42. {kompactor-0.8.1 → kompactor-0.8.2}/kompactor.egg-info/top_level.txt +0 -0
  43. {kompactor-0.8.1 → kompactor-0.8.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kompactor
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Cut the tokens Claude Code spends on noise: compacted command output (failing runs included), outline-first reads, a local code graph, and per-turn savings.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/amarkum/kompactor
@@ -98,7 +98,7 @@ Measured in 54 real Claude Code sessions on Flask, Cobra, SWR, ky and zustand at
98
98
  - **Outline-first file reads.** Big source files arrive as an outline (symbols, line ranges, who imports the file, which tests cover it). Claude reads just the ranges it needs; repeating the read returns the whole file.
99
99
  - **Local code graph.** Find code by topic, see callers, the impact of a change and the tests to run, for Python, Go, TypeScript, JavaScript and React.
100
100
  - **Terse replies and lean code.** Short, readable rules for answer-first prose and smallest-diff code, from 0 to 177 tokens depending on the level.
101
- - **Per-turn savings.** In the reply, the status line, the VS Code status bar and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
101
+ - **Per-turn savings, in tokens and dollars.** In the reply, the status line, a VS Code / Cursor sidebar (per session, per project and per turn) and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
102
102
  - **One dial for quality vs tokens.** Five levels, every option adjustable, per project, with a live preview of exactly what Claude would see.
103
103
  - **Nothing is lost.** Every shortened output keeps a raw copy (`kompactor show <id>`), and every hook fails open.
104
104
  - **Private and dependency-free.** Python 3.9+ standard library only. Runs locally, sends nothing anywhere, no telemetry.
@@ -123,7 +123,7 @@ kompactor start
123
123
  ```
124
124
  If your shell says `kompactor: command not found` (pip put the command in a folder that isn't on your PATH), run `python3 -m kompactor start` once. It links `kompactor` into a folder that is already on your PATH, such as `~/.local/bin`, so the command works in every terminal from then on.
125
125
 
126
- **VS Code.** Download `kompactor-0.8.1.vsix` from [Releases](https://github.com/amarkum/kompactor/releases), install it (Extensions › `⋯` › *Install from VSIX…*), and click **Enable** when Kompactor asks.
126
+ **VS Code and Cursor.** `kompactor start` adds the Kompactor extension to VS Code and Cursor automatically when they're installed (skip it with `--no-editor`); reload the window and a **Kompactor** icon appears in the activity bar. To install it by hand, download `kompactor-0.8.2.vsix` from [Releases](https://github.com/amarkum/kompactor/releases) and use Extensions › `⋯` › *Install from VSIX…*.
127
127
 
128
128
  **From source:**
129
129
  ```bash
@@ -136,12 +136,13 @@ git clone https://github.com/amarkum/kompactor.git && ./kompactor/install.sh
136
136
  2. **Work as usual.** You don't call Kompactor; it acts on Claude's tool calls by itself. After each reply you'll see a line like `Kompactor: −8.2k tokens this turn`, and the status line shows the running total.
137
137
  3. **Check it's on:** run `kompactor` in a terminal (or `/kompactor` in Claude Code):
138
138
  ```
139
- Kompactor 0.8.1: ON
139
+ Kompactor 0.8.2: ON
140
140
  Connected via the Claude Code plugin. New Claude Code sessions are compacted.
141
141
  Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
142
142
  Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
143
143
  ```
144
- 4. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
144
+ 4. **In VS Code or Cursor:** click the **Kompactor** icon in the activity bar for tokens and estimated dollars saved this session, in this project, today and over 30 days, plus what every recent turn saved.
145
+ 5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
145
146
 
146
147
  ## How it works
147
148
 
@@ -187,9 +188,9 @@ Ask Claude Code the way you normally would. These prompts come from the [evidenc
187
188
 
188
189
  | Command | What it does |
189
190
  |---|---|
190
- | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code) and open the dashboard on a free port |
191
+ | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code), add the extension to VS Code and Cursor, and open the dashboard on a free port |
191
192
  | `kompactor stop` | Pause it and close the dashboard; settings are kept |
192
- | `kompactor uninstall [--purge]` | Remove it from Claude Code (`--purge` also deletes `~/.kompactor`) |
193
+ | `kompactor uninstall` | Remove it from Claude Code and from VS Code / Cursor, and delete its data (`--keep-data` keeps `~/.kompactor`) |
193
194
  | `kompactor` / `kompactor status` | On or off, level, savings, how it works |
194
195
  | `kompactor presets` · `kompactor config preset 4` | List levels · change level |
195
196
  | `kompactor config <setting> <value>` | Change one [setting](#settings) |
@@ -272,7 +273,8 @@ Commit a `.kompactor.json` next to the code to give everyone the same level and
272
273
  |---|---|
273
274
  | After each reply | `Kompactor: −8.2k tokens this turn (13.1k › 4.9k, −63%) · session −41k · context ≈31% smaller` |
274
275
  | CLI status line | `Kompactor −41.3k · ctx −31% · last turn −8.2k · Balanced` |
275
- | VS Code status bar | Running savings; hover for details |
276
+ | VS Code / Cursor status bar | Tokens and ≈ dollars saved this session; hover for details |
277
+ | VS Code / Cursor sidebar | Kompactor icon in the activity bar: this session, this project, today and 30 days in tokens and dollars, recent turns (saved or "nothing to trim"), biggest wins |
276
278
  | Dashboard (`kompactor start`) | Per-turn chart, biggest wins, savings by feature and by project |
277
279
  | `kompactor gain` | The same numbers in the terminal |
278
280
  | `kompactor estimate` | Replays your **past** sessions and shows what Kompactor would have saved |
@@ -376,7 +378,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
376
378
 
377
379
  **What it reads.** The tool output Claude Code passes to its hooks, the files Claude reads (to outline them), your project's source (for the code graph), and the context size Claude Code gives the status line. Hooks never read your session transcripts. `kompactor estimate` and the dashboard's **Replay your history** panel read your local Claude Code session logs in `~/.claude/projects` only when you run them; the result isn't stored or sent anywhere.
378
380
 
379
- **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. Nothing is written to your repositories.
381
+ **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. When VS Code or Cursor is installed, `kompactor start` adds the Kompactor extension to them with their own `code` / `cursor` command (from a copy inside the package; nothing is downloaded), and `kompactor uninstall` removes it and deletes `~/.kompactor`. Nothing is written to your repositories.
380
382
 
381
383
  **What it never does.** Change your permission rules or sandbox settings, change what a command does, or send your code or output anywhere. Details: [privacy policy](https://github.com/amarkum/kompactor/blob/main/PRIVACY.md).
382
384
 
@@ -395,7 +397,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
395
397
  ```bash
396
398
  kompactor stop # pause: output passes through untouched; settings are kept
397
399
  kompactor start # turn it back on
398
- kompactor uninstall # remove hooks, status line, shell prefix and skill (--purge also deletes ~/.kompactor)
400
+ kompactor uninstall # remove hooks, status line, shell prefix, skill and editor extension, and delete ~/.kompactor
399
401
  ```
400
402
  Then remove the package the way you installed it: `claude plugin uninstall amarkum@kompactor`, `pipx uninstall kompactor`, or uninstall the extension in VS Code.
401
403
 
@@ -419,6 +421,9 @@ The hooks are Claude Code-specific, but `kompactor run -- <command>` and `kompac
419
421
  **How much latency does it add?**
420
422
  About 50–100 ms per hook, because the filters run in Python.
421
423
 
424
+ **How are the dollar figures worked out?**
425
+ They're estimates at an input-token price you set (`kompactor.pricePerMillionTokens` in VS Code, default $3 per million). Each token kept out of the context is counted once as a prompt-cache write (1.25× the input price) and once more at the cache-read price (0.1×) for every later turn in that session that would have re-read it.
426
+
422
427
  **Is it free?**
423
428
  Yes. MIT-licensed, no account, no paid tier.
424
429
 
@@ -65,7 +65,7 @@ Measured in 54 real Claude Code sessions on Flask, Cobra, SWR, ky and zustand at
65
65
  - **Outline-first file reads.** Big source files arrive as an outline (symbols, line ranges, who imports the file, which tests cover it). Claude reads just the ranges it needs; repeating the read returns the whole file.
66
66
  - **Local code graph.** Find code by topic, see callers, the impact of a change and the tests to run, for Python, Go, TypeScript, JavaScript and React.
67
67
  - **Terse replies and lean code.** Short, readable rules for answer-first prose and smallest-diff code, from 0 to 177 tokens depending on the level.
68
- - **Per-turn savings.** In the reply, the status line, the VS Code status bar and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
68
+ - **Per-turn savings, in tokens and dollars.** In the reply, the status line, a VS Code / Cursor sidebar (per session, per project and per turn) and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
69
69
  - **One dial for quality vs tokens.** Five levels, every option adjustable, per project, with a live preview of exactly what Claude would see.
70
70
  - **Nothing is lost.** Every shortened output keeps a raw copy (`kompactor show <id>`), and every hook fails open.
71
71
  - **Private and dependency-free.** Python 3.9+ standard library only. Runs locally, sends nothing anywhere, no telemetry.
@@ -90,7 +90,7 @@ kompactor start
90
90
  ```
91
91
  If your shell says `kompactor: command not found` (pip put the command in a folder that isn't on your PATH), run `python3 -m kompactor start` once. It links `kompactor` into a folder that is already on your PATH, such as `~/.local/bin`, so the command works in every terminal from then on.
92
92
 
93
- **VS Code.** Download `kompactor-0.8.1.vsix` from [Releases](https://github.com/amarkum/kompactor/releases), install it (Extensions › `⋯` › *Install from VSIX…*), and click **Enable** when Kompactor asks.
93
+ **VS Code and Cursor.** `kompactor start` adds the Kompactor extension to VS Code and Cursor automatically when they're installed (skip it with `--no-editor`); reload the window and a **Kompactor** icon appears in the activity bar. To install it by hand, download `kompactor-0.8.2.vsix` from [Releases](https://github.com/amarkum/kompactor/releases) and use Extensions › `⋯` › *Install from VSIX…*.
94
94
 
95
95
  **From source:**
96
96
  ```bash
@@ -103,12 +103,13 @@ git clone https://github.com/amarkum/kompactor.git && ./kompactor/install.sh
103
103
  2. **Work as usual.** You don't call Kompactor; it acts on Claude's tool calls by itself. After each reply you'll see a line like `Kompactor: −8.2k tokens this turn`, and the status line shows the running total.
104
104
  3. **Check it's on:** run `kompactor` in a terminal (or `/kompactor` in Claude Code):
105
105
  ```
106
- Kompactor 0.8.1: ON
106
+ Kompactor 0.8.2: ON
107
107
  Connected via the Claude Code plugin. New Claude Code sessions are compacted.
108
108
  Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
109
109
  Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
110
110
  ```
111
- 4. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
111
+ 4. **In VS Code or Cursor:** click the **Kompactor** icon in the activity bar for tokens and estimated dollars saved this session, in this project, today and over 30 days, plus what every recent turn saved.
112
+ 5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
112
113
 
113
114
  ## How it works
114
115
 
@@ -154,9 +155,9 @@ Ask Claude Code the way you normally would. These prompts come from the [evidenc
154
155
 
155
156
  | Command | What it does |
156
157
  |---|---|
157
- | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code) and open the dashboard on a free port |
158
+ | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code), add the extension to VS Code and Cursor, and open the dashboard on a free port |
158
159
  | `kompactor stop` | Pause it and close the dashboard; settings are kept |
159
- | `kompactor uninstall [--purge]` | Remove it from Claude Code (`--purge` also deletes `~/.kompactor`) |
160
+ | `kompactor uninstall` | Remove it from Claude Code and from VS Code / Cursor, and delete its data (`--keep-data` keeps `~/.kompactor`) |
160
161
  | `kompactor` / `kompactor status` | On or off, level, savings, how it works |
161
162
  | `kompactor presets` · `kompactor config preset 4` | List levels · change level |
162
163
  | `kompactor config <setting> <value>` | Change one [setting](#settings) |
@@ -239,7 +240,8 @@ Commit a `.kompactor.json` next to the code to give everyone the same level and
239
240
  |---|---|
240
241
  | After each reply | `Kompactor: −8.2k tokens this turn (13.1k › 4.9k, −63%) · session −41k · context ≈31% smaller` |
241
242
  | CLI status line | `Kompactor −41.3k · ctx −31% · last turn −8.2k · Balanced` |
242
- | VS Code status bar | Running savings; hover for details |
243
+ | VS Code / Cursor status bar | Tokens and ≈ dollars saved this session; hover for details |
244
+ | VS Code / Cursor sidebar | Kompactor icon in the activity bar: this session, this project, today and 30 days in tokens and dollars, recent turns (saved or "nothing to trim"), biggest wins |
243
245
  | Dashboard (`kompactor start`) | Per-turn chart, biggest wins, savings by feature and by project |
244
246
  | `kompactor gain` | The same numbers in the terminal |
245
247
  | `kompactor estimate` | Replays your **past** sessions and shows what Kompactor would have saved |
@@ -343,7 +345,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
343
345
 
344
346
  **What it reads.** The tool output Claude Code passes to its hooks, the files Claude reads (to outline them), your project's source (for the code graph), and the context size Claude Code gives the status line. Hooks never read your session transcripts. `kompactor estimate` and the dashboard's **Replay your history** panel read your local Claude Code session logs in `~/.claude/projects` only when you run them; the result isn't stored or sent anywhere.
345
347
 
346
- **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. Nothing is written to your repositories.
348
+ **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. When VS Code or Cursor is installed, `kompactor start` adds the Kompactor extension to them with their own `code` / `cursor` command (from a copy inside the package; nothing is downloaded), and `kompactor uninstall` removes it and deletes `~/.kompactor`. Nothing is written to your repositories.
347
349
 
348
350
  **What it never does.** Change your permission rules or sandbox settings, change what a command does, or send your code or output anywhere. Details: [privacy policy](https://github.com/amarkum/kompactor/blob/main/PRIVACY.md).
349
351
 
@@ -362,7 +364,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
362
364
  ```bash
363
365
  kompactor stop # pause: output passes through untouched; settings are kept
364
366
  kompactor start # turn it back on
365
- kompactor uninstall # remove hooks, status line, shell prefix and skill (--purge also deletes ~/.kompactor)
367
+ kompactor uninstall # remove hooks, status line, shell prefix, skill and editor extension, and delete ~/.kompactor
366
368
  ```
367
369
  Then remove the package the way you installed it: `claude plugin uninstall amarkum@kompactor`, `pipx uninstall kompactor`, or uninstall the extension in VS Code.
368
370
 
@@ -386,6 +388,9 @@ The hooks are Claude Code-specific, but `kompactor run -- <command>` and `kompac
386
388
  **How much latency does it add?**
387
389
  About 50–100 ms per hook, because the filters run in Python.
388
390
 
391
+ **How are the dollar figures worked out?**
392
+ They're estimates at an input-token price you set (`kompactor.pricePerMillionTokens` in VS Code, default $3 per million). Each token kept out of the context is counted once as a prompt-cache write (1.25× the input price) and once more at the cache-read price (0.1×) for every later turn in that session that would have re-read it.
393
+
389
394
  **Is it free?**
390
395
  Yes. MIT-licensed, no account, no paid tier.
391
396
 
@@ -1,3 +1,3 @@
1
1
  """Kompactor: cut the tokens Claude Code spends on noise."""
2
2
 
3
- __version__ = "0.8.1"
3
+ __version__ = "0.8.2"
@@ -151,6 +151,12 @@ def cmd_hook(a):
151
151
 
152
152
 
153
153
  def cmd_gain(a):
154
+ if a.json:
155
+ project = config.project_root(a.project) if a.project else ""
156
+ print(json.dumps({**store.savings(a.price, a.session or "", project), "project_path": project,
157
+ "paused": store.paused(),
158
+ "version": __version__}))
159
+ return 0
154
160
  with store.connect() as db:
155
161
  rows = db.execute("SELECT feature, COUNT(*), SUM(raw_tokens), SUM(kept_tokens) FROM events GROUP BY feature "
156
162
  "ORDER BY SUM(raw_tokens) - SUM(kept_tokens) DESC").fetchall()
@@ -218,7 +224,7 @@ Use it from Claude Code
218
224
 
219
225
  Turn it off
220
226
  kompactor stop pause it (settings kept); `kompactor start` resumes
221
- kompactor uninstall remove it from Claude Code (--purge also deletes ~/.kompactor)
227
+ kompactor uninstall remove it from Claude Code, VS Code and Cursor, and delete its data
222
228
 
223
229
  Evidence
224
230
  Measured A/B runs of real Claude Code tasks: {EVIDENCE_URL}
@@ -337,6 +343,10 @@ def cmd_start(a):
337
343
  print(f" Connected via {'the Claude Code plugin' if st['plugin_enabled'] else where}")
338
344
  _prefix_note(st)
339
345
  _path_note(installer.link_on_path())
346
+ if not a.no_editor:
347
+ added = installer.install_editor_extension()
348
+ if added:
349
+ print(f" Added the Kompactor extension to {' and '.join(added)}: reload the window to see its sidebar.")
340
350
  d = _dashboard()
341
351
  if not d:
342
352
  from . import server
@@ -375,17 +385,20 @@ def cmd_stop(a):
375
385
 
376
386
 
377
387
  def cmd_uninstall(a):
378
- """Stop, remove hooks / status line / shell prefix / skill, and optionally delete data."""
388
+ """Stop, remove hooks / status line / shell prefix / skill / editor extension, and delete Kompactor's data."""
379
389
  _kill_dashboard()
380
390
  target = installer.install(uninstall=True)
381
391
  print(f"✓ Removed Kompactor from {target}")
382
- if a.purge:
392
+ removed = installer.uninstall_editor_extension()
393
+ if removed:
394
+ print(f" Removed the Kompactor extension from {' and '.join(removed)}.")
395
+ if a.keep_data:
396
+ (store.home() / "paused").unlink(missing_ok=True)
397
+ print(" Kept savings history and settings in ~/.kompactor.")
398
+ else:
383
399
  import shutil
384
400
  shutil.rmtree(store.home(), ignore_errors=True)
385
- print(" Deleted savings history and config (~/.kompactor).")
386
- else:
387
- (store.home() / "paused").unlink(missing_ok=True)
388
- print(" Kept savings history and config in ~/.kompactor (add --purge to delete).")
401
+ print(" Deleted Kompactor's data: savings history, settings, code graphs and saved outputs (~/.kompactor).")
389
402
  if installer.status()["plugin_enabled"]:
390
403
  print(" The Claude Code plugin is still enabled; run: claude plugin uninstall amarkum@kompactor")
391
404
  print(" Installed it as a Python package? Remove that too, with the tool you installed it with (pip, pipx or uv).")
@@ -490,13 +503,15 @@ def main(argv=None):
490
503
  p = sp.add_parser("start", help="turn Kompactor on: connect it to Claude Code and open the dashboard")
491
504
  p.add_argument("--port", type=int, default=0, help="preferred port (default: any free port)")
492
505
  p.add_argument("--no-browser", action="store_true")
506
+ p.add_argument("--no-editor", action="store_true", help="don't add the extension to VS Code or Cursor")
493
507
  p.set_defaults(fn=cmd_start)
494
508
 
495
509
  p = sp.add_parser("stop", help="pause Kompactor and close the dashboard (settings are kept)")
496
510
  p.set_defaults(fn=cmd_stop)
497
511
 
498
512
  p = sp.add_parser("uninstall", help="stop and remove Kompactor from Claude Code settings")
499
- p.add_argument("--purge", action="store_true", help="also delete ~/.kompactor (history and config)")
513
+ p.add_argument("--keep-data", action="store_true", help="keep ~/.kompactor (history and settings)")
514
+ p.add_argument("--purge", action="store_true", help=argparse.SUPPRESS) # the default now; kept for old docs
500
515
  p.set_defaults(fn=cmd_uninstall)
501
516
 
502
517
  p = sp.add_parser("estimate", help="replay past Claude Code sessions and show %% Kompactor would save")
@@ -508,6 +523,10 @@ def main(argv=None):
508
523
  p.set_defaults(fn=cmd_estimate)
509
524
 
510
525
  p = sp.add_parser("gain", help="live savings recorded by the hooks")
526
+ p.add_argument("--json", action="store_true", help="machine-readable totals with a dollar estimate")
527
+ p.add_argument("--price", type=float, default=3.0, help="input-token price in USD per million (default 3)")
528
+ p.add_argument("--session", help="also report this Claude Code session")
529
+ p.add_argument("--project", help="also report this project folder, with its recent turns")
511
530
  p.set_defaults(fn=cmd_gain)
512
531
 
513
532
  p = sp.add_parser("ui", help="open the settings & savings dashboard (foreground; see `start`)")
@@ -65,6 +65,68 @@ def write_shim(only_if_changed: bool = False) -> Path:
65
65
  return d / "kompactor"
66
66
 
67
67
 
68
+ # The VS Code extension ships inside the Python package (kompactor/vsix/, built by scripts/build-vsix.sh),
69
+ # so `kompactor start` can add it to VS Code and Cursor without downloading anything.
70
+ EXTENSION_ID = "kompactor.kompactor"
71
+ EDITORS = (("VS Code", "code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", ".vscode"),
72
+ ("Cursor", "cursor", "/Applications/Cursor.app/Contents/Resources/app/bin/cursor", ".cursor"))
73
+
74
+
75
+ def bundled_vsix():
76
+ from . import __version__
77
+ p = Path(__file__).with_name("vsix") / f"kompactor-{__version__}.vsix"
78
+ return p if p.exists() else None
79
+
80
+
81
+ def editors() -> list:
82
+ """(name, command-line tool, extensions folder) for each VS Code-family editor on this machine."""
83
+ found = []
84
+ for name, cmd, mac_path, home_dir in EDITORS:
85
+ cli = shutil.which(cmd) or (mac_path if os.path.exists(mac_path) else "")
86
+ if cli:
87
+ found.append((name, cli, Path.home() / home_dir / "extensions"))
88
+ return found
89
+
90
+
91
+ def _has_extension(ext_dir: Path, version: str = "") -> bool:
92
+ return any(ext_dir.glob(f"{EXTENSION_ID}-{version or '*'}"))
93
+
94
+
95
+ def install_editor_extension() -> list:
96
+ """Add the bundled extension to each editor that doesn't have this version yet; returns the editor names."""
97
+ import subprocess
98
+ from . import __version__
99
+ vsix = bundled_vsix()
100
+ done = []
101
+ for name, cli, ext_dir in editors() if vsix else []:
102
+ if _has_extension(ext_dir, __version__):
103
+ continue
104
+ try:
105
+ r = subprocess.run([cli, "--install-extension", str(vsix), "--force"], capture_output=True, text=True,
106
+ timeout=180)
107
+ except (OSError, subprocess.SubprocessError):
108
+ continue
109
+ if r.returncode == 0:
110
+ done.append(name)
111
+ return done
112
+
113
+
114
+ def uninstall_editor_extension() -> list:
115
+ """Remove the extension from every editor that has it; returns the editor names."""
116
+ import subprocess
117
+ done = []
118
+ for name, cli, ext_dir in editors():
119
+ if not _has_extension(ext_dir):
120
+ continue
121
+ try:
122
+ r = subprocess.run([cli, "--uninstall-extension", EXTENSION_ID], capture_output=True, text=True, timeout=180)
123
+ except (OSError, subprocess.SubprocessError):
124
+ continue
125
+ if r.returncode == 0:
126
+ done.append(name)
127
+ return done
128
+
129
+
68
130
  # Where a `kompactor` command can be linked when pip put it in a folder that isn't on PATH.
69
131
  PATH_DIRS = ("~/.local/bin", "~/bin", "/opt/homebrew/bin", "/usr/local/bin")
70
132
 
@@ -139,7 +139,7 @@ svg.chev { width: 11px; height: 11px; stroke: var(--ink-3); fill: none; stroke-w
139
139
  <pre><code>pipx install kompactor
140
140
  kompactor start</code></pre></div>
141
141
  <div class="card"><b>VS Code</b><span class="muted">Download the extension file from the repo's Releases page, then click <b>Enable</b> when Kompactor asks.</span>
142
- <pre><code>code --install-extension kompactor-0.8.1.vsix</code></pre></div>
142
+ <pre><code>code --install-extension kompactor-0.8.2.vsix</code></pre></div>
143
143
  </div>
144
144
  <p class="muted">Windows: run <code>.\kompactor\install.ps1</code> from a clone, or use the VS Code extension. The CLI and the VS Code extension read the same <code>~/.claude/settings.json</code>, so one install covers both. A backup of that file is kept as <code>settings.json.kompactor-backup</code>.</p>
145
145
  <p class="muted"><code>kompactor start</code> adds hooks, a status line (if you don't have one) and, on macOS and Linux, Claude Code's <code>CLAUDE_CODE_SHELL_PREFIX</code> setting pointing at <code>~/.kompactor/bin/kompactor-shell</code>, which is what lets Kompactor compact failing commands. It never replaces a status line or shell prefix you already have. Restart open Claude Code sessions after setup.</p>
@@ -143,6 +143,49 @@ def session_totals(session: str) -> dict:
143
143
  "context": last[2] if last else 0, "last_turn_saved": (last[0] - last[1]) if last else 0}
144
144
 
145
145
 
146
+ def savings(price_per_mtok: float = 3.0, session: str = "", project: str = "") -> dict:
147
+ """Tokens kept out of Claude's context, with a dollar estimate at `price_per_mtok` (the input-token
148
+ price). A kept-out token would have been written to the prompt cache once (1.25x) and re-read on every
149
+ later turn of its session (0.1x each), the same weights `kompactor estimate` uses."""
150
+ now = time.time()
151
+ day = now - 86400
152
+ with connect() as db:
153
+ def total(where="1", args=()):
154
+ r = db.execute(f"SELECT COUNT(*), COALESCE(SUM(raw_tokens),0), COALESCE(SUM(kept_tokens),0) FROM events "
155
+ f"WHERE {where}", args).fetchone()
156
+ return {"events": r[0], "raw": r[1], "kept": r[2], "saved": r[1] - r[2]}
157
+ periods = {"all": total(), "today": total("ts > ?", (day,))}
158
+ if session:
159
+ periods["session"] = total("session = ?", (session,))
160
+ if project:
161
+ periods["project"] = total("project = ?", (project,))
162
+ recent = db.execute("SELECT session, idx, ts, raw_tokens, kept_tokens, features FROM turns "
163
+ "WHERE project = ? OR (? = '' AND session = ?) ORDER BY ts DESC LIMIT 12",
164
+ (project, project, session)).fetchall()
165
+ turns = db.execute("SELECT session, ts, raw_tokens - kept_tokens, project FROM turns "
166
+ "ORDER BY session, idx").fetchall()
167
+ top = db.execute("SELECT detail, COUNT(*), SUM(raw_tokens), SUM(kept_tokens) FROM events WHERE feature='bash' "
168
+ "GROUP BY detail ORDER BY SUM(raw_tokens) - SUM(kept_tokens) DESC LIMIT 5").fetchall()
169
+ sessions = db.execute("SELECT COUNT(DISTINCT session) FROM events").fetchone()[0]
170
+ rereads = {"all": 0.0, "today": 0.0, "session": 0.0, "project": 0.0}
171
+ by_session = {}
172
+ for s, ts, saved, proj in turns:
173
+ by_session.setdefault(s, []).append((ts, saved, proj))
174
+ for s, rows in by_session.items():
175
+ for i, (ts, saved, proj) in enumerate(rows):
176
+ later = (len(rows) - i - 1) * saved * 0.1
177
+ rereads["all"] += later
178
+ rereads["today"] += later if ts > day else 0
179
+ rereads["session"] += later if s == session else 0
180
+ rereads["project"] += later if project and proj == project else 0
181
+ for k, p in periods.items():
182
+ p["usd"] = round((p["saved"] * 1.25 + rereads[k]) * price_per_mtok / 1e6, 4)
183
+ return {"price_per_mtok": price_per_mtok, "sessions": sessions, **periods,
184
+ "top": [{"cmd": t[0], "runs": t[1], "raw": t[2], "kept": t[3]} for t in top],
185
+ "turns": [{"session": t[0], "idx": t[1], "ts": t[2], "raw": t[3], "kept": t[4], "saved": t[3] - t[4],
186
+ "features": json.loads(t[5] or "{}")} for t in recent]}
187
+
188
+
146
189
  def prune(retention_days: float) -> None:
147
190
  """Drop data older than the retention window (called at session start)."""
148
191
  cutoff = time.time() - retention_days * 86400
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kompactor
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Cut the tokens Claude Code spends on noise: compacted command output (failing runs included), outline-first reads, a local code graph, and per-turn savings.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/amarkum/kompactor
@@ -98,7 +98,7 @@ Measured in 54 real Claude Code sessions on Flask, Cobra, SWR, ky and zustand at
98
98
  - **Outline-first file reads.** Big source files arrive as an outline (symbols, line ranges, who imports the file, which tests cover it). Claude reads just the ranges it needs; repeating the read returns the whole file.
99
99
  - **Local code graph.** Find code by topic, see callers, the impact of a change and the tests to run, for Python, Go, TypeScript, JavaScript and React.
100
100
  - **Terse replies and lean code.** Short, readable rules for answer-first prose and smallest-diff code, from 0 to 177 tokens depending on the level.
101
- - **Per-turn savings.** In the reply, the status line, the VS Code status bar and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
101
+ - **Per-turn savings, in tokens and dollars.** In the reply, the status line, a VS Code / Cursor sidebar (per session, per project and per turn) and a local dashboard. Numbers are conservative and never count output Claude wouldn't have read.
102
102
  - **One dial for quality vs tokens.** Five levels, every option adjustable, per project, with a live preview of exactly what Claude would see.
103
103
  - **Nothing is lost.** Every shortened output keeps a raw copy (`kompactor show <id>`), and every hook fails open.
104
104
  - **Private and dependency-free.** Python 3.9+ standard library only. Runs locally, sends nothing anywhere, no telemetry.
@@ -123,7 +123,7 @@ kompactor start
123
123
  ```
124
124
  If your shell says `kompactor: command not found` (pip put the command in a folder that isn't on your PATH), run `python3 -m kompactor start` once. It links `kompactor` into a folder that is already on your PATH, such as `~/.local/bin`, so the command works in every terminal from then on.
125
125
 
126
- **VS Code.** Download `kompactor-0.8.1.vsix` from [Releases](https://github.com/amarkum/kompactor/releases), install it (Extensions › `⋯` › *Install from VSIX…*), and click **Enable** when Kompactor asks.
126
+ **VS Code and Cursor.** `kompactor start` adds the Kompactor extension to VS Code and Cursor automatically when they're installed (skip it with `--no-editor`); reload the window and a **Kompactor** icon appears in the activity bar. To install it by hand, download `kompactor-0.8.2.vsix` from [Releases](https://github.com/amarkum/kompactor/releases) and use Extensions › `⋯` › *Install from VSIX…*.
127
127
 
128
128
  **From source:**
129
129
  ```bash
@@ -136,12 +136,13 @@ git clone https://github.com/amarkum/kompactor.git && ./kompactor/install.sh
136
136
  2. **Work as usual.** You don't call Kompactor; it acts on Claude's tool calls by itself. After each reply you'll see a line like `Kompactor: −8.2k tokens this turn`, and the status line shows the running total.
137
137
  3. **Check it's on:** run `kompactor` in a terminal (or `/kompactor` in Claude Code):
138
138
  ```
139
- Kompactor 0.8.1: ON
139
+ Kompactor 0.8.2: ON
140
140
  Connected via the Claude Code plugin. New Claude Code sessions are compacted.
141
141
  Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
142
142
  Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
143
143
  ```
144
- 4. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
144
+ 4. **In VS Code or Cursor:** click the **Kompactor** icon in the activity bar for tokens and estimated dollars saved this session, in this project, today and over 30 days, plus what every recent turn saved.
145
+ 5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
145
146
 
146
147
  ## How it works
147
148
 
@@ -187,9 +188,9 @@ Ask Claude Code the way you normally would. These prompts come from the [evidenc
187
188
 
188
189
  | Command | What it does |
189
190
  |---|---|
190
- | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code) and open the dashboard on a free port |
191
+ | `kompactor start` | Turn Kompactor on: connect it to Claude Code (CLI + VS Code), add the extension to VS Code and Cursor, and open the dashboard on a free port |
191
192
  | `kompactor stop` | Pause it and close the dashboard; settings are kept |
192
- | `kompactor uninstall [--purge]` | Remove it from Claude Code (`--purge` also deletes `~/.kompactor`) |
193
+ | `kompactor uninstall` | Remove it from Claude Code and from VS Code / Cursor, and delete its data (`--keep-data` keeps `~/.kompactor`) |
193
194
  | `kompactor` / `kompactor status` | On or off, level, savings, how it works |
194
195
  | `kompactor presets` · `kompactor config preset 4` | List levels · change level |
195
196
  | `kompactor config <setting> <value>` | Change one [setting](#settings) |
@@ -272,7 +273,8 @@ Commit a `.kompactor.json` next to the code to give everyone the same level and
272
273
  |---|---|
273
274
  | After each reply | `Kompactor: −8.2k tokens this turn (13.1k › 4.9k, −63%) · session −41k · context ≈31% smaller` |
274
275
  | CLI status line | `Kompactor −41.3k · ctx −31% · last turn −8.2k · Balanced` |
275
- | VS Code status bar | Running savings; hover for details |
276
+ | VS Code / Cursor status bar | Tokens and ≈ dollars saved this session; hover for details |
277
+ | VS Code / Cursor sidebar | Kompactor icon in the activity bar: this session, this project, today and 30 days in tokens and dollars, recent turns (saved or "nothing to trim"), biggest wins |
276
278
  | Dashboard (`kompactor start`) | Per-turn chart, biggest wins, savings by feature and by project |
277
279
  | `kompactor gain` | The same numbers in the terminal |
278
280
  | `kompactor estimate` | Replays your **past** sessions and shows what Kompactor would have saved |
@@ -376,7 +378,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
376
378
 
377
379
  **What it reads.** The tool output Claude Code passes to its hooks, the files Claude reads (to outline them), your project's source (for the code graph), and the context size Claude Code gives the status line. Hooks never read your session transcripts. `kompactor estimate` and the dashboard's **Replay your history** panel read your local Claude Code session logs in `~/.claude/projects` only when you run them; the result isn't stored or sent anywhere.
378
380
 
379
- **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. Nothing is written to your repositories.
381
+ **What it writes.** `~/.kompactor/`: settings, the savings ledger, raw copies of shortened output (for `kompactor show`), the code graph index and the `~/.kompactor/bin/` launchers. When `kompactor` isn't on your PATH, it adds one link to that launcher in a writable folder that already is (`~/.local/bin`, `~/bin`, `/opt/homebrew/bin` or `/usr/local/bin`); it never edits shell files or replaces an existing command, and `kompactor uninstall` removes the link. History is deleted after 30 days by default. `kompactor start` edits `~/.claude/settings.json` to add Kompactor's hooks (non-plugin installs), a status line (only if you have none) and `CLAUDE_CODE_SHELL_PREFIX` (only if it isn't set), keeping a backup in `settings.json.kompactor-backup`; non-plugin installs also get the `/kompactor` skill in `~/.claude/skills`. When VS Code or Cursor is installed, `kompactor start` adds the Kompactor extension to them with their own `code` / `cursor` command (from a copy inside the package; nothing is downloaded), and `kompactor uninstall` removes it and deletes `~/.kompactor`. Nothing is written to your repositories.
380
382
 
381
383
  **What it never does.** Change your permission rules or sandbox settings, change what a command does, or send your code or output anywhere. Details: [privacy policy](https://github.com/amarkum/kompactor/blob/main/PRIVACY.md).
382
384
 
@@ -395,7 +397,7 @@ Everything below happens on your machine. Kompactor makes no network requests of
395
397
  ```bash
396
398
  kompactor stop # pause: output passes through untouched; settings are kept
397
399
  kompactor start # turn it back on
398
- kompactor uninstall # remove hooks, status line, shell prefix and skill (--purge also deletes ~/.kompactor)
400
+ kompactor uninstall # remove hooks, status line, shell prefix, skill and editor extension, and delete ~/.kompactor
399
401
  ```
400
402
  Then remove the package the way you installed it: `claude plugin uninstall amarkum@kompactor`, `pipx uninstall kompactor`, or uninstall the extension in VS Code.
401
403
 
@@ -419,6 +421,9 @@ The hooks are Claude Code-specific, but `kompactor run -- <command>` and `kompac
419
421
  **How much latency does it add?**
420
422
  About 50–100 ms per hook, because the filters run in Python.
421
423
 
424
+ **How are the dollar figures worked out?**
425
+ They're estimates at an input-token price you set (`kompactor.pricePerMillionTokens` in VS Code, default $3 per million). Each token kept out of the context is counted once as a prompt-cache write (1.25× the input price) and once more at the cache-read price (0.1×) for every later turn in that session that would have re-read it.
426
+
422
427
  **Is it free?**
423
428
  Yes. MIT-licensed, no account, no paid tier.
424
429
 
@@ -35,6 +35,7 @@ kompactor/static/fonts/plex-mono-500.woff2
35
35
  kompactor/static/fonts/plex-sans-400.woff2
36
36
  kompactor/static/fonts/plex-sans-500.woff2
37
37
  kompactor/static/fonts/plex-sans-600.woff2
38
+ kompactor/vsix/kompactor-0.8.2.vsix
38
39
  tests/test_graph.py
39
40
  tests/test_kompactor.py
40
41
  tests/test_shell.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "kompactor"
7
- version = "0.8.1"
7
+ version = "0.8.2"
8
8
  description = "Cut the tokens Claude Code spends on noise: compacted command output (failing runs included), outline-first reads, a local code graph, and per-turn savings."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -44,9 +44,10 @@ exact = ["tiktoken>=0.7"]
44
44
  kompactor = "kompactor.cli:main"
45
45
 
46
46
  [tool.setuptools]
47
- packages = ["kompactor", "kompactor.static", "kompactor.static.fonts"]
47
+ packages = ["kompactor", "kompactor.static", "kompactor.static.fonts", "kompactor.vsix"]
48
48
 
49
49
  [tool.setuptools.package-data]
50
50
  kompactor = ["ui.html"]
51
51
  "kompactor.static" = ["*.html", "*.svg"]
52
52
  "kompactor.static.fonts" = ["*.woff2", "*.txt"]
53
+ "kompactor.vsix" = ["*.vsix"]
@@ -13,6 +13,7 @@ os.environ.setdefault("KOMPACTOR_HOME", tempfile.mkdtemp())
13
13
 
14
14
  from kompactor import config, graph, hooks, installer # noqa: E402
15
15
  installer.PATH_DIRS = () # never link `kompactor` into real PATH folders from tests
16
+ installer.EDITORS = () # never install or remove the real VS Code / Cursor extension from tests
16
17
 
17
18
 
18
19
  def make_repo(files: dict) -> str:
@@ -13,6 +13,7 @@ os.environ["KOMPACTOR_HOME"] = os.path.join(TMP, "home")
13
13
 
14
14
  from kompactor import config, estimate, filters, hooks, installer, langs, outline, server, store, tokens # noqa: E402
15
15
  installer.PATH_DIRS = () # never link `kompactor` into real PATH folders from tests
16
+ installer.EDITORS = () # never install or remove the real VS Code / Cursor extension from tests
16
17
 
17
18
 
18
19
  def run_hook(name, event):
@@ -584,6 +585,29 @@ class SourceTests(unittest.TestCase):
584
585
  installer.unlink_from_path(dirs=(str(on_path),))
585
586
  self.assertTrue((on_path / "kompactor").exists())
586
587
 
588
+ @unittest.skipIf(os.name == "nt", "uses a POSIX shell script as the fake editor")
589
+ def test_editor_extension_added_once_and_removed(self):
590
+ from unittest import mock
591
+ from kompactor import __version__
592
+ tmp = Path(tempfile.mkdtemp())
593
+ ext, log, cli, vsix = tmp / "extensions", tmp / "log", tmp / "code", tmp / "k.vsix"
594
+ ext.mkdir(); vsix.write_text("x")
595
+ cli.write_text(f"""#!/bin/sh
596
+ echo "$@" >> '{log}'
597
+ [ "$1" = --install-extension ] && mkdir -p '{ext}/kompactor.kompactor-{__version__}'
598
+ [ "$1" = --uninstall-extension ] && rm -rf '{ext}'/kompactor.kompactor-*
599
+ exit 0
600
+ """)
601
+ cli.chmod(0o755)
602
+ fake = (("VS Code", "no-such-editor-command", str(cli), str(tmp)),)
603
+ with mock.patch.object(installer, "EDITORS", fake), mock.patch.object(installer, "bundled_vsix", return_value=vsix):
604
+ self.assertEqual(installer.install_editor_extension(), ["VS Code"])
605
+ self.assertEqual(installer.install_editor_extension(), []) # this version is already there
606
+ self.assertEqual(installer.uninstall_editor_extension(), ["VS Code"])
607
+ self.assertEqual(installer.uninstall_editor_extension(), []) # nothing left to remove
608
+ self.assertEqual(log.read_text().split("\n")[:2],
609
+ [f"--install-extension {vsix} --force", "--uninstall-extension kompactor.kompactor"])
610
+
587
611
  def test_source_defaults_to_the_public_repo(self):
588
612
  self.assertEqual(installer.source("")["marketplace"], "amarkum/kompactor")
589
613
  self.assertEqual(installer.source("acme/kompactor")["clone"], "https://github.com/acme/kompactor.git") # a fork
@@ -21,6 +21,7 @@ sys.path.insert(0, str(ROOT))
21
21
 
22
22
  from kompactor import filters, hooks, installer, shellwrap, tokens # noqa: E402
23
23
  installer.PATH_DIRS = () # never link `kompactor` into real PATH folders from tests
24
+ installer.EDITORS = () # never install or remove the real VS Code / Cursor extension from tests
24
25
 
25
26
  PASSING = "".join(f"tests/test_mod.py::test_case_{i} PASSED{' ' * 30}[{i // 5:3d}%]\n" for i in range(500))
26
27
  FAILURE = ("=================================== FAILURES ===================================\n"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes