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.
- package/README.md +92 -0
- package/dist/index.js +49 -467
- package/dist/package.json +35 -0
- package/dist/src/client.js +210 -102
- package/dist/src/commands/api-keys.js +277 -0
- package/dist/src/commands/auth.js +65 -0
- package/dist/src/commands/autocomplete.js +24 -0
- package/dist/src/commands/billing.js +53 -0
- package/dist/src/commands/chat.js +342 -0
- package/dist/src/commands/clusters.js +69 -0
- package/dist/src/commands/index.js +25 -0
- package/dist/src/commands/models.js +69 -0
- package/dist/src/commands/users.js +43 -0
- package/dist/src/constants/command-structure.js +14 -0
- package/dist/src/services/api-key-service.js +6 -16
- package/dist/src/services/auth-service.js +49 -47
- package/dist/src/services/chat-service.js +300 -0
- package/dist/src/utils/config-checker.js +50 -0
- package/dist/src/utils/default-api-key.js +237 -0
- package/dist/src/utils/error-handler.js +4 -4
- package/dist/src/utils/token-manager.js +165 -0
- package/index.ts +56 -566
- package/package.json +8 -2
- package/src/client.ts +279 -80
- package/src/commands/api-keys.ts +374 -0
- package/src/commands/auth.ts +58 -0
- package/src/commands/autocomplete.ts +19 -0
- package/src/commands/billing.ts +41 -0
- package/src/commands/chat.ts +445 -0
- package/src/commands/clusters.ts +65 -0
- package/src/commands/index.ts +23 -0
- package/src/commands/models.ts +63 -0
- package/src/commands/users.ts +37 -0
- package/src/constants/command-structure.ts +16 -0
- package/src/services/api-key-service.ts +12 -20
- package/src/services/auth-service.ts +90 -50
- package/src/services/chat-service.ts +295 -0
- package/src/types/api.d.ts +238 -178
- package/src/types/json.d.ts +4 -0
- package/src/utils/config-checker.ts +23 -0
- package/src/utils/default-api-key.ts +229 -0
- package/src/utils/error-handler.ts +4 -4
- package/src/utils/token-manager.ts +150 -0
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { ApiKeyService, ApiKey } from '../services/api-key-service'
|
|
4
|
+
import { handleError } from '../utils/error-handler'
|
|
5
|
+
import { DefaultApiKeyManager } from '../utils/default-api-key'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register API key commands
|
|
9
|
+
*/
|
|
10
|
+
export function registerApiKeyCommands(program: Command): void {
|
|
11
|
+
const apiKey = program
|
|
12
|
+
.command(ApiKeyService.COMMAND_GROUP)
|
|
13
|
+
.description('Manage API keys')
|
|
14
|
+
|
|
15
|
+
apiKey
|
|
16
|
+
.command(ApiKeyService.COMMANDS.LIST)
|
|
17
|
+
.description('List all API keys')
|
|
18
|
+
.action(async () => {
|
|
19
|
+
try {
|
|
20
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
21
|
+
const keys = await apiKeyService.list()
|
|
22
|
+
|
|
23
|
+
if (keys.length === 0) {
|
|
24
|
+
console.log(
|
|
25
|
+
chalk.yellow(
|
|
26
|
+
'No API keys found. Create one with `berget api-key create --name <name>`'
|
|
27
|
+
)
|
|
28
|
+
)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(chalk.bold('Your API keys:'))
|
|
33
|
+
console.log('')
|
|
34
|
+
|
|
35
|
+
// Create a table-like format with headers
|
|
36
|
+
console.log(
|
|
37
|
+
chalk.dim('ID'.padEnd(10)) +
|
|
38
|
+
chalk.dim('NAME'.padEnd(25)) +
|
|
39
|
+
chalk.dim('PREFIX'.padEnd(12)) +
|
|
40
|
+
chalk.dim('STATUS'.padEnd(12)) +
|
|
41
|
+
chalk.dim('CREATED'.padEnd(12)) +
|
|
42
|
+
chalk.dim('LAST USED')
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
console.log(chalk.dim('─'.repeat(85)))
|
|
46
|
+
|
|
47
|
+
keys.forEach((key: ApiKey) => {
|
|
48
|
+
const lastUsed = key.lastUsed ? key.lastUsed.substring(0, 10) : 'Never'
|
|
49
|
+
const status = key.active
|
|
50
|
+
? chalk.green('● Active')
|
|
51
|
+
: chalk.red('● Inactive')
|
|
52
|
+
|
|
53
|
+
// Format the prefix to ensure it's not too long
|
|
54
|
+
const prefixStr = key.prefix.length > 12
|
|
55
|
+
? key.prefix.substring(0, 12) + '...'
|
|
56
|
+
: key.prefix
|
|
57
|
+
|
|
58
|
+
console.log(
|
|
59
|
+
String(key.id).padEnd(10) +
|
|
60
|
+
key.name.padEnd(25) +
|
|
61
|
+
prefixStr.padEnd(15) +
|
|
62
|
+
status.padEnd(12) +
|
|
63
|
+
key.created.substring(0, 10).padEnd(12) +
|
|
64
|
+
lastUsed
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
console.log('')
|
|
69
|
+
console.log(
|
|
70
|
+
chalk.dim(
|
|
71
|
+
'Use `berget api-key create --name <name>` to create a new API key'
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
console.log(
|
|
75
|
+
chalk.dim('Use `berget api-key delete <id>` to delete an API key')
|
|
76
|
+
)
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.dim('Use `berget api-key rotate <id>` to rotate an API key')
|
|
79
|
+
)
|
|
80
|
+
} catch (error) {
|
|
81
|
+
handleError('Failed to list API keys', error)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
apiKey
|
|
86
|
+
.command(ApiKeyService.COMMANDS.CREATE)
|
|
87
|
+
.description('Create a new API key')
|
|
88
|
+
.option('--name <name>', 'Name of the API key')
|
|
89
|
+
.option('--description <description>', 'Description of the API key')
|
|
90
|
+
.action(async (options) => {
|
|
91
|
+
try {
|
|
92
|
+
if (!options.name) {
|
|
93
|
+
console.error(chalk.red('Error: --name is required'))
|
|
94
|
+
console.log('')
|
|
95
|
+
console.log(
|
|
96
|
+
'Usage: berget api-key create --name <name> [--description <description>]'
|
|
97
|
+
)
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(chalk.blue('Creating API key...'))
|
|
102
|
+
|
|
103
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
104
|
+
const result = await apiKeyService.create({
|
|
105
|
+
name: options.name,
|
|
106
|
+
description: options.description,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
console.log('')
|
|
110
|
+
console.log(chalk.green('✓ API key created'))
|
|
111
|
+
console.log('')
|
|
112
|
+
console.log(chalk.bold('API key details:'))
|
|
113
|
+
console.log('')
|
|
114
|
+
console.log(`${chalk.dim('ID:')} ${result.id}`)
|
|
115
|
+
console.log(`${chalk.dim('Name:')} ${result.name}`)
|
|
116
|
+
if (result.description) {
|
|
117
|
+
console.log(`${chalk.dim('Description:')} ${result.description}`)
|
|
118
|
+
}
|
|
119
|
+
console.log(
|
|
120
|
+
`${chalk.dim('Created:')} ${new Date(
|
|
121
|
+
result.created
|
|
122
|
+
).toLocaleString()}`
|
|
123
|
+
)
|
|
124
|
+
console.log('')
|
|
125
|
+
console.log(chalk.bold('API key:'))
|
|
126
|
+
console.log(chalk.cyan(result.key))
|
|
127
|
+
console.log('')
|
|
128
|
+
console.log(
|
|
129
|
+
chalk.yellow('⚠️ IMPORTANT: Save this API key in a secure location.')
|
|
130
|
+
)
|
|
131
|
+
console.log(chalk.yellow(' It will not be displayed again.'))
|
|
132
|
+
|
|
133
|
+
console.log('')
|
|
134
|
+
console.log(
|
|
135
|
+
chalk.dim(
|
|
136
|
+
'Use this key in your applications to authenticate with the Berget API.'
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
} catch (error) {
|
|
140
|
+
handleError('Failed to create API key', error)
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
apiKey
|
|
145
|
+
.command(ApiKeyService.COMMANDS.DELETE)
|
|
146
|
+
.description('Delete an API key')
|
|
147
|
+
.argument('<id>', 'ID of the API key to delete')
|
|
148
|
+
.action(async (id) => {
|
|
149
|
+
try {
|
|
150
|
+
console.log(chalk.blue(`Deleting API key ${id}...`))
|
|
151
|
+
|
|
152
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
153
|
+
await apiKeyService.delete(id)
|
|
154
|
+
|
|
155
|
+
console.log(chalk.green(`✓ API key ${id} has been deleted`))
|
|
156
|
+
console.log('')
|
|
157
|
+
console.log(
|
|
158
|
+
chalk.dim(
|
|
159
|
+
'Applications using this key will no longer be able to authenticate.'
|
|
160
|
+
)
|
|
161
|
+
)
|
|
162
|
+
console.log(
|
|
163
|
+
chalk.dim('Use `berget api-key list` to see your remaining API keys.')
|
|
164
|
+
)
|
|
165
|
+
} catch (error) {
|
|
166
|
+
handleError('Failed to delete API key', error)
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
apiKey
|
|
171
|
+
.command(ApiKeyService.COMMANDS.ROTATE)
|
|
172
|
+
.description(
|
|
173
|
+
'Rotate an API key (creates a new one and invalidates the old one)'
|
|
174
|
+
)
|
|
175
|
+
.argument('<id>', 'ID of the API key to rotate')
|
|
176
|
+
.action(async (id) => {
|
|
177
|
+
try {
|
|
178
|
+
console.log(chalk.blue(`Rotating API key ${id}...`))
|
|
179
|
+
console.log(
|
|
180
|
+
chalk.dim('This will invalidate the old key and generate a new one.')
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
184
|
+
const result = await apiKeyService.rotate(id)
|
|
185
|
+
|
|
186
|
+
console.log('')
|
|
187
|
+
console.log(chalk.green('✓ API key rotated'))
|
|
188
|
+
console.log('')
|
|
189
|
+
console.log(chalk.bold('New API key details:'))
|
|
190
|
+
console.log('')
|
|
191
|
+
console.log(`${chalk.dim('ID:')} ${result.id}`)
|
|
192
|
+
console.log(`${chalk.dim('Name:')} ${result.name}`)
|
|
193
|
+
if (result.description) {
|
|
194
|
+
console.log(`${chalk.dim('Description:')} ${result.description}`)
|
|
195
|
+
}
|
|
196
|
+
console.log(
|
|
197
|
+
`${chalk.dim('Created:')} ${new Date(
|
|
198
|
+
result.created
|
|
199
|
+
).toLocaleString()}`
|
|
200
|
+
)
|
|
201
|
+
console.log('')
|
|
202
|
+
console.log(chalk.bold('New API key:'))
|
|
203
|
+
console.log(chalk.cyan(result.key))
|
|
204
|
+
console.log('')
|
|
205
|
+
console.log(
|
|
206
|
+
chalk.yellow(
|
|
207
|
+
'⚠️ IMPORTANT: Update your applications with this new API key.'
|
|
208
|
+
)
|
|
209
|
+
)
|
|
210
|
+
console.log(
|
|
211
|
+
chalk.yellow(
|
|
212
|
+
' The old key has been invalidated and will no longer work.'
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
console.log(chalk.yellow(' This new key will not be displayed again.'))
|
|
216
|
+
} catch (error) {
|
|
217
|
+
handleError('Failed to rotate API key', error)
|
|
218
|
+
}
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
apiKey
|
|
222
|
+
.command(ApiKeyService.COMMANDS.DESCRIBE)
|
|
223
|
+
.description('Show usage statistics for an API key')
|
|
224
|
+
.argument('<id>', 'ID of the API key')
|
|
225
|
+
.option('--start <date>', 'Start date (YYYY-MM-DD)')
|
|
226
|
+
.option('--end <date>', 'End date (YYYY-MM-DD)')
|
|
227
|
+
.action(async (id, options) => {
|
|
228
|
+
try {
|
|
229
|
+
console.log(chalk.blue(`Fetching usage statistics for API key ${id}...`))
|
|
230
|
+
|
|
231
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
232
|
+
const usage = await apiKeyService.describe(id)
|
|
233
|
+
|
|
234
|
+
console.log('')
|
|
235
|
+
console.log(
|
|
236
|
+
chalk.bold(`Usage statistics for API key: ${usage.name} (${id})`)
|
|
237
|
+
)
|
|
238
|
+
console.log('')
|
|
239
|
+
|
|
240
|
+
// Period information
|
|
241
|
+
console.log(
|
|
242
|
+
chalk.dim(`Period: ${usage.period.start} to ${usage.period.end}`)
|
|
243
|
+
)
|
|
244
|
+
console.log('')
|
|
245
|
+
|
|
246
|
+
// Request statistics
|
|
247
|
+
console.log(chalk.bold('Request statistics:'))
|
|
248
|
+
console.log(
|
|
249
|
+
`Total requests: ${chalk.cyan(usage.requests.total.toLocaleString())}`
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
// Daily breakdown if available
|
|
253
|
+
if (usage.requests.daily && usage.requests.daily.length > 0) {
|
|
254
|
+
console.log('')
|
|
255
|
+
console.log(chalk.bold('Daily breakdown:'))
|
|
256
|
+
console.log(chalk.dim('─'.repeat(30)))
|
|
257
|
+
console.log(chalk.dim('DATE'.padEnd(12) + 'REQUESTS'))
|
|
258
|
+
|
|
259
|
+
usage.requests.daily.forEach((day: { date: string; count: number }) => {
|
|
260
|
+
console.log(`${day.date.padEnd(12)}${day.count.toLocaleString()}`)
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Model usage if available
|
|
265
|
+
if (usage.models && usage.models.length > 0) {
|
|
266
|
+
console.log('')
|
|
267
|
+
console.log(chalk.bold('Model usage:'))
|
|
268
|
+
console.log(chalk.dim('─'.repeat(70)))
|
|
269
|
+
console.log(
|
|
270
|
+
chalk.dim('MODEL'.padEnd(20)) +
|
|
271
|
+
chalk.dim('REQUESTS'.padEnd(10)) +
|
|
272
|
+
chalk.dim('INPUT'.padEnd(12)) +
|
|
273
|
+
chalk.dim('OUTPUT'.padEnd(12)) +
|
|
274
|
+
chalk.dim('TOTAL TOKENS')
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
usage.models.forEach(
|
|
278
|
+
(model: {
|
|
279
|
+
name: string
|
|
280
|
+
requests: number
|
|
281
|
+
tokens: {
|
|
282
|
+
input: number
|
|
283
|
+
output: number
|
|
284
|
+
total: number
|
|
285
|
+
}
|
|
286
|
+
}) => {
|
|
287
|
+
console.log(
|
|
288
|
+
model.name.padEnd(20) +
|
|
289
|
+
model.requests.toString().padEnd(10) +
|
|
290
|
+
model.tokens.input.toLocaleString().padEnd(12) +
|
|
291
|
+
model.tokens.output.toLocaleString().padEnd(12) +
|
|
292
|
+
model.tokens.total.toLocaleString()
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
console.log('')
|
|
299
|
+
console.log(
|
|
300
|
+
chalk.dim(
|
|
301
|
+
'Use these statistics to understand your API usage and optimize your costs.'
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
} catch (error) {
|
|
305
|
+
handleError('Failed to get API key usage', error)
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
apiKey
|
|
310
|
+
.command(ApiKeyService.COMMANDS.SET_DEFAULT)
|
|
311
|
+
.description('Set an API key as the default for chat commands')
|
|
312
|
+
.argument('<id>', 'ID of the API key to set as default')
|
|
313
|
+
.action(async (id) => {
|
|
314
|
+
try {
|
|
315
|
+
const apiKeyService = ApiKeyService.getInstance()
|
|
316
|
+
const keys = await apiKeyService.list()
|
|
317
|
+
const selectedKey = keys.find(key => key.id.toString() === id)
|
|
318
|
+
|
|
319
|
+
if (!selectedKey) {
|
|
320
|
+
console.error(chalk.red(`Error: API key with ID ${id} not found`))
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Save the default API key
|
|
325
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
326
|
+
|
|
327
|
+
// We need to rotate the key to get the actual key value
|
|
328
|
+
const rotatedKey = await apiKeyService.rotate(id)
|
|
329
|
+
|
|
330
|
+
defaultApiKeyManager.setDefaultApiKey(
|
|
331
|
+
id,
|
|
332
|
+
selectedKey.name,
|
|
333
|
+
selectedKey.prefix,
|
|
334
|
+
rotatedKey.key
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
console.log(chalk.green(`✓ API key "${selectedKey.name}" set as default for chat commands`))
|
|
338
|
+
console.log('')
|
|
339
|
+
console.log(chalk.dim('This API key will be used by default when running chat commands'))
|
|
340
|
+
console.log(chalk.dim('You can override it with --api-key or --api-key-id options'))
|
|
341
|
+
} catch (error) {
|
|
342
|
+
handleError('Failed to set default API key', error)
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
apiKey
|
|
347
|
+
.command(ApiKeyService.COMMANDS.GET_DEFAULT)
|
|
348
|
+
.description('Show the current default API key')
|
|
349
|
+
.action(() => {
|
|
350
|
+
try {
|
|
351
|
+
const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
|
|
352
|
+
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
|
|
353
|
+
|
|
354
|
+
if (!defaultApiKeyData) {
|
|
355
|
+
console.log(chalk.yellow('No default API key set'))
|
|
356
|
+
console.log('')
|
|
357
|
+
console.log('To set a default API key, run:')
|
|
358
|
+
console.log(chalk.cyan(' berget api-keys set-default <id>'))
|
|
359
|
+
return
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
console.log(chalk.bold('Default API key:'))
|
|
363
|
+
console.log('')
|
|
364
|
+
console.log(`${chalk.dim('ID:')} ${defaultApiKeyData.id}`)
|
|
365
|
+
console.log(`${chalk.dim('Name:')} ${defaultApiKeyData.name}`)
|
|
366
|
+
console.log(`${chalk.dim('Prefix:')} ${defaultApiKeyData.prefix}`)
|
|
367
|
+
console.log('')
|
|
368
|
+
console.log(chalk.dim('This API key will be used by default when running chat commands'))
|
|
369
|
+
console.log(chalk.dim('You can override it with --api-key or --api-key-id options'))
|
|
370
|
+
} catch (error) {
|
|
371
|
+
handleError('Failed to get default API key', error)
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { AuthService } from '../services/auth-service'
|
|
4
|
+
import { clearAuthToken } from '../client'
|
|
5
|
+
import { handleError } from '../utils/error-handler'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register authentication commands
|
|
9
|
+
*/
|
|
10
|
+
export function registerAuthCommands(program: Command): void {
|
|
11
|
+
const auth = program
|
|
12
|
+
.command(AuthService.COMMAND_GROUP)
|
|
13
|
+
.description('Manage authentication and authorization')
|
|
14
|
+
|
|
15
|
+
auth
|
|
16
|
+
.command(AuthService.COMMANDS.LOGIN)
|
|
17
|
+
.description('Log in to Berget')
|
|
18
|
+
.action(async () => {
|
|
19
|
+
const authService = AuthService.getInstance()
|
|
20
|
+
await authService.login()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
auth
|
|
24
|
+
.command(AuthService.COMMANDS.LOGOUT)
|
|
25
|
+
.description('Log out from Berget')
|
|
26
|
+
.action(() => {
|
|
27
|
+
clearAuthToken()
|
|
28
|
+
console.log(chalk.green('You have been logged out from Berget'))
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
auth
|
|
32
|
+
.command(AuthService.COMMANDS.WHOAMI)
|
|
33
|
+
.description('Show information about the logged in user')
|
|
34
|
+
.action(async () => {
|
|
35
|
+
try {
|
|
36
|
+
const authService = AuthService.getInstance()
|
|
37
|
+
const profile = await authService.whoami()
|
|
38
|
+
|
|
39
|
+
if (profile) {
|
|
40
|
+
console.log(
|
|
41
|
+
chalk.bold(`Logged in as: ${profile.name || profile.login}`)
|
|
42
|
+
)
|
|
43
|
+
console.log(`Email: ${chalk.cyan(profile.email || 'Not available')}`)
|
|
44
|
+
console.log(`Role: ${chalk.cyan(profile.role || 'Not available')}`)
|
|
45
|
+
|
|
46
|
+
if (profile.company) {
|
|
47
|
+
console.log(`Company: ${chalk.cyan(profile.company.name)}`)
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
console.log(
|
|
51
|
+
chalk.yellow('You are not logged in. Use `berget login` to log in.')
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
handleError('You are not logged in or an error occurred', error)
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Register autocomplete commands
|
|
6
|
+
*/
|
|
7
|
+
export function registerAutocompleteCommands(program: Command): void {
|
|
8
|
+
const autocomplete = program
|
|
9
|
+
.command('autocomplete')
|
|
10
|
+
.command('install')
|
|
11
|
+
.description('Install shell autocompletion')
|
|
12
|
+
.action(() => {
|
|
13
|
+
console.log(chalk.green('✓ Berget autocomplete installed in your shell'))
|
|
14
|
+
console.log(chalk.green('✓ Shell completion for kubectl also installed'))
|
|
15
|
+
console.log('')
|
|
16
|
+
console.log('Restart your shell or run:')
|
|
17
|
+
console.log(' source ~/.bashrc')
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure'
|
|
3
|
+
import { createAuthenticatedClient } from '../client'
|
|
4
|
+
import { handleError } from '../utils/error-handler'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register billing commands
|
|
8
|
+
*/
|
|
9
|
+
export function registerBillingCommands(program: Command): void {
|
|
10
|
+
const billing = program
|
|
11
|
+
.command(COMMAND_GROUPS.BILLING)
|
|
12
|
+
.description('Manage billing and usage')
|
|
13
|
+
|
|
14
|
+
billing
|
|
15
|
+
.command(SUBCOMMANDS.BILLING.GET_USAGE)
|
|
16
|
+
.description('Get token usage statistics')
|
|
17
|
+
.option('--model <modelId>', 'Get usage for a specific model')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = createAuthenticatedClient()
|
|
21
|
+
let response
|
|
22
|
+
|
|
23
|
+
if (options.model) {
|
|
24
|
+
const { data, error } = await client.GET('/v1/usage/tokens/{modelId}', {
|
|
25
|
+
params: { path: { modelId: options.model } },
|
|
26
|
+
})
|
|
27
|
+
if (error) throw new Error(JSON.stringify(error))
|
|
28
|
+
response = data
|
|
29
|
+
} else {
|
|
30
|
+
const { data, error } = await client.GET('/v1/usage/tokens')
|
|
31
|
+
if (error) throw new Error(JSON.stringify(error))
|
|
32
|
+
response = data
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log('Token Usage:')
|
|
36
|
+
console.log(JSON.stringify(response, null, 2))
|
|
37
|
+
} catch (error) {
|
|
38
|
+
handleError('Failed to get token usage', error)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
}
|