@f3d1/llmkit-cli 0.0.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.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'node:child_process';
3
+ import { startProxy } from './proxy.js';
4
+ import { printSummary } from './summary.js';
5
+ function parseArgs() {
6
+ const argv = process.argv.slice(2);
7
+ const dashIdx = argv.indexOf('--');
8
+ if (dashIdx === -1 || dashIdx === argv.length - 1) {
9
+ process.stderr.write('Usage: npx @f3d1/llmkit-cli [--port N] [--verbose] [--json] -- <command> [args...]\n' +
10
+ '\nWraps any command, intercepts OpenAI/Anthropic API calls, prints cost summary.\n' +
11
+ '\nExample: npx @f3d1/llmkit-cli -- python my_agent.py\n');
12
+ process.exit(1);
13
+ }
14
+ const flags = argv.slice(0, dashIdx);
15
+ const command = argv.slice(dashIdx + 1);
16
+ let port = 0;
17
+ let verbose = false;
18
+ let json = false;
19
+ for (let i = 0; i < flags.length; i++) {
20
+ const flag = flags[i];
21
+ if (flag === '--port' && flags[i + 1]) {
22
+ port = parseInt(flags[++i], 10);
23
+ }
24
+ else if (flag === '--verbose' || flag === '-v') {
25
+ verbose = true;
26
+ }
27
+ else if (flag === '--json') {
28
+ json = true;
29
+ }
30
+ }
31
+ return { port, verbose, json, command };
32
+ }
33
+ async function main() {
34
+ const opts = parseArgs();
35
+ const proxy = await startProxy({ port: opts.port, verbose: opts.verbose });
36
+ const startTime = Date.now();
37
+ const env = {
38
+ ...process.env,
39
+ OPENAI_BASE_URL: `http://127.0.0.1:${proxy.port}/v1`,
40
+ ANTHROPIC_BASE_URL: `http://127.0.0.1:${proxy.port}`,
41
+ };
42
+ const useShell = process.platform === 'win32';
43
+ const child = spawn(opts.command[0], opts.command.slice(1), {
44
+ stdio: 'inherit',
45
+ env,
46
+ shell: useShell,
47
+ });
48
+ let exiting = false;
49
+ const cleanup = async (code) => {
50
+ if (exiting)
51
+ return;
52
+ exiting = true;
53
+ await proxy.stop();
54
+ printSummary(proxy.records, opts.json, Date.now() - startTime);
55
+ process.exit(code);
56
+ };
57
+ child.on('exit', (code) => {
58
+ cleanup(code ?? 1);
59
+ });
60
+ child.on('error', (err) => {
61
+ process.stderr.write(`failed to start command: ${err.message}\n`);
62
+ cleanup(1);
63
+ });
64
+ // forward signals to child - let it exit gracefully, then we clean up
65
+ for (const sig of ['SIGINT', 'SIGTERM']) {
66
+ process.on(sig, () => {
67
+ if (child.exitCode === null) {
68
+ child.kill(sig);
69
+ }
70
+ });
71
+ }
72
+ }
73
+ main().catch((err) => {
74
+ process.stderr.write(`llmkit: ${err instanceof Error ? err.message : String(err)}\n`);
75
+ process.exit(1);
76
+ });
77
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ProviderName } from '@f3d1/llmkit-shared';
2
+ export interface ParsedUsage {
3
+ provider: ProviderName;
4
+ model: string;
5
+ inputTokens: number;
6
+ outputTokens: number;
7
+ cacheReadTokens: number;
8
+ cacheWriteTokens: number;
9
+ }
10
+ export declare function parseOpenAIResponse(body: string): ParsedUsage | null;
11
+ export declare function parseAnthropicResponse(body: string): ParsedUsage | null;
12
+ export declare function parseOpenAIStream(buffer: string): ParsedUsage | null;
13
+ export declare function parseAnthropicStream(buffer: string): ParsedUsage | null;
14
+ //# sourceMappingURL=parsers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsers.d.ts","sourceRoot":"","sources":["../src/parsers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAepE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAevE;AAID,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAyBpE;AAID,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAqCvE"}
@@ -0,0 +1,104 @@
1
+ export function parseOpenAIResponse(body) {
2
+ try {
3
+ const data = JSON.parse(body);
4
+ if (!data.usage)
5
+ return null;
6
+ return {
7
+ provider: 'openai',
8
+ model: data.model ?? 'unknown',
9
+ inputTokens: data.usage.prompt_tokens ?? 0,
10
+ outputTokens: data.usage.completion_tokens ?? 0,
11
+ cacheReadTokens: 0,
12
+ cacheWriteTokens: 0,
13
+ };
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export function parseAnthropicResponse(body) {
20
+ try {
21
+ const data = JSON.parse(body);
22
+ if (!data.usage)
23
+ return null;
24
+ return {
25
+ provider: 'anthropic',
26
+ model: data.model ?? 'unknown',
27
+ inputTokens: data.usage.input_tokens ?? 0,
28
+ outputTokens: data.usage.output_tokens ?? 0,
29
+ cacheReadTokens: data.usage.cache_read_input_tokens ?? 0,
30
+ cacheWriteTokens: data.usage.cache_creation_input_tokens ?? 0,
31
+ };
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ // OpenAI streams: final chunk before [DONE] contains usage when
38
+ // stream_options.include_usage is true (Python SDK default since v1.3)
39
+ export function parseOpenAIStream(buffer) {
40
+ let model = 'unknown';
41
+ let inputTokens = 0;
42
+ let outputTokens = 0;
43
+ let found = false;
44
+ for (const line of buffer.split('\n')) {
45
+ if (!line.startsWith('data: '))
46
+ continue;
47
+ const raw = line.slice(6).trim();
48
+ if (!raw || raw === '[DONE]')
49
+ continue;
50
+ try {
51
+ const chunk = JSON.parse(raw);
52
+ if (chunk.model)
53
+ model = chunk.model;
54
+ if (chunk.usage) {
55
+ inputTokens = chunk.usage.prompt_tokens ?? 0;
56
+ outputTokens = chunk.usage.completion_tokens ?? 0;
57
+ found = true;
58
+ }
59
+ }
60
+ catch {
61
+ // partial JSON at chunk boundary
62
+ }
63
+ }
64
+ return found ? { provider: 'openai', model, inputTokens, outputTokens, cacheReadTokens: 0, cacheWriteTokens: 0 } : null;
65
+ }
66
+ // Anthropic streams: message_start has input_tokens + cache tokens,
67
+ // message_delta has output_tokens
68
+ export function parseAnthropicStream(buffer) {
69
+ let model = 'unknown';
70
+ let inputTokens = 0;
71
+ let outputTokens = 0;
72
+ let cacheReadTokens = 0;
73
+ let cacheWriteTokens = 0;
74
+ let found = false;
75
+ for (const line of buffer.split('\n')) {
76
+ if (!line.startsWith('data: '))
77
+ continue;
78
+ const raw = line.slice(6).trim();
79
+ if (!raw)
80
+ continue;
81
+ try {
82
+ const event = JSON.parse(raw);
83
+ if (event.type === 'message_start' && event.message) {
84
+ model = event.message.model ?? model;
85
+ const usage = event.message.usage;
86
+ if (usage) {
87
+ inputTokens = usage.input_tokens ?? 0;
88
+ cacheReadTokens = usage.cache_read_input_tokens ?? 0;
89
+ cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
90
+ found = true;
91
+ }
92
+ }
93
+ if (event.type === 'message_delta' && event.usage) {
94
+ outputTokens = event.usage.output_tokens ?? 0;
95
+ found = true;
96
+ }
97
+ }
98
+ catch {
99
+ // partial JSON
100
+ }
101
+ }
102
+ return found ? { provider: 'anthropic', model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens } : null;
103
+ }
104
+ //# sourceMappingURL=parsers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsers.js","sourceRoot":"","sources":["../src/parsers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type RequestRecord } from './summary.js';
2
+ export interface ProxyHandle {
3
+ port: number;
4
+ records: RequestRecord[];
5
+ stop: () => Promise<void>;
6
+ }
7
+ export declare function startProxy(opts: {
8
+ port: number;
9
+ verbose: boolean;
10
+ }): Promise<ProxyHandle>;
11
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AASA,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAiBhE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAkHzF"}
package/dist/proxy.js ADDED
@@ -0,0 +1,140 @@
1
+ import http from 'node:http';
2
+ import https from 'node:https';
3
+ import { calculateCost } from '@f3d1/llmkit-shared';
4
+ import { parseAnthropicResponse, parseAnthropicStream, parseOpenAIResponse, parseOpenAIStream, } from './parsers.js';
5
+ import { printVerbose } from './summary.js';
6
+ const OPENAI_TARGET = { host: 'api.openai.com', provider: 'openai', basePath: '' };
7
+ const ANTHROPIC_TARGET = { host: 'api.anthropic.com', provider: 'anthropic', basePath: '' };
8
+ function resolveTarget(url) {
9
+ if (url.startsWith('/v1/chat/completions'))
10
+ return OPENAI_TARGET;
11
+ if (url.startsWith('/v1/messages'))
12
+ return ANTHROPIC_TARGET;
13
+ return null;
14
+ }
15
+ export function startProxy(opts) {
16
+ const records = [];
17
+ const server = http.createServer((clientReq, clientRes) => {
18
+ const target = resolveTarget(clientReq.url ?? '');
19
+ if (!target) {
20
+ clientRes.writeHead(404, { 'content-type': 'text/plain' });
21
+ clientRes.end('not found');
22
+ return;
23
+ }
24
+ const bodyChunks = [];
25
+ clientReq.on('data', (chunk) => bodyChunks.push(chunk));
26
+ clientReq.on('end', () => {
27
+ const body = Buffer.concat(bodyChunks);
28
+ let isStream = false;
29
+ try {
30
+ const parsed = JSON.parse(body.toString());
31
+ isStream = parsed.stream === true;
32
+ }
33
+ catch {
34
+ // not JSON or parse error - forward anyway
35
+ }
36
+ const headers = {};
37
+ for (const [key, val] of Object.entries(clientReq.headers)) {
38
+ if (!val)
39
+ continue;
40
+ const k = key.toLowerCase();
41
+ if (k === 'host' || k === 'accept-encoding' || k === 'connection')
42
+ continue;
43
+ headers[k] = val;
44
+ }
45
+ headers.host = target.host;
46
+ headers['accept-encoding'] = 'identity';
47
+ const start = Date.now();
48
+ const proxyReq = https.request({
49
+ hostname: target.host,
50
+ port: 443,
51
+ path: clientReq.url,
52
+ method: clientReq.method,
53
+ headers,
54
+ }, (proxyRes) => {
55
+ const resHeaders = { ...proxyRes.headers };
56
+ // remove transfer-encoding if we're buffering non-stream responses
57
+ // (we write the full body at once, so chunked encoding would be wrong)
58
+ if (!isStream)
59
+ delete resHeaders['transfer-encoding'];
60
+ clientRes.writeHead(proxyRes.statusCode ?? 502, resHeaders);
61
+ // only track 2xx responses
62
+ const ok = (proxyRes.statusCode ?? 0) >= 200 && (proxyRes.statusCode ?? 0) < 300;
63
+ if (isStream) {
64
+ const sseChunks = [];
65
+ proxyRes.on('data', (chunk) => {
66
+ clientRes.write(chunk);
67
+ if (ok)
68
+ sseChunks.push(chunk.toString());
69
+ });
70
+ proxyRes.on('end', () => {
71
+ clientRes.end();
72
+ if (!ok)
73
+ return;
74
+ const buffer = sseChunks.join('');
75
+ const parsed = target.provider === 'anthropic'
76
+ ? parseAnthropicStream(buffer)
77
+ : parseOpenAIStream(buffer);
78
+ if (parsed) {
79
+ trackUsage(records, parsed, Date.now() - start, opts.verbose);
80
+ }
81
+ });
82
+ }
83
+ else {
84
+ const resChunks = [];
85
+ proxyRes.on('data', (chunk) => resChunks.push(chunk));
86
+ proxyRes.on('end', () => {
87
+ const resBody = Buffer.concat(resChunks);
88
+ clientRes.end(resBody);
89
+ if (!ok)
90
+ return;
91
+ const text = resBody.toString();
92
+ const parsed = target.provider === 'anthropic'
93
+ ? parseAnthropicResponse(text)
94
+ : parseOpenAIResponse(text);
95
+ if (parsed) {
96
+ trackUsage(records, parsed, Date.now() - start, opts.verbose);
97
+ }
98
+ });
99
+ }
100
+ });
101
+ proxyReq.on('error', (err) => {
102
+ if (!clientRes.headersSent) {
103
+ clientRes.writeHead(502, { 'content-type': 'text/plain' });
104
+ }
105
+ clientRes.end(`proxy error: ${err.message}`);
106
+ });
107
+ proxyReq.write(body);
108
+ proxyReq.end();
109
+ });
110
+ });
111
+ return new Promise((resolve, reject) => {
112
+ server.on('error', reject);
113
+ server.listen(opts.port, '127.0.0.1', () => {
114
+ const addr = server.address();
115
+ const port = typeof addr === 'object' && addr ? addr.port : opts.port;
116
+ resolve({
117
+ port,
118
+ records,
119
+ stop: () => new Promise((res) => server.close(() => res())),
120
+ });
121
+ });
122
+ });
123
+ }
124
+ function trackUsage(records, usage, latencyMs, verbose) {
125
+ const costUsd = calculateCost(usage.provider, usage.model, usage.inputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens);
126
+ const rec = {
127
+ provider: usage.provider,
128
+ model: usage.model,
129
+ inputTokens: usage.inputTokens,
130
+ outputTokens: usage.outputTokens,
131
+ cacheReadTokens: usage.cacheReadTokens,
132
+ cacheWriteTokens: usage.cacheWriteTokens,
133
+ costUsd,
134
+ latencyMs,
135
+ };
136
+ records.push(rec);
137
+ if (verbose)
138
+ printVerbose(rec);
139
+ }
140
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface RequestRecord {
2
+ provider: 'openai' | 'anthropic';
3
+ model: string;
4
+ inputTokens: number;
5
+ outputTokens: number;
6
+ cacheReadTokens: number;
7
+ cacheWriteTokens: number;
8
+ costUsd: number;
9
+ latencyMs: number;
10
+ }
11
+ export declare function printSummary(records: RequestRecord[], json: boolean, elapsedMs: number): void;
12
+ export declare function printVerbose(rec: RequestRecord): void;
13
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA4D7F;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAGrD"}
@@ -0,0 +1,62 @@
1
+ export function printSummary(records, json, elapsedMs) {
2
+ if (records.length === 0) {
3
+ if (json) {
4
+ process.stdout.write(`${JSON.stringify({ totalCost: 0, totalRequests: 0, byModel: {} })}\n`);
5
+ }
6
+ else {
7
+ process.stderr.write('\nNo AI API calls detected. Make sure your code uses the default OpenAI/Anthropic base URL.\n');
8
+ }
9
+ return;
10
+ }
11
+ const byModel = new Map();
12
+ let totalCost = 0;
13
+ for (const rec of records) {
14
+ totalCost += rec.costUsd;
15
+ const existing = byModel.get(rec.model);
16
+ if (existing) {
17
+ existing.requests++;
18
+ existing.cost += rec.costUsd;
19
+ }
20
+ else {
21
+ byModel.set(rec.model, { requests: 1, cost: rec.costUsd });
22
+ }
23
+ }
24
+ if (json) {
25
+ const modelObj = {};
26
+ for (const [model, stats] of byModel) {
27
+ modelObj[model] = { requests: stats.requests, cost: +stats.cost.toFixed(6) };
28
+ }
29
+ process.stdout.write(`${JSON.stringify({
30
+ totalCost: +totalCost.toFixed(6),
31
+ totalRequests: records.length,
32
+ elapsedMs,
33
+ byModel: modelObj,
34
+ })}\n`);
35
+ return;
36
+ }
37
+ const elapsed = (elapsedMs / 1000).toFixed(1);
38
+ const lines = [
39
+ '',
40
+ 'LLMKit Cost Summary',
41
+ '---',
42
+ `Total: $${totalCost.toFixed(4)} (${records.length} request${records.length === 1 ? '' : 's'}, ${elapsed}s)`,
43
+ '',
44
+ ];
45
+ if (byModel.size > 1) {
46
+ lines.push('By model:');
47
+ const sorted = [...byModel.entries()].sort((a, b) => b[1].cost - a[1].cost);
48
+ const maxName = Math.max(...sorted.map(([m]) => m.length));
49
+ for (const [model, stats] of sorted) {
50
+ const name = model.padEnd(maxName + 2);
51
+ const reqs = `${stats.requests} req${stats.requests === 1 ? '' : 's'}`.padEnd(8);
52
+ lines.push(` ${name}${reqs} $${stats.cost.toFixed(4)}`);
53
+ }
54
+ lines.push('');
55
+ }
56
+ process.stderr.write(lines.join('\n'));
57
+ }
58
+ export function printVerbose(rec) {
59
+ const cost = rec.costUsd > 0 ? `$${rec.costUsd.toFixed(4)}` : 'free';
60
+ process.stderr.write(` [llmkit] ${rec.provider}/${rec.model} ${cost} (${rec.latencyMs}ms)\n`);
61
+ }
62
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@f3d1/llmkit-cli",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "description": "Zero-code AI cost tracking. Wraps any command, intercepts API calls, prints cost summary.",
7
+ "bin": {
8
+ "llmkit": "./dist/index.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "files": ["dist"],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "typecheck": "tsc --noEmit",
16
+ "clean": "rm -rf dist"
17
+ },
18
+ "dependencies": {
19
+ "@f3d1/llmkit-shared": "workspace:*"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.0.0"
23
+ }
24
+ }