@curatedmcp/tokenshield 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +238 -0
  3. package/dist/cli.js.map +1 -0
  4. package/dist/commands/bench.d.ts +5 -0
  5. package/dist/commands/bench.js +191 -0
  6. package/dist/commands/bench.js.map +1 -0
  7. package/dist/commands/demo.d.ts +3 -0
  8. package/dist/commands/demo.js +99 -0
  9. package/dist/commands/demo.js.map +1 -0
  10. package/dist/commands/doctor.d.ts +1 -0
  11. package/dist/commands/doctor.js +119 -0
  12. package/dist/commands/doctor.js.map +1 -0
  13. package/dist/commands/estimate.d.ts +3 -0
  14. package/dist/commands/estimate.js +90 -0
  15. package/dist/commands/estimate.js.map +1 -0
  16. package/dist/commands/integrations.d.ts +14 -0
  17. package/dist/commands/integrations.js +138 -0
  18. package/dist/commands/integrations.js.map +1 -0
  19. package/dist/commands/logs.d.ts +6 -0
  20. package/dist/commands/logs.js +66 -0
  21. package/dist/commands/logs.js.map +1 -0
  22. package/dist/commands/setup.d.ts +9 -0
  23. package/dist/commands/setup.js +159 -0
  24. package/dist/commands/setup.js.map +1 -0
  25. package/dist/commands/status.d.ts +1 -0
  26. package/dist/commands/status.js +102 -0
  27. package/dist/commands/status.js.map +1 -0
  28. package/dist/commands/stop.d.ts +1 -0
  29. package/dist/commands/stop.js +27 -0
  30. package/dist/commands/stop.js.map +1 -0
  31. package/dist/commands/up.d.ts +15 -0
  32. package/dist/commands/up.js +145 -0
  33. package/dist/commands/up.js.map +1 -0
  34. package/dist/dashboard.d.ts +4 -0
  35. package/dist/dashboard.js +186 -0
  36. package/dist/dashboard.js.map +1 -0
  37. package/dist/lib/daemon.d.ts +23 -0
  38. package/dist/lib/daemon.js +164 -0
  39. package/dist/lib/daemon.js.map +1 -0
  40. package/dist/lib/errors.d.ts +23 -0
  41. package/dist/lib/errors.js +131 -0
  42. package/dist/lib/errors.js.map +1 -0
  43. package/dist/lib/integrations.d.ts +47 -0
  44. package/dist/lib/integrations.js +210 -0
  45. package/dist/lib/integrations.js.map +1 -0
  46. package/dist/lib/paths.d.ts +5 -0
  47. package/dist/lib/paths.js +18 -0
  48. package/dist/lib/paths.js.map +1 -0
  49. package/dist/lib/preflight.d.ts +20 -0
  50. package/dist/lib/preflight.js +97 -0
  51. package/dist/lib/preflight.js.map +1 -0
  52. package/dist/lib/ui.d.ts +68 -0
  53. package/dist/lib/ui.js +221 -0
  54. package/dist/lib/ui.js.map +1 -0
  55. package/package.json +44 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ import { Command, Option } from "commander";
3
+ import { runUp, runSupervised } from "./commands/up.js";
4
+ import { runDoctor } from "./commands/doctor.js";
5
+ import { runDemo } from "./commands/demo.js";
6
+ import { runBench } from "./commands/bench.js";
7
+ import { runEstimate } from "./commands/estimate.js";
8
+ import { runStatus } from "./commands/status.js";
9
+ import { runStop } from "./commands/stop.js";
10
+ import { runLogs } from "./commands/logs.js";
11
+ import { runSetup } from "./commands/setup.js";
12
+ import { runIntegrationsList, runIntegrationsEnable, runIntegrationsShow, runIntegrationsDisable, } from "./commands/integrations.js";
13
+ import { setOutputMode, c, dim, emit, isJson } from "./lib/ui.js";
14
+ import { ensureNumber, runCommand, installProcessHandlers } from "./lib/errors.js";
15
+ installProcessHandlers();
16
+ const VERSION = "0.2.0";
17
+ const program = new Command();
18
+ program
19
+ .name("tokenshield")
20
+ .description("Local API-layer proxy that cuts your Claude Code bill 40–70%.\n" +
21
+ "Your ANTHROPIC_API_KEY stays on your machine. No signup to start measuring.")
22
+ .version(VERSION, "-v, --version", "show version")
23
+ .helpOption("-h, --help", "show help")
24
+ .addOption(new Option("--debug", "verbose output incl. stack traces").default(false))
25
+ .addOption(new Option("--quiet, -q", "suppress non-essential output").default(false))
26
+ .addOption(new Option("--json", "machine-readable JSON output").default(false))
27
+ .hook("preAction", (cmd) => {
28
+ const opts = cmd.optsWithGlobals();
29
+ setOutputMode({
30
+ debug: opts.debug === true,
31
+ quiet: opts.quiet === true,
32
+ json: opts.json === true,
33
+ });
34
+ })
35
+ .addHelpText("after", `
36
+ ${c.bold("Quickstart")}
37
+ ${c.cyan("$ tokenshield setup")} ${dim("# 60-second guided install")}
38
+ ${c.cyan("$ tokenshield up")} ${dim("# start in foreground (Ctrl-C to stop)")}
39
+ ${c.cyan("$ tokenshield up --daemon")} ${dim("# start in background")}
40
+ ${c.cyan("$ tokenshield status")} ${dim("# is it running? what did it cost today?")}
41
+ ${c.cyan("$ tokenshield logs --limit 20")} ${dim("# recent requests")}
42
+ ${c.cyan("$ tokenshield stop")} ${dim("# stop the daemon")}
43
+
44
+ ${c.bold("First-time setup")}
45
+ ${c.cyan("$ tokenshield doctor")} ${dim("# verify Node, key, network")}
46
+ ${c.cyan("$ tokenshield integrations list")} ${dim("# see what we can configure")}
47
+ ${c.cyan("$ tokenshield demo")} ${dim("# offline savings replay")}
48
+
49
+ ${c.bold("Privacy")}
50
+ TokenShield runs entirely on your machine. Your API key is never read by us,
51
+ and prompt content is never sent anywhere. Localhost binding by default.
52
+
53
+ ${c.bold("Docs")}
54
+ ${c.cyan("https://curatedmcp.com/tokenshield")}
55
+ `);
56
+ // ── up ────────────────────────────────────────────────────────────────────────
57
+ program
58
+ .command("up")
59
+ .description("Start the proxy and the local dashboard")
60
+ .option("--port <port>", "proxy port", "7777")
61
+ .option("--dashboard-port <port>", "dashboard port", "7778")
62
+ .option("--bind <host>", "bind address (default 127.0.0.1)", "127.0.0.1")
63
+ .option("--upstream <url>", "upstream Anthropic base URL", "https://api.anthropic.com")
64
+ .option("--ledger <path>", "SQLite ledger path")
65
+ .option("--retention-days <n>", "ledger retention in days", "7")
66
+ .option("--daemon, -d", "run in background", false)
67
+ .addHelpText("after", `\n${c.bold("Examples")}
68
+ ${c.cyan("$ tokenshield up")} ${dim("# foreground, default ports")}
69
+ ${c.cyan("$ tokenshield up --daemon")} ${dim("# background, stop with `tokenshield stop`")}
70
+ ${c.cyan("$ tokenshield up --port 7780")} ${dim("# different proxy port")}
71
+ ${c.cyan("$ tokenshield up --bind 0.0.0.0 --port 7777")} ${dim("# expose to LAN (trusted networks only)")}
72
+ `)
73
+ .action((raw) => runCommand(async () => {
74
+ await runUp({
75
+ port: ensureNumber("port", raw["port"]),
76
+ dashboardPort: ensureNumber("dashboard-port", raw["dashboardPort"]),
77
+ bind: String(raw["bind"]),
78
+ upstream: String(raw["upstream"]),
79
+ ledger: raw["ledger"] ? String(raw["ledger"]) : undefined,
80
+ retentionDays: ensureNumber("retention-days", raw["retentionDays"], 1, 365),
81
+ daemon: raw["daemon"] === true,
82
+ });
83
+ }));
84
+ // ── __supervise (hidden): daemon entrypoint ──────────────────────────────────
85
+ program
86
+ .command("__supervise", { hidden: true })
87
+ .option("--port <port>", "proxy port", "7777")
88
+ .option("--dashboard-port <port>", "dashboard port", "7778")
89
+ .option("--bind <host>", "bind address", "127.0.0.1")
90
+ .option("--upstream <url>", "upstream Anthropic base URL", "https://api.anthropic.com")
91
+ .option("--ledger <path>", "SQLite ledger path")
92
+ .option("--retention-days <n>", "ledger retention", "7")
93
+ .action((raw) => runCommand(async () => {
94
+ await runSupervised({
95
+ port: ensureNumber("port", raw["port"]),
96
+ dashboardPort: ensureNumber("dashboard-port", raw["dashboardPort"]),
97
+ bind: String(raw["bind"]),
98
+ upstream: String(raw["upstream"]),
99
+ ledger: raw["ledger"] ? String(raw["ledger"]) : undefined,
100
+ retentionDays: ensureNumber("retention-days", raw["retentionDays"], 1, 365),
101
+ daemon: false,
102
+ });
103
+ }));
104
+ // ── setup ─────────────────────────────────────────────────────────────────────
105
+ program
106
+ .command("setup")
107
+ .description("60-second guided install: detect tools, check network, start daemon")
108
+ .option("--port <port>", "proxy port", "7777")
109
+ .option("--dashboard-port <port>", "dashboard port", "7778")
110
+ .option("--bind <host>", "bind address", "127.0.0.1")
111
+ .option("--upstream <url>", "upstream Anthropic base URL", "https://api.anthropic.com")
112
+ .option("--retention-days <n>", "ledger retention", "7")
113
+ .option("--yes, -y", "accept all defaults non-interactively", false)
114
+ .action((raw) => runCommand(async () => {
115
+ await runSetup({
116
+ port: ensureNumber("port", raw["port"]),
117
+ dashboardPort: ensureNumber("dashboard-port", raw["dashboardPort"]),
118
+ bind: String(raw["bind"]),
119
+ upstream: String(raw["upstream"]),
120
+ retentionDays: ensureNumber("retention-days", raw["retentionDays"], 1, 365),
121
+ yes: raw["yes"] === true,
122
+ });
123
+ }));
124
+ // ── status ────────────────────────────────────────────────────────────────────
125
+ program
126
+ .command("status")
127
+ .description("Show daemon state + last-24h spend")
128
+ .action(() => runCommand(runStatus));
129
+ // ── stop ──────────────────────────────────────────────────────────────────────
130
+ program
131
+ .command("stop")
132
+ .description("Stop the background daemon if one is running")
133
+ .action(() => runCommand(runStop));
134
+ // ── doctor ────────────────────────────────────────────────────────────────────
135
+ program
136
+ .command("doctor")
137
+ .description("Run health checks on your TokenShield setup")
138
+ .action(() => runCommand(runDoctor));
139
+ // ── logs ──────────────────────────────────────────────────────────────────────
140
+ program
141
+ .command("logs")
142
+ .description("Show recent requests recorded in the local ledger")
143
+ .option("--limit <n>", "max rows to show", "20")
144
+ .option("--model <substring>", "filter by model name (substring match)")
145
+ .option("--errors-only", "only show non-2xx responses", false)
146
+ .action((raw) => runCommand(async () => {
147
+ await runLogs({
148
+ limit: ensureNumber("limit", raw["limit"], 1, 500),
149
+ ...(raw["model"] ? { modelFilter: String(raw["model"]) } : {}),
150
+ errorsOnly: raw["errorsOnly"] === true,
151
+ });
152
+ }));
153
+ // ── estimate ──────────────────────────────────────────────────────────────────
154
+ program
155
+ .command("estimate")
156
+ .description("Show measured spend + projected v1.0 savings from the ledger")
157
+ .option("--hours <n>", "lookback window in hours", "24")
158
+ .action((raw) => runCommand(async () => {
159
+ await runEstimate({ hours: ensureNumber("hours", raw["hours"], 1, 24 * 30) });
160
+ }));
161
+ // ── demo ──────────────────────────────────────────────────────────────────────
162
+ program
163
+ .command("demo")
164
+ .description("Replay a recorded session and show projected savings (no network)")
165
+ .option("--no-live", "skip the typewriter animation")
166
+ .action((raw) => runCommand(async () => {
167
+ await runDemo({ live: raw["live"] !== false });
168
+ }));
169
+ // ── bench ─────────────────────────────────────────────────────────────────────
170
+ program
171
+ .command("bench")
172
+ .description("Run TokenShield against recorded request fixtures and report savings")
173
+ .option("--fixture <name>", "single fixture (light|medium|heavy) or a path to a .json file")
174
+ .option("--fixtures-dir <dir>", "override the fixtures directory")
175
+ .addHelpText("after", `\n${c.bold("Examples")}\n ${c.cyan("$ tokenshield bench")} ${dim("# all built-in fixtures")}\n ${c.cyan("$ tokenshield bench --fixture heavy")}\n ${c.cyan("$ tokenshield --json bench | jq")}\n`)
176
+ .action((raw) => runCommand(async () => {
177
+ await runBench({
178
+ ...(raw["fixture"] ? { fixture: String(raw["fixture"]) } : {}),
179
+ ...(raw["fixturesDir"] ? { fixturesDir: String(raw["fixturesDir"]) } : {}),
180
+ });
181
+ }));
182
+ // ── integrations ──────────────────────────────────────────────────────────────
183
+ const integrations = program
184
+ .command("integrations")
185
+ .alias("int")
186
+ .description("Detect + configure Claude Code, Cursor, Windsurf, Zed, Aider")
187
+ .addHelpText("after", `\n${c.bold("Examples")}
188
+ ${c.cyan("$ tokenshield integrations list")}
189
+ ${c.cyan("$ tokenshield integrations enable claude-code")}
190
+ ${c.cyan("$ tokenshield integrations show")} ${dim("# copy-paste snippets for every tool")}
191
+ ${c.cyan("$ tokenshield integrations disable shell")} ${dim("# remove our managed block from shell rc")}
192
+ `);
193
+ integrations
194
+ .command("list")
195
+ .description("List detected AI tools and how each is configured")
196
+ .option("--port <port>", "proxy port (for the snippet URL)", "7777")
197
+ .option("--bind <host>", "bind address", "127.0.0.1")
198
+ .action((raw) => runCommand(() => {
199
+ const port = ensureNumber("port", raw["port"]);
200
+ runIntegrationsList({ baseUrl: `http://${String(raw["bind"])}:${port}` });
201
+ }));
202
+ integrations
203
+ .command("enable <tool>")
204
+ .description("Configure one tool to route through TokenShield")
205
+ .option("--port <port>", "proxy port", "7777")
206
+ .option("--bind <host>", "bind address", "127.0.0.1")
207
+ .action((tool, raw) => runCommand(() => {
208
+ const port = ensureNumber("port", raw["port"]);
209
+ runIntegrationsEnable({
210
+ id: tool,
211
+ baseUrl: `http://${String(raw["bind"])}:${port}`,
212
+ });
213
+ }));
214
+ integrations
215
+ .command("show")
216
+ .description("Print copy-paste snippets for every supported tool")
217
+ .option("--port <port>", "proxy port", "7777")
218
+ .option("--bind <host>", "bind address", "127.0.0.1")
219
+ .action((raw) => runCommand(() => {
220
+ const port = ensureNumber("port", raw["port"]);
221
+ runIntegrationsShow({ baseUrl: `http://${String(raw["bind"])}:${port}` });
222
+ }));
223
+ integrations
224
+ .command("disable <target>")
225
+ .description("Remove TokenShield config (currently: only 'shell')")
226
+ .action((target) => runCommand(() => runIntegrationsDisable(target)));
227
+ // ── go ────────────────────────────────────────────────────────────────────────
228
+ program.parseAsync(process.argv).catch((err) => {
229
+ // Anything not caught by runCommand wrappers
230
+ if (isJson()) {
231
+ process.stderr.write(JSON.stringify({ ok: false, error: { message: err?.message ?? String(err) } }) + "\n");
232
+ }
233
+ else {
234
+ emit(err?.message ?? String(err));
235
+ }
236
+ process.exit(1);
237
+ });
238
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface BenchOptions {
2
+ fixturesDir?: string;
3
+ fixture?: string;
4
+ }
5
+ export declare function runBench(opts: BenchOptions): Promise<void>;
@@ -0,0 +1,191 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname } from "node:path";
5
+ import { Pipeline, conversationDedup, anthropic, dollarsFor, } from "@curatedmcp/tokenshield-core";
6
+ import { c, sym, dim, emit, emitJson, isJson, heading, table } from "../lib/ui.js";
7
+ import { TokenShieldError } from "../lib/errors.js";
8
+ const TOKEN_PER_BYTE = 1 / 3.5; // industry rule-of-thumb for English+code
9
+ function defaultFixturesDir() {
10
+ // packages/cli/dist/commands/bench.js — fixtures at ../../../../test-fixtures/sessions
11
+ const here = dirname(fileURLToPath(import.meta.url));
12
+ return join(here, "..", "..", "..", "test-fixtures", "sessions");
13
+ }
14
+ async function listFixtures(dir) {
15
+ let entries;
16
+ try {
17
+ entries = await readdir(dir);
18
+ }
19
+ catch (err) {
20
+ throw new TokenShieldError({
21
+ code: "NOT_FOUND",
22
+ message: `Fixtures directory not found: ${dir}`,
23
+ hint: err.message,
24
+ nextSteps: ["node packages/test-fixtures/generate.mjs"],
25
+ });
26
+ }
27
+ return entries.filter((e) => e.endsWith(".json")).map((e) => join(dir, e)).sort();
28
+ }
29
+ async function loadFixture(path) {
30
+ let raw;
31
+ try {
32
+ raw = await readFile(path, "utf8");
33
+ }
34
+ catch (err) {
35
+ throw new TokenShieldError({
36
+ code: "NOT_FOUND",
37
+ message: `Cannot read fixture: ${path}`,
38
+ hint: err.message,
39
+ });
40
+ }
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(raw);
44
+ }
45
+ catch (err) {
46
+ throw new TokenShieldError({
47
+ code: "BAD_CONFIG",
48
+ message: `Fixture is not valid JSON: ${path}`,
49
+ hint: err.message,
50
+ });
51
+ }
52
+ if (typeof parsed.body !== "object" || parsed.body === null) {
53
+ throw new TokenShieldError({
54
+ code: "BAD_CONFIG",
55
+ message: `Fixture missing 'body': ${path}`,
56
+ });
57
+ }
58
+ return parsed;
59
+ }
60
+ function bytesOf(json) {
61
+ return Buffer.byteLength(JSON.stringify(json ?? null), "utf8");
62
+ }
63
+ function runSingle(fixture, processors) {
64
+ const enabled = new Set(processors.map((p) => p.id));
65
+ const pipeline = new Pipeline({ processors, enabled });
66
+ const bytesIn = bytesOf(fixture.body);
67
+ const conv = anthropic.toConversation(fixture.body);
68
+ if (conv === null) {
69
+ throw new TokenShieldError({
70
+ code: "BAD_CONFIG",
71
+ message: `Fixture body is not a valid Anthropic /v1/messages request: ${fixture.name}`,
72
+ });
73
+ }
74
+ const wireSize = (cn) => bytesOf(anthropic.applyConversation(fixture.body, cn));
75
+ const result = pipeline.run(conv, { providerId: "anthropic", conversationFingerprint: fixture.name, inboundBytes: bytesIn }, wireSize);
76
+ // Mirror passthrough: only count the new wire bytes if effects actually fired
77
+ // AND the new payload is strictly smaller. Otherwise no change happens on the wire.
78
+ let bytesOut = bytesIn;
79
+ if (result.effects.length > 0) {
80
+ const outBody = anthropic.applyConversation(fixture.body, result.conversation);
81
+ const candidate = bytesOf(outBody);
82
+ if (candidate < bytesIn)
83
+ bytesOut = candidate;
84
+ }
85
+ const byteSavings = bytesIn - bytesOut;
86
+ const byteSavingsPct = bytesIn > 0 ? (byteSavings / bytesIn) * 100 : 0;
87
+ const estimatedTokensIn = Math.round(bytesIn * TOKEN_PER_BYTE);
88
+ const estimatedTokensOut = Math.round(bytesOut * TOKEN_PER_BYTE);
89
+ // Estimate completion output at 600 tokens (typical Claude response)
90
+ const ASSUMED_OUTPUT_TOKENS = 600;
91
+ const model = anthropic.extractModel(fixture.body);
92
+ const dIn = dollarsFor(model, {
93
+ inputTokens: estimatedTokensIn,
94
+ outputTokens: ASSUMED_OUTPUT_TOKENS,
95
+ cacheCreationInputTokens: 0,
96
+ cacheReadInputTokens: 0,
97
+ });
98
+ const dOut = dollarsFor(model, {
99
+ inputTokens: estimatedTokensOut,
100
+ outputTokens: ASSUMED_OUTPUT_TOKENS,
101
+ cacheCreationInputTokens: 0,
102
+ cacheReadInputTokens: 0,
103
+ });
104
+ return {
105
+ fixture: fixture.name,
106
+ description: fixture.description,
107
+ model,
108
+ bytesIn,
109
+ bytesOut,
110
+ byteSavings,
111
+ byteSavingsPct,
112
+ estimatedTokensIn,
113
+ estimatedTokensOut,
114
+ estimatedDollarsIn: dIn,
115
+ estimatedDollarsOut: dOut,
116
+ estimatedDollarsSaved: dIn - dOut,
117
+ effects: result.effects,
118
+ };
119
+ }
120
+ function fmtBytes(n) {
121
+ if (n < 1024)
122
+ return `${n}B`;
123
+ if (n < 1024 * 1024)
124
+ return `${(n / 1024).toFixed(1)}KB`;
125
+ return `${(n / 1024 / 1024).toFixed(2)}MB`;
126
+ }
127
+ function fmtDollars(n) {
128
+ return "$" + (n < 1 ? n.toFixed(4) : n.toFixed(2));
129
+ }
130
+ export async function runBench(opts) {
131
+ const dir = opts.fixturesDir ?? defaultFixturesDir();
132
+ const paths = opts.fixture
133
+ ? [opts.fixture.includes("/") ? opts.fixture : join(dir, `${opts.fixture}.json`)]
134
+ : await listFixtures(dir);
135
+ if (paths.length === 0) {
136
+ throw new TokenShieldError({
137
+ code: "NOT_FOUND",
138
+ message: `No fixtures found in ${dir}`,
139
+ nextSteps: ["node packages/test-fixtures/generate.mjs"],
140
+ });
141
+ }
142
+ const processors = [conversationDedup];
143
+ const results = [];
144
+ for (const p of paths) {
145
+ const fx = await loadFixture(p);
146
+ results.push(runSingle(fx, processors));
147
+ }
148
+ if (isJson()) {
149
+ emitJson({ ok: true, results });
150
+ return;
151
+ }
152
+ heading("TokenShield bench — replay against recorded fixtures");
153
+ emit("");
154
+ emit(dim(" No network calls. Pipeline runs against canned request bodies; numbers are wire-byte deltas + projected savings at the listed model's price."));
155
+ emit("");
156
+ emit(table(results.map((r) => [
157
+ " " + c.bold(r.fixture),
158
+ r.model,
159
+ fmtBytes(r.bytesIn),
160
+ fmtBytes(r.bytesOut),
161
+ c.green(`-${fmtBytes(r.byteSavings)}`),
162
+ c.green(`${r.byteSavingsPct.toFixed(1)}%`),
163
+ fmtDollars(r.estimatedDollarsIn),
164
+ fmtDollars(r.estimatedDollarsOut),
165
+ c.green(fmtDollars(r.estimatedDollarsSaved)),
166
+ ]), { header: [" Fixture", "Model", "In", "Out", "Δ bytes", "Saved %", "$ in", "$ out", "$ saved"] }));
167
+ emit("");
168
+ for (const r of results) {
169
+ emit(" " + c.bold(r.fixture) + dim(" " + r.description));
170
+ if (r.effects.length === 0) {
171
+ emit(dim(" (no processors triggered)"));
172
+ }
173
+ else {
174
+ for (const e of r.effects) {
175
+ const detail = e.detail ? dim(" " + JSON.stringify(e.detail)) : "";
176
+ emit(` ${sym.bullet} ${e.name.padEnd(22)} bytes-saved=${fmtBytes(e.bytesSaved)}${detail}`);
177
+ }
178
+ }
179
+ }
180
+ emit("");
181
+ const totalIn = results.reduce((s, r) => s + r.bytesIn, 0);
182
+ const totalOut = results.reduce((s, r) => s + r.bytesOut, 0);
183
+ const totalSavedPct = totalIn > 0 ? ((totalIn - totalOut) / totalIn) * 100 : 0;
184
+ emit(` ${c.bold("Aggregate:")} ${fmtBytes(totalIn)} → ${fmtBytes(totalOut)} ` +
185
+ `${c.green(`(${totalSavedPct.toFixed(1)}% saved across ${results.length} fixtures)`)}`);
186
+ emit("");
187
+ emit(dim(" Note: these are SINGLE-PROCESSOR numbers (conversation-dedup only)."));
188
+ emit(dim(" v0.3 adds diff-based file reads + streaming early-stop; v1.0 adds context auto-summarize."));
189
+ emit("");
190
+ }
191
+ //# sourceMappingURL=bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bench.js","sourceRoot":"","sources":["../../src/commands/bench.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function runDemo(opts: {
2
+ live: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,99 @@
1
+ import { dollarsFor, emptyUsage } from "@curatedmcp/tokenshield-core";
2
+ import { c, sym, dim, emit, say, isJson, emitJson } from "../lib/ui.js";
3
+ const SCRIPT = [
4
+ { model: "claude-opus-4-7", description: "User: refactor the auth middleware",
5
+ raw: { inputTokens: 14_000, outputTokens: 1_200, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
6
+ optimized: { inputTokens: 14_000, outputTokens: 1_200, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: [] },
7
+ { model: "claude-opus-4-7", description: "tool_use: Read('auth.ts')",
8
+ raw: { inputTokens: 18_200, outputTokens: 250, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
9
+ optimized: { inputTokens: 18_200, outputTokens: 250, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: [] },
10
+ { model: "claude-opus-4-7", description: "tool_use: Read('auth.ts') again (5 turns later)",
11
+ raw: { inputTokens: 26_400, outputTokens: 200, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
12
+ optimized: { inputTokens: 12_300, outputTokens: 200, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["conversation-dedup"] },
13
+ { model: "claude-opus-4-7", description: "tool_use: gh pr list (30KB response)",
14
+ raw: { inputTokens: 38_700, outputTokens: 400, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
15
+ optimized: { inputTokens: 14_900, outputTokens: 400, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["result-cache"] },
16
+ { model: "claude-opus-4-7", description: "User: now run the tests",
17
+ raw: { inputTokens: 52_800, outputTokens: 950, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
18
+ optimized: { inputTokens: 19_100, outputTokens: 950, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["conversation-dedup"] },
19
+ { model: "claude-opus-4-7", description: "tool_use: Read('auth.ts') again after edit",
20
+ raw: { inputTokens: 64_100, outputTokens: 180, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
21
+ optimized: { inputTokens: 22_400, outputTokens: 180, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["diff-file-reads"] },
22
+ { model: "claude-opus-4-7", description: "User: also fix the typing in user.ts",
23
+ raw: { inputTokens: 81_300, outputTokens: 1_400, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
24
+ optimized: { inputTokens: 26_900, outputTokens: 1_400, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["conversation-dedup"] },
25
+ { model: "claude-opus-4-7", description: "Long assistant turn — early-stop after 'Would you like me to…'",
26
+ raw: { inputTokens: 92_400, outputTokens: 3_200, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 },
27
+ optimized: { inputTokens: 31_400, outputTokens: 850, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 }, processors: ["conversation-dedup", "stream-early-stop"] },
28
+ ];
29
+ function dollars(n) { return "$" + n.toFixed(n < 1 ? 4 : 2); }
30
+ function bar(value, max, width, color) {
31
+ const filled = Math.max(0, Math.min(width, Math.round((value / Math.max(1, max)) * width)));
32
+ return color("█".repeat(filled)) + dim("░".repeat(width - filled));
33
+ }
34
+ export async function runDemo(opts) {
35
+ const liveMode = opts.live && process.stdout.isTTY;
36
+ const totalRaw = emptyUsage();
37
+ const totalOpt = emptyUsage();
38
+ let totalDollarsRaw = 0;
39
+ let totalDollarsOpt = 0;
40
+ const turnResults = [];
41
+ for (const turn of SCRIPT) {
42
+ totalRaw.inputTokens += turn.raw.inputTokens;
43
+ totalRaw.outputTokens += turn.raw.outputTokens;
44
+ totalOpt.inputTokens += turn.optimized.inputTokens;
45
+ totalOpt.outputTokens += turn.optimized.outputTokens;
46
+ const dRaw = dollarsFor(turn.model, turn.raw);
47
+ const dOpt = dollarsFor(turn.model, turn.optimized);
48
+ totalDollarsRaw += dRaw;
49
+ totalDollarsOpt += dOpt;
50
+ const saved = dRaw - dOpt;
51
+ const pct = dRaw > 0 ? (saved / dRaw) * 100 : 0;
52
+ turnResults.push({ description: turn.description, processors: turn.processors, rawDollars: dRaw, optDollars: dOpt, savedDollars: saved, savedPct: pct });
53
+ }
54
+ const totalSaved = totalDollarsRaw - totalDollarsOpt;
55
+ const overallPct = totalDollarsRaw > 0 ? (totalSaved / totalDollarsRaw) * 100 : 0;
56
+ if (isJson()) {
57
+ emitJson({
58
+ ok: true,
59
+ turns: turnResults,
60
+ total: {
61
+ baselineDollars: totalDollarsRaw,
62
+ optimizedDollars: totalDollarsOpt,
63
+ savedDollars: totalSaved,
64
+ savedPercent: overallPct,
65
+ },
66
+ });
67
+ return;
68
+ }
69
+ emit("");
70
+ emit(c.bold(" TokenShield demo") + dim(" — replaying a recorded 8-turn coding session"));
71
+ emit("");
72
+ for (let i = 0; i < turnResults.length; i++) {
73
+ const t = turnResults[i];
74
+ const proc = t.processors.length > 0 ? c.cyan(`[${t.processors.join(", ")}]`) : "";
75
+ const savedStr = t.savedDollars > 0 ? ` ${c.green("saved " + dollars(t.savedDollars))} ${dim(`(${t.savedPct.toFixed(0)}%)`)} ${proc}` : "";
76
+ emit(` ${dim(`Turn ${String(i + 1).padStart(2)}/${turnResults.length}`)} ` +
77
+ t.description.padEnd(48) +
78
+ ` ${dollars(t.rawDollars).padStart(8)} ${dim("→")} ${c.green(dollars(t.optDollars).padStart(8))}` +
79
+ savedStr);
80
+ if (liveMode)
81
+ await new Promise((r) => setTimeout(r, 280));
82
+ }
83
+ const barWidth = 30;
84
+ emit("");
85
+ emit(c.gray(" " + "─".repeat(barWidth + 30)));
86
+ emit(` Baseline (no TokenShield) ${dollars(totalDollarsRaw).padStart(8)} ${bar(totalDollarsRaw, totalDollarsRaw, barWidth, c.gray)}`);
87
+ emit(` With TokenShield v1.0 ${c.green(dollars(totalDollarsOpt).padStart(8))} ${bar(totalDollarsOpt, totalDollarsRaw, barWidth, c.green)}`);
88
+ emit(` ${c.bold("Saved")} ${c.green(dollars(totalSaved).padStart(8))} ${c.bold(c.green(`(${overallPct.toFixed(1)}%)`))}`);
89
+ emit(c.gray(" " + "─".repeat(barWidth + 30)));
90
+ emit("");
91
+ emit(dim(" This was a recorded demo. To measure your real workload:"));
92
+ emit(` ${c.cyan("tokenshield setup")} ${dim("# guided 60-second install")}`);
93
+ emit(` ${c.cyan("tokenshield up")} ${dim("# run in foreground")}`);
94
+ emit("");
95
+ // suppress unused
96
+ void say;
97
+ void sym;
98
+ }
99
+ //# sourceMappingURL=demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo.js","sourceRoot":"","sources":["../../src/commands/demo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runDoctor(): Promise<void>;