berget 2.2.6 → 2.2.7

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 (144) hide show
  1. package/.github/workflows/publish.yml +6 -6
  2. package/.github/workflows/test.yml +11 -5
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +5 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +21 -21
  9. package/dist/package.json +28 -2
  10. package/dist/src/agents/app.js +28 -0
  11. package/dist/src/agents/backend.js +25 -0
  12. package/dist/src/agents/devops.js +34 -0
  13. package/dist/src/agents/frontend.js +25 -0
  14. package/dist/src/agents/fullstack.js +25 -0
  15. package/dist/src/agents/index.js +61 -0
  16. package/dist/src/agents/quality.js +70 -0
  17. package/dist/src/agents/security.js +26 -0
  18. package/dist/src/agents/types.js +2 -0
  19. package/dist/src/client.js +54 -62
  20. package/dist/src/commands/api-keys.js +132 -140
  21. package/dist/src/commands/auth.js +9 -9
  22. package/dist/src/commands/autocomplete.js +9 -9
  23. package/dist/src/commands/billing.js +7 -9
  24. package/dist/src/commands/chat.js +90 -92
  25. package/dist/src/commands/clusters.js +12 -12
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +348 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +23 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +55 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +5 -7
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +9 -0
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +60 -18
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +374 -107
  33. package/dist/src/commands/code/adapters/clack-prompter.js +10 -0
  34. package/dist/src/commands/code/adapters/fs-file-store.js +8 -3
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +15 -11
  36. package/dist/src/commands/code/auth-sync.js +283 -0
  37. package/dist/src/commands/code/errors.js +4 -4
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/setup.js +234 -93
  40. package/dist/src/commands/code.js +139 -251
  41. package/dist/src/commands/models.js +13 -15
  42. package/dist/src/commands/users.js +6 -8
  43. package/dist/src/constants/command-structure.js +116 -116
  44. package/dist/src/services/api-key-service.js +43 -48
  45. package/dist/src/services/auth-service.js +60 -299
  46. package/dist/src/services/browser-auth.js +278 -0
  47. package/dist/src/services/chat-service.js +78 -91
  48. package/dist/src/services/cluster-service.js +6 -6
  49. package/dist/src/services/collaborator-service.js +5 -8
  50. package/dist/src/services/flux-service.js +5 -8
  51. package/dist/src/services/helm-service.js +5 -8
  52. package/dist/src/services/kubectl-service.js +7 -10
  53. package/dist/src/utils/config-checker.js +5 -5
  54. package/dist/src/utils/config-loader.js +25 -25
  55. package/dist/src/utils/default-api-key.js +23 -23
  56. package/dist/src/utils/env-manager.js +7 -7
  57. package/dist/src/utils/error-handler.js +60 -61
  58. package/dist/src/utils/logger.js +7 -7
  59. package/dist/src/utils/markdown-renderer.js +2 -2
  60. package/dist/src/utils/opencode-validator.js +17 -20
  61. package/dist/src/utils/token-manager.js +38 -11
  62. package/dist/tests/commands/chat.test.js +24 -24
  63. package/dist/tests/commands/code.test.js +147 -147
  64. package/dist/tests/utils/config-loader.test.js +114 -114
  65. package/dist/tests/utils/env-manager.test.js +57 -57
  66. package/dist/tests/utils/opencode-validator.test.js +33 -33
  67. package/dist/vitest.config.js +1 -1
  68. package/eslint.config.mjs +47 -0
  69. package/index.ts +42 -48
  70. package/package.json +28 -2
  71. package/src/agents/app.ts +27 -0
  72. package/src/agents/backend.ts +24 -0
  73. package/src/agents/devops.ts +33 -0
  74. package/src/agents/frontend.ts +24 -0
  75. package/src/agents/fullstack.ts +24 -0
  76. package/src/agents/index.ts +71 -0
  77. package/src/agents/quality.ts +69 -0
  78. package/src/agents/security.ts +26 -0
  79. package/src/agents/types.ts +17 -0
  80. package/src/client.ts +125 -167
  81. package/src/commands/api-keys.ts +261 -358
  82. package/src/commands/auth.ts +24 -30
  83. package/src/commands/autocomplete.ts +12 -12
  84. package/src/commands/billing.ts +22 -27
  85. package/src/commands/chat.ts +230 -323
  86. package/src/commands/clusters.ts +33 -33
  87. package/src/commands/code/__tests__/auth-sync.test.ts +481 -0
  88. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  89. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  90. package/src/commands/code/__tests__/fake-command-runner.ts +39 -42
  91. package/src/commands/code/__tests__/fake-file-store.ts +32 -23
  92. package/src/commands/code/__tests__/fake-prompter.ts +107 -69
  93. package/src/commands/code/__tests__/setup-flow.test.ts +624 -270
  94. package/src/commands/code/adapters/clack-prompter.ts +50 -38
  95. package/src/commands/code/adapters/fs-file-store.ts +31 -27
  96. package/src/commands/code/adapters/spawn-command-runner.ts +33 -29
  97. package/src/commands/code/auth-sync.ts +329 -0
  98. package/src/commands/code/errors.ts +15 -15
  99. package/src/commands/code/ports/auth-services.ts +14 -0
  100. package/src/commands/code/ports/command-runner.ts +8 -4
  101. package/src/commands/code/ports/file-store.ts +5 -4
  102. package/src/commands/code/ports/prompter.ts +24 -18
  103. package/src/commands/code/setup.ts +545 -317
  104. package/src/commands/code.ts +271 -473
  105. package/src/commands/index.ts +19 -19
  106. package/src/commands/models.ts +32 -37
  107. package/src/commands/users.ts +15 -22
  108. package/src/constants/command-structure.ts +119 -142
  109. package/src/services/api-key-service.ts +96 -113
  110. package/src/services/auth-service.ts +92 -339
  111. package/src/services/browser-auth.ts +296 -0
  112. package/src/services/chat-service.ts +246 -279
  113. package/src/services/cluster-service.ts +29 -32
  114. package/src/services/collaborator-service.ts +13 -18
  115. package/src/services/flux-service.ts +16 -18
  116. package/src/services/helm-service.ts +16 -18
  117. package/src/services/kubectl-service.ts +12 -14
  118. package/src/types/api.d.ts +924 -926
  119. package/src/types/json.d.ts +3 -3
  120. package/src/utils/config-checker.ts +10 -10
  121. package/src/utils/config-loader.ts +110 -127
  122. package/src/utils/default-api-key.ts +81 -93
  123. package/src/utils/env-manager.ts +36 -40
  124. package/src/utils/error-handler.ts +83 -78
  125. package/src/utils/logger.ts +41 -41
  126. package/src/utils/markdown-renderer.ts +11 -11
  127. package/src/utils/opencode-validator.ts +51 -56
  128. package/src/utils/token-manager.ts +84 -64
  129. package/templates/agents/app.md +1 -0
  130. package/templates/agents/backend.md +1 -0
  131. package/templates/agents/devops.md +2 -0
  132. package/templates/agents/frontend.md +1 -0
  133. package/templates/agents/fullstack.md +1 -0
  134. package/templates/agents/quality.md +45 -40
  135. package/templates/agents/security.md +1 -0
  136. package/tests/commands/chat.test.ts +60 -70
  137. package/tests/commands/code.test.ts +330 -376
  138. package/tests/utils/config-loader.test.ts +260 -260
  139. package/tests/utils/env-manager.test.ts +127 -134
  140. package/tests/utils/opencode-validator.test.ts +58 -63
  141. package/tsconfig.json +2 -2
  142. package/vitest.config.ts +3 -3
  143. package/AGENTS.md +0 -374
  144. package/TODO.md +0 -19
@@ -1,108 +1,106 @@
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'
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
6
 
7
7
  // Helper functions for better date formatting
8
8
  function formatDate(dateString: string): string {
9
- const date = new Date(dateString)
10
- const now = new Date()
11
- const diffTime = Math.abs(now.getTime() - date.getTime())
12
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
13
-
14
- if (diffDays === 0) return chalk.green('Today')
15
- if (diffDays === 1) return chalk.yellow('Yesterday')
16
- if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`)
17
- if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`)
18
- if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`)
19
- return chalk.gray(`${Math.floor(diffDays / 365)} years ago`)
9
+ const date = new Date(dateString);
10
+ const now = new Date();
11
+ const diffTime = Math.abs(now.getTime() - date.getTime());
12
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
13
+
14
+ if (diffDays === 0) return chalk.green("Today");
15
+ if (diffDays === 1) return chalk.yellow("Yesterday");
16
+ if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`);
17
+ if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`);
18
+ if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`);
19
+ return chalk.gray(`${Math.floor(diffDays / 365)} years ago`);
20
20
  }
21
21
 
22
22
  function formatLastUsed(dateString: string): string {
23
- const date = new Date(dateString)
24
- const now = new Date()
25
- const diffTime = Math.abs(now.getTime() - date.getTime())
26
- const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
27
-
28
- if (diffDays === 0) return chalk.green('Today')
29
- if (diffDays === 1) return chalk.yellow('Yesterday')
30
- if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`)
31
- if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`)
32
- if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`)
33
- return chalk.gray(`${Math.floor(diffDays / 365)} years ago`)
23
+ const date = new Date(dateString);
24
+ const now = new Date();
25
+ const diffTime = Math.abs(now.getTime() - date.getTime());
26
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
27
+
28
+ if (diffDays === 0) return chalk.green("Today");
29
+ if (diffDays === 1) return chalk.yellow("Yesterday");
30
+ if (diffDays < 7) return chalk.yellow(`${diffDays} days ago`);
31
+ if (diffDays < 30) return chalk.blue(`${Math.floor(diffDays / 7)} weeks ago`);
32
+ if (diffDays < 365) return chalk.magenta(`${Math.floor(diffDays / 30)} months ago`);
33
+ return chalk.gray(`${Math.floor(diffDays / 365)} years ago`);
34
34
  }
35
35
 
36
36
  /**
37
37
  * Register API key commands
38
38
  */
39
39
  export function registerApiKeyCommands(program: Command): void {
40
- const apiKey = program
41
- .command(ApiKeyService.COMMAND_GROUP)
42
- .description('Manage API keys')
40
+ const apiKey = program.command(ApiKeyService.COMMAND_GROUP).description("Manage API keys");
43
41
 
44
42
  apiKey
45
43
  .command(ApiKeyService.COMMANDS.LIST)
46
- .description('List all API keys')
44
+ .description("List all API keys")
47
45
  .action(async () => {
48
46
  try {
49
- const apiKeyService = ApiKeyService.getInstance()
50
- const keys = await apiKeyService.list()
47
+ const apiKeyService = ApiKeyService.getInstance();
48
+ const keys = await apiKeyService.list();
51
49
 
52
50
  if (keys.length === 0) {
53
51
  console.log(
54
- chalk.yellow(
55
- 'No API keys found. Create one with `berget api-key create --name <name>`',
56
- ),
57
- )
58
- return
52
+ chalk.yellow("No API keys found. Create one with `berget api-key create --name <name>`")
53
+ );
54
+ return;
59
55
  }
60
56
 
61
- console.log(chalk.bold('🔑 Your API keys:'))
62
- console.log('')
57
+ console.log(chalk.bold("🔑 Your API keys:"));
58
+ console.log("");
63
59
 
64
60
  // Create a more readable table with better spacing and colors
65
- const idWidth = 10
66
- const nameWidth = 30
67
- const prefixWidth = 20
68
- const statusWidth = 12
69
- const createdWidth = 12
70
- const usedWidth = 15
61
+ const idWidth = 10;
62
+ const nameWidth = 30;
63
+ const prefixWidth = 20;
64
+ const statusWidth = 12;
65
+ const createdWidth = 12;
66
+ const usedWidth = 15;
71
67
 
72
68
  console.log(
73
- chalk.dim('ID'.padEnd(idWidth)) +
74
- chalk.dim('NAME'.padEnd(nameWidth)) +
75
- chalk.dim('PREFIX'.padEnd(prefixWidth)) +
76
- chalk.dim('STATUS'.padEnd(statusWidth)) +
77
- chalk.dim('CREATED'.padEnd(createdWidth)) +
78
- chalk.dim('LAST USED')
79
- )
69
+ chalk.dim("ID".padEnd(idWidth)) +
70
+ chalk.dim("NAME".padEnd(nameWidth)) +
71
+ chalk.dim("PREFIX".padEnd(prefixWidth)) +
72
+ chalk.dim("STATUS".padEnd(statusWidth)) +
73
+ chalk.dim("CREATED".padEnd(createdWidth)) +
74
+ chalk.dim("LAST USED")
75
+ );
80
76
 
81
- console.log(chalk.dim('─'.repeat(idWidth + nameWidth + prefixWidth + statusWidth + createdWidth + usedWidth + 5)))
77
+ console.log(
78
+ chalk.dim(
79
+ "─".repeat(
80
+ idWidth + nameWidth + prefixWidth + statusWidth + createdWidth + usedWidth + 5
81
+ )
82
+ )
83
+ );
82
84
 
83
85
  keys.forEach((key: ApiKey) => {
84
- const lastUsed = key.lastUsed
85
- ? formatLastUsed(key.lastUsed)
86
- : chalk.yellow('Never used')
87
- const status = key.active
88
- ? chalk.green('● Active')
89
- : chalk.red('● Inactive')
86
+ const lastUsed = key.lastUsed ? formatLastUsed(key.lastUsed) : chalk.yellow("Never used");
87
+ const status = key.active ? chalk.green("● Active") : chalk.red("● Inactive");
90
88
 
91
89
  // Show only first 8 characters of ID for easier reading
92
- const shortId = chalk.cyan(String(key.id).substring(0, 8))
90
+ const shortId = chalk.cyan(String(key.id).substring(0, 8));
93
91
 
94
92
  // Format the prefix with better truncation
95
- const prefixStr = key.prefix.length > prefixWidth
96
- ? key.prefix.substring(0, prefixWidth - 3) + '...'
97
- : chalk.gray(key.prefix)
93
+ const prefixStr =
94
+ key.prefix.length > prefixWidth
95
+ ? key.prefix.substring(0, prefixWidth - 3) + "..."
96
+ : chalk.gray(key.prefix);
98
97
 
99
98
  // Truncate name if too long
100
- const nameStr = key.name.length > nameWidth
101
- ? key.name.substring(0, nameWidth - 3) + '...'
102
- : key.name
99
+ const nameStr =
100
+ key.name.length > nameWidth ? key.name.substring(0, nameWidth - 3) + "..." : key.name;
103
101
 
104
102
  // Format created date
105
- const createdDate = formatDate(key.created)
103
+ const createdDate = formatDate(key.created);
106
104
 
107
105
  console.log(
108
106
  shortId.padEnd(idWidth) +
@@ -111,101 +109,78 @@ export function registerApiKeyCommands(program: Command): void {
111
109
  status.padEnd(statusWidth) +
112
110
  createdDate.padEnd(createdWidth) +
113
111
  lastUsed
114
- )
115
- })
112
+ );
113
+ });
116
114
 
117
- console.log('')
118
- console.log(
119
- chalk.dim(
120
- 'Use `berget api-key create --name <name>` to create a new API key',
121
- ),
122
- )
123
- console.log(
124
- chalk.dim('Use `berget api-key delete <id>` to delete an API key'),
125
- )
126
- console.log(
127
- chalk.dim('Use `berget api-key rotate <id>` to rotate an API key'),
128
- )
115
+ console.log("");
116
+ console.log(chalk.dim("Use `berget api-key create --name <name>` to create a new API key"));
117
+ console.log(chalk.dim("Use `berget api-key delete <id>` to delete an API key"));
118
+ console.log(chalk.dim("Use `berget api-key rotate <id>` to rotate an API key"));
129
119
  } catch (error) {
130
- handleError('Failed to list API keys', error)
120
+ handleError("Failed to list API keys", error);
131
121
  }
132
- })
122
+ });
133
123
 
134
124
  apiKey
135
125
  .command(ApiKeyService.COMMANDS.CREATE)
136
- .description('Create a new API key')
137
- .option('--name <name>', 'Name of the API key')
138
- .option('--description <description>', 'Description of the API key')
126
+ .description("Create a new API key")
127
+ .option("--name <name>", "Name of the API key")
128
+ .option("--description <description>", "Description of the API key")
139
129
 
140
- .action(async (options) => {
130
+ .action(async options => {
141
131
  try {
142
132
  if (!options.name) {
143
- console.error(chalk.red('Error: --name is required'))
144
- console.log('')
145
- console.log(
146
- 'Usage: berget api-key create --name <name> [--description <description>]',
147
- )
148
- return
133
+ console.error(chalk.red("Error: --name is required"));
134
+ console.log("");
135
+ console.log("Usage: berget api-key create --name <name> [--description <description>]");
136
+ return;
149
137
  }
150
138
 
151
- console.log(chalk.blue('Creating API key...'))
139
+ console.log(chalk.blue("Creating API key..."));
152
140
 
153
- const apiKeyService = ApiKeyService.getInstance()
141
+ const apiKeyService = ApiKeyService.getInstance();
154
142
  const result = await apiKeyService.create({
155
143
  name: options.name,
156
144
  description: options.description,
157
- })
158
-
159
- console.log('')
160
- console.log(chalk.green('✓ API key created'))
161
- console.log('')
162
- console.log(chalk.bold('API key details:'))
163
- console.log('')
164
- console.log(`${chalk.dim('ID:')} ${result.id}`)
165
- console.log(`${chalk.dim('Name:')} ${result.name}`)
145
+ });
146
+
147
+ console.log("");
148
+ console.log(chalk.green("✓ API key created"));
149
+ console.log("");
150
+ console.log(chalk.bold("API key details:"));
151
+ console.log("");
152
+ console.log(`${chalk.dim("ID:")} ${result.id}`);
153
+ console.log(`${chalk.dim("Name:")} ${result.name}`);
166
154
  if (result.description) {
167
- console.log(`${chalk.dim('Description:')} ${result.description}`)
155
+ console.log(`${chalk.dim("Description:")} ${result.description}`);
168
156
  }
157
+ console.log(`${chalk.dim("Created:")} ${new Date(result.created).toLocaleString()}`);
158
+ console.log("");
159
+ console.log(chalk.bold("API key:"));
160
+ console.log(chalk.cyan(result.key));
161
+ console.log("");
162
+ console.log(chalk.yellow("⚠️ IMPORTANT: Save this API key in a secure location."));
163
+ console.log(chalk.yellow(" It will not be displayed again."));
164
+
165
+ console.log("");
169
166
  console.log(
170
- `${chalk.dim('Created:')} ${new Date(
171
- result.created,
172
- ).toLocaleString()}`,
173
- )
174
- console.log('')
175
- console.log(chalk.bold('API key:'))
176
- console.log(chalk.cyan(result.key))
177
- console.log('')
178
- console.log(
179
- chalk.yellow(
180
- '⚠️ IMPORTANT: Save this API key in a secure location.',
181
- ),
182
- )
183
- console.log(chalk.yellow(' It will not be displayed again.'))
184
-
185
- console.log('')
186
- console.log(
187
- chalk.dim(
188
- 'Use this key in your applications to authenticate with the Berget API.',
189
- ),
190
- )
167
+ chalk.dim("Use this key in your applications to authenticate with the Berget API.")
168
+ );
191
169
  } catch (error) {
192
- handleError('Failed to create API key', error)
170
+ handleError("Failed to create API key", error);
193
171
  }
194
- })
172
+ });
195
173
 
196
174
  apiKey
197
175
  .command(ApiKeyService.COMMANDS.DELETE)
198
- .description('Delete an API key')
199
- .argument(
200
- '<identifier>',
201
- 'ID (first 8 chars), full ID, or name of the API key to delete',
202
- )
203
- .action(async (identifier) => {
176
+ .description("Delete an API key")
177
+ .argument("<identifier>", "ID (first 8 chars), full ID, or name of the API key to delete")
178
+ .action(async identifier => {
204
179
  try {
205
- const apiKeyService = ApiKeyService.getInstance()
180
+ const apiKeyService = ApiKeyService.getInstance();
206
181
 
207
182
  // First, get all API keys to find the matching one
208
- const keys = await apiKeyService.list()
183
+ const keys = await apiKeyService.list();
209
184
 
210
185
  // Try to find the key by:
211
186
  // 1. Full ID match
@@ -215,321 +190,249 @@ export function registerApiKeyCommands(program: Command): void {
215
190
 
216
191
  // Check for exact matches first (full ID or exact name)
217
192
  let exactMatches = keys.filter(
218
- (key) => String(key.id) === identifier || key.name === identifier,
219
- )
193
+ key => String(key.id) === identifier || key.name === identifier
194
+ );
220
195
 
221
196
  // If no exact matches, check for short ID matches
222
197
  if (exactMatches.length === 0) {
223
- exactMatches = keys.filter(
224
- (key) => String(key.id).substring(0, 8) === identifier,
225
- )
198
+ exactMatches = keys.filter(key => String(key.id).substring(0, 8) === identifier);
226
199
  }
227
200
 
228
201
  // If still no matches, check for partial name matches
229
202
  if (exactMatches.length === 0) {
230
- exactMatches = keys.filter((key) =>
231
- key.name.toLowerCase().includes(identifier.toLowerCase()),
232
- )
203
+ exactMatches = keys.filter(key =>
204
+ key.name.toLowerCase().includes(identifier.toLowerCase())
205
+ );
233
206
  }
234
207
 
235
208
  // Handle multiple matches
236
209
  if (exactMatches.length > 1) {
237
- console.error(
238
- chalk.red(
239
- `Error: Multiple API keys found matching "${identifier}"`,
240
- ),
241
- )
242
- console.log('')
243
- console.log('Please be more specific. Matching keys:')
244
- exactMatches.forEach((key) => {
245
- const shortId = String(key.id).substring(0, 8)
246
- console.log(` ${shortId.padEnd(8)} ${key.name}`)
247
- })
248
- console.log('')
249
- console.log(
250
- 'Use the first 8 characters of the ID to specify which key to delete.',
251
- )
252
- return
210
+ console.error(chalk.red(`Error: Multiple API keys found matching "${identifier}"`));
211
+ console.log("");
212
+ console.log("Please be more specific. Matching keys:");
213
+ exactMatches.forEach(key => {
214
+ const shortId = String(key.id).substring(0, 8);
215
+ console.log(` ${shortId.padEnd(8)} ${key.name}`);
216
+ });
217
+ console.log("");
218
+ console.log("Use the first 8 characters of the ID to specify which key to delete.");
219
+ return;
253
220
  }
254
221
 
255
222
  // Handle no matches
256
223
  if (exactMatches.length === 0) {
257
- console.error(
258
- chalk.red(`Error: No API key found matching "${identifier}"`),
259
- )
260
- console.log('')
261
- console.log('Available API keys:')
262
- keys.forEach((key) => {
263
- const shortId = String(key.id).substring(0, 8)
264
- console.log(` ${shortId.padEnd(8)} ${key.name}`)
265
- })
266
- console.log('')
267
- console.log(
268
- 'Use the first 8 characters of the ID, full ID, or name to delete.',
269
- )
270
- return
224
+ console.error(chalk.red(`Error: No API key found matching "${identifier}"`));
225
+ console.log("");
226
+ console.log("Available API keys:");
227
+ keys.forEach(key => {
228
+ const shortId = String(key.id).substring(0, 8);
229
+ console.log(` ${shortId.padEnd(8)} ${key.name}`);
230
+ });
231
+ console.log("");
232
+ console.log("Use the first 8 characters of the ID, full ID, or name to delete.");
233
+ return;
271
234
  }
272
235
 
273
- const matchingKey = exactMatches[0]
236
+ const matchingKey = exactMatches[0];
274
237
 
275
- const keyId = String(matchingKey.id)
276
- const shortId = keyId.substring(0, 8)
238
+ const keyId = String(matchingKey.id);
239
+ const shortId = keyId.substring(0, 8);
277
240
 
278
- console.log(
279
- chalk.blue(`Deleting API key ${shortId} (${matchingKey.name})...`),
280
- )
241
+ console.log(chalk.blue(`Deleting API key ${shortId} (${matchingKey.name})...`));
281
242
 
282
- await apiKeyService.delete(keyId)
243
+ await apiKeyService.delete(keyId);
283
244
 
245
+ console.log(chalk.green(`✓ API key ${shortId} (${matchingKey.name}) has been deleted`));
246
+ console.log("");
284
247
  console.log(
285
- chalk.green(
286
- `✓ API key ${shortId} (${matchingKey.name}) has been deleted`,
287
- ),
288
- )
289
- console.log('')
290
- console.log(
291
- chalk.dim(
292
- 'Applications using this key will no longer be able to authenticate.',
293
- ),
294
- )
295
- console.log(
296
- chalk.dim(
297
- 'Use `berget api-key list` to see your remaining API keys.',
298
- ),
299
- )
248
+ chalk.dim("Applications using this key will no longer be able to authenticate.")
249
+ );
250
+ console.log(chalk.dim("Use `berget api-key list` to see your remaining API keys."));
300
251
  } catch (error) {
301
- handleError('Failed to delete API key', error)
252
+ handleError("Failed to delete API key", error);
302
253
  }
303
- })
254
+ });
304
255
 
305
256
  apiKey
306
257
  .command(ApiKeyService.COMMANDS.ROTATE)
307
- .description(
308
- 'Rotate an API key (creates a new one and invalidates the old one)',
309
- )
310
- .argument('<id>', 'ID of the API key to rotate')
311
- .action(async (id) => {
258
+ .description("Rotate an API key (creates a new one and invalidates the old one)")
259
+ .argument("<id>", "ID of the API key to rotate")
260
+ .action(async id => {
312
261
  try {
313
- console.log(chalk.blue(`Rotating API key ${id}...`))
314
- console.log(
315
- chalk.dim('This will invalidate the old key and generate a new one.'),
316
- )
317
-
318
- const apiKeyService = ApiKeyService.getInstance()
319
- const result = await apiKeyService.rotate(id)
320
-
321
- console.log('')
322
- console.log(chalk.green('✓ API key rotated'))
323
- console.log('')
324
- console.log(chalk.bold('New API key details:'))
325
- console.log('')
326
- console.log(`${chalk.dim('ID:')} ${result.id}`)
327
- console.log(`${chalk.dim('Name:')} ${result.name}`)
262
+ console.log(chalk.blue(`Rotating API key ${id}...`));
263
+ console.log(chalk.dim("This will invalidate the old key and generate a new one."));
264
+
265
+ const apiKeyService = ApiKeyService.getInstance();
266
+ const result = await apiKeyService.rotate(id);
267
+
268
+ console.log("");
269
+ console.log(chalk.green("✓ API key rotated"));
270
+ console.log("");
271
+ console.log(chalk.bold("New API key details:"));
272
+ console.log("");
273
+ console.log(`${chalk.dim("ID:")} ${result.id}`);
274
+ console.log(`${chalk.dim("Name:")} ${result.name}`);
328
275
  if (result.description) {
329
- console.log(`${chalk.dim('Description:')} ${result.description}`)
276
+ console.log(`${chalk.dim("Description:")} ${result.description}`);
330
277
  }
331
- console.log(
332
- `${chalk.dim('Created:')} ${new Date(
333
- result.created,
334
- ).toLocaleString()}`,
335
- )
336
- console.log('')
337
- console.log(chalk.bold('New API key:'))
338
- console.log(chalk.cyan(result.key))
339
- console.log('')
340
- console.log(
341
- chalk.yellow(
342
- '⚠️ IMPORTANT: Update your applications with this new API key.',
343
- ),
344
- )
345
- console.log(
346
- chalk.yellow(
347
- ' The old key has been invalidated and will no longer work.',
348
- ),
349
- )
350
- console.log(
351
- chalk.yellow(' This new key will not be displayed again.'),
352
- )
278
+ console.log(`${chalk.dim("Created:")} ${new Date(result.created).toLocaleString()}`);
279
+ console.log("");
280
+ console.log(chalk.bold("New API key:"));
281
+ console.log(chalk.cyan(result.key));
282
+ console.log("");
283
+ console.log(chalk.yellow("⚠️ IMPORTANT: Update your applications with this new API key."));
284
+ console.log(chalk.yellow(" The old key has been invalidated and will no longer work."));
285
+ console.log(chalk.yellow(" This new key will not be displayed again."));
353
286
  } catch (error) {
354
- handleError('Failed to rotate API key', error)
287
+ handleError("Failed to rotate API key", error);
355
288
  }
356
- })
289
+ });
357
290
 
358
291
  apiKey
359
292
  .command(ApiKeyService.COMMANDS.DESCRIBE)
360
- .description('Show usage statistics for an API key')
361
- .argument('<id>', 'ID of the API key')
362
- .option('--start <date>', 'Start date (YYYY-MM-DD)')
363
- .option('--end <date>', 'End date (YYYY-MM-DD)')
364
- .action(async (id, options) => {
293
+ .description("Show usage statistics for an API key")
294
+ .argument("<id>", "ID of the API key")
295
+ .option("--start <date>", "Start date (YYYY-MM-DD)")
296
+ .option("--end <date>", "End date (YYYY-MM-DD)")
297
+ .action(async (id, _options) => {
365
298
  try {
366
- console.log(
367
- chalk.blue(`Fetching usage statistics for API key ${id}...`),
368
- )
299
+ console.log(chalk.blue(`Fetching usage statistics for API key ${id}...`));
369
300
 
370
- const apiKeyService = ApiKeyService.getInstance()
371
- const usage = await apiKeyService.describe(id)
301
+ const apiKeyService = ApiKeyService.getInstance();
302
+ const usage = await apiKeyService.describe(id);
372
303
 
373
- console.log('')
374
- console.log(
375
- chalk.bold(`Usage statistics for API key: ${usage.name} (${id})`),
376
- )
377
- console.log('')
304
+ console.log("");
305
+ console.log(chalk.bold(`Usage statistics for API key: ${usage.name} (${id})`));
306
+ console.log("");
378
307
 
379
308
  // Period information
380
- console.log(
381
- chalk.dim(`Period: ${usage.period.start} to ${usage.period.end}`),
382
- )
383
- console.log('')
309
+ console.log(chalk.dim(`Period: ${usage.period.start} to ${usage.period.end}`));
310
+ console.log("");
384
311
 
385
312
  // Request statistics
386
- console.log(chalk.bold('Request statistics:'))
387
- console.log(
388
- `Total requests: ${chalk.cyan(usage.requests.total.toLocaleString())}`,
389
- )
313
+ console.log(chalk.bold("Request statistics:"));
314
+ console.log(`Total requests: ${chalk.cyan(usage.requests.total.toLocaleString())}`);
390
315
 
391
316
  // Daily breakdown if available
392
317
  if (usage.requests.daily && usage.requests.daily.length > 0) {
393
- console.log('')
394
- console.log(chalk.bold('Daily breakdown:'))
395
- console.log(chalk.dim(''.repeat(30)))
396
- console.log(chalk.dim('DATE'.padEnd(12) + 'REQUESTS'))
397
-
398
- usage.requests.daily.forEach(
399
- (day: { date: string; count: number }) => {
400
- console.log(`${day.date.padEnd(12)}${day.count.toLocaleString()}`)
401
- },
402
- )
318
+ console.log("");
319
+ console.log(chalk.bold("Daily breakdown:"));
320
+ console.log(chalk.dim("".repeat(30)));
321
+ console.log(chalk.dim("DATE".padEnd(12) + "REQUESTS"));
322
+
323
+ usage.requests.daily.forEach((day: { date: string; count: number }) => {
324
+ console.log(`${day.date.padEnd(12)}${day.count.toLocaleString()}`);
325
+ });
403
326
  }
404
327
 
405
328
  // Model usage if available
406
329
  if (usage.models && usage.models.length > 0) {
407
- console.log('')
408
- console.log(chalk.bold('Model usage:'))
409
- console.log(chalk.dim(''.repeat(70)))
330
+ console.log("");
331
+ console.log(chalk.bold("Model usage:"));
332
+ console.log(chalk.dim("".repeat(70)));
410
333
  console.log(
411
- chalk.dim('MODEL'.padEnd(20)) +
412
- chalk.dim('REQUESTS'.padEnd(10)) +
413
- chalk.dim('INPUT'.padEnd(12)) +
414
- chalk.dim('OUTPUT'.padEnd(12)) +
415
- chalk.dim('TOTAL TOKENS'),
416
- )
334
+ chalk.dim("MODEL".padEnd(20)) +
335
+ chalk.dim("REQUESTS".padEnd(10)) +
336
+ chalk.dim("INPUT".padEnd(12)) +
337
+ chalk.dim("OUTPUT".padEnd(12)) +
338
+ chalk.dim("TOTAL TOKENS")
339
+ );
417
340
 
418
341
  usage.models.forEach(
419
342
  (model: {
420
- name: string
421
- requests: number
343
+ name: string;
344
+ requests: number;
422
345
  tokens: {
423
- input: number
424
- output: number
425
- total: number
426
- }
346
+ input: number;
347
+ output: number;
348
+ total: number;
349
+ };
427
350
  }) => {
428
351
  console.log(
429
352
  model.name.padEnd(20) +
430
353
  model.requests.toString().padEnd(10) +
431
354
  model.tokens.input.toLocaleString().padEnd(12) +
432
355
  model.tokens.output.toLocaleString().padEnd(12) +
433
- model.tokens.total.toLocaleString(),
434
- )
435
- },
436
- )
356
+ model.tokens.total.toLocaleString()
357
+ );
358
+ }
359
+ );
437
360
  }
438
361
 
439
- console.log('')
362
+ console.log("");
440
363
  console.log(
441
- chalk.dim(
442
- 'Use these statistics to understand your API usage and optimize your costs.',
443
- ),
444
- )
364
+ chalk.dim("Use these statistics to understand your API usage and optimize your costs.")
365
+ );
445
366
  } catch (error) {
446
- handleError('Failed to get API key usage', error)
367
+ handleError("Failed to get API key usage", error);
447
368
  }
448
- })
369
+ });
449
370
 
450
371
  apiKey
451
372
  .command(ApiKeyService.COMMANDS.SET_DEFAULT)
452
- .description('Set an API key as the default for chat commands')
453
- .argument('<id>', 'ID of the API key to set as default')
454
- .action(async (id) => {
373
+ .description("Set an API key as the default for chat commands")
374
+ .argument("<id>", "ID of the API key to set as default")
375
+ .action(async id => {
455
376
  try {
456
- const apiKeyService = ApiKeyService.getInstance()
457
- const keys = await apiKeyService.list()
458
- const selectedKey = keys.find((key) => key.id.toString() === id)
377
+ const apiKeyService = ApiKeyService.getInstance();
378
+ const keys = await apiKeyService.list();
379
+ const selectedKey = keys.find(key => key.id.toString() === id);
459
380
 
460
381
  if (!selectedKey) {
461
- console.error(chalk.red(`Error: API key with ID ${id} not found`))
462
- return
382
+ console.error(chalk.red(`Error: API key with ID ${id} not found`));
383
+ return;
463
384
  }
464
385
 
465
386
  // Save the default API key
466
- const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
387
+ const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
467
388
 
468
389
  // We need to rotate the key to get the actual key value
469
- const rotatedKey = await apiKeyService.rotate(id)
390
+ const rotatedKey = await apiKeyService.rotate(id);
470
391
 
471
392
  defaultApiKeyManager.setDefaultApiKey(
472
393
  id,
473
394
  selectedKey.name,
474
395
  selectedKey.prefix,
475
- rotatedKey.key,
476
- )
396
+ rotatedKey.key
397
+ );
477
398
 
478
399
  console.log(
479
- chalk.green(
480
- `✓ API key "${selectedKey.name}" set as default for chat commands`,
481
- ),
482
- )
483
- console.log('')
484
- console.log(
485
- chalk.dim(
486
- 'This API key will be used by default when running chat commands',
487
- ),
488
- )
489
- console.log(
490
- chalk.dim(
491
- 'You can override it with --api-key or --api-key-id options',
492
- ),
493
- )
400
+ chalk.green(`✓ API key "${selectedKey.name}" set as default for chat commands`)
401
+ );
402
+ console.log("");
403
+ console.log(chalk.dim("This API key will be used by default when running chat commands"));
404
+ console.log(chalk.dim("You can override it with --api-key or --api-key-id options"));
494
405
  } catch (error) {
495
- handleError('Failed to set default API key', error)
406
+ handleError("Failed to set default API key", error);
496
407
  }
497
- })
408
+ });
498
409
 
499
410
  apiKey
500
411
  .command(ApiKeyService.COMMANDS.GET_DEFAULT)
501
- .description('Show the current default API key')
412
+ .description("Show the current default API key")
502
413
  .action(() => {
503
414
  try {
504
- const defaultApiKeyManager = DefaultApiKeyManager.getInstance()
505
- const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData()
415
+ const defaultApiKeyManager = DefaultApiKeyManager.getInstance();
416
+ const defaultApiKeyData = defaultApiKeyManager.getDefaultApiKeyData();
506
417
 
507
418
  if (!defaultApiKeyData) {
508
- console.log(chalk.yellow('No default API key set'))
509
- console.log('')
510
- console.log('To set a default API key, run:')
511
- console.log(chalk.cyan(' berget api-keys set-default <id>'))
512
- return
419
+ console.log(chalk.yellow("No default API key set"));
420
+ console.log("");
421
+ console.log("To set a default API key, run:");
422
+ console.log(chalk.cyan(" berget api-keys set-default <id>"));
423
+ return;
513
424
  }
514
425
 
515
- console.log(chalk.bold('Default API key:'))
516
- console.log('')
517
- console.log(`${chalk.dim('ID:')} ${defaultApiKeyData.id}`)
518
- console.log(`${chalk.dim('Name:')} ${defaultApiKeyData.name}`)
519
- console.log(`${chalk.dim('Prefix:')} ${defaultApiKeyData.prefix}`)
520
- console.log('')
521
- console.log(
522
- chalk.dim(
523
- 'This API key will be used by default when running chat commands',
524
- ),
525
- )
526
- console.log(
527
- chalk.dim(
528
- 'You can override it with --api-key or --api-key-id options',
529
- ),
530
- )
426
+ console.log(chalk.bold("Default API key:"));
427
+ console.log("");
428
+ console.log(`${chalk.dim("ID:")} ${defaultApiKeyData.id}`);
429
+ console.log(`${chalk.dim("Name:")} ${defaultApiKeyData.name}`);
430
+ console.log(`${chalk.dim("Prefix:")} ${defaultApiKeyData.prefix}`);
431
+ console.log("");
432
+ console.log(chalk.dim("This API key will be used by default when running chat commands"));
433
+ console.log(chalk.dim("You can override it with --api-key or --api-key-id options"));
531
434
  } catch (error) {
532
- handleError('Failed to get default API key', error)
435
+ handleError("Failed to get default API key", error);
533
436
  }
534
- })
437
+ });
535
438
  }