ai-cost-cli 1.0.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 (42) hide show
  1. package/README.md +228 -0
  2. package/dist/analytics.d.ts +8 -0
  3. package/dist/analytics.d.ts.map +1 -0
  4. package/dist/analytics.js +128 -0
  5. package/dist/analytics.js.map +1 -0
  6. package/dist/api.d.ts +11 -0
  7. package/dist/api.d.ts.map +1 -0
  8. package/dist/api.js +152 -0
  9. package/dist/api.js.map +1 -0
  10. package/dist/commands/analyze.d.ts +8 -0
  11. package/dist/commands/analyze.d.ts.map +1 -0
  12. package/dist/commands/analyze.js +210 -0
  13. package/dist/commands/analyze.js.map +1 -0
  14. package/dist/commands/connect.d.ts +7 -0
  15. package/dist/commands/connect.d.ts.map +1 -0
  16. package/dist/commands/connect.js +67 -0
  17. package/dist/commands/connect.js.map +1 -0
  18. package/dist/commands/login.d.ts +7 -0
  19. package/dist/commands/login.d.ts.map +1 -0
  20. package/dist/commands/login.js +100 -0
  21. package/dist/commands/login.js.map +1 -0
  22. package/dist/commands/models.d.ts +6 -0
  23. package/dist/commands/models.d.ts.map +1 -0
  24. package/dist/commands/models.js +74 -0
  25. package/dist/commands/models.js.map +1 -0
  26. package/dist/commands/optimize.d.ts +6 -0
  27. package/dist/commands/optimize.d.ts.map +1 -0
  28. package/dist/commands/optimize.js +129 -0
  29. package/dist/commands/optimize.js.map +1 -0
  30. package/dist/commands/status.d.ts +2 -0
  31. package/dist/commands/status.d.ts.map +1 -0
  32. package/dist/commands/status.js +31 -0
  33. package/dist/commands/status.js.map +1 -0
  34. package/dist/config.d.ts +13 -0
  35. package/dist/config.d.ts.map +1 -0
  36. package/dist/config.js +71 -0
  37. package/dist/config.js.map +1 -0
  38. package/dist/index.d.ts +3 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +54 -0
  41. package/dist/index.js.map +1 -0
  42. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,228 @@
1
+ # ai-cost-cli
2
+
3
+ > 🛡️ **AI Cost Guard CLI** — Analyze and optimize your AI/LLM API costs from the terminal.
4
+ > Monitor OpenAI, Anthropic, Gemini, and Cohere spending with real-time dashboards, cost breakdowns, and optimization recommendations across 50+ models.
5
+
6
+ [![npm version](https://img.shields.io/npm/v/ai-cost-cli.svg)](https://www.npmjs.com/package/ai-cost-cli)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Node.js ≥ 16](https://img.shields.io/badge/node-%3E%3D16-brightgreen)](https://nodejs.org)
9
+
10
+ ---
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install -g ai-cost-cli
16
+ ```
17
+
18
+ After installation, two aliases are available:
19
+
20
+ ```bash
21
+ ai-cost-cli --help
22
+ ai-cost --help # shorthand
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Quick Start
28
+
29
+ ```bash
30
+ # 1. Log in and select a project (recommended)
31
+ ai-cost-cli login
32
+
33
+ # 2. — OR — connect directly with an API key
34
+ ai-cost-cli connect --key YOUR_API_KEY
35
+
36
+ # 3. Analyze the last 30 days of AI spending
37
+ ai-cost-cli analyze
38
+
39
+ # 4. Get model-switch recommendations to cut costs
40
+ ai-cost-cli optimize
41
+
42
+ # 5. Browse all supported models and pricing
43
+ ai-cost-cli models
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Commands
49
+
50
+ ### `login`
51
+
52
+ Authenticate with your AI Cost Guard account. Automatically fetches your projects and lets you select one to connect.
53
+
54
+ ```bash
55
+ ai-cost-cli login
56
+ ai-cost-cli login --email you@example.com
57
+ ai-cost-cli login --email you@example.com --url https://api.aicostguard.com
58
+ ```
59
+
60
+ | Option | Description |
61
+ |--------|-------------|
62
+ | `-e, --email <email>` | Pre-fill your email address |
63
+ | `-u, --url <url>` | API base URL (default: `http://localhost:4000`) |
64
+
65
+ After login, your JWT token and selected project's API key are saved to `~/.ai-cost-guard/config.json`.
66
+
67
+ ---
68
+
69
+ ### `connect`
70
+
71
+ Connect to a project directly using a project API key (no account required).
72
+
73
+ ```bash
74
+ ai-cost-cli connect
75
+ ai-cost-cli connect --key acg_live_xxxxxxxxxxxx
76
+ ai-cost-cli connect --key acg_live_xxxxxxxxxxxx --url https://api.aicostguard.com
77
+ ```
78
+
79
+ | Option | Description |
80
+ |--------|-------------|
81
+ | `-k, --key <apiKey>` | Your project API key |
82
+ | `-u, --url <url>` | API base URL (default: `http://localhost:4000`) |
83
+
84
+ ---
85
+
86
+ ### `status`
87
+
88
+ Display the current connection status, project info, and recent activity.
89
+
90
+ ```bash
91
+ ai-cost-cli status
92
+ ```
93
+
94
+ Shows: logged-in email, project name, API key (masked), server URL, and events seen today.
95
+
96
+ ---
97
+
98
+ ### `analyze`
99
+
100
+ Pull a full cost report for your connected project.
101
+
102
+ ```bash
103
+ ai-cost-cli analyze
104
+ ai-cost-cli analyze --days 7
105
+ ai-cost-cli analyze --days 90 --model gpt-4o
106
+ ai-cost-cli analyze --provider anthropic
107
+ ```
108
+
109
+ | Option | Description |
110
+ |--------|-------------|
111
+ | `-d, --days <n>` | Analysis window in days (default: `30`) |
112
+ | `-m, --model <model>` | Filter results to a specific model |
113
+ | `-p, --provider <provider>` | Filter by provider: `openai`, `anthropic`, `google` |
114
+
115
+ **Output includes:**
116
+ - Total cost, total events, avg cost/event
117
+ - Input / output token totals
118
+ - Cost breakdown by model
119
+ - Cost breakdown by day (time series)
120
+ - Latency percentiles (p50 / p95 / p99) when available
121
+
122
+ When no JWT token is present, falls back to a pricing-only estimate based on the public `/pricing/models` endpoint.
123
+
124
+ ---
125
+
126
+ ### `optimize`
127
+
128
+ Get model-switch recommendations that can reduce your bill.
129
+
130
+ ```bash
131
+ ai-cost-cli optimize
132
+ ai-cost-cli optimize --days 7
133
+ ```
134
+
135
+ | Option | Description |
136
+ |--------|-------------|
137
+ | `-d, --days <n>` | Analysis period for usage context (default: `30`) |
138
+
139
+ Compares models within each provider and surfaces alternatives that cost **30%+ less** per token, with estimated savings percentages.
140
+
141
+ ---
142
+
143
+ ### `models`
144
+
145
+ Browse all supported models and their per-token pricing.
146
+
147
+ ```bash
148
+ ai-cost-cli models
149
+ ai-cost-cli models --provider openai
150
+ ai-cost-cli models --provider anthropic
151
+ ```
152
+
153
+ | Option | Description |
154
+ |--------|-------------|
155
+ | `-p, --provider <provider>` | Filter by provider name (case-insensitive) |
156
+
157
+ Displays a grouped, color-coded table with input price / output price per 1M tokens and a cost tier label.
158
+
159
+ ---
160
+
161
+ ## Configuration
162
+
163
+ Credentials and project info are stored locally in:
164
+
165
+ ```
166
+ ~/.ai-cost-guard/config.json
167
+ ```
168
+
169
+ | Field | Set by | Description |
170
+ |-------|--------|-------------|
171
+ | `token` | `login` | JWT access token |
172
+ | `email` | `login` | Logged-in user's email |
173
+ | `apiKey` | `login` / `connect` | Project API key (used as `x-api-key` header) |
174
+ | `projectId` | `login` | Selected project UUID |
175
+ | `projectName` | `login` | Selected project display name |
176
+ | `baseUrl` | `login` / `connect` | Backend API base URL |
177
+
178
+ To reset, simply delete the file:
179
+
180
+ ```bash
181
+ rm ~/.ai-cost-guard/config.json
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Self-Hosting
187
+
188
+ By default the CLI points to `http://localhost:4000`. To connect to a self-hosted or cloud instance, pass `--url` to any authentication command:
189
+
190
+ ```bash
191
+ ai-cost-cli login --url https://api.your-instance.com
192
+ ai-cost-cli connect --key YOUR_KEY --url https://api.your-instance.com
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Supported Providers
198
+
199
+ | Provider | Example Models |
200
+ |----------|---------------|
201
+ | **OpenAI** | gpt-4o, gpt-4o-mini, gpt-4-turbo, o1, o3-mini |
202
+ | **Anthropic** | claude-3-5-sonnet, claude-3-5-haiku, claude-3-opus |
203
+ | **Google** | gemini-1.5-pro, gemini-1.5-flash, gemini-2.0-flash |
204
+ | **Cohere** | command-r-plus, command-r |
205
+
206
+ Run `ai-cost-cli models` for the full, live list sourced directly from your backend.
207
+
208
+ ---
209
+
210
+ ## Requirements
211
+
212
+ - **Node.js** ≥ 16.0.0
213
+ - A running [AI Cost Guard backend](https://github.com/crediblearena/ai-cost-guard) **or** a cloud account at [aicostguard.com](https://aicostguard.com)
214
+
215
+ ---
216
+
217
+ ## Links
218
+
219
+ - 🌐 [aicostguard.com](https://aicostguard.com)
220
+ - 📦 [npm: ai-cost-cli](https://www.npmjs.com/package/ai-cost-cli)
221
+ - 🐛 [Issue tracker](https://github.com/crediblearena/ai-cost-guard/issues)
222
+ - 📖 [Full documentation](https://aicostguard.com/docs)
223
+
224
+ ---
225
+
226
+ ## License
227
+
228
+ MIT © [AI Cost Guard](https://aicostguard.com)
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Track cli_used_daily — fires at most once per calendar day.
3
+ * Fire-and-forget, never blocks CLI execution.
4
+ */
5
+ export declare function trackCliUsage(command: string): Promise<void>;
6
+ /** Allow users to opt out of analytics */
7
+ export declare function setAnalyticsOptOut(optOut: boolean): void;
8
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAoDA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuClE;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAIxD"}
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.trackCliUsage = trackCliUsage;
37
+ exports.setAnalyticsOptOut = setAnalyticsOptOut;
38
+ const posthog_node_1 = require("posthog-node");
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ const POSTHOG_API_KEY = 'phc_bX4Ab8QZ0WZL8nsEQfaTw2E6xtijwVjb6jIvbhZ436f';
43
+ const POSTHOG_HOST = 'https://us.i.posthog.com';
44
+ const CONFIG_DIR = path.join(os.homedir(), '.ai-cost-guard');
45
+ const ANALYTICS_FILE = path.join(CONFIG_DIR, 'analytics.json');
46
+ function getState() {
47
+ try {
48
+ if (fs.existsSync(ANALYTICS_FILE)) {
49
+ return JSON.parse(fs.readFileSync(ANALYTICS_FILE, 'utf-8'));
50
+ }
51
+ }
52
+ catch {
53
+ // ignore
54
+ }
55
+ return {};
56
+ }
57
+ function saveState(state) {
58
+ try {
59
+ if (!fs.existsSync(CONFIG_DIR)) {
60
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
61
+ }
62
+ fs.writeFileSync(ANALYTICS_FILE, JSON.stringify(state, null, 2));
63
+ }
64
+ catch {
65
+ // ignore — analytics should never break CLI
66
+ }
67
+ }
68
+ /** Get user ID from CLI config (set during login) */
69
+ function getUserId() {
70
+ try {
71
+ const configPath = path.join(CONFIG_DIR, 'config.json');
72
+ if (fs.existsSync(configPath)) {
73
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
74
+ return config.userId || config.email || null;
75
+ }
76
+ }
77
+ catch {
78
+ // ignore
79
+ }
80
+ return null;
81
+ }
82
+ /**
83
+ * Track cli_used_daily — fires at most once per calendar day.
84
+ * Fire-and-forget, never blocks CLI execution.
85
+ */
86
+ async function trackCliUsage(command) {
87
+ try {
88
+ const state = getState();
89
+ // Respect opt-out
90
+ if (state.optOut)
91
+ return;
92
+ const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
93
+ // Daily dedup — only one event per day
94
+ if (state.lastCliDay === today)
95
+ return;
96
+ const userId = getUserId();
97
+ if (!userId)
98
+ return; // Only track logged-in users
99
+ const client = new posthog_node_1.PostHog(POSTHOG_API_KEY, { host: POSTHOG_HOST });
100
+ client.capture({
101
+ distinctId: userId,
102
+ event: 'cli_used_daily',
103
+ properties: {
104
+ command,
105
+ platform: process.platform,
106
+ node_version: process.version,
107
+ },
108
+ });
109
+ // Update last usage day
110
+ state.lastCliDay = today;
111
+ saveState(state);
112
+ // Flush and close — with a timeout so we don't block CLI exit
113
+ await Promise.race([
114
+ client.shutdown(),
115
+ new Promise((resolve) => setTimeout(resolve, 2000)),
116
+ ]);
117
+ }
118
+ catch {
119
+ // Analytics should NEVER break the CLI
120
+ }
121
+ }
122
+ /** Allow users to opt out of analytics */
123
+ function setAnalyticsOptOut(optOut) {
124
+ const state = getState();
125
+ state.optOut = optOut;
126
+ saveState(state);
127
+ }
128
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ interface RequestOptions {
2
+ path: string;
3
+ method?: string;
4
+ body?: any;
5
+ apiKey?: string;
6
+ baseUrl?: string;
7
+ }
8
+ export declare function apiRequest<T>(options: RequestOptions): Promise<T>;
9
+ export declare function apiRequestAuth<T>(path: string, token: string, baseUrl?: string): Promise<T>;
10
+ export {};
11
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAoEvE;AAED,wBAAsB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAmDjG"}
package/dist/api.js ADDED
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.apiRequest = apiRequest;
37
+ exports.apiRequestAuth = apiRequestAuth;
38
+ const http = __importStar(require("http"));
39
+ const https = __importStar(require("https"));
40
+ const config_1 = require("./config");
41
+ async function apiRequest(options) {
42
+ const config = (0, config_1.getConfig)();
43
+ const baseUrl = options.baseUrl || config?.baseUrl || 'http://localhost:4000';
44
+ const apiKey = options.apiKey || config?.apiKey;
45
+ const fullUrl = `${baseUrl}/api/v1${options.path}`;
46
+ const url = new URL(fullUrl);
47
+ const isHttps = url.protocol === 'https:';
48
+ const lib = isHttps ? https : http;
49
+ const headers = {
50
+ 'Content-Type': 'application/json',
51
+ };
52
+ if (apiKey) {
53
+ headers['x-api-key'] = apiKey;
54
+ }
55
+ const body = options.body ? JSON.stringify(options.body) : undefined;
56
+ return new Promise((resolve, reject) => {
57
+ const req = lib.request({
58
+ hostname: url.hostname,
59
+ port: url.port || (isHttps ? 443 : 80),
60
+ path: url.pathname + url.search,
61
+ method: options.method || 'GET',
62
+ headers,
63
+ }, (res) => {
64
+ let data = '';
65
+ res.on('data', (chunk) => (data += chunk));
66
+ res.on('end', () => {
67
+ if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
68
+ try {
69
+ const json = JSON.parse(data);
70
+ const message = json.message || json.error || `HTTP ${res.statusCode}`;
71
+ reject(new Error(message));
72
+ }
73
+ catch {
74
+ reject(new Error(`HTTP ${res.statusCode}: ${data.substring(0, 200)}`));
75
+ }
76
+ return;
77
+ }
78
+ try {
79
+ const json = JSON.parse(data);
80
+ // Handle TransformInterceptor wrapper
81
+ if (json.data !== undefined) {
82
+ resolve(json.data);
83
+ }
84
+ else {
85
+ resolve(json);
86
+ }
87
+ }
88
+ catch {
89
+ reject(new Error(`Invalid JSON response: ${data.substring(0, 200)}`));
90
+ }
91
+ });
92
+ });
93
+ req.on('error', (err) => {
94
+ reject(new Error(`Connection failed: ${err.message}\nMake sure the AI Cost Guard server is running.`));
95
+ });
96
+ if (body) {
97
+ req.write(body);
98
+ }
99
+ req.end();
100
+ });
101
+ }
102
+ async function apiRequestAuth(path, token, baseUrl) {
103
+ const config = (0, config_1.getConfig)();
104
+ const base = baseUrl || config?.baseUrl || 'http://localhost:4000';
105
+ const fullUrl = `${base}/api/v1${path}`;
106
+ const url = new URL(fullUrl);
107
+ const isHttps = url.protocol === 'https:';
108
+ const lib = isHttps ? https : http;
109
+ return new Promise((resolve, reject) => {
110
+ const req = lib.request({
111
+ hostname: url.hostname,
112
+ port: url.port || (isHttps ? 443 : 80),
113
+ path: url.pathname + url.search,
114
+ method: 'GET',
115
+ headers: {
116
+ 'Content-Type': 'application/json',
117
+ Authorization: `Bearer ${token}`,
118
+ },
119
+ }, (res) => {
120
+ let data = '';
121
+ res.on('data', (chunk) => (data += chunk));
122
+ res.on('end', () => {
123
+ if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
124
+ try {
125
+ const json = JSON.parse(data);
126
+ const message = json.message || json.error || `HTTP ${res.statusCode}`;
127
+ reject(new Error(message));
128
+ }
129
+ catch {
130
+ reject(new Error(`HTTP ${res.statusCode}: ${data.substring(0, 200)}`));
131
+ }
132
+ return;
133
+ }
134
+ try {
135
+ const json = JSON.parse(data);
136
+ if (json.data !== undefined) {
137
+ resolve(json.data);
138
+ }
139
+ else {
140
+ resolve(json);
141
+ }
142
+ }
143
+ catch {
144
+ reject(new Error(`Invalid JSON response`));
145
+ }
146
+ });
147
+ });
148
+ req.on('error', (err) => reject(new Error(`Connection failed: ${err.message}`)));
149
+ req.end();
150
+ });
151
+ }
152
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,gCAoEC;AAED,wCAmDC;AArID,2CAA6B;AAC7B,6CAA+B;AAC/B,qCAAqC;AAU9B,KAAK,UAAU,UAAU,CAAI,OAAuB;IACzD,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO,IAAI,uBAAuB,CAAC;IAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,EAAE,MAAM,CAAC;IAEhD,MAAM,OAAO,GAAG,GAAG,OAAO,UAAU,OAAO,CAAC,IAAI,EAAE,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAE7B,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnC,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC;IAChC,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAErE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CACrB;YACE,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,IAAI,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM;YAC/B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;YAC/B,OAAO;SACR,EACD,CAAC,GAAG,EAAE,EAAE;YACN,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE,CAAC;oBACtE,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,UAAU,EAAE,CAAC;wBACvE,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC7B,CAAC;oBAAC,MAAM,CAAC;wBACP,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzE,CAAC;oBACD,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC9B,sCAAsC;oBACtC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;wBAC5B,OAAO,CAAC,IAAI,CAAC,IAAS,CAAC,CAAC;oBAC1B,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,IAAS,CAAC,CAAC;oBACrB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBACxE,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CACF,CAAC;QAEF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,kDAAkD,CAAC,CAAC,CAAC;QACzG,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,EAAE,CAAC;YACT,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAI,IAAY,EAAE,KAAa,EAAE,OAAgB;IACnF,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,OAAO,IAAI,MAAM,EAAE,OAAO,IAAI,uBAAuB,CAAC;IACnE,MAAM,OAAO,GAAG,GAAG,IAAI,UAAU,IAAI,EAAE,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAE7B,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CACrB;YACE,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,IAAI,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM;YAC/B,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;SACF,EACD,CAAC,GAAG,EAAE,EAAE;YACN,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;YAC3C,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACjB,IAAI,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,EAAE,CAAC;oBACtE,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,UAAU,EAAE,CAAC;wBACvE,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;oBAC7B,CAAC;oBAAC,MAAM,CAAC;wBACP,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;oBACzE,CAAC;oBACD,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;wBAC5B,OAAO,CAAC,IAAI,CAAC,IAAS,CAAC,CAAC;oBAC1B,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,IAAS,CAAC,CAAC;oBACrB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CACF,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACjF,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ interface AnalyzeOptions {
2
+ days: string;
3
+ model?: string;
4
+ provider?: string;
5
+ }
6
+ export declare function analyzeCommand(options: AnalyzeOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAMA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,iBA2B3D"}