berget 2.2.7 → 2.2.8
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/.github/workflows/publish.yml +6 -6
- package/.github/workflows/test.yml +1 -1
- package/.prettierrc +5 -3
- package/dist/index.js +24 -25
- package/dist/package.json +5 -3
- package/dist/src/agents/app.js +8 -8
- package/dist/src/agents/backend.js +3 -3
- package/dist/src/agents/devops.js +8 -8
- package/dist/src/agents/frontend.js +3 -3
- package/dist/src/agents/fullstack.js +3 -3
- package/dist/src/agents/index.js +18 -18
- package/dist/src/agents/quality.js +8 -8
- package/dist/src/agents/security.js +8 -8
- package/dist/src/client.js +115 -127
- package/dist/src/commands/api-keys.js +195 -202
- package/dist/src/commands/auth.js +16 -25
- package/dist/src/commands/autocomplete.js +8 -8
- package/dist/src/commands/billing.js +10 -19
- package/dist/src/commands/chat.js +139 -170
- package/dist/src/commands/clusters.js +21 -30
- package/dist/src/commands/code/__tests__/auth-sync.test.js +189 -186
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +3 -13
- package/dist/src/commands/code/__tests__/fake-auth-service.js +21 -29
- package/dist/src/commands/code/__tests__/fake-command-runner.js +22 -33
- package/dist/src/commands/code/__tests__/fake-file-store.js +19 -41
- package/dist/src/commands/code/__tests__/fake-prompter.js +81 -97
- package/dist/src/commands/code/__tests__/setup-flow.test.js +295 -295
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -32
- package/dist/src/commands/code/adapters/fs-file-store.js +25 -44
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -41
- package/dist/src/commands/code/auth-sync.js +215 -228
- package/dist/src/commands/code/errors.js +15 -12
- package/dist/src/commands/code/setup.js +390 -425
- package/dist/src/commands/code.js +279 -294
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +16 -25
- package/dist/src/commands/users.js +9 -18
- package/dist/src/constants/command-structure.js +138 -138
- package/dist/src/services/api-key-service.js +132 -152
- package/dist/src/services/auth-service.js +81 -95
- package/dist/src/services/browser-auth.js +121 -131
- package/dist/src/services/chat-service.js +369 -386
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +9 -21
- package/dist/src/services/flux-service.js +13 -25
- package/dist/src/services/helm-service.js +9 -21
- package/dist/src/services/kubectl-service.js +15 -29
- package/dist/src/utils/config-checker.js +7 -7
- package/dist/src/utils/config-loader.js +109 -109
- package/dist/src/utils/default-api-key.js +129 -139
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +62 -62
- package/dist/src/utils/logger.js +74 -67
- package/dist/src/utils/markdown-renderer.js +28 -28
- package/dist/src/utils/opencode-validator.js +67 -69
- package/dist/src/utils/token-manager.js +67 -65
- package/dist/tests/commands/chat.test.js +30 -39
- package/dist/tests/commands/code.test.js +186 -195
- package/dist/tests/utils/config-loader.test.js +107 -107
- package/dist/tests/utils/env-manager.test.js +81 -90
- package/dist/tests/utils/opencode-validator.test.js +42 -41
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +50 -30
- package/index.ts +30 -31
- package/package.json +5 -3
- package/src/agents/app.ts +9 -9
- package/src/agents/backend.ts +4 -4
- package/src/agents/devops.ts +9 -9
- package/src/agents/frontend.ts +4 -4
- package/src/agents/fullstack.ts +4 -4
- package/src/agents/index.ts +27 -25
- package/src/agents/quality.ts +9 -9
- package/src/agents/security.ts +9 -9
- package/src/agents/types.ts +10 -10
- package/src/client.ts +85 -77
- package/src/commands/api-keys.ts +190 -185
- package/src/commands/auth.ts +15 -14
- package/src/commands/autocomplete.ts +10 -10
- package/src/commands/billing.ts +13 -12
- package/src/commands/chat.ts +145 -142
- package/src/commands/clusters.ts +20 -19
- package/src/commands/code/__tests__/auth-sync.test.ts +176 -175
- package/src/commands/code/__tests__/fake-api-key-service.ts +2 -2
- package/src/commands/code/__tests__/fake-auth-service.ts +18 -18
- package/src/commands/code/__tests__/fake-command-runner.ts +28 -22
- package/src/commands/code/__tests__/fake-file-store.ts +15 -15
- package/src/commands/code/__tests__/fake-prompter.ts +86 -85
- package/src/commands/code/__tests__/setup-flow.test.ts +253 -251
- package/src/commands/code/adapters/clack-prompter.ts +32 -30
- package/src/commands/code/adapters/fs-file-store.ts +18 -17
- package/src/commands/code/adapters/spawn-command-runner.ts +20 -15
- package/src/commands/code/auth-sync.ts +210 -210
- package/src/commands/code/errors.ts +11 -11
- package/src/commands/code/ports/auth-services.ts +7 -7
- package/src/commands/code/ports/command-runner.ts +2 -2
- package/src/commands/code/ports/file-store.ts +3 -3
- package/src/commands/code/ports/prompter.ts +13 -13
- package/src/commands/code/setup.ts +408 -406
- package/src/commands/code.ts +288 -287
- package/src/commands/index.ts +11 -10
- package/src/commands/models.ts +19 -18
- package/src/commands/users.ts +11 -10
- package/src/constants/command-structure.ts +159 -159
- package/src/services/api-key-service.ts +85 -85
- package/src/services/auth-service.ts +55 -54
- package/src/services/browser-auth.ts +62 -62
- package/src/services/chat-service.ts +169 -170
- package/src/services/cluster-service.ts +28 -28
- package/src/services/collaborator-service.ts +6 -6
- package/src/services/flux-service.ts +17 -17
- package/src/services/helm-service.ts +11 -11
- package/src/services/kubectl-service.ts +12 -12
- package/src/types/api.d.ts +1933 -1933
- package/src/types/json.d.ts +1 -1
- package/src/utils/config-checker.ts +6 -6
- package/src/utils/config-loader.ts +130 -129
- package/src/utils/default-api-key.ts +81 -80
- package/src/utils/env-manager.ts +37 -37
- package/src/utils/error-handler.ts +64 -64
- package/src/utils/logger.ts +72 -66
- package/src/utils/markdown-renderer.ts +28 -28
- package/src/utils/opencode-validator.ts +72 -71
- package/src/utils/token-manager.ts +69 -68
- package/tests/commands/chat.test.ts +32 -31
- package/tests/commands/code.test.ts +182 -181
- package/tests/utils/config-loader.test.ts +111 -110
- package/tests/utils/env-manager.test.ts +83 -79
- package/tests/utils/opencode-validator.test.ts +43 -42
- package/tsconfig.json +2 -1
- package/vitest.config.ts +2 -2
|
@@ -1,13 +1,4 @@
|
|
|
1
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
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
@@ -15,61 +6,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
6
|
exports.registerApiKeyCommands = void 0;
|
|
16
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
17
8
|
const api_key_service_1 = require("../services/api-key-service");
|
|
18
|
-
const error_handler_1 = require("../utils/error-handler");
|
|
19
9
|
const default_api_key_1 = require("../utils/default-api-key");
|
|
20
|
-
|
|
21
|
-
function formatDate(dateString) {
|
|
22
|
-
const date = new Date(dateString);
|
|
23
|
-
const now = new Date();
|
|
24
|
-
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
25
|
-
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
26
|
-
if (diffDays === 0)
|
|
27
|
-
return chalk_1.default.green("Today");
|
|
28
|
-
if (diffDays === 1)
|
|
29
|
-
return chalk_1.default.yellow("Yesterday");
|
|
30
|
-
if (diffDays < 7)
|
|
31
|
-
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
32
|
-
if (diffDays < 30)
|
|
33
|
-
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
34
|
-
if (diffDays < 365)
|
|
35
|
-
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
36
|
-
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
37
|
-
}
|
|
38
|
-
function formatLastUsed(dateString) {
|
|
39
|
-
const date = new Date(dateString);
|
|
40
|
-
const now = new Date();
|
|
41
|
-
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
42
|
-
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
43
|
-
if (diffDays === 0)
|
|
44
|
-
return chalk_1.default.green("Today");
|
|
45
|
-
if (diffDays === 1)
|
|
46
|
-
return chalk_1.default.yellow("Yesterday");
|
|
47
|
-
if (diffDays < 7)
|
|
48
|
-
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
49
|
-
if (diffDays < 30)
|
|
50
|
-
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
51
|
-
if (diffDays < 365)
|
|
52
|
-
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
53
|
-
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
54
|
-
}
|
|
10
|
+
const error_handler_1 = require("../utils/error-handler");
|
|
55
11
|
/**
|
|
56
12
|
* Register API key commands
|
|
57
13
|
*/
|
|
58
14
|
function registerApiKeyCommands(program) {
|
|
59
|
-
const apiKey = program.command(api_key_service_1.ApiKeyService.COMMAND_GROUP).description(
|
|
15
|
+
const apiKey = program.command(api_key_service_1.ApiKeyService.COMMAND_GROUP).description('Manage API keys');
|
|
60
16
|
apiKey
|
|
61
17
|
.command(api_key_service_1.ApiKeyService.COMMANDS.LIST)
|
|
62
|
-
.description(
|
|
63
|
-
.action(() =>
|
|
18
|
+
.description('List all API keys')
|
|
19
|
+
.action(async () => {
|
|
64
20
|
try {
|
|
65
21
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
66
|
-
const keys =
|
|
22
|
+
const keys = await apiKeyService.list();
|
|
67
23
|
if (keys.length === 0) {
|
|
68
|
-
console.log(chalk_1.default.yellow(
|
|
24
|
+
console.log(chalk_1.default.yellow('No API keys found. Create one with `berget api-key create --name <name>`'));
|
|
69
25
|
return;
|
|
70
26
|
}
|
|
71
|
-
console.log(chalk_1.default.bold(
|
|
72
|
-
console.log(
|
|
27
|
+
console.log(chalk_1.default.bold('🔑 Your API keys:'));
|
|
28
|
+
console.log('');
|
|
73
29
|
// Create a more readable table with better spacing and colors
|
|
74
30
|
const idWidth = 10;
|
|
75
31
|
const nameWidth = 30;
|
|
@@ -77,222 +33,224 @@ function registerApiKeyCommands(program) {
|
|
|
77
33
|
const statusWidth = 12;
|
|
78
34
|
const createdWidth = 12;
|
|
79
35
|
const usedWidth = 15;
|
|
80
|
-
console.log(chalk_1.default.dim(
|
|
81
|
-
chalk_1.default.dim(
|
|
82
|
-
chalk_1.default.dim(
|
|
83
|
-
chalk_1.default.dim(
|
|
84
|
-
chalk_1.default.dim(
|
|
85
|
-
chalk_1.default.dim(
|
|
86
|
-
console.log(chalk_1.default.dim(
|
|
36
|
+
console.log(chalk_1.default.dim('ID'.padEnd(idWidth)) +
|
|
37
|
+
chalk_1.default.dim('NAME'.padEnd(nameWidth)) +
|
|
38
|
+
chalk_1.default.dim('PREFIX'.padEnd(prefixWidth)) +
|
|
39
|
+
chalk_1.default.dim('STATUS'.padEnd(statusWidth)) +
|
|
40
|
+
chalk_1.default.dim('CREATED'.padEnd(createdWidth)) +
|
|
41
|
+
chalk_1.default.dim('LAST USED'));
|
|
42
|
+
console.log(chalk_1.default.dim('─'.repeat(idWidth + nameWidth + prefixWidth + statusWidth + createdWidth + usedWidth + 5)));
|
|
87
43
|
keys.forEach((key) => {
|
|
88
|
-
const lastUsed = key.lastUsed ? formatLastUsed(key.lastUsed) : chalk_1.default.yellow(
|
|
89
|
-
const status = key.active ? chalk_1.default.green(
|
|
44
|
+
const lastUsed = key.lastUsed ? formatLastUsed(key.lastUsed) : chalk_1.default.yellow('Never used');
|
|
45
|
+
const status = key.active ? chalk_1.default.green('● Active') : chalk_1.default.red('● Inactive');
|
|
90
46
|
// Show only first 8 characters of ID for easier reading
|
|
91
|
-
const shortId = chalk_1.default.cyan(String(key.id).
|
|
47
|
+
const shortId = chalk_1.default.cyan(String(key.id).slice(0, 8));
|
|
92
48
|
// Format the prefix with better truncation
|
|
93
|
-
const
|
|
94
|
-
? key.prefix.
|
|
49
|
+
const prefixString = key.prefix.length > prefixWidth
|
|
50
|
+
? key.prefix.slice(0, Math.max(0, prefixWidth - 3)) + '...'
|
|
95
51
|
: chalk_1.default.gray(key.prefix);
|
|
96
52
|
// Truncate name if too long
|
|
97
|
-
const
|
|
53
|
+
const nameString = key.name.length > nameWidth
|
|
54
|
+
? key.name.slice(0, Math.max(0, nameWidth - 3)) + '...'
|
|
55
|
+
: key.name;
|
|
98
56
|
// Format created date
|
|
99
57
|
const createdDate = formatDate(key.created);
|
|
100
58
|
console.log(shortId.padEnd(idWidth) +
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
nameString.padEnd(nameWidth) +
|
|
60
|
+
prefixString.padEnd(prefixWidth) +
|
|
103
61
|
status.padEnd(statusWidth) +
|
|
104
62
|
createdDate.padEnd(createdWidth) +
|
|
105
63
|
lastUsed);
|
|
106
64
|
});
|
|
107
|
-
console.log(
|
|
108
|
-
console.log(chalk_1.default.dim(
|
|
109
|
-
console.log(chalk_1.default.dim(
|
|
110
|
-
console.log(chalk_1.default.dim(
|
|
65
|
+
console.log('');
|
|
66
|
+
console.log(chalk_1.default.dim('Use `berget api-key create --name <name>` to create a new API key'));
|
|
67
|
+
console.log(chalk_1.default.dim('Use `berget api-key delete <id>` to delete an API key'));
|
|
68
|
+
console.log(chalk_1.default.dim('Use `berget api-key rotate <id>` to rotate an API key'));
|
|
111
69
|
}
|
|
112
70
|
catch (error) {
|
|
113
|
-
(0, error_handler_1.handleError)(
|
|
71
|
+
(0, error_handler_1.handleError)('Failed to list API keys', error);
|
|
114
72
|
}
|
|
115
|
-
})
|
|
73
|
+
});
|
|
116
74
|
apiKey
|
|
117
75
|
.command(api_key_service_1.ApiKeyService.COMMANDS.CREATE)
|
|
118
|
-
.description(
|
|
119
|
-
.option(
|
|
120
|
-
.option(
|
|
121
|
-
.action((options) =>
|
|
76
|
+
.description('Create a new API key')
|
|
77
|
+
.option('--name <name>', 'Name of the API key')
|
|
78
|
+
.option('--description <description>', 'Description of the API key')
|
|
79
|
+
.action(async (options) => {
|
|
122
80
|
try {
|
|
123
81
|
if (!options.name) {
|
|
124
|
-
console.error(chalk_1.default.red(
|
|
125
|
-
console.log(
|
|
126
|
-
console.log(
|
|
82
|
+
console.error(chalk_1.default.red('Error: --name is required'));
|
|
83
|
+
console.log('');
|
|
84
|
+
console.log('Usage: berget api-key create --name <name> [--description <description>]');
|
|
127
85
|
return;
|
|
128
86
|
}
|
|
129
|
-
console.log(chalk_1.default.blue(
|
|
87
|
+
console.log(chalk_1.default.blue('Creating API key...'));
|
|
130
88
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
131
|
-
const result =
|
|
132
|
-
name: options.name,
|
|
89
|
+
const result = await apiKeyService.create({
|
|
133
90
|
description: options.description,
|
|
91
|
+
name: options.name,
|
|
134
92
|
});
|
|
135
|
-
console.log(
|
|
136
|
-
console.log(chalk_1.default.green(
|
|
137
|
-
console.log(
|
|
138
|
-
console.log(chalk_1.default.bold(
|
|
139
|
-
console.log(
|
|
140
|
-
console.log(`${chalk_1.default.dim(
|
|
141
|
-
console.log(`${chalk_1.default.dim(
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(chalk_1.default.green('✓ API key created'));
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log(chalk_1.default.bold('API key details:'));
|
|
97
|
+
console.log('');
|
|
98
|
+
console.log(`${chalk_1.default.dim('ID:')} ${result.id}`);
|
|
99
|
+
console.log(`${chalk_1.default.dim('Name:')} ${result.name}`);
|
|
142
100
|
if (result.description) {
|
|
143
|
-
console.log(`${chalk_1.default.dim(
|
|
101
|
+
console.log(`${chalk_1.default.dim('Description:')} ${result.description}`);
|
|
144
102
|
}
|
|
145
|
-
console.log(`${chalk_1.default.dim(
|
|
146
|
-
console.log(
|
|
147
|
-
console.log(chalk_1.default.bold(
|
|
103
|
+
console.log(`${chalk_1.default.dim('Created:')} ${new Date(result.created).toLocaleString()}`);
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(chalk_1.default.bold('API key:'));
|
|
148
106
|
console.log(chalk_1.default.cyan(result.key));
|
|
149
|
-
console.log(
|
|
150
|
-
console.log(chalk_1.default.yellow(
|
|
151
|
-
console.log(chalk_1.default.yellow(
|
|
152
|
-
console.log(
|
|
153
|
-
console.log(chalk_1.default.dim(
|
|
107
|
+
console.log('');
|
|
108
|
+
console.log(chalk_1.default.yellow('⚠️ IMPORTANT: Save this API key in a secure location.'));
|
|
109
|
+
console.log(chalk_1.default.yellow(' It will not be displayed again.'));
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(chalk_1.default.dim('Use this key in your applications to authenticate with the Berget API.'));
|
|
154
112
|
}
|
|
155
113
|
catch (error) {
|
|
156
|
-
(0, error_handler_1.handleError)(
|
|
114
|
+
(0, error_handler_1.handleError)('Failed to create API key', error);
|
|
157
115
|
}
|
|
158
|
-
})
|
|
116
|
+
});
|
|
159
117
|
apiKey
|
|
160
118
|
.command(api_key_service_1.ApiKeyService.COMMANDS.DELETE)
|
|
161
|
-
.description(
|
|
162
|
-
.argument(
|
|
163
|
-
.action((identifier) =>
|
|
119
|
+
.description('Delete an API key')
|
|
120
|
+
.argument('<identifier>', 'ID (first 8 chars), full ID, or name of the API key to delete')
|
|
121
|
+
.action(async (identifier) => {
|
|
164
122
|
try {
|
|
165
123
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
166
124
|
// First, get all API keys to find the matching one
|
|
167
|
-
const keys =
|
|
125
|
+
const keys = await apiKeyService.list();
|
|
168
126
|
// Try to find the key by:
|
|
169
127
|
// 1. Full ID match
|
|
170
128
|
// 2. Short ID (first 8 chars) match
|
|
171
129
|
// 3. Exact name match
|
|
172
130
|
// 4. Partial name match
|
|
173
131
|
// Check for exact matches first (full ID or exact name)
|
|
174
|
-
let exactMatches = keys.filter(key => String(key.id) === identifier || key.name === identifier);
|
|
132
|
+
let exactMatches = keys.filter((key) => String(key.id) === identifier || key.name === identifier);
|
|
175
133
|
// If no exact matches, check for short ID matches
|
|
176
134
|
if (exactMatches.length === 0) {
|
|
177
|
-
exactMatches = keys.filter(key => String(key.id).
|
|
135
|
+
exactMatches = keys.filter((key) => String(key.id).slice(0, 8) === identifier);
|
|
178
136
|
}
|
|
179
137
|
// If still no matches, check for partial name matches
|
|
180
138
|
if (exactMatches.length === 0) {
|
|
181
|
-
exactMatches = keys.filter(key => key.name.toLowerCase().includes(identifier.toLowerCase()));
|
|
139
|
+
exactMatches = keys.filter((key) => key.name.toLowerCase().includes(identifier.toLowerCase()));
|
|
182
140
|
}
|
|
183
141
|
// Handle multiple matches
|
|
184
142
|
if (exactMatches.length > 1) {
|
|
185
143
|
console.error(chalk_1.default.red(`Error: Multiple API keys found matching "${identifier}"`));
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
188
|
-
|
|
189
|
-
const shortId = String(key.id).
|
|
144
|
+
console.log('');
|
|
145
|
+
console.log('Please be more specific. Matching keys:');
|
|
146
|
+
for (const key of exactMatches) {
|
|
147
|
+
const shortId = String(key.id).slice(0, 8);
|
|
190
148
|
console.log(` ${shortId.padEnd(8)} ${key.name}`);
|
|
191
|
-
}
|
|
192
|
-
console.log(
|
|
193
|
-
console.log(
|
|
149
|
+
}
|
|
150
|
+
console.log('');
|
|
151
|
+
console.log('Use the first 8 characters of the ID to specify which key to delete.');
|
|
194
152
|
return;
|
|
195
153
|
}
|
|
196
154
|
// Handle no matches
|
|
197
155
|
if (exactMatches.length === 0) {
|
|
198
156
|
console.error(chalk_1.default.red(`Error: No API key found matching "${identifier}"`));
|
|
199
|
-
console.log(
|
|
200
|
-
console.log(
|
|
201
|
-
|
|
202
|
-
const shortId = String(key.id).
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log('Available API keys:');
|
|
159
|
+
for (const key of keys) {
|
|
160
|
+
const shortId = String(key.id).slice(0, 8);
|
|
203
161
|
console.log(` ${shortId.padEnd(8)} ${key.name}`);
|
|
204
|
-
}
|
|
205
|
-
console.log(
|
|
206
|
-
console.log(
|
|
162
|
+
}
|
|
163
|
+
console.log('');
|
|
164
|
+
console.log('Use the first 8 characters of the ID, full ID, or name to delete.');
|
|
207
165
|
return;
|
|
208
166
|
}
|
|
209
167
|
const matchingKey = exactMatches[0];
|
|
210
168
|
const keyId = String(matchingKey.id);
|
|
211
|
-
const shortId = keyId.
|
|
169
|
+
const shortId = keyId.slice(0, 8);
|
|
212
170
|
console.log(chalk_1.default.blue(`Deleting API key ${shortId} (${matchingKey.name})...`));
|
|
213
|
-
|
|
171
|
+
await apiKeyService.delete(keyId);
|
|
214
172
|
console.log(chalk_1.default.green(`✓ API key ${shortId} (${matchingKey.name}) has been deleted`));
|
|
215
|
-
console.log(
|
|
216
|
-
console.log(chalk_1.default.dim(
|
|
217
|
-
console.log(chalk_1.default.dim(
|
|
173
|
+
console.log('');
|
|
174
|
+
console.log(chalk_1.default.dim('Applications using this key will no longer be able to authenticate.'));
|
|
175
|
+
console.log(chalk_1.default.dim('Use `berget api-key list` to see your remaining API keys.'));
|
|
218
176
|
}
|
|
219
177
|
catch (error) {
|
|
220
|
-
(0, error_handler_1.handleError)(
|
|
178
|
+
(0, error_handler_1.handleError)('Failed to delete API key', error);
|
|
221
179
|
}
|
|
222
|
-
})
|
|
180
|
+
});
|
|
223
181
|
apiKey
|
|
224
182
|
.command(api_key_service_1.ApiKeyService.COMMANDS.ROTATE)
|
|
225
|
-
.description(
|
|
226
|
-
.argument(
|
|
227
|
-
.action((id) =>
|
|
183
|
+
.description('Rotate an API key (creates a new one and invalidates the old one)')
|
|
184
|
+
.argument('<id>', 'ID of the API key to rotate')
|
|
185
|
+
.action(async (id) => {
|
|
228
186
|
try {
|
|
229
187
|
console.log(chalk_1.default.blue(`Rotating API key ${id}...`));
|
|
230
|
-
console.log(chalk_1.default.dim(
|
|
188
|
+
console.log(chalk_1.default.dim('This will invalidate the old key and generate a new one.'));
|
|
231
189
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
232
|
-
const result =
|
|
233
|
-
console.log(
|
|
234
|
-
console.log(chalk_1.default.green(
|
|
235
|
-
console.log(
|
|
236
|
-
console.log(chalk_1.default.bold(
|
|
237
|
-
console.log(
|
|
238
|
-
console.log(`${chalk_1.default.dim(
|
|
239
|
-
console.log(`${chalk_1.default.dim(
|
|
190
|
+
const result = await apiKeyService.rotate(id);
|
|
191
|
+
console.log('');
|
|
192
|
+
console.log(chalk_1.default.green('✓ API key rotated'));
|
|
193
|
+
console.log('');
|
|
194
|
+
console.log(chalk_1.default.bold('New API key details:'));
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(`${chalk_1.default.dim('ID:')} ${result.id}`);
|
|
197
|
+
console.log(`${chalk_1.default.dim('Name:')} ${result.name}`);
|
|
240
198
|
if (result.description) {
|
|
241
|
-
console.log(`${chalk_1.default.dim(
|
|
199
|
+
console.log(`${chalk_1.default.dim('Description:')} ${result.description}`);
|
|
242
200
|
}
|
|
243
|
-
console.log(`${chalk_1.default.dim(
|
|
244
|
-
console.log(
|
|
245
|
-
console.log(chalk_1.default.bold(
|
|
201
|
+
console.log(`${chalk_1.default.dim('Created:')} ${new Date(result.created).toLocaleString()}`);
|
|
202
|
+
console.log('');
|
|
203
|
+
console.log(chalk_1.default.bold('New API key:'));
|
|
246
204
|
console.log(chalk_1.default.cyan(result.key));
|
|
247
|
-
console.log(
|
|
248
|
-
console.log(chalk_1.default.yellow(
|
|
249
|
-
console.log(chalk_1.default.yellow(
|
|
250
|
-
console.log(chalk_1.default.yellow(
|
|
205
|
+
console.log('');
|
|
206
|
+
console.log(chalk_1.default.yellow('⚠️ IMPORTANT: Update your applications with this new API key.'));
|
|
207
|
+
console.log(chalk_1.default.yellow(' The old key has been invalidated and will no longer work.'));
|
|
208
|
+
console.log(chalk_1.default.yellow(' This new key will not be displayed again.'));
|
|
251
209
|
}
|
|
252
210
|
catch (error) {
|
|
253
|
-
(0, error_handler_1.handleError)(
|
|
211
|
+
(0, error_handler_1.handleError)('Failed to rotate API key', error);
|
|
254
212
|
}
|
|
255
|
-
})
|
|
213
|
+
});
|
|
256
214
|
apiKey
|
|
257
215
|
.command(api_key_service_1.ApiKeyService.COMMANDS.DESCRIBE)
|
|
258
|
-
.description(
|
|
259
|
-
.argument(
|
|
260
|
-
.option(
|
|
261
|
-
.option(
|
|
262
|
-
.action((id, _options) =>
|
|
216
|
+
.description('Show usage statistics for an API key')
|
|
217
|
+
.argument('<id>', 'ID of the API key')
|
|
218
|
+
.option('--start <date>', 'Start date (YYYY-MM-DD)')
|
|
219
|
+
.option('--end <date>', 'End date (YYYY-MM-DD)')
|
|
220
|
+
.action(async (id, _options) => {
|
|
263
221
|
try {
|
|
264
222
|
console.log(chalk_1.default.blue(`Fetching usage statistics for API key ${id}...`));
|
|
265
223
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
266
|
-
const usage =
|
|
267
|
-
console.log(
|
|
224
|
+
const usage = await apiKeyService.describe(id);
|
|
225
|
+
console.log('');
|
|
268
226
|
console.log(chalk_1.default.bold(`Usage statistics for API key: ${usage.name} (${id})`));
|
|
269
|
-
console.log(
|
|
227
|
+
console.log('');
|
|
270
228
|
// Period information
|
|
271
229
|
console.log(chalk_1.default.dim(`Period: ${usage.period.start} to ${usage.period.end}`));
|
|
272
|
-
console.log(
|
|
230
|
+
console.log('');
|
|
273
231
|
// Request statistics
|
|
274
|
-
console.log(chalk_1.default.bold(
|
|
232
|
+
console.log(chalk_1.default.bold('Request statistics:'));
|
|
275
233
|
console.log(`Total requests: ${chalk_1.default.cyan(usage.requests.total.toLocaleString())}`);
|
|
276
234
|
// Daily breakdown if available
|
|
277
235
|
if (usage.requests.daily && usage.requests.daily.length > 0) {
|
|
278
|
-
console.log(
|
|
279
|
-
console.log(chalk_1.default.bold(
|
|
280
|
-
console.log(chalk_1.default.dim(
|
|
281
|
-
console.log(chalk_1.default.dim(
|
|
236
|
+
console.log('');
|
|
237
|
+
console.log(chalk_1.default.bold('Daily breakdown:'));
|
|
238
|
+
console.log(chalk_1.default.dim('─'.repeat(30)));
|
|
239
|
+
console.log(chalk_1.default.dim('DATE'.padEnd(12) + 'REQUESTS'));
|
|
282
240
|
usage.requests.daily.forEach((day) => {
|
|
283
241
|
console.log(`${day.date.padEnd(12)}${day.count.toLocaleString()}`);
|
|
284
242
|
});
|
|
285
243
|
}
|
|
286
244
|
// Model usage if available
|
|
287
245
|
if (usage.models && usage.models.length > 0) {
|
|
288
|
-
console.log(
|
|
289
|
-
console.log(chalk_1.default.bold(
|
|
290
|
-
console.log(chalk_1.default.dim(
|
|
291
|
-
console.log(chalk_1.default.dim(
|
|
292
|
-
chalk_1.default.dim(
|
|
293
|
-
chalk_1.default.dim(
|
|
294
|
-
chalk_1.default.dim(
|
|
295
|
-
chalk_1.default.dim(
|
|
246
|
+
console.log('');
|
|
247
|
+
console.log(chalk_1.default.bold('Model usage:'));
|
|
248
|
+
console.log(chalk_1.default.dim('─'.repeat(70)));
|
|
249
|
+
console.log(chalk_1.default.dim('MODEL'.padEnd(20)) +
|
|
250
|
+
chalk_1.default.dim('REQUESTS'.padEnd(10)) +
|
|
251
|
+
chalk_1.default.dim('INPUT'.padEnd(12)) +
|
|
252
|
+
chalk_1.default.dim('OUTPUT'.padEnd(12)) +
|
|
253
|
+
chalk_1.default.dim('TOTAL TOKENS'));
|
|
296
254
|
usage.models.forEach((model) => {
|
|
297
255
|
console.log(model.name.padEnd(20) +
|
|
298
256
|
model.requests.toString().padEnd(10) +
|
|
@@ -301,22 +259,22 @@ function registerApiKeyCommands(program) {
|
|
|
301
259
|
model.tokens.total.toLocaleString());
|
|
302
260
|
});
|
|
303
261
|
}
|
|
304
|
-
console.log(
|
|
305
|
-
console.log(chalk_1.default.dim(
|
|
262
|
+
console.log('');
|
|
263
|
+
console.log(chalk_1.default.dim('Use these statistics to understand your API usage and optimize your costs.'));
|
|
306
264
|
}
|
|
307
265
|
catch (error) {
|
|
308
|
-
(0, error_handler_1.handleError)(
|
|
266
|
+
(0, error_handler_1.handleError)('Failed to get API key usage', error);
|
|
309
267
|
}
|
|
310
|
-
})
|
|
268
|
+
});
|
|
311
269
|
apiKey
|
|
312
270
|
.command(api_key_service_1.ApiKeyService.COMMANDS.SET_DEFAULT)
|
|
313
|
-
.description(
|
|
314
|
-
.argument(
|
|
315
|
-
.action((id) =>
|
|
271
|
+
.description('Set an API key as the default for chat commands')
|
|
272
|
+
.argument('<id>', 'ID of the API key to set as default')
|
|
273
|
+
.action(async (id) => {
|
|
316
274
|
try {
|
|
317
275
|
const apiKeyService = api_key_service_1.ApiKeyService.getInstance();
|
|
318
|
-
const keys =
|
|
319
|
-
const selectedKey = keys.find(key => key.id.toString() === id);
|
|
276
|
+
const keys = await apiKeyService.list();
|
|
277
|
+
const selectedKey = keys.find((key) => key.id.toString() === id);
|
|
320
278
|
if (!selectedKey) {
|
|
321
279
|
console.error(chalk_1.default.red(`Error: API key with ID ${id} not found`));
|
|
322
280
|
return;
|
|
@@ -324,43 +282,78 @@ function registerApiKeyCommands(program) {
|
|
|
324
282
|
// Save the default API key
|
|
325
283
|
const defaultApiKeyManager = default_api_key_1.DefaultApiKeyManager.getInstance();
|
|
326
284
|
// We need to rotate the key to get the actual key value
|
|
327
|
-
const rotatedKey =
|
|
285
|
+
const rotatedKey = await apiKeyService.rotate(id);
|
|
328
286
|
defaultApiKeyManager.setDefaultApiKey(id, selectedKey.name, selectedKey.prefix, rotatedKey.key);
|
|
329
287
|
console.log(chalk_1.default.green(`✓ API key "${selectedKey.name}" set as default for chat commands`));
|
|
330
|
-
console.log(
|
|
331
|
-
console.log(chalk_1.default.dim(
|
|
332
|
-
console.log(chalk_1.default.dim(
|
|
288
|
+
console.log('');
|
|
289
|
+
console.log(chalk_1.default.dim('This API key will be used by default when running chat commands'));
|
|
290
|
+
console.log(chalk_1.default.dim('You can override it with --api-key or --api-key-id options'));
|
|
333
291
|
}
|
|
334
292
|
catch (error) {
|
|
335
|
-
(0, error_handler_1.handleError)(
|
|
293
|
+
(0, error_handler_1.handleError)('Failed to set default API key', error);
|
|
336
294
|
}
|
|
337
|
-
})
|
|
295
|
+
});
|
|
338
296
|
apiKey
|
|
339
297
|
.command(api_key_service_1.ApiKeyService.COMMANDS.GET_DEFAULT)
|
|
340
|
-
.description(
|
|
298
|
+
.description('Show the current default API key')
|
|
341
299
|
.action(() => {
|
|
342
300
|
try {
|
|
343
301
|
const defaultApiKeyManager = default_api_key_1.DefaultApiKeyManager.getInstance();
|
|
344
302
|
const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
|
|
345
303
|
if (!defaultApiKeyData) {
|
|
346
|
-
console.log(chalk_1.default.yellow(
|
|
347
|
-
console.log(
|
|
348
|
-
console.log(
|
|
349
|
-
console.log(chalk_1.default.cyan(
|
|
304
|
+
console.log(chalk_1.default.yellow('No default API key set'));
|
|
305
|
+
console.log('');
|
|
306
|
+
console.log('To set a default API key, run:');
|
|
307
|
+
console.log(chalk_1.default.cyan(' berget api-keys set-default <id>'));
|
|
350
308
|
return;
|
|
351
309
|
}
|
|
352
|
-
console.log(chalk_1.default.bold(
|
|
353
|
-
console.log(
|
|
354
|
-
console.log(`${chalk_1.default.dim(
|
|
355
|
-
console.log(`${chalk_1.default.dim(
|
|
356
|
-
console.log(`${chalk_1.default.dim(
|
|
357
|
-
console.log(
|
|
358
|
-
console.log(chalk_1.default.dim(
|
|
359
|
-
console.log(chalk_1.default.dim(
|
|
310
|
+
console.log(chalk_1.default.bold('Default API key:'));
|
|
311
|
+
console.log('');
|
|
312
|
+
console.log(`${chalk_1.default.dim('ID:')} ${defaultApiKeyData.id}`);
|
|
313
|
+
console.log(`${chalk_1.default.dim('Name:')} ${defaultApiKeyData.name}`);
|
|
314
|
+
console.log(`${chalk_1.default.dim('Prefix:')} ${defaultApiKeyData.prefix}`);
|
|
315
|
+
console.log('');
|
|
316
|
+
console.log(chalk_1.default.dim('This API key will be used by default when running chat commands'));
|
|
317
|
+
console.log(chalk_1.default.dim('You can override it with --api-key or --api-key-id options'));
|
|
360
318
|
}
|
|
361
319
|
catch (error) {
|
|
362
|
-
(0, error_handler_1.handleError)(
|
|
320
|
+
(0, error_handler_1.handleError)('Failed to get default API key', error);
|
|
363
321
|
}
|
|
364
322
|
});
|
|
365
323
|
}
|
|
366
324
|
exports.registerApiKeyCommands = registerApiKeyCommands;
|
|
325
|
+
// Helper functions for better date formatting
|
|
326
|
+
function formatDate(dateString) {
|
|
327
|
+
const date = new Date(dateString);
|
|
328
|
+
const now = new Date();
|
|
329
|
+
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
330
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
331
|
+
if (diffDays === 0)
|
|
332
|
+
return chalk_1.default.green('Today');
|
|
333
|
+
if (diffDays === 1)
|
|
334
|
+
return chalk_1.default.yellow('Yesterday');
|
|
335
|
+
if (diffDays < 7)
|
|
336
|
+
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
337
|
+
if (diffDays < 30)
|
|
338
|
+
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
339
|
+
if (diffDays < 365)
|
|
340
|
+
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
341
|
+
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
342
|
+
}
|
|
343
|
+
function formatLastUsed(dateString) {
|
|
344
|
+
const date = new Date(dateString);
|
|
345
|
+
const now = new Date();
|
|
346
|
+
const diffTime = Math.abs(now.getTime() - date.getTime());
|
|
347
|
+
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
348
|
+
if (diffDays === 0)
|
|
349
|
+
return chalk_1.default.green('Today');
|
|
350
|
+
if (diffDays === 1)
|
|
351
|
+
return chalk_1.default.yellow('Yesterday');
|
|
352
|
+
if (diffDays < 7)
|
|
353
|
+
return chalk_1.default.yellow(`${diffDays} days ago`);
|
|
354
|
+
if (diffDays < 30)
|
|
355
|
+
return chalk_1.default.blue(`${Math.floor(diffDays / 7)} weeks ago`);
|
|
356
|
+
if (diffDays < 365)
|
|
357
|
+
return chalk_1.default.magenta(`${Math.floor(diffDays / 30)} months ago`);
|
|
358
|
+
return chalk_1.default.gray(`${Math.floor(diffDays / 365)} years ago`);
|
|
359
|
+
}
|