context-doctor 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -28
- package/dist/autoclear.d.ts +128 -0
- package/dist/autoclear.js +295 -0
- package/dist/autopilot.d.ts +55 -0
- package/dist/autopilot.js +325 -0
- package/dist/cli.js +43 -2
- package/dist/doctor.js +22 -0
- package/dist/hook.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/install.d.ts +4 -0
- package/dist/install.js +3 -3
- package/dist/mcp.js +1 -1
- package/dist/proxy.d.ts +28 -0
- package/dist/proxy.js +57 -2
- package/package.json +18 -2
package/README.md
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
# context-doctor 🩺
|
|
2
2
|
|
|
3
|
-
[](https://github.com/KushalP1/context-doctor/actions) [](https://www.npmjs.com/package/context-doctor)
|
|
3
|
+
[](https://github.com/KushalP1/context-doctor/actions) [](https://www.npmjs.com/package/context-doctor) [](https://www.npmjs.com/package/context-doctor) [](./LICENSE) 
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**Keep every AI session's context lean, automatically, without ever making it more expensive.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Long agent sessions fill up with tool output nobody reads again: file dumps, shell logs, search results, screenshots. You pay for all of it on every request, the model gets slower, and it drifts as the window fills. `context-doctor` measures that, and with **autopilot** it removes it from every Claude Code (and GPT API) request on your machine, only at moments when doing so costs nothing extra.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **9.8% less input cost, no session worse.** Replaying 130 days of the author's real Claude Code use (43 sessions) through the shipped code: **3.8 billion input tokens not sent, $4,694 saved at API list price, about $1,080 a month**, and not one session more expensive. Up to 37.7% on a long session. [What it saves →](#what-it-saves)
|
|
10
|
+
- **Counts Claude correctly.** Current Claude models pack 2.75 characters per token, not the 4 most tools assume; estimates built on 4 undercount Claude by about 40%. The ratios here were measured from the API's own counts, and `context-doctor accuracy` re-checks them on yours. [How →](#why-token-counts-are--and-where-they-are-exact)
|
|
11
|
+
- **Works where you work:** Claude Code, Cursor, Codex, Claude Desktop, any Anthropic or OpenAI API app, VS Code, CI. macOS, Linux and Windows, Node 20+.
|
|
12
|
+
- **Local and keyless.** No account, no telemetry, no API key. Your own login passes through untouched. MIT.
|
|
10
13
|
|
|
11
14
|
Built and maintained by [gAI Ventures](https://gai.ventures).
|
|
12
15
|
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g context-doctor
|
|
20
|
+
context-doctor install # hooks, MCP server and skill in every AI app it finds
|
|
21
|
+
context-doctor autopilot on # every new Claude Code session keeps its context lean
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Then start a new Claude Code session and work as usual. `context-doctor autopilot status` shows what it did; `context-doctor doctor` checks the whole setup. Everything is reversible: `context-doctor autopilot off`, `context-doctor uninstall`.
|
|
25
|
+
|
|
26
|
+
Just want a look first? `npx context-doctor session` profiles your latest Claude Code or Codex session in place, no install.
|
|
27
|
+
|
|
13
28
|
```
|
|
14
29
|
Where the tokens go
|
|
15
30
|
────────────────────────────────────────────────────────
|
|
@@ -26,35 +41,67 @@ Findings (4)
|
|
|
26
41
|
→ Truncate or summarize large tool outputs before they enter history.
|
|
27
42
|
```
|
|
28
43
|
|
|
29
|
-
##
|
|
44
|
+
## What it saves
|
|
30
45
|
|
|
31
|
-
|
|
46
|
+
Measured, not modelled: every Claude Code session on the author's machine from 18 May to 25 September 2026 (43 sessions, 130 days, mostly Opus 5 and Fable 5 with the 1M window) was replayed request by request through the shipped autopilot code, with the real timestamps, and priced the way the prompt cache bills it (cached reads 0.1x, writes 1.25x). Run it on your own history with `node scripts/replay-autopilot.mjs`.
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
| | Without autopilot | With autopilot | Saved |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| Input tokens sent | 41.4 billion | 37.6 billion | **3.8 billion (9.2%)** |
|
|
51
|
+
| Input cost at API list price | $48,962 | $44,268 | **$4,694 (9.8%)** |
|
|
52
|
+
| Per 30 days | | | **~875 million tokens, ~$1,080** |
|
|
53
|
+
| Sessions made more expensive | | | **0 of 43** |
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
How it spreads: the median session saves 1.9%, the best 37.7%. Short sessions barely change, because they rarely pile up 20k tokens of stale tool output before they end. Long sessions are where the money is: on this machine 94% of input cost came from requests above 200k tokens, and those are the requests autopilot makes smaller. Savings scale with how long your sessions run and how much they read, so a lighter user saves proportionally less, and never pays more.
|
|
38
56
|
|
|
39
|
-
|
|
57
|
+
On a Claude subscription you do not pay list price; the same tokens come out of your usage limit instead. Anthropic does not publish how limits weight cached tokens, so read the dollar column as the size of the effect, not as your bill. The token column holds either way, and every request that is 9% smaller is also faster to first token and further from auto-compaction.
|
|
40
58
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
What is not counted here: the proxy's full optimizer for your own API apps, the hook's guidance to the model, and fixes you make from `session` findings. Those save more on top, but they depend on what the model or you do with the advice, so they are not in this table.
|
|
60
|
+
|
|
61
|
+
## What happens on each platform
|
|
62
|
+
|
|
63
|
+
| Where you work | Automatic, every request | What you get on top |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| **Claude Code** (terminal, VS Code, JetBrains, desktop app's Code tab) | **Autopilot** clears stale tool output (cold cache only, never more expensive). **Hook** on every prompt warns the model with the real context size and its largest waste | Status bar context meter, `/context-doctor` skill, `session`, `watch`, `report`, dashboard |
|
|
66
|
+
| **Cursor** (agent) | Cursor runs Claude Code's hooks, so the same every-prompt check fires inside Cursor | MCP tools, editor status bar extension, `cursor` profiler. With your own OpenAI key, autopilot too via a tokened tunnel ([how](#putting-the-proxy-on-a-public-url-cursor-with-your-own-openai-key-remote-apps)) |
|
|
67
|
+
| **Codex** (ChatGPT app's Codex tab, IDE extension, CLI) | Every-prompt hook with the API's own token counts | MCP tools, skill, `session` reads Codex rollouts. On an API key, autopilot too (`OPENAI_BASE_URL`) |
|
|
68
|
+
| **Your own apps on the Anthropic or OpenAI API** | Autopilot on `/v1/messages`, `/v1/chat/completions` and `/v1/responses` (`ANTHROPIC_BASE_URL` / `OPENAI_BASE_URL`), or the full optimizing proxy | Exact usage and cache hit rates in `/stats`, prompt-cache placement advice |
|
|
69
|
+
| **Claude Desktop chat** | Standing context rules in every chat; one cheap `profile_context` call the model makes past ~30 turns or on any cost question | One-click `.mcpb` install, `context_checkup` prompt |
|
|
70
|
+
| **claude.ai, ChatGPT, the phone apps** | Your account's standing preferences (`context-doctor instructions --copy`) | Profile an exported chat with `analyze` |
|
|
71
|
+
| **CI** | `analyze --fail-over-budget` fails a build whose prompts outgrow a budget | `.contextdoctorrc` budgets and presets |
|
|
72
|
+
|
|
73
|
+
Not claimed, because no process on your machine sends those requests: trimming inside Claude Desktop chat, claude.ai, ChatGPT, Cursor's own subscription models, or Codex signed in with ChatGPT. Those get the rules and the measurements above, not autopilot.
|
|
74
|
+
|
|
75
|
+
## What's new
|
|
76
|
+
|
|
77
|
+
- **0.20 Autopilot**: stale tool output cleared from every Claude Code request, only when the prompt cache is cold, so it cannot cost more (measured: 9.8% less input cost, ~$1,080 a month on the author's usage, no session worse); runs as a login service on macOS, Linux and Windows; now also for GPT via OpenAI's Chat Completions and Responses APIs.
|
|
78
|
+
- **0.20.1 Releases that finish themselves**: one tag publishes to npm and creates a GitHub release with the Claude Desktop bundle (signed when a certificate is configured); the editor extension is ready for the VS Code Marketplace and Open VSX.
|
|
79
|
+
- **0.19 Measured Claude tokenizer**: estimates were 40% low for Claude; fixed from the API's own counts, with a per-model check in `accuracy`.
|
|
80
|
+
- **0.18** `proxy --token` for putting the proxy on a public URL safely. **0.17** Claude Desktop: a `profile_context` the model can afford to call from chat, `.mcpb` bundle, standing preferences for web and mobile. **0.16** Codex. **0.15** Cursor.
|
|
81
|
+
|
|
82
|
+
Full history with the measurements behind each change: [ROADMAP.md](./ROADMAP.md).
|
|
83
|
+
|
|
84
|
+
## Setup details
|
|
85
|
+
|
|
86
|
+
`install` configures every app it detects and does not stop at the first problem: a corrupt Claude Desktop config still gets you Claude Code and Cursor. It does not pretend either. Any target that failed is named with a ✗ line, the summary reads "Done with N problem(s)" instead of "Done.", and the **exit code is 1**, so dotfiles and onboarding scripts can react. A broken config file is never overwritten; fix it and re-run.
|
|
44
87
|
|
|
45
|
-
|
|
88
|
+
`npx context-doctor install` works too, but autopilot needs the global install: a background service cannot point into npx's cache, which npm deletes at will.
|
|
46
89
|
|
|
47
90
|
**No API keys, ever.** Everything is deterministic local code; when an LLM is needed (summarizing pruned history), the model already running in your app does it. The proxy forwards *your app's* credentials untouched — context-doctor itself holds nothing.
|
|
48
91
|
|
|
49
92
|
## What `install` actually does — and what happens in every session after
|
|
50
93
|
|
|
51
|
-
One run of `
|
|
94
|
+
One run of `context-doctor install` writes these (each config edit makes a `.backup` first; `uninstall` reverses all of it):
|
|
52
95
|
|
|
53
96
|
1. **Claude Desktop config** (`claude_desktop_config.json`) — registers the MCP server
|
|
54
97
|
2. **Claude Code config** (`~/.claude.json`) — registers the MCP server
|
|
55
98
|
3. **Cursor config** (`~/.cursor/mcp.json`) — registers the MCP server
|
|
56
99
|
4. **Agent Skill** → `~/.claude/skills/context-doctor/` — context-hygiene playbook for Claude Code
|
|
57
|
-
5. **Every-prompt hook** → `~/.claude/settings.json` — the per-query context check for Claude Code
|
|
100
|
+
5. **Every-prompt hook** → `~/.claude/settings.json` — the per-query context check for Claude Code (Cursor runs it too)
|
|
101
|
+
6. **Codex**, when present: MCP server in `~/.codex/config.toml`, the hook in `~/.codex/hooks.json`, the skill in `~/.codex/skills/`
|
|
102
|
+
7. With `--statusline`: live context size, cache share and cost in Claude Code's status bar
|
|
103
|
+
|
|
104
|
+
`context-doctor autopilot on` is separate and opt-in: it adds the background proxy service and one line (`env.ANTHROPIC_BASE_URL`) to `~/.claude/settings.json`, after the proxy has answered a health check.
|
|
58
105
|
|
|
59
106
|
**In every chat afterward (Claude Desktop, Cursor):** when the conversation starts, the app launches the MCP server, which hands the model standing instructions that stay in force for the whole chat:
|
|
60
107
|
|
|
@@ -72,11 +119,12 @@ One run of `npx context-doctor install` writes five things (each config edit mak
|
|
|
72
119
|
|
|
73
120
|
## Do you need MCP? Only sometimes — all the ways to use context-doctor
|
|
74
121
|
|
|
75
|
-
MCP is just one of
|
|
122
|
+
MCP is just one of seven delivery mechanisms. It's only required when you want the AI **inside a chat app** to run the tools itself. Everything else works without it:
|
|
76
123
|
|
|
77
124
|
| How you use it | MCP needed? | What it requires |
|
|
78
125
|
|---|---|---|
|
|
79
126
|
| **CLI** — `analyze`, `optimize`, `session` on files/transcripts | ❌ No | Nothing but `npx` — works in any terminal, scripts, CI |
|
|
127
|
+
| **Autopilot** — every Claude Code session, and GPT API apps | ❌ No | `context-doctor autopilot on` (a login service + one line in `~/.claude/settings.json`) |
|
|
80
128
|
| **Proxy** — always-on optimization of your API apps | ❌ No | `context-doctor proxy` + one env var in your app |
|
|
81
129
|
| **Claude Code every-prompt hook** | ❌ No | Written by `install`; Claude Code invokes it directly |
|
|
82
130
|
| **Agent Skill** — hygiene behavior in Claude Code / claude.ai | ❌ No | A markdown file; `install` places it (or upload to claude.ai) |
|
|
@@ -90,6 +138,7 @@ Practical upshot: a developer who only wants cheaper, faster API calls never tou
|
|
|
90
138
|
| Command | What it does |
|
|
91
139
|
|---|---|
|
|
92
140
|
| `context-doctor install` / `uninstall` | Wire (or remove) everything: MCP for Claude Desktop/Code/Cursor/Codex, the Agent Skill, the every-prompt hook |
|
|
141
|
+
| `context-doctor autopilot on\|off\|pause\|resume\|status` | Every new Claude Code session goes through the local proxy, which clears stale tool output only when the prompt cache is cold: measured 9.8% less input cost, no session worse |
|
|
93
142
|
| `context-doctor instructions [--copy]` | The ~180-token standing rules (~120 on GPT) for claude.ai / ChatGPT preferences, for web and phones where no server runs |
|
|
94
143
|
| `context-doctor analyze <file>` | Profile a conversation: token breakdown, findings, cost + latency estimates. `--fail-over-budget` exits 1 on a breach, for CI |
|
|
95
144
|
| `context-doctor optimize <file>` | Apply the safe fixes; add `--strategy trim-tool-calls` for big inline file writes, `--strategy prune-history` for consented lossy compaction |
|
|
@@ -112,14 +161,13 @@ Practical upshot: a developer who only wants cheaper, faster API calls never tou
|
|
|
112
161
|
|
|
113
162
|
| Where you run LLMs | Mechanism | Guarantee |
|
|
114
163
|
|---|---|---|
|
|
115
|
-
|
|
|
164
|
+
| Claude Code sessions, with autopilot on | The login-service proxy clears stale tool output from every request, only when the cache is cold | **Every request; never more expensive (measured)** |
|
|
165
|
+
| Your own apps/agents (API) | `context-doctor proxy` rewrites every request in flight, or `proxy --autopilot` for the cache-safe mode | **Every call, automatic** |
|
|
116
166
|
| Claude Code / Cowork sessions | `install` registers a **UserPromptSubmit hook**: every query measures the session; heavy sessions get injected hygiene guidance (silent when lean, rate-limited, never blocks a prompt) | **Every query checked** |
|
|
117
167
|
| Claude Desktop chat / Cursor | **MCP server instructions** — standing hygiene directives injected into every conversation where the server is enabled, plus prescriptive tool triggers | **Every conversation carries the rules** |
|
|
118
|
-
| claude.ai (web) / ChatGPT
|
|
119
|
-
|
|
120
|
-
Nothing runs in the background for the Claude apps — the hook, skill, MCP server, and its instructions are all delivered by the app itself at the right moment. The proxy is the only long-running piece, and only your API-calling apps need it.
|
|
168
|
+
| claude.ai (web) / ChatGPT / phone apps | `context-doctor instructions --copy`, pasted once into the account's preferences (or upload `skills/context-doctor/SKILL.md` as a skill) | Every chat on that account carries the rules |
|
|
121
169
|
|
|
122
|
-
|
|
170
|
+
Without autopilot nothing runs in the background: the hook, skill, MCP server and its instructions are delivered by the apps themselves at the right moment. With autopilot, one small proxy runs as a login service (launchd / systemd user service / logon task) and is restarted by the service or by the next prompt's hook if it ever stops.
|
|
123
171
|
|
|
124
172
|
Or use the CLI directly, no install needed:
|
|
125
173
|
|
|
@@ -150,6 +198,35 @@ npx context-doctor session --list # browse sessions
|
|
|
150
198
|
|
|
151
199
|
Parses the transcripts Claude Code writes locally and answers "where did my tokens go today?" — it will happily tell you that one giant skill load is 67% of your context.
|
|
152
200
|
|
|
201
|
+
## Autopilot: every Claude Code session keeps its own context lean
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
context-doctor autopilot on # once; survives reboots
|
|
205
|
+
context-doctor autopilot status # what it has done
|
|
206
|
+
context-doctor autopilot pause # instant passthrough, nothing restarts
|
|
207
|
+
context-doctor autopilot off # remove it
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`autopilot on` runs the local proxy as a background service (launchd on macOS, a systemd user service on Linux, a logon task on Windows), waits until it answers, and only then points Claude Code at it through `env.ANTHROPIC_BASE_URL` in `~/.claude/settings.json`. Every Claude Code session started afterwards, in the terminal, an IDE, or the desktop app's Code tab, sends its requests through it. Your login (subscription or API key) passes through untouched.
|
|
211
|
+
|
|
212
|
+
**What it does to each request:** once old tool output adds up to 20k+ tokens (file reads, shell output, search and web results, screenshots inside them), it replaces that output with a one-line note, keeping the 3 most recent results. The tool call stays in the history, so the model can simply run it again if it needs the output. Your messages, its answers, answers you gave to its questions, subagent reports and MCP results are never touched.
|
|
213
|
+
|
|
214
|
+
**Why it cannot make a session more expensive.** A prompt cache matches a byte-identical prefix, and changing old history re-bills everything after the change at the write rate (1.25x instead of 0.1x). So autopilot changes history only when the cache is cold anyway: after an idle gap longer than the cache lifetime the request itself declares (1 hour for Claude Code on a subscription, 5 minutes otherwise), when the whole prompt is re-written regardless. Once cleared, an output stays cleared on every later request, so the prefix is identical between clearings and the cache keeps hitting.
|
|
215
|
+
|
|
216
|
+
**Measured before it shipped**, by replaying every Claude Code session on the author's machine (43 sessions, 130 days) request by request through the shipped code, priced as the cache bills it, with real timestamps: 3.8 billion input tokens not sent and $4,694 at list price, ~$1,080 a month ([details](#what-it-saves)). `scripts/replay-autopilot.mjs` does this on yours:
|
|
217
|
+
|
|
218
|
+
| Policy | Input cost saved | Worst session |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| **Autopilot: clear only when the cache is cold (default)** | **9.8%** (9.2% of raw input tokens; best session 37.7%) | **0.00%, no session worse** |
|
|
221
|
+
| Also clear on a warm cache when the saving "should" repay the rewrite | 9.9% | −0.13% (one session worse) |
|
|
222
|
+
| The proxy's general strategies (dedupe, trim, strip-base64) | 6.7% | −13% (one session worse) |
|
|
223
|
+
|
|
224
|
+
94% of input cost on that machine came from requests above 200k tokens, which is where the clearing lands. Smaller requests also mean later auto-compaction and a faster first token.
|
|
225
|
+
|
|
226
|
+
**Never in the way:** anything it cannot parse is forwarded unchanged; only Anthropic `/v1/messages` requests are touched. It adds about 7 ms to a 2.9 MB (~1M token) request. If the proxy dies, the service restarts it within seconds, and the every-prompt hook checks it before each prompt and starts it if needed (measured: 0.6 s once, when it had to). `pause` turns it into a passthrough without restarting anything; `off` removes the setting before stopping the service, and sessions started while it was on need a restart.
|
|
227
|
+
|
|
228
|
+
**What it cannot reach** (no process on your machine sends those requests): Claude Desktop's chat tab and claude.ai, which use the standing instructions and the `profile_context` sketch instead; Cursor's own models (Cursor's servers call the model; with your own OpenAI key, see the tunnel section below); and Codex signed in with ChatGPT, where the every-prompt hook still reports context size.
|
|
229
|
+
|
|
153
230
|
## Always-on: optimize every request automatically
|
|
154
231
|
|
|
155
232
|
Run the proxy and every Anthropic/OpenAI API call your apps make gets optimized in flight — no code changes:
|
|
@@ -504,14 +581,27 @@ Contributions welcome — this project is small on purpose. Open an issue before
|
|
|
504
581
|
|
|
505
582
|
## Releasing (maintainers)
|
|
506
583
|
|
|
584
|
+
**One-time setup.** Each row switches on one channel; any that is missing is skipped with a notice, never a failed run. Secrets go in the repo's Settings > Secrets and variables > Actions:
|
|
585
|
+
|
|
586
|
+
| Secret | Turns on | Where to get it |
|
|
587
|
+
|---|---|---|
|
|
588
|
+
| *(no secret: npm trusted publishing)* | `npm publish` on every `v*` tag, with provenance | npmjs.com > package `context-doctor` > Settings > Trusted Publisher > GitHub Actions: owner `KushalP1`, repository `context-doctor`, workflow `publish.yml`. npm is phasing out publish tokens that bypass 2FA; an `NPM_TOKEN` secret still works as a fallback |
|
|
589
|
+
| `MCPB_CERT`, `MCPB_KEY` (+ `MCPB_INTERMEDIATE`) | A signed Claude Desktop bundle, no install warning | A code-signing certificate from a trusted CA; paste the PEM text. `mcpb verify` must pass in CI or the release stops |
|
|
590
|
+
| `VSCE_PAT` | VS Code Marketplace on `vscode-v*` tags | Azure DevOps PAT, scope Marketplace > Manage, for the `gai-ventures` publisher |
|
|
591
|
+
| `OVSX_PAT` | Open VSX (where Cursor installs from) | open-vsx.org > Settings > Access Tokens |
|
|
592
|
+
|
|
593
|
+
**Each release:**
|
|
594
|
+
|
|
507
595
|
```bash
|
|
508
|
-
npm version
|
|
509
|
-
npm test #
|
|
510
|
-
npm publish
|
|
511
|
-
git push --follow-tags
|
|
512
|
-
npm run build:mcpb # context-doctor-<version>.mcpb for Claude Desktop; attach it to the GitHub release
|
|
596
|
+
npm version minor # or patch/major: bumps package.json and tags vX.Y.Z
|
|
597
|
+
npm test # the full suite; CI runs it on 3 OSes x Node 20/22/24
|
|
598
|
+
git push --follow-tags # npm publish + GitHub release with the .mcpb attached
|
|
513
599
|
```
|
|
514
600
|
|
|
601
|
+
For the editor extension: bump `vscode/package.json`, add a `vscode/CHANGELOG.md` entry, then `git tag vscode-vX.Y.Z && git push --tags`. The `.vsix` is attached to a GitHub release either way.
|
|
602
|
+
|
|
603
|
+
Locally, `npm run build:mcpb` builds the bundle (`MCPB_SELF_SIGNED=1` exercises the signing path with a throwaway certificate; Desktop still warns for those).
|
|
604
|
+
|
|
515
605
|
**What the npm download number measures.** `install` writes `npx -y context-doctor-mcp` into MCP configs, and npx re-fetches the tarball whenever a new version exists. So every release is downloaded once by every active install within about a day, and the daily count is almost entirely those refreshes: on this package, release days run ~170 downloads and non-release days ~27. Read it as "size of the active installed base × number of releases", not as new users — a quiet week with no releases will look like a decline while nothing has changed. Two corollaries: the release-day figure is a live count of machines running context-doctor, and a broken release reaches all of them automatically, which is why `prepublishOnly` runs the full test suite. npm's stats also lag by several days and occasionally record a day as zero; a zero on a release day is a gap in their pipeline, not in usage.
|
|
516
606
|
|
|
517
607
|
Known gotcha: if `npm publish` fails with **`404 Not Found - PUT …/context-doctor`** on a package that clearly exists, the real cause is an **expired npm login token** — npm reports unauthenticated publishes as a 404, not a 401. Check with `npm whoami`; if that errors, run `npm login` and publish again.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autopilot: clear stale tool output from agent requests in flight, without
|
|
3
|
+
* ever costing more than it saves.
|
|
4
|
+
*
|
|
5
|
+
* Why this and not the proxy's general strategies: replayed over 33 real
|
|
6
|
+
* Claude Code sessions with prompt-cache pricing, the general trim saved 6.7%
|
|
7
|
+
* overall but made one session 13% MORE expensive, because every change to
|
|
8
|
+
* history the cache already holds re-bills everything after it at the write
|
|
9
|
+
* rate. Most of the bill sits in long sessions (94% of input cost came from
|
|
10
|
+
* requests above 200k tokens), so the win is real, but only if each change
|
|
11
|
+
* pays for its cache rewrite.
|
|
12
|
+
*
|
|
13
|
+
* The rules, modelled on the microcompact logic Claude Code ships (and keeps
|
|
14
|
+
* switched off by a server flag), tightened for "never worse":
|
|
15
|
+
*
|
|
16
|
+
* 1. Only output of read-only, re-runnable tools is eligible (file reads,
|
|
17
|
+
* shell, search, web fetch). Answers the user gave, subagent reports and
|
|
18
|
+
* MCP results are never touched.
|
|
19
|
+
* 2. The most recent `keepRecent` tool results always stay.
|
|
20
|
+
* 3. Clearing happens in batches of at least `minClearTokens`, so each cache
|
|
21
|
+
* rewrite buys a lot.
|
|
22
|
+
* 4. A cleared result stays cleared on every later request (ids are
|
|
23
|
+
* remembered, across restarts), so the prefix is byte-stable between
|
|
24
|
+
* batches and the cache keeps hitting.
|
|
25
|
+
* 5. By default a batch is taken ONLY when the cache is cold anyway (idle
|
|
26
|
+
* longer than the request's own cache TTL), because the whole prompt is
|
|
27
|
+
* re-written on that request regardless, so clearing costs nothing and
|
|
28
|
+
* every later request is smaller. That makes it never-worse by
|
|
29
|
+
* construction, and measured: replaying every Claude Code session on the
|
|
30
|
+
* author's machine through this class, with real timestamps and cache
|
|
31
|
+
* pricing, it saved 9.8% of cache-weighted input cost (9.2% of raw input
|
|
32
|
+
* tokens, up to 37.7% in one long session) and made no session worse.
|
|
33
|
+
* Clearing on a warm cache when the saving "should" repay the rewrite
|
|
34
|
+
* (`paybackSafety` > 0) added 0.1% and made one session 0.13% worse: the
|
|
35
|
+
* future is not knowable, so it is off unless asked for.
|
|
36
|
+
*
|
|
37
|
+
* The model sees a one-line note in place of the output and can simply re-run
|
|
38
|
+
* the tool; the file, command or URL is still in the tool call.
|
|
39
|
+
*/
|
|
40
|
+
/** Tools whose output can be regenerated by calling them again (read-only or re-runnable). */
|
|
41
|
+
export declare const CLEARABLE_TOOLS: Set<string>;
|
|
42
|
+
export interface AutoClearOptions {
|
|
43
|
+
/** Most recent tool results that always stay. Default 3. */
|
|
44
|
+
keepRecent?: number;
|
|
45
|
+
/** Smallest batch worth a cache rewrite. Default 20,000 tokens. */
|
|
46
|
+
minClearTokens?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Warm-cache rule: clear only if the saving over the requests still to come
|
|
49
|
+
* repays the rewrite this many times over. Requests still to come are
|
|
50
|
+
* estimated as the number already made in this conversation. Default 0:
|
|
51
|
+
* warm clearing off, cold cache only (the never-worse setting).
|
|
52
|
+
*/
|
|
53
|
+
paybackSafety?: number;
|
|
54
|
+
/** Where cleared ids persist so a restart does not un-clear (and re-bill) them. */
|
|
55
|
+
statePath?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface AutoClearResult {
|
|
58
|
+
changed: boolean;
|
|
59
|
+
/** Results cleared by this request's new batch (0 when none was taken). */
|
|
60
|
+
newlyCleared: number;
|
|
61
|
+
/** Tokens removed from this request, old batches included. */
|
|
62
|
+
tokensRemoved: number;
|
|
63
|
+
cold: boolean;
|
|
64
|
+
reason: string;
|
|
65
|
+
/** Index of the first message rewritten on this request (the cache breaks from here), or -1. */
|
|
66
|
+
firstChanged: number;
|
|
67
|
+
}
|
|
68
|
+
interface Found {
|
|
69
|
+
/** Index of the message / input item that holds the result (cache breaks from here). */
|
|
70
|
+
unit: number;
|
|
71
|
+
id: string;
|
|
72
|
+
tokens: number;
|
|
73
|
+
content: unknown;
|
|
74
|
+
set: (note: string) => void;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One request, whatever its API: the units that make up history, tool names
|
|
78
|
+
* by call id, the tool results in order, and the cache lifetime to assume.
|
|
79
|
+
* Anthropic Messages (Claude Code, Anthropic SDKs), OpenAI Chat Completions
|
|
80
|
+
* (role "tool" messages) and OpenAI Responses (function_call_output items,
|
|
81
|
+
* as Codex with an API key sends).
|
|
82
|
+
*/
|
|
83
|
+
interface View {
|
|
84
|
+
format: "anthropic" | "openai-chat" | "openai-responses";
|
|
85
|
+
units: Array<Record<string, unknown>>;
|
|
86
|
+
toolName: Map<string, string>;
|
|
87
|
+
results: Array<Omit<Found, "tokens">>;
|
|
88
|
+
firstUser: unknown;
|
|
89
|
+
firstToolId: string;
|
|
90
|
+
ttlMs: number;
|
|
91
|
+
}
|
|
92
|
+
export declare function clearedNote(tokens: number): string;
|
|
93
|
+
/**
|
|
94
|
+
* How long the provider may keep this prompt cached, taking the LONGER
|
|
95
|
+
* possibility when unsure: calling a warm cache cold would pay a rewrite,
|
|
96
|
+
* calling a cold one warm only delays a free clearing.
|
|
97
|
+
* - Anthropic: the request's own cache_control, "1h" or the 5-minute default.
|
|
98
|
+
* - OpenAI: caches live up to an hour (in-memory retention), or 24 hours when
|
|
99
|
+
* the request sets prompt_cache_retention "24h".
|
|
100
|
+
*/
|
|
101
|
+
export declare function requestTtlMs(body: Record<string, unknown>): number;
|
|
102
|
+
export declare function viewOf(body: Record<string, unknown>): View | undefined;
|
|
103
|
+
export declare class AutoClearer {
|
|
104
|
+
private cleared;
|
|
105
|
+
/** Tool results never change once sent, so their size is computed once per id. */
|
|
106
|
+
private sizes;
|
|
107
|
+
private convs;
|
|
108
|
+
private opts;
|
|
109
|
+
private dirty;
|
|
110
|
+
constructor(options?: AutoClearOptions);
|
|
111
|
+
/**
|
|
112
|
+
* Rewrite `body` in place: an Anthropic Messages, OpenAI Chat Completions or
|
|
113
|
+
* OpenAI Responses request. Never throws; anything unrecognised is left alone.
|
|
114
|
+
*/
|
|
115
|
+
apply(body: Record<string, unknown>, now?: number): AutoClearResult;
|
|
116
|
+
/**
|
|
117
|
+
* Warm cache: clearing rewrites everything after the first cleared result
|
|
118
|
+
* at the write rate (1.25x instead of 0.1x: 1.15x extra, once), and saves
|
|
119
|
+
* the cleared tokens at the read rate (0.1x) on every later request.
|
|
120
|
+
* Later requests are estimated as the number made so far (a conversation's
|
|
121
|
+
* age is the best predictor of how long it keeps going), and the saving must
|
|
122
|
+
* cover the rewrite `paybackSafety` times over.
|
|
123
|
+
*/
|
|
124
|
+
private shouldClearWarm;
|
|
125
|
+
private load;
|
|
126
|
+
private save;
|
|
127
|
+
}
|
|
128
|
+
export {};
|