berget 1.0.0 → 1.1.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 (37) hide show
  1. package/README.md +92 -0
  2. package/dist/index.js +7 -471
  3. package/dist/src/client.js +193 -102
  4. package/dist/src/commands/api-keys.js +271 -0
  5. package/dist/src/commands/auth.js +65 -0
  6. package/dist/src/commands/autocomplete.js +24 -0
  7. package/dist/src/commands/billing.js +53 -0
  8. package/dist/src/commands/chat.js +276 -0
  9. package/dist/src/commands/clusters.js +69 -0
  10. package/dist/src/commands/index.js +25 -0
  11. package/dist/src/commands/models.js +69 -0
  12. package/dist/src/commands/users.js +43 -0
  13. package/dist/src/constants/command-structure.js +14 -0
  14. package/dist/src/services/auth-service.js +49 -47
  15. package/dist/src/services/chat-service.js +177 -0
  16. package/dist/src/utils/config-checker.js +50 -0
  17. package/dist/src/utils/default-api-key.js +111 -0
  18. package/dist/src/utils/token-manager.js +165 -0
  19. package/index.ts +5 -566
  20. package/package.json +6 -1
  21. package/src/client.ts +262 -80
  22. package/src/commands/api-keys.ts +364 -0
  23. package/src/commands/auth.ts +58 -0
  24. package/src/commands/autocomplete.ts +19 -0
  25. package/src/commands/billing.ts +41 -0
  26. package/src/commands/chat.ts +345 -0
  27. package/src/commands/clusters.ts +65 -0
  28. package/src/commands/index.ts +23 -0
  29. package/src/commands/models.ts +63 -0
  30. package/src/commands/users.ts +37 -0
  31. package/src/constants/command-structure.ts +16 -0
  32. package/src/services/auth-service.ts +90 -50
  33. package/src/services/chat-service.ts +177 -0
  34. package/src/types/api.d.ts +58 -192
  35. package/src/utils/config-checker.ts +23 -0
  36. package/src/utils/default-api-key.ts +94 -0
  37. package/src/utils/token-manager.ts +150 -0
@@ -1,46 +1,27 @@
1
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 (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
24
10
  };
25
11
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
13
  };
28
14
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.createAuthenticatedClient = exports.clearAuthToken = exports.saveAuthToken = exports.isTokenExpired = exports.getAuthToken = exports.apiClient = void 0;
15
+ exports.createAuthenticatedClient = exports.clearAuthToken = exports.saveAuthToken = exports.getAuthToken = exports.apiClient = void 0;
30
16
  const openapi_fetch_1 = __importDefault(require("openapi-fetch"));
31
- const fs = __importStar(require("fs"));
32
- const path = __importStar(require("path"));
33
- const os = __importStar(require("os"));
34
17
  const chalk_1 = __importDefault(require("chalk"));
35
- // Configuration directory
36
- const CONFIG_DIR = path.join(os.homedir(), '.berget');
37
- const TOKEN_FILE = path.join(CONFIG_DIR, 'token.json');
18
+ const token_manager_1 = require("./utils/token-manager");
38
19
  // API Base URL
39
20
  // Use --local flag to test against local API
40
21
  const isLocalMode = process.argv.includes('--local');
41
22
  const API_BASE_URL = process.env.BERGET_API_URL ||
42
23
  (isLocalMode ? 'http://localhost:3000' : 'https://api.berget.ai');
43
- if (isLocalMode && !process.env.BERGET_API_URL) {
24
+ if (isLocalMode && !process.env.BERGET_API_URL && process.argv.includes('--debug')) {
44
25
  console.log(chalk_1.default.yellow('Using local API endpoint: http://localhost:3000'));
45
26
  }
46
27
  // Create a typed client for the Berget API
@@ -53,89 +34,32 @@ exports.apiClient = (0, openapi_fetch_1.default)({
53
34
  });
54
35
  // Authentication functions
55
36
  const getAuthToken = () => {
56
- try {
57
- if (fs.existsSync(TOKEN_FILE)) {
58
- const tokenData = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'));
59
- return tokenData.accessToken;
60
- }
61
- }
62
- catch (error) {
63
- console.error('Error reading auth token:', error);
64
- }
65
- return null;
37
+ const tokenManager = token_manager_1.TokenManager.getInstance();
38
+ return tokenManager.getAccessToken();
66
39
  };
67
40
  exports.getAuthToken = getAuthToken;
68
- // Check if token is expired (JWT tokens have an exp claim)
69
- const isTokenExpired = (token) => {
70
- try {
71
- const base64Url = token.split('.')[1];
72
- const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
73
- const jsonPayload = decodeURIComponent(atob(base64)
74
- .split('')
75
- .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
76
- .join(''));
77
- const payload = JSON.parse(jsonPayload);
78
- // Check if token has expired
79
- if (payload.exp) {
80
- return payload.exp * 1000 < Date.now();
81
- }
82
- }
83
- catch (error) {
84
- // If we can't decode the token, assume it's expired
85
- return true;
86
- }
87
- // If there's no exp claim, assume it's valid
88
- return false;
89
- };
90
- exports.isTokenExpired = isTokenExpired;
91
- const saveAuthToken = (token) => {
92
- try {
93
- if (!fs.existsSync(CONFIG_DIR)) {
94
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
95
- }
96
- fs.writeFileSync(TOKEN_FILE, JSON.stringify({ accessToken: token }), 'utf8');
97
- // Set file permissions to be readable only by the owner
98
- fs.chmodSync(TOKEN_FILE, 0o600);
99
- }
100
- catch (error) {
101
- console.error('Error saving auth token:', error);
102
- }
41
+ const saveAuthToken = (accessToken, refreshToken, expiresIn = 3600) => {
42
+ const tokenManager = token_manager_1.TokenManager.getInstance();
43
+ tokenManager.setTokens(accessToken, refreshToken, expiresIn);
103
44
  };
104
45
  exports.saveAuthToken = saveAuthToken;
105
46
  const clearAuthToken = () => {
106
- try {
107
- if (fs.existsSync(TOKEN_FILE)) {
108
- fs.unlinkSync(TOKEN_FILE);
109
- }
110
- }
111
- catch (error) {
112
- console.error('Error clearing auth token:', error);
113
- }
47
+ const tokenManager = token_manager_1.TokenManager.getInstance();
48
+ tokenManager.clearTokens();
114
49
  };
115
50
  exports.clearAuthToken = clearAuthToken;
116
- // Create an authenticated client
51
+ // Create an authenticated client with refresh token support
117
52
  const createAuthenticatedClient = () => {
118
- const token = (0, exports.getAuthToken)();
119
- if (!token) {
120
- console.warn(chalk_1.default.yellow('No authentication token found. Please run `berget login` first.'));
53
+ const tokenManager = token_manager_1.TokenManager.getInstance();
54
+ if (!tokenManager.getAccessToken() && process.argv.includes('--debug')) {
55
+ console.warn(chalk_1.default.yellow('No authentication token found. Please run `berget auth login` first.'));
121
56
  }
122
- else if ((0, exports.isTokenExpired)(token)) {
123
- console.warn(chalk_1.default.yellow('Your authentication token has expired. Please run `berget login` to get a new token.'));
124
- // Optionally clear the expired token
125
- (0, exports.clearAuthToken)();
126
- return (0, openapi_fetch_1.default)({
127
- baseUrl: API_BASE_URL,
128
- headers: {
129
- 'Content-Type': 'application/json',
130
- Accept: 'application/json',
131
- },
132
- });
133
- }
134
- return (0, openapi_fetch_1.default)({
57
+ // Create the base client
58
+ const client = (0, openapi_fetch_1.default)({
135
59
  baseUrl: API_BASE_URL,
136
- headers: token
60
+ headers: tokenManager.getAccessToken()
137
61
  ? {
138
- Authorization: `Bearer ${token}`,
62
+ Authorization: `Bearer ${tokenManager.getAccessToken()}`,
139
63
  'Content-Type': 'application/json',
140
64
  Accept: 'application/json',
141
65
  }
@@ -144,5 +68,172 @@ const createAuthenticatedClient = () => {
144
68
  Accept: 'application/json',
145
69
  },
146
70
  });
71
+ // Wrap the client to handle token refresh
72
+ return new Proxy(client, {
73
+ get(target, prop) {
74
+ // For HTTP methods (GET, POST, etc.), add token refresh logic
75
+ if (typeof target[prop] === 'function' &&
76
+ ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(String(prop))) {
77
+ return (...args) => __awaiter(this, void 0, void 0, function* () {
78
+ var _a, _b;
79
+ // Check if token is expired before making the request
80
+ if (tokenManager.isTokenExpired() && tokenManager.getRefreshToken()) {
81
+ yield refreshAccessToken(tokenManager);
82
+ }
83
+ // Update the Authorization header with the current token
84
+ if (tokenManager.getAccessToken()) {
85
+ if (!args[1])
86
+ args[1] = {};
87
+ if (!args[1].headers)
88
+ args[1].headers = {};
89
+ args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
90
+ }
91
+ // Make the original request
92
+ let result;
93
+ try {
94
+ result = yield target[prop](...args);
95
+ }
96
+ catch (requestError) {
97
+ if (process.argv.includes('--debug')) {
98
+ console.log(chalk_1.default.red(`DEBUG: Request error: ${requestError instanceof Error
99
+ ? requestError.message
100
+ : String(requestError)}`));
101
+ }
102
+ return {
103
+ error: {
104
+ message: `Request failed: ${requestError instanceof Error
105
+ ? requestError.message
106
+ : String(requestError)}`,
107
+ },
108
+ };
109
+ }
110
+ // If we get an auth error, try to refresh the token and retry
111
+ if (result.error) {
112
+ // Detect various forms of authentication errors
113
+ const isAuthError =
114
+ // Standard 401 Unauthorized
115
+ (typeof result.error === 'object' && result.error.status === 401) ||
116
+ // OAuth specific errors
117
+ (result.error.error &&
118
+ (result.error.error.code === 'invalid_token' ||
119
+ result.error.error.code === 'token_expired' ||
120
+ result.error.error.message === 'Invalid API key' ||
121
+ ((_a = result.error.error.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('token')) ||
122
+ ((_b = result.error.error.message) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('unauthorized')))) ||
123
+ // Message-based detection as fallback
124
+ (typeof result.error === 'string' &&
125
+ (result.error.toLowerCase().includes('unauthorized') ||
126
+ result.error.toLowerCase().includes('token') ||
127
+ result.error.toLowerCase().includes('auth')));
128
+ if (isAuthError && tokenManager.getRefreshToken()) {
129
+ if (process.argv.includes('--debug')) {
130
+ console.log(chalk_1.default.yellow('DEBUG: Auth error detected, attempting token refresh'));
131
+ console.log(chalk_1.default.yellow(`DEBUG: Error details: ${JSON.stringify(result.error, null, 2)}`));
132
+ }
133
+ const refreshed = yield refreshAccessToken(tokenManager);
134
+ if (refreshed) {
135
+ if (process.argv.includes('--debug')) {
136
+ console.log(chalk_1.default.green('DEBUG: Token refreshed successfully, retrying request'));
137
+ }
138
+ // Update the Authorization header with the new token
139
+ if (!args[1])
140
+ args[1] = {};
141
+ if (!args[1].headers)
142
+ args[1].headers = {};
143
+ args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
144
+ // Retry the request
145
+ return yield target[prop](...args);
146
+ }
147
+ else {
148
+ if (process.argv.includes('--debug')) {
149
+ console.log(chalk_1.default.red('DEBUG: Token refresh failed'));
150
+ }
151
+ // Add a more helpful error message for users
152
+ if (typeof result.error === 'object') {
153
+ result.error.userMessage = 'Your session has expired. Please run `berget auth login` to log in again.';
154
+ }
155
+ }
156
+ }
157
+ }
158
+ return result;
159
+ });
160
+ }
161
+ // For other properties, just return the original
162
+ return target[prop];
163
+ },
164
+ });
147
165
  };
148
166
  exports.createAuthenticatedClient = createAuthenticatedClient;
167
+ // Helper function to refresh the access token
168
+ function refreshAccessToken(tokenManager) {
169
+ return __awaiter(this, void 0, void 0, function* () {
170
+ try {
171
+ const refreshToken = tokenManager.getRefreshToken();
172
+ if (!refreshToken)
173
+ return false;
174
+ if (process.argv.includes('--debug')) {
175
+ console.log(chalk_1.default.yellow('DEBUG: Attempting to refresh access token'));
176
+ }
177
+ // Use fetch directly since this endpoint might not be in the OpenAPI spec
178
+ try {
179
+ const response = yield fetch(`${API_BASE_URL}/v1/auth/refresh`, {
180
+ method: 'POST',
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ Accept: 'application/json',
184
+ },
185
+ body: JSON.stringify({ refresh_token: refreshToken }),
186
+ });
187
+ // Handle HTTP errors
188
+ if (!response.ok) {
189
+ if (process.argv.includes('--debug')) {
190
+ console.log(chalk_1.default.yellow(`DEBUG: Token refresh error: HTTP ${response.status} ${response.statusText}`));
191
+ }
192
+ // Check if the refresh token itself is expired or invalid
193
+ if (response.status === 401 || response.status === 403) {
194
+ console.warn(chalk_1.default.yellow('Your refresh token has expired. Please run `berget auth login` again.'));
195
+ // Clear tokens if unauthorized - they're invalid
196
+ tokenManager.clearTokens();
197
+ }
198
+ else {
199
+ console.warn(chalk_1.default.yellow(`Failed to refresh token: ${response.status} ${response.statusText}`));
200
+ }
201
+ return false;
202
+ }
203
+ // Parse the response
204
+ const contentType = response.headers.get('content-type');
205
+ if (!contentType || !contentType.includes('application/json')) {
206
+ console.warn(chalk_1.default.yellow(`Unexpected content type in response: ${contentType}`));
207
+ return false;
208
+ }
209
+ const data = yield response.json();
210
+ // Validate the response data
211
+ if (!data || !data.token) {
212
+ console.warn(chalk_1.default.yellow('Invalid token response. Please run `berget auth login` again.'));
213
+ return false;
214
+ }
215
+ if (process.argv.includes('--debug')) {
216
+ console.log(chalk_1.default.green('DEBUG: Token refreshed successfully'));
217
+ }
218
+ // Update the token
219
+ tokenManager.updateAccessToken(data.token, data.expires_in || 3600);
220
+ // If a new refresh token was provided, update that too
221
+ if (data.refresh_token) {
222
+ tokenManager.setTokens(data.token, data.refresh_token, data.expires_in || 3600);
223
+ if (process.argv.includes('--debug')) {
224
+ console.log(chalk_1.default.green('DEBUG: Refresh token also updated'));
225
+ }
226
+ }
227
+ }
228
+ catch (fetchError) {
229
+ console.warn(chalk_1.default.yellow(`Failed to refresh token: ${fetchError instanceof Error ? fetchError.message : String(fetchError)}`));
230
+ return false;
231
+ }
232
+ return true;
233
+ }
234
+ catch (error) {
235
+ console.warn(chalk_1.default.yellow(`Failed to refresh authentication token: ${error instanceof Error ? error.message : String(error)}`));
236
+ return false;
237
+ }
238
+ });
239
+ }
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.registerApiKeyCommands = void 0;
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ const api_key_service_1 = require("../services/api-key-service");
18
+ const error_handler_1 = require("../utils/error-handler");
19
+ const default_api_key_1 = require("../utils/default-api-key");
20
+ /**
21
+ * Register API key commands
22
+ */
23
+ function registerApiKeyCommands(program) {
24
+ const apiKey = program
25
+ .command(api_key_service_1.ApiKeyService.COMMAND_GROUP)
26
+ .description('Manage API keys');
27
+ apiKey
28
+ .command(api_key_service_1.ApiKeyService.COMMANDS.LIST)
29
+ .description('List all API keys')
30
+ .action(() => __awaiter(this, void 0, void 0, function* () {
31
+ try {
32
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
33
+ const keys = yield apiKeyService.list();
34
+ if (keys.length === 0) {
35
+ console.log(chalk_1.default.yellow('No API keys found. Create one with `berget api-key create --name <name>`'));
36
+ return;
37
+ }
38
+ console.log(chalk_1.default.bold('Your API keys:'));
39
+ console.log('');
40
+ // Create a table-like format with headers
41
+ console.log(chalk_1.default.dim('ID'.padEnd(10)) +
42
+ chalk_1.default.dim('NAME'.padEnd(25)) +
43
+ chalk_1.default.dim('PREFIX'.padEnd(12)) +
44
+ chalk_1.default.dim('STATUS'.padEnd(12)) +
45
+ chalk_1.default.dim('CREATED'.padEnd(12)) +
46
+ chalk_1.default.dim('LAST USED'));
47
+ console.log(chalk_1.default.dim('─'.repeat(85)));
48
+ keys.forEach((key) => {
49
+ const lastUsed = key.lastUsed ? key.lastUsed.substring(0, 10) : 'Never';
50
+ const status = key.active
51
+ ? chalk_1.default.green('● Active')
52
+ : chalk_1.default.red('● Inactive');
53
+ console.log(String(key.id).padEnd(10) +
54
+ key.name.padEnd(25) +
55
+ key.prefix.padEnd(12) +
56
+ status.padEnd(12) +
57
+ key.created.substring(0, 10).padEnd(12) +
58
+ lastUsed);
59
+ });
60
+ console.log('');
61
+ console.log(chalk_1.default.dim('Use `berget api-key create --name <name>` to create a new API key'));
62
+ console.log(chalk_1.default.dim('Use `berget api-key delete <id>` to delete an API key'));
63
+ console.log(chalk_1.default.dim('Use `berget api-key rotate <id>` to rotate an API key'));
64
+ }
65
+ catch (error) {
66
+ (0, error_handler_1.handleError)('Failed to list API keys', error);
67
+ }
68
+ }));
69
+ apiKey
70
+ .command(api_key_service_1.ApiKeyService.COMMANDS.CREATE)
71
+ .description('Create a new API key')
72
+ .option('--name <name>', 'Name of the API key')
73
+ .option('--description <description>', 'Description of the API key')
74
+ .action((options) => __awaiter(this, void 0, void 0, function* () {
75
+ try {
76
+ if (!options.name) {
77
+ console.error(chalk_1.default.red('Error: --name is required'));
78
+ console.log('');
79
+ console.log('Usage: berget api-key create --name <name> [--description <description>]');
80
+ return;
81
+ }
82
+ console.log(chalk_1.default.blue('Creating API key...'));
83
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
84
+ const result = yield apiKeyService.create({
85
+ name: options.name,
86
+ description: options.description,
87
+ });
88
+ console.log('');
89
+ console.log(chalk_1.default.green('✓ API key created'));
90
+ console.log('');
91
+ console.log(chalk_1.default.bold('API key details:'));
92
+ console.log('');
93
+ console.log(`${chalk_1.default.dim('ID:')} ${result.id}`);
94
+ console.log(`${chalk_1.default.dim('Name:')} ${result.name}`);
95
+ if (result.description) {
96
+ console.log(`${chalk_1.default.dim('Description:')} ${result.description}`);
97
+ }
98
+ console.log(`${chalk_1.default.dim('Created:')} ${new Date(result.created).toLocaleString()}`);
99
+ console.log('');
100
+ console.log(chalk_1.default.bold('API key:'));
101
+ console.log(chalk_1.default.cyan(result.key));
102
+ console.log('');
103
+ console.log(chalk_1.default.yellow('⚠️ IMPORTANT: Save this API key in a secure location.'));
104
+ console.log(chalk_1.default.yellow(' It will not be displayed again.'));
105
+ console.log('');
106
+ console.log(chalk_1.default.dim('Use this key in your applications to authenticate with the Berget API.'));
107
+ }
108
+ catch (error) {
109
+ (0, error_handler_1.handleError)('Failed to create API key', error);
110
+ }
111
+ }));
112
+ apiKey
113
+ .command(api_key_service_1.ApiKeyService.COMMANDS.DELETE)
114
+ .description('Delete an API key')
115
+ .argument('<id>', 'ID of the API key to delete')
116
+ .action((id) => __awaiter(this, void 0, void 0, function* () {
117
+ try {
118
+ console.log(chalk_1.default.blue(`Deleting API key ${id}...`));
119
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
120
+ yield apiKeyService.delete(id);
121
+ console.log(chalk_1.default.green(`✓ API key ${id} has been deleted`));
122
+ console.log('');
123
+ console.log(chalk_1.default.dim('Applications using this key will no longer be able to authenticate.'));
124
+ console.log(chalk_1.default.dim('Use `berget api-key list` to see your remaining API keys.'));
125
+ }
126
+ catch (error) {
127
+ (0, error_handler_1.handleError)('Failed to delete API key', error);
128
+ }
129
+ }));
130
+ apiKey
131
+ .command(api_key_service_1.ApiKeyService.COMMANDS.ROTATE)
132
+ .description('Rotate an API key (creates a new one and invalidates the old one)')
133
+ .argument('<id>', 'ID of the API key to rotate')
134
+ .action((id) => __awaiter(this, void 0, void 0, function* () {
135
+ try {
136
+ console.log(chalk_1.default.blue(`Rotating API key ${id}...`));
137
+ console.log(chalk_1.default.dim('This will invalidate the old key and generate a new one.'));
138
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
139
+ const result = yield apiKeyService.rotate(id);
140
+ console.log('');
141
+ console.log(chalk_1.default.green('✓ API key rotated'));
142
+ console.log('');
143
+ console.log(chalk_1.default.bold('New API key details:'));
144
+ console.log('');
145
+ console.log(`${chalk_1.default.dim('ID:')} ${result.id}`);
146
+ console.log(`${chalk_1.default.dim('Name:')} ${result.name}`);
147
+ if (result.description) {
148
+ console.log(`${chalk_1.default.dim('Description:')} ${result.description}`);
149
+ }
150
+ console.log(`${chalk_1.default.dim('Created:')} ${new Date(result.created).toLocaleString()}`);
151
+ console.log('');
152
+ console.log(chalk_1.default.bold('New API key:'));
153
+ console.log(chalk_1.default.cyan(result.key));
154
+ console.log('');
155
+ console.log(chalk_1.default.yellow('⚠️ IMPORTANT: Update your applications with this new API key.'));
156
+ console.log(chalk_1.default.yellow(' The old key has been invalidated and will no longer work.'));
157
+ console.log(chalk_1.default.yellow(' This new key will not be displayed again.'));
158
+ }
159
+ catch (error) {
160
+ (0, error_handler_1.handleError)('Failed to rotate API key', error);
161
+ }
162
+ }));
163
+ apiKey
164
+ .command(api_key_service_1.ApiKeyService.COMMANDS.DESCRIBE)
165
+ .description('Show usage statistics for an API key')
166
+ .argument('<id>', 'ID of the API key')
167
+ .option('--start <date>', 'Start date (YYYY-MM-DD)')
168
+ .option('--end <date>', 'End date (YYYY-MM-DD)')
169
+ .action((id, options) => __awaiter(this, void 0, void 0, function* () {
170
+ try {
171
+ console.log(chalk_1.default.blue(`Fetching usage statistics for API key ${id}...`));
172
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
173
+ const usage = yield apiKeyService.describe(id);
174
+ console.log('');
175
+ console.log(chalk_1.default.bold(`Usage statistics for API key: ${usage.name} (${id})`));
176
+ console.log('');
177
+ // Period information
178
+ console.log(chalk_1.default.dim(`Period: ${usage.period.start} to ${usage.period.end}`));
179
+ console.log('');
180
+ // Request statistics
181
+ console.log(chalk_1.default.bold('Request statistics:'));
182
+ console.log(`Total requests: ${chalk_1.default.cyan(usage.requests.total.toLocaleString())}`);
183
+ // Daily breakdown if available
184
+ if (usage.requests.daily && usage.requests.daily.length > 0) {
185
+ console.log('');
186
+ console.log(chalk_1.default.bold('Daily breakdown:'));
187
+ console.log(chalk_1.default.dim('─'.repeat(30)));
188
+ console.log(chalk_1.default.dim('DATE'.padEnd(12) + 'REQUESTS'));
189
+ usage.requests.daily.forEach((day) => {
190
+ console.log(`${day.date.padEnd(12)}${day.count.toLocaleString()}`);
191
+ });
192
+ }
193
+ // Model usage if available
194
+ if (usage.models && usage.models.length > 0) {
195
+ console.log('');
196
+ console.log(chalk_1.default.bold('Model usage:'));
197
+ console.log(chalk_1.default.dim('─'.repeat(70)));
198
+ console.log(chalk_1.default.dim('MODEL'.padEnd(20)) +
199
+ chalk_1.default.dim('REQUESTS'.padEnd(10)) +
200
+ chalk_1.default.dim('INPUT'.padEnd(12)) +
201
+ chalk_1.default.dim('OUTPUT'.padEnd(12)) +
202
+ chalk_1.default.dim('TOTAL TOKENS'));
203
+ usage.models.forEach((model) => {
204
+ console.log(model.name.padEnd(20) +
205
+ model.requests.toString().padEnd(10) +
206
+ model.tokens.input.toLocaleString().padEnd(12) +
207
+ model.tokens.output.toLocaleString().padEnd(12) +
208
+ model.tokens.total.toLocaleString());
209
+ });
210
+ }
211
+ console.log('');
212
+ console.log(chalk_1.default.dim('Use these statistics to understand your API usage and optimize your costs.'));
213
+ }
214
+ catch (error) {
215
+ (0, error_handler_1.handleError)('Failed to get API key usage', error);
216
+ }
217
+ }));
218
+ apiKey
219
+ .command(api_key_service_1.ApiKeyService.COMMANDS.SET_DEFAULT)
220
+ .description('Set an API key as the default for chat commands')
221
+ .argument('<id>', 'ID of the API key to set as default')
222
+ .action((id) => __awaiter(this, void 0, void 0, function* () {
223
+ try {
224
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
225
+ const keys = yield apiKeyService.list();
226
+ const selectedKey = keys.find(key => key.id.toString() === id);
227
+ if (!selectedKey) {
228
+ console.error(chalk_1.default.red(`Error: API key with ID ${id} not found`));
229
+ return;
230
+ }
231
+ // Save the default API key
232
+ const defaultApiKeyManager = default_api_key_1.DefaultApiKeyManager.getInstance();
233
+ defaultApiKeyManager.setDefaultApiKey(id, selectedKey.name, selectedKey.prefix);
234
+ console.log(chalk_1.default.green(`✓ API key "${selectedKey.name}" set as default for chat commands`));
235
+ console.log('');
236
+ console.log(chalk_1.default.dim('This API key will be used by default when running chat commands'));
237
+ console.log(chalk_1.default.dim('You can override it with --api-key or --api-key-id options'));
238
+ }
239
+ catch (error) {
240
+ (0, error_handler_1.handleError)('Failed to set default API key', error);
241
+ }
242
+ }));
243
+ apiKey
244
+ .command(api_key_service_1.ApiKeyService.COMMANDS.GET_DEFAULT)
245
+ .description('Show the current default API key')
246
+ .action(() => {
247
+ try {
248
+ const defaultApiKeyManager = default_api_key_1.DefaultApiKeyManager.getInstance();
249
+ const defaultApiKey = defaultApiKeyManager.getDefaultApiKey();
250
+ if (!defaultApiKey) {
251
+ console.log(chalk_1.default.yellow('No default API key set'));
252
+ console.log('');
253
+ console.log('To set a default API key, run:');
254
+ console.log(chalk_1.default.cyan(' berget api-keys set-default <id>'));
255
+ return;
256
+ }
257
+ console.log(chalk_1.default.bold('Default API key:'));
258
+ console.log('');
259
+ console.log(`${chalk_1.default.dim('ID:')} ${defaultApiKey.id}`);
260
+ console.log(`${chalk_1.default.dim('Name:')} ${defaultApiKey.name}`);
261
+ console.log(`${chalk_1.default.dim('Prefix:')} ${defaultApiKey.prefix}`);
262
+ console.log('');
263
+ console.log(chalk_1.default.dim('This API key will be used by default when running chat commands'));
264
+ console.log(chalk_1.default.dim('You can override it with --api-key or --api-key-id options'));
265
+ }
266
+ catch (error) {
267
+ (0, error_handler_1.handleError)('Failed to get default API key', error);
268
+ }
269
+ });
270
+ }
271
+ exports.registerApiKeyCommands = registerApiKeyCommands;