kompactor 0.8.2__tar.gz → 0.8.3__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.3}/PKG-INFO +10 -7
  2. {kompactor-0.8.2 → kompactor-0.8.3}/README.md +9 -6
  3. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/__init__.py +1 -1
  4. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/cli.py +77 -38
  5. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/usage.html +1 -1
  6. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/store.py +18 -2
  7. kompactor-0.8.2/kompactor/vsix/kompactor-0.8.2.vsix → kompactor-0.8.3/kompactor/vsix/kompactor-0.8.3.vsix +0 -0
  8. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/PKG-INFO +10 -7
  9. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/SOURCES.txt +1 -1
  10. {kompactor-0.8.2 → kompactor-0.8.3}/pyproject.toml +1 -1
  11. {kompactor-0.8.2 → kompactor-0.8.3}/tests/test_kompactor.py +19 -0
  12. {kompactor-0.8.2 → kompactor-0.8.3}/LICENSE +0 -0
  13. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/__main__.py +0 -0
  14. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/_launch.py +0 -0
  15. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/config.py +0 -0
  16. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/estimate.py +0 -0
  17. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/filters.py +0 -0
  18. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/graph.py +0 -0
  19. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/hooks.py +0 -0
  20. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/installer.py +0 -0
  21. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/langs.py +0 -0
  22. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/outline.py +0 -0
  23. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/prove.py +0 -0
  24. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/rules.py +0 -0
  25. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/samples.py +0 -0
  26. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/server.py +0 -0
  27. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/shellwrap.py +0 -0
  28. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/OFL.txt +0 -0
  29. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/plex-mono-400.woff2 +0 -0
  30. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/plex-mono-500.woff2 +0 -0
  31. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/plex-sans-400.woff2 +0 -0
  32. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/plex-sans-500.woff2 +0 -0
  33. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/fonts/plex-sans-600.woff2 +0 -0
  34. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/static/logo-mark.svg +0 -0
  35. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/tokens.py +0 -0
  36. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor/ui.html +0 -0
  37. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/dependency_links.txt +0 -0
  38. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/entry_points.txt +0 -0
  39. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/requires.txt +0 -0
  40. {kompactor-0.8.2 → kompactor-0.8.3}/kompactor.egg-info/top_level.txt +0 -0
  41. {kompactor-0.8.2 → kompactor-0.8.3}/setup.cfg +0 -0
  42. {kompactor-0.8.2 → kompactor-0.8.3}/tests/test_graph.py +0 -0
  43. {kompactor-0.8.2 → kompactor-0.8.3}/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.3
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.3.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.3 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.3.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.3 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.3"
@@ -190,47 +190,36 @@ 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 ({_pct(raw - kept, raw)}) in {n} tool calls" if n else "nothing yet"
213
205
  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""")
206
+ print(f"""Kompactor {__version__} is {state}
207
+
208
+ Claude Code {claude}
209
+ Level {config.PRESETS[cfg['preset']]['name']} ({cfg['preset']} of 5)
210
+ Saved {saved}
211
+ Dashboard {d['url'] if d else "not running"}
212
+
213
+ Commands:
214
+ start Turn Kompactor on and open the dashboard
215
+ stop Pause Kompactor (settings are kept)
216
+ uninstall Remove Kompactor and delete its data
217
+ gain Show what it saved, command by command
218
+ help List all commands
219
+
220
+ Kompactor shortens test runs, installs, logs and big file reads
221
+ before Claude reads them, keeping every error, failure and summary.
222
+ Evidence: {EVIDENCE_URL}""")
234
223
  return 0
235
224
 
236
225
 
@@ -486,16 +475,59 @@ def cmd_doctor(a):
486
475
  return 0
487
476
 
488
477
 
478
+ HELP = """Kompactor {version}: cut the tokens Claude Code spends on noise
479
+
480
+ Usage:
481
+ kompactor <command> [options]
482
+
483
+ Getting started:
484
+ start Turn Kompactor on and open the dashboard
485
+ stop Pause Kompactor (settings are kept)
486
+ uninstall Remove Kompactor and delete its data
487
+ status Show whether it's on and what it saved
488
+
489
+ Savings:
490
+ gain Show what it saved, command by command
491
+ estimate Estimate savings on your past sessions
492
+ ui Open the dashboard in this terminal
493
+
494
+ Settings:
495
+ presets List the quality-vs-tokens levels
496
+ config Show or change settings
497
+
498
+ Code:
499
+ graph Find code, callers and the impact of a change
500
+ outline List a file's symbols with line ranges
501
+ symbol Print one definition
502
+ show Print an output Kompactor shortened
503
+ search Search outputs Kompactor shortened
504
+
505
+ Other:
506
+ run Run a command and print its compacted output
507
+ doctor Check the installation
508
+ prove A/B test Kompactor in Claude Code sessions
509
+
510
+ Options:
511
+ -h, --help Show this help
512
+ --version Show the version
513
+
514
+ Run 'kompactor <command> --help' for details on a command.
515
+ Docs: https://github.com/amarkum/kompactor"""
516
+
517
+
489
518
  def main(argv=None):
490
519
  argv = sys.argv[1:] if argv is None else argv
491
520
  if argv[:1] == ["setup"]: # the old name for `start`; older docs still say it
492
521
  argv = ["start"] + ["--no-browser" if x == "--no-ui" else x for x in argv[1:]]
522
+ if argv[:1] in (["help"], ["-h"], ["--help"]):
523
+ print(HELP.format(version=__version__))
524
+ return 0
493
525
  if argv[:1] == ["prove"]: # has its own parser
494
526
  from . import prove
495
527
  return prove.main(argv[1:])
496
528
  ap = argparse.ArgumentParser(prog="kompactor", description="Cut the tokens Claude Code spends on noise.")
497
529
  ap.add_argument("--version", action="version", version=__version__)
498
- sp = ap.add_subparsers(dest="cmd")
530
+ sp = ap.add_subparsers(dest="cmd", metavar="<command>")
499
531
 
500
532
  p = sp.add_parser("status", help="is it on, your level, savings so far, and how to use it (also: plain `kompactor`)")
501
533
  p.set_defaults(fn=cmd_status)
@@ -543,7 +575,7 @@ def main(argv=None):
543
575
  help="don't set CLAUDE_CODE_SHELL_PREFIX (then commands that fail are not compacted)")
544
576
  p.set_defaults(fn=cmd_install)
545
577
 
546
- p = sp.add_parser("statusline", help="(internal) Claude Code status line")
578
+ p = sp.add_parser("statusline") # internal: Claude Code's status line
547
579
  p.set_defaults(fn=cmd_statusline)
548
580
 
549
581
  p = sp.add_parser("map", help="ranked repo skeleton within a token budget")
@@ -606,13 +638,20 @@ def main(argv=None):
606
638
  p.add_argument("--json", action="store_true")
607
639
  p.set_defaults(fn=cmd_presets)
608
640
 
609
- p = sp.add_parser("hook", help="(internal) Claude Code hook entrypoint")
641
+ p = sp.add_parser("hook") # internal: Claude Code hook entry point
610
642
  p.add_argument("name", choices=list(hooks.HANDLERS))
611
643
  p.set_defaults(fn=cmd_hook)
612
644
 
613
645
  p = sp.add_parser("doctor", help="check installation")
614
646
  p.set_defaults(fn=cmd_doctor)
615
647
 
648
+ if argv and not argv[0].startswith("-") and argv[0] not in sp.choices:
649
+ import difflib
650
+ near = difflib.get_close_matches(argv[0], [c for c in sp.choices if c not in ("hook", "statusline")], n=1)
651
+ print(f"kompactor: unknown command '{argv[0]}'" + (f"\n\nDid you mean this?\n kompactor {near[0]}" if near else ""),
652
+ file=sys.stderr)
653
+ print("\nRun 'kompactor help' for a list of commands.", file=sys.stderr)
654
+ return 2
616
655
  a = ap.parse_args(argv)
617
656
  if not a.cmd:
618
657
  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.3.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.3
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.3.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.3 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.3.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.3"
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