@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.
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +238 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/bench.d.ts +5 -0
- package/dist/commands/bench.js +191 -0
- package/dist/commands/bench.js.map +1 -0
- package/dist/commands/demo.d.ts +3 -0
- package/dist/commands/demo.js +99 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +119 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/estimate.d.ts +3 -0
- package/dist/commands/estimate.js +90 -0
- package/dist/commands/estimate.js.map +1 -0
- package/dist/commands/integrations.d.ts +14 -0
- package/dist/commands/integrations.js +138 -0
- package/dist/commands/integrations.js.map +1 -0
- package/dist/commands/logs.d.ts +6 -0
- package/dist/commands/logs.js +66 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/setup.d.ts +9 -0
- package/dist/commands/setup.js +159 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +102 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +1 -0
- package/dist/commands/stop.js +27 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/up.d.ts +15 -0
- package/dist/commands/up.js +145 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/dashboard.d.ts +4 -0
- package/dist/dashboard.js +186 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/lib/daemon.d.ts +23 -0
- package/dist/lib/daemon.js +164 -0
- package/dist/lib/daemon.js.map +1 -0
- package/dist/lib/errors.d.ts +23 -0
- package/dist/lib/errors.js +131 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/integrations.d.ts +47 -0
- package/dist/lib/integrations.js +210 -0
- package/dist/lib/integrations.js.map +1 -0
- package/dist/lib/paths.d.ts +5 -0
- package/dist/lib/paths.js +18 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/preflight.d.ts +20 -0
- package/dist/lib/preflight.js +97 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/ui.d.ts +68 -0
- package/dist/lib/ui.js +221 -0
- package/dist/lib/ui.js.map +1 -0
- package/package.json +44 -0
package/dist/cli.d.ts
ADDED
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
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,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>;
|