@lim324/my-claude-code-viewer 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.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # My Claude Code Viewer
2
+
3
+ A CLI tool to view Claude Code statistics from your local sessions.
4
+
5
+ ## Features
6
+
7
+ - 📊 View global statistics (total projects, sessions, messages, cost)
8
+ - 📁 Browse projects and their sessions
9
+ - 💰 Cost estimation with token usage breakdown
10
+ - 🌐 Web interface with dark theme
11
+ - 🔌 RESTful API endpoints
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # Clone the repository
17
+ cd my-claude-code-viewer
18
+
19
+ # Install dependencies
20
+ pnpm install
21
+
22
+ # Build the project
23
+ pnpm build
24
+
25
+ # Link for global usage
26
+ npm link
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Start the server
32
+
33
+ ```bash
34
+ # Default port (8888)
35
+ my-claude-code-viewer
36
+
37
+ # Custom port
38
+ my-claude-code-viewer --port 3000
39
+ ```
40
+
41
+ ### Web Interface
42
+
43
+ Open your browser and navigate to `http://localhost:8888`
44
+
45
+ ### API Endpoints
46
+
47
+ - `GET /api/stats` - Global statistics
48
+ - `GET /api/projects` - List all projects
49
+ - `GET /api/projects/:id` - Project details with sessions
50
+ - `GET /api/projects/:projectId/sessions/:sessionId` - Session details
51
+
52
+ ## Data Source
53
+
54
+ The tool reads Claude Code session data from `~/.claude/projects/`
55
+
56
+ Each project directory contains `.jsonl` files representing individual sessions.
57
+
58
+ ## Development
59
+
60
+ ```bash
61
+ # Run in development mode with auto-reload
62
+ pnpm dev
63
+
64
+ # Build
65
+ pnpm build
66
+
67
+ # Start
68
+ pnpm start
69
+ ```
70
+
71
+ ## Technology Stack
72
+
73
+ - TypeScript
74
+ - Express.js
75
+ - Commander.js (CLI)
76
+ - HTML/CSS (frontend)
77
+
78
+ ## License
79
+
80
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/index.js');
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# 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,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const commander_1 = require("commander");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const api_1 = __importDefault(require("./routes/api"));
10
+ const views_1 = __importDefault(require("./routes/views"));
11
+ const program = new commander_1.Command();
12
+ program
13
+ .name("my-claude-code-viewer")
14
+ .description("CLI tool to view Claude Code statistics")
15
+ .version("1.0.0")
16
+ .option("-p, --port <port>", "Port to run the server on", "8888")
17
+ .parse(process.argv);
18
+ const options = program.opts();
19
+ const port = parseInt(options.port, 10);
20
+ const app = (0, express_1.default)();
21
+ // Middleware
22
+ app.use(express_1.default.json());
23
+ app.use(express_1.default.static(node_path_1.default.join(__dirname, "../public")));
24
+ // Routes
25
+ app.use("/api", api_1.default);
26
+ app.use("/", views_1.default);
27
+ // Start server
28
+ app.listen(port, () => {
29
+ console.log(`
30
+ ╔════════════════════════════════════════════════════════════╗
31
+ ║ 🔍 My Claude Code Viewer ║
32
+ ╠════════════════════════════════════════════════════════════╣
33
+ ║ Server running at: http://localhost:${port} ║
34
+ ║ ║
35
+ ║ API Endpoints: ║
36
+ ║ • GET /api/stats - Global statistics ║
37
+ ║ • GET /api/projects - List all projects ║
38
+ ║ • GET /api/projects/:id - Project details ║
39
+ ║ • GET /api/projects/:projectId/sessions/:sessionId ║
40
+ ║ - Session details ║
41
+ ║ ║
42
+ ║ Web Interface: ║
43
+ ║ • http://localhost:${port} ║
44
+ ╚════════════════════════════════════════════════════════════╝
45
+ `);
46
+ });
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,yCAAoC;AACpC,0DAA6B;AAC7B,uDAAqC;AACrC,2DAAwC;AAExC,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,uBAAuB,CAAC;KAC7B,WAAW,CAAC,yCAAyC,CAAC;KACtD,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,CAAC;KAChE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;AAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAExC,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AAEtB,aAAa;AACb,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AAE3D,SAAS;AACT,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,aAAS,CAAC,CAAC;AAC3B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,eAAU,CAAC,CAAC;AAEzB,eAAe;AACf,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC;;;;yCAI2B,IAAI;;;;;;;;;;0BAUnB,IAAI;;GAE3B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface AggregatedCost {
2
+ totalUsd: number;
3
+ breakdown: {
4
+ inputTokensUsd: number;
5
+ outputTokensUsd: number;
6
+ cacheCreationUsd: number;
7
+ cacheReadUsd: number;
8
+ };
9
+ tokenUsage: {
10
+ inputTokens: number;
11
+ outputTokens: number;
12
+ cacheCreationTokens: number;
13
+ cacheReadTokens: number;
14
+ };
15
+ modelName: string;
16
+ }
17
+ /**
18
+ * Aggregates token usage and cost from multiple file contents
19
+ */
20
+ export declare function aggregateTokenUsageAndCost(fileContents: string[]): AggregatedCost;
21
+ /**
22
+ * Calculate cost for a single file content
23
+ */
24
+ export declare function calculateFileCost(content: string): AggregatedCost;
25
+ //# sourceMappingURL=cost-calculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.d.ts","sourceRoot":"","sources":["../../src/lib/cost-calculator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE;QACT,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EAAE,GACrB,cAAc,CAqEhB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEjE"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.aggregateTokenUsageAndCost = aggregateTokenUsageAndCost;
4
+ exports.calculateFileCost = calculateFileCost;
5
+ const jsonl_parser_1 = require("./jsonl-parser");
6
+ const pricing_1 = require("./pricing");
7
+ /**
8
+ * Aggregates token usage and cost from multiple file contents
9
+ */
10
+ function aggregateTokenUsageAndCost(fileContents) {
11
+ let totalInputTokens = 0;
12
+ let totalOutputTokens = 0;
13
+ let totalCacheCreationTokens = 0;
14
+ let totalCacheReadTokens = 0;
15
+ let totalInputTokensUsd = 0;
16
+ let totalOutputTokensUsd = 0;
17
+ let totalCacheCreationUsd = 0;
18
+ let totalCacheReadUsd = 0;
19
+ let lastModelName = "claude-3.5-sonnet";
20
+ for (const content of fileContents) {
21
+ const conversations = (0, jsonl_parser_1.parseJsonl)(content);
22
+ for (const conversation of conversations) {
23
+ if (conversation.type === "assistant") {
24
+ const assistantConv = conversation;
25
+ const usage = assistantConv.message.usage;
26
+ const modelName = assistantConv.message.model;
27
+ if (!usage)
28
+ continue;
29
+ const messageCost = (0, pricing_1.calculateTokenCost)({
30
+ input_tokens: usage.input_tokens,
31
+ output_tokens: usage.output_tokens,
32
+ cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,
33
+ cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,
34
+ }, modelName || "claude-3.5-sonnet");
35
+ totalInputTokens += usage.input_tokens;
36
+ totalOutputTokens += usage.output_tokens;
37
+ totalCacheCreationTokens += usage.cache_creation_input_tokens ?? 0;
38
+ totalCacheReadTokens += usage.cache_read_input_tokens ?? 0;
39
+ totalInputTokensUsd += messageCost.breakdown.inputTokensUsd;
40
+ totalOutputTokensUsd += messageCost.breakdown.outputTokensUsd;
41
+ totalCacheCreationUsd += messageCost.breakdown.cacheCreationUsd;
42
+ totalCacheReadUsd += messageCost.breakdown.cacheReadUsd;
43
+ if (modelName) {
44
+ lastModelName = modelName;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ return {
50
+ totalUsd: totalInputTokensUsd +
51
+ totalOutputTokensUsd +
52
+ totalCacheCreationUsd +
53
+ totalCacheReadUsd,
54
+ breakdown: {
55
+ inputTokensUsd: totalInputTokensUsd,
56
+ outputTokensUsd: totalOutputTokensUsd,
57
+ cacheCreationUsd: totalCacheCreationUsd,
58
+ cacheReadUsd: totalCacheReadUsd,
59
+ },
60
+ tokenUsage: {
61
+ inputTokens: totalInputTokens,
62
+ outputTokens: totalOutputTokens,
63
+ cacheCreationTokens: totalCacheCreationTokens,
64
+ cacheReadTokens: totalCacheReadTokens,
65
+ },
66
+ modelName: lastModelName,
67
+ };
68
+ }
69
+ /**
70
+ * Calculate cost for a single file content
71
+ */
72
+ function calculateFileCost(content) {
73
+ return aggregateTokenUsageAndCost([content]);
74
+ }
75
+ //# sourceMappingURL=cost-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-calculator.js","sourceRoot":"","sources":["../../src/lib/cost-calculator.ts"],"names":[],"mappings":";;AAuBA,gEAuEC;AAKD,8CAEC;AArGD,iDAA0D;AAC1D,uCAA2D;AAmB3D;;GAEG;AACH,SAAgB,0BAA0B,CACxC,YAAsB;IAEtB,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,wBAAwB,GAAG,CAAC,CAAC;IACjC,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAC7B,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAC5B,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAC7B,IAAI,qBAAqB,GAAG,CAAC,CAAC;IAC9B,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,IAAI,aAAa,GAAG,mBAAmB,CAAC;IAExC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,aAAa,GAAG,IAAA,yBAAU,EAAC,OAAO,CAAC,CAAC;QAE1C,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;YACzC,IAAI,YAAY,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACtC,MAAM,aAAa,GAAG,YAA4B,CAAC;gBACnD,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;gBAC1C,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;gBAE9C,IAAI,CAAC,KAAK;oBAAE,SAAS;gBAErB,MAAM,WAAW,GAAG,IAAA,4BAAkB,EACpC;oBACE,YAAY,EAAE,KAAK,CAAC,YAAY;oBAChC,aAAa,EAAE,KAAK,CAAC,aAAa;oBAClC,2BAA2B,EAAE,KAAK,CAAC,2BAA2B,IAAI,CAAC;oBACnE,uBAAuB,EAAE,KAAK,CAAC,uBAAuB,IAAI,CAAC;iBAC5D,EACD,SAAS,IAAI,mBAAmB,CACjC,CAAC;gBAEF,gBAAgB,IAAI,KAAK,CAAC,YAAY,CAAC;gBACvC,iBAAiB,IAAI,KAAK,CAAC,aAAa,CAAC;gBACzC,wBAAwB,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,CAAC;gBACnE,oBAAoB,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,CAAC;gBAE3D,mBAAmB,IAAI,WAAW,CAAC,SAAS,CAAC,cAAc,CAAC;gBAC5D,oBAAoB,IAAI,WAAW,CAAC,SAAS,CAAC,eAAe,CAAC;gBAC9D,qBAAqB,IAAI,WAAW,CAAC,SAAS,CAAC,gBAAgB,CAAC;gBAChE,iBAAiB,IAAI,WAAW,CAAC,SAAS,CAAC,YAAY,CAAC;gBAExD,IAAI,SAAS,EAAE,CAAC;oBACd,aAAa,GAAG,SAAS,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EACN,mBAAmB;YACnB,oBAAoB;YACpB,qBAAqB;YACrB,iBAAiB;QACnB,SAAS,EAAE;YACT,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,oBAAoB;YACrC,gBAAgB,EAAE,qBAAqB;YACvC,YAAY,EAAE,iBAAiB;SAChC;QACD,UAAU,EAAE;YACV,WAAW,EAAE,gBAAgB;YAC7B,YAAY,EAAE,iBAAiB;YAC/B,mBAAmB,EAAE,wBAAwB;YAC7C,eAAe,EAAE,oBAAoB;SACtC;QACD,SAAS,EAAE,aAAa;KACzB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,OAAO,0BAA0B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Represents a conversation entry in the JSONL file
3
+ */
4
+ export interface Conversation {
5
+ type: "user" | "assistant" | "system" | "summary" | string;
6
+ timestamp: string;
7
+ uuid?: string;
8
+ sessionId?: string;
9
+ message: {
10
+ content: string | Array<{
11
+ type: string;
12
+ text: string;
13
+ }>;
14
+ usage?: {
15
+ input_tokens: number;
16
+ output_tokens: number;
17
+ cache_creation_input_tokens?: number;
18
+ cache_read_input_tokens?: number;
19
+ };
20
+ model?: string;
21
+ };
22
+ leafUuid?: string;
23
+ }
24
+ export interface ErrorJsonl {
25
+ type: "x-error";
26
+ line: string;
27
+ lineNumber: number;
28
+ }
29
+ export type ExtendedConversation = Conversation | ErrorJsonl;
30
+ /**
31
+ * Parse a JSONL content string into an array of conversation entries
32
+ */
33
+ export declare function parseJsonl(content: string): ExtendedConversation[];
34
+ /**
35
+ * Extract first user message text from conversations
36
+ */
37
+ export declare function extractFirstUserMessage(conversations: ExtendedConversation[]): string | null;
38
+ /**
39
+ * Count user and assistant messages
40
+ */
41
+ export declare function countMessages(conversations: ExtendedConversation[]): {
42
+ user: number;
43
+ assistant: number;
44
+ system: number;
45
+ total: number;
46
+ };
47
+ //# sourceMappingURL=jsonl-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl-parser.d.ts","sourceRoot":"","sources":["../../src/lib/jsonl-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACxD,KAAK,CAAC,EAAE;YACN,YAAY,EAAE,MAAM,CAAC;YACrB,aAAa,EAAE,MAAM,CAAC;YACtB,2BAA2B,CAAC,EAAE,MAAM,CAAC;YACrC,uBAAuB,CAAC,EAAE,MAAM,CAAC;SAClC,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE7D;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAmBlE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,oBAAoB,EAAE,GACpC,MAAM,GAAG,IAAI,CAoBf;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,oBAAoB,EAAE,GACpC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAkBpE"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseJsonl = parseJsonl;
4
+ exports.extractFirstUserMessage = extractFirstUserMessage;
5
+ exports.countMessages = countMessages;
6
+ /**
7
+ * Parse a JSONL content string into an array of conversation entries
8
+ */
9
+ function parseJsonl(content) {
10
+ const lines = content
11
+ .trim()
12
+ .split("\n")
13
+ .filter((line) => line.trim() !== "");
14
+ return lines.map((line, index) => {
15
+ try {
16
+ const parsed = JSON.parse(line);
17
+ return parsed;
18
+ }
19
+ catch {
20
+ const errorData = {
21
+ type: "x-error",
22
+ line,
23
+ lineNumber: index + 1,
24
+ };
25
+ return errorData;
26
+ }
27
+ });
28
+ }
29
+ /**
30
+ * Extract first user message text from conversations
31
+ */
32
+ function extractFirstUserMessage(conversations) {
33
+ for (const conversation of conversations) {
34
+ if (conversation.type === "x-error")
35
+ continue;
36
+ if (conversation.type !== "user")
37
+ continue;
38
+ const content = conversation.message.content;
39
+ if (typeof content === "string") {
40
+ return content;
41
+ }
42
+ if (Array.isArray(content) && content.length > 0) {
43
+ const firstContent = content[0];
44
+ if (firstContent.type === "text") {
45
+ return firstContent.text;
46
+ }
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * Count user and assistant messages
53
+ */
54
+ function countMessages(conversations) {
55
+ const counts = { user: 0, assistant: 0, system: 0, total: 0 };
56
+ for (const conversation of conversations) {
57
+ if (conversation.type === "x-error")
58
+ continue;
59
+ counts.total++;
60
+ if (conversation.type === "user" ||
61
+ conversation.type === "assistant" ||
62
+ conversation.type === "system") {
63
+ counts[conversation.type]++;
64
+ }
65
+ }
66
+ return counts;
67
+ }
68
+ //# sourceMappingURL=jsonl-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl-parser.js","sourceRoot":"","sources":["../../src/lib/jsonl-parser.ts"],"names":[],"mappings":";;AAgCA,gCAmBC;AAKD,0DAsBC;AAKD,sCAoBC;AA1ED;;GAEG;AACH,SAAgB,UAAU,CAAC,OAAe;IACxC,MAAM,KAAK,GAAG,OAAO;SAClB,IAAI,EAAE;SACN,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAExC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,OAAO,MAAsB,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,SAAS,GAAe;gBAC5B,IAAI,EAAE,SAAS;gBACf,IAAI;gBACJ,UAAU,EAAE,KAAK,GAAG,CAAC;aACtB,CAAC;YACF,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,uBAAuB,CACrC,aAAqC;IAErC,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QACzC,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QAC9C,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAE3C,MAAM,OAAO,GAAI,YAA6B,CAAC,OAAO,CAAC,OAAO,CAAC;QAE/D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACjC,OAAO,YAAY,CAAC,IAAI,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa,CAC3B,aAAqC;IAErC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAE9D,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QACzC,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QAE9C,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,IACE,YAAY,CAAC,IAAI,KAAK,MAAM;YAC5B,YAAY,CAAC,IAAI,KAAK,WAAW;YACjC,YAAY,CAAC,IAAI,KAAK,QAAQ,EAC9B,CAAC;YACD,MAAM,CAAC,YAAY,CAAC,IAAuC,CAAC,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Model pricing per 1M tokens in USD
3
+ */
4
+ export interface ModelPricing {
5
+ input: number;
6
+ output: number;
7
+ cache_creation: number;
8
+ cache_read: number;
9
+ }
10
+ export declare const MODEL_PRICING: Record<string, ModelPricing>;
11
+ export declare const DEFAULT_MODEL_PRICING: ModelPricing;
12
+ export type ModelName = keyof typeof MODEL_PRICING;
13
+ /**
14
+ * Normalizes Claude API model names to standard model identifiers
15
+ */
16
+ export declare function normalizeModelName(modelName: string): ModelName;
17
+ /**
18
+ * Gets pricing for a model, with fallback to default pricing
19
+ */
20
+ export declare function getModelPricing(modelName: string): ModelPricing;
21
+ export interface TokenUsage {
22
+ input_tokens: number;
23
+ output_tokens: number;
24
+ cache_creation_input_tokens: number;
25
+ cache_read_input_tokens: number;
26
+ }
27
+ export interface CostBreakdown {
28
+ inputTokensUsd: number;
29
+ outputTokensUsd: number;
30
+ cacheCreationUsd: number;
31
+ cacheReadUsd: number;
32
+ }
33
+ export interface CostCalculationResult {
34
+ totalUsd: number;
35
+ breakdown: CostBreakdown;
36
+ tokenUsage: {
37
+ inputTokens: number;
38
+ outputTokens: number;
39
+ cacheCreationTokens: number;
40
+ cacheReadTokens: number;
41
+ };
42
+ }
43
+ /**
44
+ * Calculates the cost in USD for token usage
45
+ */
46
+ export declare function calculateTokenCost(usage: TokenUsage, modelName: string): CostCalculationResult;
47
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/lib/pricing.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA2CtD,CAAC;AAEF,eAAO,MAAM,qBAAqB,cAAqC,CAAC;AAExE,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,aAAa,CAAC;AAEnD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAoC/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAG/D;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B,EAAE,MAAM,CAAC;IACpC,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,MAAM,GAChB,qBAAqB,CA+BvB"}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_MODEL_PRICING = exports.MODEL_PRICING = void 0;
4
+ exports.normalizeModelName = normalizeModelName;
5
+ exports.getModelPricing = getModelPricing;
6
+ exports.calculateTokenCost = calculateTokenCost;
7
+ exports.MODEL_PRICING = {
8
+ "claude-opus-4.5": {
9
+ input: 15.0,
10
+ output: 75.0,
11
+ cache_creation: 18.75,
12
+ cache_read: 1.5,
13
+ },
14
+ "claude-opus-4.1": {
15
+ input: 15.0,
16
+ output: 75.0,
17
+ cache_creation: 18.75,
18
+ cache_read: 1.5,
19
+ },
20
+ "claude-sonnet-4.5": {
21
+ input: 8.0,
22
+ output: 40.0,
23
+ cache_creation: 10.0,
24
+ cache_read: 0.8,
25
+ },
26
+ "claude-haiku-4.5": {
27
+ input: 1.0,
28
+ output: 5.0,
29
+ cache_creation: 1.25,
30
+ cache_read: 0.1,
31
+ },
32
+ "claude-3.5-sonnet": {
33
+ input: 3.0,
34
+ output: 15.0,
35
+ cache_creation: 3.75,
36
+ cache_read: 0.3,
37
+ },
38
+ "claude-3-opus": {
39
+ input: 15.0,
40
+ output: 75.0,
41
+ cache_creation: 18.75,
42
+ cache_read: 1.5,
43
+ },
44
+ "claude-3-haiku": {
45
+ input: 0.25,
46
+ output: 1.25,
47
+ cache_creation: 0.3125,
48
+ cache_read: 0.025,
49
+ },
50
+ };
51
+ exports.DEFAULT_MODEL_PRICING = exports.MODEL_PRICING["claude-3.5-sonnet"];
52
+ /**
53
+ * Normalizes Claude API model names to standard model identifiers
54
+ */
55
+ function normalizeModelName(modelName) {
56
+ const normalized = modelName.toLowerCase();
57
+ if (normalized.includes("opus-4-5") || normalized.includes("opus-4.5")) {
58
+ return "claude-opus-4.5";
59
+ }
60
+ if (normalized.includes("opus-4-1") || normalized.includes("opus-4.1")) {
61
+ return "claude-opus-4.1";
62
+ }
63
+ if (normalized.includes("sonnet-4-5") || normalized.includes("sonnet-4.5")) {
64
+ return "claude-sonnet-4.5";
65
+ }
66
+ if (normalized.includes("haiku-4-5") || normalized.includes("haiku-4.5")) {
67
+ return "claude-haiku-4.5";
68
+ }
69
+ if (normalized.includes("sonnet-4") ||
70
+ normalized.includes("3-5-sonnet") ||
71
+ normalized.includes("3.5-sonnet")) {
72
+ return "claude-3.5-sonnet";
73
+ }
74
+ if (normalized.includes("3-opus") || normalized.includes("opus-20")) {
75
+ return "claude-3-opus";
76
+ }
77
+ if (normalized.includes("3-haiku") || normalized.includes("haiku-20")) {
78
+ return "claude-3-haiku";
79
+ }
80
+ return "claude-3.5-sonnet";
81
+ }
82
+ /**
83
+ * Gets pricing for a model, with fallback to default pricing
84
+ */
85
+ function getModelPricing(modelName) {
86
+ const normalized = normalizeModelName(modelName);
87
+ return exports.MODEL_PRICING[normalized] ?? exports.DEFAULT_MODEL_PRICING;
88
+ }
89
+ /**
90
+ * Calculates the cost in USD for token usage
91
+ */
92
+ function calculateTokenCost(usage, modelName) {
93
+ const pricing = getModelPricing(modelName);
94
+ const inputMTok = usage.input_tokens / 1_000_000;
95
+ const outputMTok = usage.output_tokens / 1_000_000;
96
+ const cacheCreationMTok = (usage.cache_creation_input_tokens ?? 0) / 1_000_000;
97
+ const cacheReadMTok = (usage.cache_read_input_tokens ?? 0) / 1_000_000;
98
+ const inputTokensUsd = inputMTok * pricing.input;
99
+ const outputTokensUsd = outputMTok * pricing.output;
100
+ const cacheCreationUsd = cacheCreationMTok * pricing.cache_creation;
101
+ const cacheReadUsd = cacheReadMTok * pricing.cache_read;
102
+ const totalUsd = inputTokensUsd + outputTokensUsd + cacheCreationUsd + cacheReadUsd;
103
+ return {
104
+ totalUsd,
105
+ breakdown: {
106
+ inputTokensUsd,
107
+ outputTokensUsd,
108
+ cacheCreationUsd,
109
+ cacheReadUsd,
110
+ },
111
+ tokenUsage: {
112
+ inputTokens: usage.input_tokens,
113
+ outputTokens: usage.output_tokens,
114
+ cacheCreationTokens: usage.cache_creation_input_tokens ?? 0,
115
+ cacheReadTokens: usage.cache_read_input_tokens ?? 0,
116
+ },
117
+ };
118
+ }
119
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/lib/pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Router } from "express";
2
+ declare const router: Router;
3
+ export default router;
4
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/routes/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAWjC,QAAA,MAAM,MAAM,EAAE,MAAiB,CAAC;AAwGhC,eAAe,MAAM,CAAC"}