berget 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +92 -0
  2. package/dist/index.js +49 -467
  3. package/dist/package.json +35 -0
  4. package/dist/src/client.js +210 -102
  5. package/dist/src/commands/api-keys.js +277 -0
  6. package/dist/src/commands/auth.js +65 -0
  7. package/dist/src/commands/autocomplete.js +24 -0
  8. package/dist/src/commands/billing.js +53 -0
  9. package/dist/src/commands/chat.js +342 -0
  10. package/dist/src/commands/clusters.js +69 -0
  11. package/dist/src/commands/index.js +25 -0
  12. package/dist/src/commands/models.js +69 -0
  13. package/dist/src/commands/users.js +43 -0
  14. package/dist/src/constants/command-structure.js +14 -0
  15. package/dist/src/services/api-key-service.js +6 -16
  16. package/dist/src/services/auth-service.js +49 -47
  17. package/dist/src/services/chat-service.js +300 -0
  18. package/dist/src/utils/config-checker.js +50 -0
  19. package/dist/src/utils/default-api-key.js +237 -0
  20. package/dist/src/utils/error-handler.js +4 -4
  21. package/dist/src/utils/token-manager.js +165 -0
  22. package/index.ts +56 -566
  23. package/package.json +8 -2
  24. package/src/client.ts +279 -80
  25. package/src/commands/api-keys.ts +374 -0
  26. package/src/commands/auth.ts +58 -0
  27. package/src/commands/autocomplete.ts +19 -0
  28. package/src/commands/billing.ts +41 -0
  29. package/src/commands/chat.ts +445 -0
  30. package/src/commands/clusters.ts +65 -0
  31. package/src/commands/index.ts +23 -0
  32. package/src/commands/models.ts +63 -0
  33. package/src/commands/users.ts +37 -0
  34. package/src/constants/command-structure.ts +16 -0
  35. package/src/services/api-key-service.ts +12 -20
  36. package/src/services/auth-service.ts +90 -50
  37. package/src/services/chat-service.ts +295 -0
  38. package/src/types/api.d.ts +238 -178
  39. package/src/types/json.d.ts +4 -0
  40. package/src/utils/config-checker.ts +23 -0
  41. package/src/utils/default-api-key.ts +229 -0
  42. package/src/utils/error-handler.ts +4 -4
  43. package/src/utils/token-manager.ts +150 -0
  44. package/tsconfig.json +1 -1
@@ -0,0 +1,237 @@
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;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.DefaultApiKeyManager = void 0;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const os = __importStar(require("os"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const api_key_service_1 = require("../services/api-key-service");
44
+ const readline_1 = __importDefault(require("readline"));
45
+ /**
46
+ * Manages the default API key for chat commands
47
+ */
48
+ class DefaultApiKeyManager {
49
+ constructor() {
50
+ this.defaultApiKey = null;
51
+ // Set up config file path in user's home directory
52
+ const bergetDir = path.join(os.homedir(), '.berget');
53
+ if (!fs.existsSync(bergetDir)) {
54
+ fs.mkdirSync(bergetDir, { recursive: true });
55
+ }
56
+ this.configFilePath = path.join(bergetDir, 'default-api-key.json');
57
+ this.loadConfig();
58
+ }
59
+ static getInstance() {
60
+ if (!DefaultApiKeyManager.instance) {
61
+ DefaultApiKeyManager.instance = new DefaultApiKeyManager();
62
+ }
63
+ return DefaultApiKeyManager.instance;
64
+ }
65
+ /**
66
+ * Load default API key from file
67
+ */
68
+ loadConfig() {
69
+ try {
70
+ if (fs.existsSync(this.configFilePath)) {
71
+ const data = fs.readFileSync(this.configFilePath, 'utf8');
72
+ this.defaultApiKey = JSON.parse(data);
73
+ }
74
+ }
75
+ catch (error) {
76
+ if (process.argv.includes('--debug')) {
77
+ console.error(chalk_1.default.dim('Failed to load default API key configuration'));
78
+ }
79
+ this.defaultApiKey = null;
80
+ }
81
+ }
82
+ /**
83
+ * Save default API key to file
84
+ */
85
+ saveConfig() {
86
+ try {
87
+ if (this.defaultApiKey) {
88
+ fs.writeFileSync(this.configFilePath, JSON.stringify(this.defaultApiKey, null, 2));
89
+ // Set file permissions to be readable only by the owner
90
+ fs.chmodSync(this.configFilePath, 0o600);
91
+ }
92
+ else {
93
+ // If default API key is null, remove the file
94
+ if (fs.existsSync(this.configFilePath)) {
95
+ fs.unlinkSync(this.configFilePath);
96
+ }
97
+ }
98
+ }
99
+ catch (error) {
100
+ if (process.argv.includes('--debug')) {
101
+ console.error(chalk_1.default.dim('Failed to save default API key configuration'));
102
+ }
103
+ }
104
+ }
105
+ /**
106
+ * Set the default API key
107
+ */
108
+ setDefaultApiKey(id, name, prefix, key) {
109
+ this.defaultApiKey = { id, name, prefix, key };
110
+ this.saveConfig();
111
+ }
112
+ /**
113
+ * Get the default API key string
114
+ */
115
+ getDefaultApiKey() {
116
+ var _a;
117
+ return ((_a = this.defaultApiKey) === null || _a === void 0 ? void 0 : _a.key) || null;
118
+ }
119
+ /**
120
+ * Get the default API key data object
121
+ */
122
+ getDefaultApiKeyData() {
123
+ return this.defaultApiKey;
124
+ }
125
+ /**
126
+ * Clear the default API key
127
+ */
128
+ clearDefaultApiKey() {
129
+ this.defaultApiKey = null;
130
+ this.saveConfig();
131
+ }
132
+ /**
133
+ * Prompts the user to select a default API key if none is set
134
+ * @returns The selected API key or null if none was selected
135
+ */
136
+ promptForDefaultApiKey() {
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ try {
139
+ const isDebug = process.argv.includes('--debug');
140
+ if (isDebug) {
141
+ console.log(chalk_1.default.yellow('DEBUG: promptForDefaultApiKey called'));
142
+ }
143
+ // If we already have a default API key, return it
144
+ if (this.defaultApiKey) {
145
+ if (isDebug) {
146
+ console.log(chalk_1.default.yellow('DEBUG: Using existing default API key'));
147
+ }
148
+ return this.defaultApiKey.key;
149
+ }
150
+ if (isDebug) {
151
+ console.log(chalk_1.default.yellow('DEBUG: No default API key found, getting ApiKeyService'));
152
+ }
153
+ const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
154
+ // Get all API keys
155
+ let apiKeys;
156
+ try {
157
+ if (isDebug) {
158
+ console.log(chalk_1.default.yellow('DEBUG: Calling apiKeyService.list()'));
159
+ }
160
+ apiKeys = yield apiKeyService.list();
161
+ if (isDebug) {
162
+ console.log(chalk_1.default.yellow(`DEBUG: Got ${apiKeys ? apiKeys.length : 0} API keys`));
163
+ }
164
+ if (!apiKeys || apiKeys.length === 0) {
165
+ console.log(chalk_1.default.yellow('No API keys found. Create one with:'));
166
+ console.log(chalk_1.default.blue(' berget api-keys create --name "My Key"'));
167
+ return null;
168
+ }
169
+ }
170
+ catch (error) {
171
+ // Check if this is an authentication error
172
+ const errorMessage = error instanceof Error ? error.message : String(error);
173
+ const isAuthError = errorMessage.includes('Unauthorized') ||
174
+ errorMessage.includes('Authentication failed') ||
175
+ errorMessage.includes('AUTH_FAILED');
176
+ if (isAuthError) {
177
+ console.log(chalk_1.default.yellow('Authentication required. Please run `berget auth login` first.'));
178
+ }
179
+ else {
180
+ console.log(chalk_1.default.red('Error fetching API keys:'));
181
+ if (error instanceof Error) {
182
+ console.log(chalk_1.default.red(error.message));
183
+ if (isDebug) {
184
+ console.log(chalk_1.default.yellow(`DEBUG: API key list error: ${error.message}`));
185
+ console.log(chalk_1.default.yellow(`DEBUG: Stack: ${error.stack}`));
186
+ }
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+ console.log(chalk_1.default.blue('Select an API key to use as default:'));
192
+ // Display available API keys
193
+ apiKeys.forEach((key, index) => {
194
+ console.log(` ${index + 1}. ${key.name} (${key.prefix}...)`);
195
+ });
196
+ // Create readline interface for user input
197
+ const rl = readline_1.default.createInterface({
198
+ input: process.stdin,
199
+ output: process.stdout
200
+ });
201
+ // Prompt for selection
202
+ const selection = yield new Promise((resolve) => {
203
+ rl.question('Enter number (or press Enter to cancel): ', (answer) => {
204
+ rl.close();
205
+ const num = parseInt(answer.trim(), 10);
206
+ if (isNaN(num) || num < 1 || num > apiKeys.length) {
207
+ resolve(-1); // Invalid selection
208
+ }
209
+ else {
210
+ resolve(num - 1); // Convert to zero-based index
211
+ }
212
+ });
213
+ });
214
+ if (selection === -1) {
215
+ console.log(chalk_1.default.yellow('No API key selected'));
216
+ return null;
217
+ }
218
+ const selectedKey = apiKeys[selection];
219
+ // Create a new API key with the selected name
220
+ const newKey = yield apiKeyService.create({
221
+ name: `CLI Default (copy of ${selectedKey.name})`,
222
+ description: 'Created automatically by the Berget CLI for default use'
223
+ });
224
+ // Save the new key as default
225
+ this.setDefaultApiKey(newKey.id.toString(), newKey.name, newKey.key.substring(0, 8), // Use first 8 chars as prefix
226
+ newKey.key);
227
+ console.log(chalk_1.default.green(`✓ Default API key set to: ${newKey.name}`));
228
+ return newKey.key;
229
+ }
230
+ catch (error) {
231
+ console.error(chalk_1.default.red('Failed to set default API key:'), error);
232
+ return null;
233
+ }
234
+ });
235
+ }
236
+ }
237
+ exports.DefaultApiKeyManager = DefaultApiKeyManager;
@@ -35,11 +35,11 @@ function handleError(message, error) {
35
35
  console.error(chalk_1.default.dim(`Details: ${error.message}`));
36
36
  }
37
37
  // Check for authentication errors
38
- if ((typeof error === 'string' && error.includes('Unauthorized')) ||
39
- (error && error.message && error.message.includes('Unauthorized')) ||
40
- (error && error.code && error.code === 401)) {
38
+ if ((typeof error === 'string' && (error.includes('Unauthorized') || error.includes('Authentication failed'))) ||
39
+ (error && error.message && (error.message.includes('Unauthorized') || error.message.includes('Authentication failed'))) ||
40
+ (error && error.code && (error.code === 401 || error.code === 'AUTH_FAILED'))) {
41
41
  console.error(chalk_1.default.yellow('\nYou need to be logged in to use this command.'));
42
- console.error(chalk_1.default.yellow('Run `berget login` to authenticate.'));
42
+ console.error(chalk_1.default.yellow('Run `berget auth login` to authenticate.'));
43
43
  }
44
44
  }
45
45
  exports.handleError = handleError;
@@ -0,0 +1,165 @@
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;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.TokenManager = void 0;
30
+ const fs = __importStar(require("fs"));
31
+ const path = __importStar(require("path"));
32
+ const os = __importStar(require("os"));
33
+ const chalk_1 = __importDefault(require("chalk"));
34
+ /**
35
+ * Manages authentication tokens including refresh functionality
36
+ */
37
+ class TokenManager {
38
+ constructor() {
39
+ this.tokenData = null;
40
+ // Set up token file path in user's home directory
41
+ const bergetDir = path.join(os.homedir(), '.berget');
42
+ if (!fs.existsSync(bergetDir)) {
43
+ fs.mkdirSync(bergetDir, { recursive: true });
44
+ }
45
+ this.tokenFilePath = path.join(bergetDir, 'auth.json');
46
+ this.loadToken();
47
+ }
48
+ static getInstance() {
49
+ if (!TokenManager.instance) {
50
+ TokenManager.instance = new TokenManager();
51
+ }
52
+ return TokenManager.instance;
53
+ }
54
+ /**
55
+ * Load token data from file
56
+ */
57
+ loadToken() {
58
+ try {
59
+ if (fs.existsSync(this.tokenFilePath)) {
60
+ const data = fs.readFileSync(this.tokenFilePath, 'utf8');
61
+ this.tokenData = JSON.parse(data);
62
+ }
63
+ }
64
+ catch (error) {
65
+ console.error(chalk_1.default.dim('Failed to load authentication token'));
66
+ this.tokenData = null;
67
+ }
68
+ }
69
+ /**
70
+ * Save token data to file
71
+ */
72
+ saveToken() {
73
+ try {
74
+ if (this.tokenData) {
75
+ fs.writeFileSync(this.tokenFilePath, JSON.stringify(this.tokenData, null, 2));
76
+ // Set file permissions to be readable only by the owner
77
+ fs.chmodSync(this.tokenFilePath, 0o600);
78
+ }
79
+ else {
80
+ // If token data is null, remove the file
81
+ if (fs.existsSync(this.tokenFilePath)) {
82
+ fs.unlinkSync(this.tokenFilePath);
83
+ }
84
+ }
85
+ }
86
+ catch (error) {
87
+ console.error(chalk_1.default.dim('Failed to save authentication token'));
88
+ }
89
+ }
90
+ /**
91
+ * Get the current access token
92
+ * @returns The access token or null if not available
93
+ */
94
+ getAccessToken() {
95
+ if (!this.tokenData)
96
+ return null;
97
+ return this.tokenData.access_token;
98
+ }
99
+ /**
100
+ * Get the refresh token
101
+ * @returns The refresh token or null if not available
102
+ */
103
+ getRefreshToken() {
104
+ if (!this.tokenData)
105
+ return null;
106
+ return this.tokenData.refresh_token;
107
+ }
108
+ /**
109
+ * Check if the access token is expired
110
+ * @returns true if expired or about to expire (within 5 minutes), false otherwise
111
+ */
112
+ isTokenExpired() {
113
+ if (!this.tokenData || !this.tokenData.expires_at)
114
+ return true;
115
+ try {
116
+ // Consider token expired if it's within 10 minutes of expiration
117
+ // Using a larger buffer to be more proactive about refreshing
118
+ const expirationBuffer = 10 * 60 * 1000; // 10 minutes in milliseconds
119
+ const isExpired = Date.now() + expirationBuffer >= this.tokenData.expires_at;
120
+ if (isExpired && process.argv.includes('--debug')) {
121
+ console.log(chalk_1.default.yellow(`DEBUG: Token expired or expiring soon. Current time: ${new Date().toISOString()}, Expiry: ${new Date(this.tokenData.expires_at).toISOString()}`));
122
+ }
123
+ return isExpired;
124
+ }
125
+ catch (error) {
126
+ // If there's any error checking expiration, assume token is expired
127
+ console.error(chalk_1.default.dim(`Error checking token expiration: ${error instanceof Error ? error.message : String(error)}`));
128
+ return true;
129
+ }
130
+ }
131
+ /**
132
+ * Set new token data
133
+ * @param accessToken The new access token
134
+ * @param refreshToken The new refresh token
135
+ * @param expiresIn Expiration time in seconds
136
+ */
137
+ setTokens(accessToken, refreshToken, expiresIn) {
138
+ this.tokenData = {
139
+ access_token: accessToken,
140
+ refresh_token: refreshToken,
141
+ expires_at: Date.now() + (expiresIn * 1000)
142
+ };
143
+ this.saveToken();
144
+ }
145
+ /**
146
+ * Update just the access token and its expiration
147
+ * @param accessToken The new access token
148
+ * @param expiresIn Expiration time in seconds
149
+ */
150
+ updateAccessToken(accessToken, expiresIn) {
151
+ if (!this.tokenData)
152
+ return;
153
+ this.tokenData.access_token = accessToken;
154
+ this.tokenData.expires_at = Date.now() + (expiresIn * 1000);
155
+ this.saveToken();
156
+ }
157
+ /**
158
+ * Clear all token data
159
+ */
160
+ clearTokens() {
161
+ this.tokenData = null;
162
+ this.saveToken();
163
+ }
164
+ }
165
+ exports.TokenManager = TokenManager;