kompactor 0.8.2__tar.gz → 0.8.4__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.2 → kompactor-0.8.4}/PKG-INFO +10 -7
  2. {kompactor-0.8.2 → kompactor-0.8.4}/README.md +9 -6
  3. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/__init__.py +1 -1
  4. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/cli.py +78 -38
  5. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/usage.html +1 -1
  6. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/store.py +18 -2
  7. kompactor-0.8.2/kompactor/vsix/kompactor-0.8.2.vsix → kompactor-0.8.4/kompactor/vsix/kompactor-0.8.4.vsix +0 -0
  8. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/PKG-INFO +10 -7
  9. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/SOURCES.txt +1 -1
  10. {kompactor-0.8.2 → kompactor-0.8.4}/pyproject.toml +1 -1
  11. {kompactor-0.8.2 → kompactor-0.8.4}/tests/test_kompactor.py +19 -0
  12. {kompactor-0.8.2 → kompactor-0.8.4}/LICENSE +0 -0
  13. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/__main__.py +0 -0
  14. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/_launch.py +0 -0
  15. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/config.py +0 -0
  16. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/estimate.py +0 -0
  17. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/filters.py +0 -0
  18. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/graph.py +0 -0
  19. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/hooks.py +0 -0
  20. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/installer.py +0 -0
  21. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/langs.py +0 -0
  22. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/outline.py +0 -0
  23. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/prove.py +0 -0
  24. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/rules.py +0 -0
  25. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/samples.py +0 -0
  26. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/server.py +0 -0
  27. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/shellwrap.py +0 -0
  28. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/OFL.txt +0 -0
  29. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/plex-mono-400.woff2 +0 -0
  30. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/plex-mono-500.woff2 +0 -0
  31. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/plex-sans-400.woff2 +0 -0
  32. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/plex-sans-500.woff2 +0 -0
  33. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/fonts/plex-sans-600.woff2 +0 -0
  34. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/static/logo-mark.svg +0 -0
  35. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/tokens.py +0 -0
  36. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor/ui.html +0 -0
  37. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/dependency_links.txt +0 -0
  38. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/entry_points.txt +0 -0
  39. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/requires.txt +0 -0
  40. {kompactor-0.8.2 → kompactor-0.8.4}/kompactor.egg-info/top_level.txt +0 -0
  41. {kompactor-0.8.2 → kompactor-0.8.4}/setup.cfg +0 -0
  42. {kompactor-0.8.2 → kompactor-0.8.4}/tests/test_graph.py +0 -0
  43. {kompactor-0.8.2 → kompactor-0.8.4}/tests/test_shell.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kompactor
3
- Version: 0.8.2
3
+ Version: 0.8.4
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
@@ -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 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…*.
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.4.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,15 @@ 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.2: ON
140
- Connected via the Claude Code plugin. New Claude Code sessions are compacted.
141
- Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
142
- Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
139
+ Kompactor 0.8.4 is on
140
+
141
+ Claude Code connected
142
+ Level Balanced (3 of 5)
143
+ Saved 41.3k tokens (−38%) in 52 tool calls
144
+ Dashboard http://127.0.0.1:56710/
143
145
  ```
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.
146
+ `kompactor help` lists every command.
147
+ 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 Kompactor shortened in each of Claude's recent replies.
145
148
  5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
146
149
 
147
150
  ## How it works
@@ -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 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…*.
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.4.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,15 @@ 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.2: ON
107
- Connected via the Claude Code plugin. New Claude Code sessions are compacted.
108
- Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
109
- Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
106
+ Kompactor 0.8.4 is on
107
+
108
+ Claude Code connected
109
+ Level Balanced (3 of 5)
110
+ Saved 41.3k tokens (−38%) in 52 tool calls
111
+ Dashboard http://127.0.0.1:56710/
110
112
  ```
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.
113
+ `kompactor help` lists every command.
114
+ 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 Kompactor shortened in each of Claude's recent replies.
112
115
  5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
113
116
 
114
117
  ## How it works
@@ -1,3 +1,3 @@
1
1
  """Kompactor: cut the tokens Claude Code spends on noise."""
2
2
 
3
- __version__ = "0.8.2"
3
+ __version__ = "0.8.4"
@@ -190,47 +190,37 @@ def cmd_status(a):
190
190
  """What Kompactor is doing right now, and what to do next. Also what plain `kompactor` prints."""
191
191
  st = installer.status()
192
192
  cfg = config.load(os.getcwd())
193
- level = f"{config.PRESETS[cfg['preset']]['name']} (level {cfg['preset']} of 5)"
194
- on = (st["plugin_enabled"] or st["hooks_installed"]) and not store.paused()
195
- state = ("ON" if on else "STOPPED" if store.paused() else "NOT SET UP")
196
- print(f"Kompactor {__version__}: {state}")
197
- if not (st["plugin_enabled"] or st["hooks_installed"]):
198
- print(" Run `kompactor start` to connect it to Claude Code (CLI and VS Code).")
193
+ connected = st["plugin_enabled"] or st["hooks_installed"]
194
+ state = "on" if connected and not store.paused() else "stopped" if connected else "not set up"
195
+ if not connected:
196
+ claude = "not connected; run 'kompactor start'"
199
197
  elif store.paused():
200
- print(" Claude Code output passes through untouched. Turn it back on: `kompactor start`")
198
+ claude = "paused; run 'kompactor start' to resume"
201
199
  else:
202
- print(f" Connected via {'the Claude Code plugin' if st['plugin_enabled'] else st['settings_file']}."
203
- " New Claude Code sessions are compacted.")
204
- print(f" Level: {level}. Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced")
200
+ claude = "connected (plugin)" if st["plugin_enabled"] else "connected"
205
201
  with store.connect() as db:
206
202
  raw, kept, n = db.execute("SELECT COALESCE(SUM(raw_tokens),0), COALESCE(SUM(kept_tokens),0), COUNT(*) "
207
203
  "FROM events").fetchone()
208
- if n:
209
- print(f" Saved so far: {_fmt(raw - kept)} tokens ({_pct(raw - kept, raw)}) over {n} tool calls."
210
- " Details: `kompactor gain`")
211
- else:
212
- print(" Saved so far: nothing yet. Use Claude Code as usual; the status line shows savings per turn.")
204
+ saved = (f"{_fmt(raw - kept)} tokens (−{100 * (raw - kept) / raw:.0f}%) in {n} tool call{'s' if n != 1 else ''}"
205
+ if n and raw else "nothing yet")
213
206
  d = _dashboard()
214
- print(f" Dashboard: {d['url'] if d else 'not running (`kompactor start` opens it)'}")
215
- print(f"""
216
- How it works
217
- Kompactor sits between Claude Code's tools and Claude. Long command output (test runs, installs,
218
- git log), big file reads and searches are shortened before Claude reads them: errors, failing tests,
219
- your own stack frames and summary lines are always kept. Claude can still get the full text with
220
- `kompactor show <id>`. You don't change how you work; just use Claude Code.
221
-
222
- Use it from Claude Code
223
- /kompactor status · /kompactor max savings · /kompactor balanced · /kompactor stop · /kompactor start
224
-
225
- Turn it off
226
- kompactor stop pause it (settings kept); `kompactor start` resumes
227
- kompactor uninstall remove it from Claude Code, VS Code and Cursor, and delete its data
228
-
229
- Evidence
230
- Measured A/B runs of real Claude Code tasks: {EVIDENCE_URL}
231
- Your own sessions: `kompactor estimate` replays them and shows what it would have saved.
232
-
233
- All commands: kompactor --help""")
207
+ print(f"""Kompactor {__version__} is {state}
208
+
209
+ Claude Code {claude}
210
+ Level {config.PRESETS[cfg['preset']]['name']} ({cfg['preset']} of 5)
211
+ Saved {saved}
212
+ Dashboard {d['url'] if d else "not running"}
213
+
214
+ Commands:
215
+ start Turn Kompactor on and open the dashboard
216
+ stop Pause Kompactor (settings are kept)
217
+ uninstall Remove Kompactor and delete its data
218
+ gain Show what it saved, command by command
219
+ help List all commands
220
+
221
+ Kompactor shortens test runs, installs, logs and big file reads
222
+ before Claude reads them, keeping every error, failure and summary.
223
+ Evidence: {EVIDENCE_URL}""")
234
224
  return 0
235
225
 
236
226
 
@@ -486,16 +476,59 @@ def cmd_doctor(a):
486
476
  return 0
487
477
 
488
478
 
479
+ HELP = """Kompactor {version}: cut the tokens Claude Code spends on noise
480
+
481
+ Usage:
482
+ kompactor <command> [options]
483
+
484
+ Getting started:
485
+ start Turn Kompactor on and open the dashboard
486
+ stop Pause Kompactor (settings are kept)
487
+ uninstall Remove Kompactor and delete its data
488
+ status Show whether it's on and what it saved
489
+
490
+ Savings:
491
+ gain Show what it saved, command by command
492
+ estimate Estimate savings on your past sessions
493
+ ui Open the dashboard in this terminal
494
+
495
+ Settings:
496
+ presets List the quality-vs-tokens levels
497
+ config Show or change settings
498
+
499
+ Code:
500
+ graph Find code, callers and the impact of a change
501
+ outline List a file's symbols with line ranges
502
+ symbol Print one definition
503
+ show Print an output Kompactor shortened
504
+ search Search outputs Kompactor shortened
505
+
506
+ Other:
507
+ run Run a command and print its compacted output
508
+ doctor Check the installation
509
+ prove A/B test Kompactor in Claude Code sessions
510
+
511
+ Options:
512
+ -h, --help Show this help
513
+ --version Show the version
514
+
515
+ Run 'kompactor <command> --help' for details on a command.
516
+ Docs: https://github.com/amarkum/kompactor"""
517
+
518
+
489
519
  def main(argv=None):
490
520
  argv = sys.argv[1:] if argv is None else argv
491
521
  if argv[:1] == ["setup"]: # the old name for `start`; older docs still say it
492
522
  argv = ["start"] + ["--no-browser" if x == "--no-ui" else x for x in argv[1:]]
523
+ if argv[:1] in (["help"], ["-h"], ["--help"]):
524
+ print(HELP.format(version=__version__))
525
+ return 0
493
526
  if argv[:1] == ["prove"]: # has its own parser
494
527
  from . import prove
495
528
  return prove.main(argv[1:])
496
529
  ap = argparse.ArgumentParser(prog="kompactor", description="Cut the tokens Claude Code spends on noise.")
497
530
  ap.add_argument("--version", action="version", version=__version__)
498
- sp = ap.add_subparsers(dest="cmd")
531
+ sp = ap.add_subparsers(dest="cmd", metavar="<command>")
499
532
 
500
533
  p = sp.add_parser("status", help="is it on, your level, savings so far, and how to use it (also: plain `kompactor`)")
501
534
  p.set_defaults(fn=cmd_status)
@@ -543,7 +576,7 @@ def main(argv=None):
543
576
  help="don't set CLAUDE_CODE_SHELL_PREFIX (then commands that fail are not compacted)")
544
577
  p.set_defaults(fn=cmd_install)
545
578
 
546
- p = sp.add_parser("statusline", help="(internal) Claude Code status line")
579
+ p = sp.add_parser("statusline") # internal: Claude Code's status line
547
580
  p.set_defaults(fn=cmd_statusline)
548
581
 
549
582
  p = sp.add_parser("map", help="ranked repo skeleton within a token budget")
@@ -606,13 +639,20 @@ def main(argv=None):
606
639
  p.add_argument("--json", action="store_true")
607
640
  p.set_defaults(fn=cmd_presets)
608
641
 
609
- p = sp.add_parser("hook", help="(internal) Claude Code hook entrypoint")
642
+ p = sp.add_parser("hook") # internal: Claude Code hook entry point
610
643
  p.add_argument("name", choices=list(hooks.HANDLERS))
611
644
  p.set_defaults(fn=cmd_hook)
612
645
 
613
646
  p = sp.add_parser("doctor", help="check installation")
614
647
  p.set_defaults(fn=cmd_doctor)
615
648
 
649
+ if argv and not argv[0].startswith("-") and argv[0] not in sp.choices:
650
+ import difflib
651
+ near = difflib.get_close_matches(argv[0], [c for c in sp.choices if c not in ("hook", "statusline")], n=1)
652
+ print(f"kompactor: unknown command '{argv[0]}'" + (f"\n\nDid you mean this?\n kompactor {near[0]}" if near else ""),
653
+ file=sys.stderr)
654
+ print("\nRun 'kompactor help' for a list of commands.", file=sys.stderr)
655
+ return 2
616
656
  a = ap.parse_args(argv)
617
657
  if not a.cmd:
618
658
  a.fn = cmd_status
@@ -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.2.vsix</code></pre></div>
142
+ <pre><code>code --install-extension kompactor-0.8.4.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>
@@ -160,8 +160,18 @@ def savings(price_per_mtok: float = 3.0, session: str = "", project: str = "") -
160
160
  if project:
161
161
  periods["project"] = total("project = ?", (project,))
162
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",
163
+ "WHERE project = ? OR (? = '' AND session = ?) ORDER BY ts DESC LIMIT 30",
164
164
  (project, project, session)).fetchall()
165
+ shortened = {} # what each recent reply shortened: its commands and files, biggest first
166
+ for s, idx, ts, *_ in recent:
167
+ prev = db.execute("SELECT COALESCE(MAX(ts), 0) FROM turns WHERE session = ? AND idx < ?", (s, idx)).fetchone()[0]
168
+ items = {}
169
+ for f, d, r, k in db.execute("SELECT feature, detail, raw_tokens, kept_tokens FROM events WHERE session = ? "
170
+ "AND ts > ? AND ts <= ? AND raw_tokens > kept_tokens", (s, prev, ts)):
171
+ it = items.setdefault(_label(f, d), {"what": _label(f, d), "saved": 0, "times": 0})
172
+ it["saved"] += r - k
173
+ it["times"] += 1
174
+ shortened[(s, idx)] = sorted(items.values(), key=lambda it: -it["saved"])[:3]
165
175
  turns = db.execute("SELECT session, ts, raw_tokens - kept_tokens, project FROM turns "
166
176
  "ORDER BY session, idx").fetchall()
167
177
  top = db.execute("SELECT detail, COUNT(*), SUM(raw_tokens), SUM(kept_tokens) FROM events WHERE feature='bash' "
@@ -183,7 +193,13 @@ def savings(price_per_mtok: float = 3.0, session: str = "", project: str = "") -
183
193
  return {"price_per_mtok": price_per_mtok, "sessions": sessions, **periods,
184
194
  "top": [{"cmd": t[0], "runs": t[1], "raw": t[2], "kept": t[3]} for t in top],
185
195
  "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]}
196
+ "features": json.loads(t[5] or "{}"), "shortened": shortened[(t[0], t[1])]} for t in recent]}
197
+
198
+
199
+ def _label(feature: str, detail: str) -> str:
200
+ """How a saving reads in a list: the command, or the file that was outlined or not re-read."""
201
+ name = os.path.basename((detail or "").split(" (")[0])
202
+ return {"read_outline": f"read {name}", "read_dedupe": f"re-read {name}"}.get(feature, detail or feature)
187
203
 
188
204
 
189
205
  def prune(retention_days: float) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kompactor
3
- Version: 0.8.2
3
+ Version: 0.8.4
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
@@ -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 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…*.
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.4.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,15 @@ 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.2: ON
140
- Connected via the Claude Code plugin. New Claude Code sessions are compacted.
141
- Level: Balanced (level 3 of 5). Change it: `kompactor config preset 1-5`, the dashboard, or /kompactor balanced
142
- Saved so far: 41.3k tokens (−38%) over 52 tool calls. Details: `kompactor gain`
139
+ Kompactor 0.8.4 is on
140
+
141
+ Claude Code connected
142
+ Level Balanced (3 of 5)
143
+ Saved 41.3k tokens (−38%) in 52 tool calls
144
+ Dashboard http://127.0.0.1:56710/
143
145
  ```
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.
146
+ `kompactor help` lists every command.
147
+ 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 Kompactor shortened in each of Claude's recent replies.
145
148
  5. **Three commands to remember:** `kompactor start` turns it on and opens the dashboard, `kompactor stop` pauses it, `kompactor uninstall` removes it.
146
149
 
147
150
  ## How it works
@@ -35,7 +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
+ kompactor/vsix/kompactor-0.8.4.vsix
39
39
  tests/test_graph.py
40
40
  tests/test_kompactor.py
41
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.2"
7
+ version = "0.8.4"
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"
@@ -16,6 +16,11 @@ installer.PATH_DIRS = () # never link `kompactor` into real PATH folders from t
16
16
  installer.EDITORS = () # never install or remove the real VS Code / Cursor extension from tests
17
17
 
18
18
 
19
+ def mock_stderr(buf):
20
+ from contextlib import redirect_stderr
21
+ return redirect_stderr(buf)
22
+
23
+
19
24
  def run_hook(name, event):
20
25
  sys.stdin = io.StringIO(json.dumps(event))
21
26
  buf = io.StringIO()
@@ -608,6 +613,20 @@ exit 0
608
613
  self.assertEqual(log.read_text().split("\n")[:2],
609
614
  [f"--install-extension {vsix} --force", "--uninstall-extension kompactor.kompactor"])
610
615
 
616
+ def test_help_and_mistyped_commands(self):
617
+ from kompactor import cli
618
+ out = io.StringIO()
619
+ with redirect_stdout(out):
620
+ self.assertEqual(cli.main(["help"]), 0)
621
+ self.assertIn("Usage:\n kompactor <command> [options]", out.getvalue())
622
+ self.assertIn(" start Turn Kompactor on", out.getvalue())
623
+ self.assertLessEqual(max(len(line) for line in out.getvalue().splitlines()), 80) # fits a normal terminal
624
+ self.assertNotIn("statusline", out.getvalue()) # internal commands stay out of the help
625
+ err = io.StringIO()
626
+ with mock_stderr(err):
627
+ self.assertEqual(cli.main(["strt"]), 2)
628
+ self.assertIn("Did you mean this?\n kompactor start", err.getvalue())
629
+
611
630
  def test_source_defaults_to_the_public_repo(self):
612
631
  self.assertEqual(installer.source("")["marketplace"], "amarkum/kompactor")
613
632
  self.assertEqual(installer.source("acme/kompactor")["clone"], "https://github.com/acme/kompactor.git") # a fork
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
File without changes
File without changes