berget 2.2.6 → 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.
Files changed (145) hide show
  1. package/.github/workflows/publish.yml +2 -2
  2. package/.github/workflows/test.yml +10 -4
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +7 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +10 -11
  9. package/dist/package.json +30 -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 +97 -117
  20. package/dist/src/commands/api-keys.js +75 -90
  21. package/dist/src/commands/auth.js +7 -16
  22. package/dist/src/commands/autocomplete.js +1 -1
  23. package/dist/src/commands/billing.js +6 -17
  24. package/dist/src/commands/chat.js +68 -101
  25. package/dist/src/commands/clusters.js +9 -18
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
  33. package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
  34. package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
  36. package/dist/src/commands/code/auth-sync.js +270 -0
  37. package/dist/src/commands/code/errors.js +12 -9
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/setup.js +387 -281
  40. package/dist/src/commands/code.js +205 -332
  41. package/dist/src/commands/index.js +5 -5
  42. package/dist/src/commands/models.js +6 -17
  43. package/dist/src/commands/users.js +5 -16
  44. package/dist/src/constants/command-structure.js +104 -104
  45. package/dist/src/services/api-key-service.js +132 -157
  46. package/dist/src/services/auth-service.js +89 -342
  47. package/dist/src/services/browser-auth.js +268 -0
  48. package/dist/src/services/chat-service.js +371 -401
  49. package/dist/src/services/cluster-service.js +47 -62
  50. package/dist/src/services/collaborator-service.js +10 -25
  51. package/dist/src/services/flux-service.js +14 -29
  52. package/dist/src/services/helm-service.js +10 -25
  53. package/dist/src/services/kubectl-service.js +16 -33
  54. package/dist/src/utils/config-checker.js +3 -3
  55. package/dist/src/utils/config-loader.js +95 -95
  56. package/dist/src/utils/default-api-key.js +124 -134
  57. package/dist/src/utils/env-manager.js +55 -66
  58. package/dist/src/utils/error-handler.js +20 -21
  59. package/dist/src/utils/logger.js +72 -65
  60. package/dist/src/utils/markdown-renderer.js +27 -27
  61. package/dist/src/utils/opencode-validator.js +63 -68
  62. package/dist/src/utils/token-manager.js +74 -45
  63. package/dist/tests/commands/chat.test.js +16 -25
  64. package/dist/tests/commands/code.test.js +95 -104
  65. package/dist/tests/utils/config-loader.test.js +48 -48
  66. package/dist/tests/utils/env-manager.test.js +43 -52
  67. package/dist/tests/utils/opencode-validator.test.js +22 -21
  68. package/dist/vitest.config.js +1 -1
  69. package/eslint.config.mjs +67 -0
  70. package/index.ts +35 -42
  71. package/package.json +30 -2
  72. package/src/agents/app.ts +27 -0
  73. package/src/agents/backend.ts +24 -0
  74. package/src/agents/devops.ts +33 -0
  75. package/src/agents/frontend.ts +24 -0
  76. package/src/agents/fullstack.ts +24 -0
  77. package/src/agents/index.ts +73 -0
  78. package/src/agents/quality.ts +69 -0
  79. package/src/agents/security.ts +26 -0
  80. package/src/agents/types.ts +17 -0
  81. package/src/client.ts +118 -152
  82. package/src/commands/api-keys.ts +241 -333
  83. package/src/commands/auth.ts +22 -27
  84. package/src/commands/autocomplete.ts +9 -9
  85. package/src/commands/billing.ts +20 -24
  86. package/src/commands/chat.ts +248 -338
  87. package/src/commands/clusters.ts +27 -26
  88. package/src/commands/code/__tests__/auth-sync.test.ts +482 -0
  89. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  90. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  91. package/src/commands/code/__tests__/fake-command-runner.ts +45 -42
  92. package/src/commands/code/__tests__/fake-file-store.ts +32 -23
  93. package/src/commands/code/__tests__/fake-prompter.ts +116 -77
  94. package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
  95. package/src/commands/code/adapters/clack-prompter.ts +53 -39
  96. package/src/commands/code/adapters/fs-file-store.ts +32 -27
  97. package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
  98. package/src/commands/code/auth-sync.ts +329 -0
  99. package/src/commands/code/errors.ts +18 -18
  100. package/src/commands/code/ports/auth-services.ts +14 -0
  101. package/src/commands/code/ports/command-runner.ts +8 -4
  102. package/src/commands/code/ports/file-store.ts +5 -4
  103. package/src/commands/code/ports/prompter.ts +24 -18
  104. package/src/commands/code/setup.ts +570 -340
  105. package/src/commands/code.ts +338 -539
  106. package/src/commands/index.ts +20 -19
  107. package/src/commands/models.ts +28 -32
  108. package/src/commands/users.ts +15 -21
  109. package/src/constants/command-structure.ts +134 -157
  110. package/src/services/api-key-service.ts +105 -122
  111. package/src/services/auth-service.ts +99 -345
  112. package/src/services/browser-auth.ts +296 -0
  113. package/src/services/chat-service.ts +265 -299
  114. package/src/services/cluster-service.ts +42 -45
  115. package/src/services/collaborator-service.ts +14 -19
  116. package/src/services/flux-service.ts +23 -25
  117. package/src/services/helm-service.ts +19 -21
  118. package/src/services/kubectl-service.ts +17 -19
  119. package/src/types/api.d.ts +1905 -1907
  120. package/src/types/json.d.ts +2 -2
  121. package/src/utils/config-checker.ts +10 -10
  122. package/src/utils/config-loader.ts +162 -178
  123. package/src/utils/default-api-key.ts +114 -125
  124. package/src/utils/env-manager.ts +53 -57
  125. package/src/utils/error-handler.ts +61 -56
  126. package/src/utils/logger.ts +79 -73
  127. package/src/utils/markdown-renderer.ts +31 -31
  128. package/src/utils/opencode-validator.ts +85 -89
  129. package/src/utils/token-manager.ts +108 -87
  130. package/templates/agents/app.md +1 -0
  131. package/templates/agents/backend.md +1 -0
  132. package/templates/agents/devops.md +2 -0
  133. package/templates/agents/frontend.md +1 -0
  134. package/templates/agents/fullstack.md +1 -0
  135. package/templates/agents/quality.md +45 -40
  136. package/templates/agents/security.md +1 -0
  137. package/tests/commands/chat.test.ts +53 -62
  138. package/tests/commands/code.test.ts +265 -310
  139. package/tests/utils/config-loader.test.ts +189 -188
  140. package/tests/utils/env-manager.test.ts +110 -113
  141. package/tests/utils/opencode-validator.test.ts +52 -56
  142. package/tsconfig.json +4 -3
  143. package/vitest.config.ts +3 -3
  144. package/AGENTS.md +0 -374
  145. package/TODO.md +0 -19
@@ -1,29 +1,29 @@
1
- import { createAuthenticatedClient } from '../client'
2
- import { handleError } from '../utils/error-handler'
3
- import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure'
1
+ import { createAuthenticatedClient } from '../client';
2
+ import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure';
3
+ import { handleError } from '../utils/error-handler';
4
4
 
5
5
  export interface ApiKey {
6
- id: number
7
- name: string
8
- description: string | null
9
- created: string
10
- lastUsed: string | null
11
- prefix: string
12
- active: boolean
13
- modified: string
6
+ active: boolean;
7
+ created: string;
8
+ description: null | string;
9
+ id: number;
10
+ lastUsed: null | string;
11
+ modified: string;
12
+ name: string;
13
+ prefix: string;
14
14
  }
15
15
 
16
- export interface CreateApiKeyOptions {
17
- name: string
18
- description?: string
16
+ export interface ApiKeyResponse {
17
+ created: string;
18
+ description: null | string;
19
+ id: number;
20
+ key: string;
21
+ name: string;
19
22
  }
20
23
 
21
- export interface ApiKeyResponse {
22
- id: number
23
- name: string
24
- description: string | null
25
- key: string
26
- created: string
24
+ export interface CreateApiKeyOptions {
25
+ description?: string;
26
+ name: string;
27
27
  }
28
28
 
29
29
  /**
@@ -31,37 +31,22 @@ export interface ApiKeyResponse {
31
31
  * Command group: api-keys
32
32
  */
33
33
  export class ApiKeyService {
34
- private static instance: ApiKeyService
35
- private client = createAuthenticatedClient()
36
-
37
34
  // Command group name for this service
38
- public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS
39
-
35
+ public static readonly COMMAND_GROUP = COMMAND_GROUPS.API_KEYS;
40
36
  // Subcommands for this service
41
- public static readonly COMMANDS = SUBCOMMANDS.API_KEYS
37
+ public static readonly COMMANDS = SUBCOMMANDS.API_KEYS;
38
+
39
+ private static instance: ApiKeyService;
40
+
41
+ private client = createAuthenticatedClient();
42
42
 
43
43
  private constructor() {}
44
44
 
45
45
  public static getInstance(): ApiKeyService {
46
46
  if (!ApiKeyService.instance) {
47
- ApiKeyService.instance = new ApiKeyService()
48
- }
49
- return ApiKeyService.instance
50
- }
51
-
52
- /**
53
- * List all API keys
54
- * Command: berget api-keys list
55
- */
56
- public async list(): Promise<ApiKey[]> {
57
- try {
58
- const { data, error } = await this.client.GET('/v1/api-keys')
59
- if (error) throw error
60
- return data || []
61
- } catch (error) {
62
- handleError('Failed to list API keys', error)
63
- throw error
47
+ ApiKeyService.instance = new ApiKeyService();
64
48
  }
49
+ return ApiKeyService.instance;
65
50
  }
66
51
 
67
52
  /**
@@ -72,116 +57,102 @@ export class ApiKeyService {
72
57
  try {
73
58
  // Validate input before sending request
74
59
  if (!options.name || options.name.trim().length === 0) {
75
- throw new Error('API key name is required and cannot be empty')
60
+ throw new Error('API key name is required and cannot be empty');
76
61
  }
77
62
 
78
63
  if (options.name.length > 100) {
79
- throw new Error('API key name must be 100 characters or less')
64
+ throw new Error('API key name must be 100 characters or less');
80
65
  }
81
66
 
82
67
  if (options.description && options.description.length > 500) {
83
- throw new Error('API key description must be 500 characters or less')
68
+ throw new Error('API key description must be 500 characters or less');
84
69
  }
85
70
 
86
71
  const { data, error } = await this.client.POST('/v1/api-keys', {
87
72
  body: options,
88
- })
73
+ });
89
74
 
90
75
  if (error) {
91
76
  // Enhanced error handling with specific troubleshooting
92
77
 
93
78
  // Handle specific error cases
94
79
  if (typeof error === 'object' && error !== null) {
95
- const errorObj = error as any
96
-
97
- if (errorObj.error?.code === 'API_KEY_CREATION_FAILED') {
98
- let detailedMessage =
99
- 'Failed to create API key. This could be due to:\n'
100
- detailedMessage += '• Account limits or quota restrictions\n'
101
- detailedMessage +=
102
- '• Insufficient permissions for API key creation\n'
103
- detailedMessage += ' Temporary server issues\n'
104
- detailedMessage += ' Billing or subscription issues\n\n'
105
- detailedMessage += 'Troubleshooting steps:\n'
106
- detailedMessage +=
107
- '1. Check if you have reached your API key limit\n'
108
- detailedMessage +=
109
- '2. Verify your account has API key creation permissions\n'
110
- detailedMessage += '3. Check your billing status and subscription\n'
111
- detailedMessage +=
112
- '4. Try again in a few minutes if this is a temporary issue\n'
113
- detailedMessage += '5. Contact support if the problem persists'
114
-
115
- throw new Error(detailedMessage)
80
+ const errorObject = error as any;
81
+
82
+ if (errorObject.error?.code === 'API_KEY_CREATION_FAILED') {
83
+ let detailedMessage = 'Failed to create API key. This could be due to:\n';
84
+ detailedMessage += '• Account limits or quota restrictions\n';
85
+ detailedMessage += '• Insufficient permissions for API key creation\n';
86
+ detailedMessage += '• Temporary server issues\n';
87
+ detailedMessage += '• Billing or subscription issues\n\n';
88
+ detailedMessage += 'Troubleshooting steps:\n';
89
+ detailedMessage += '1. Check if you have reached your API key limit\n';
90
+ detailedMessage += '2. Verify your account has API key creation permissions\n';
91
+ detailedMessage += '3. Check your billing status and subscription\n';
92
+ detailedMessage += '4. Try again in a few minutes if this is a temporary issue\n';
93
+ detailedMessage += '5. Contact support if the problem persists';
94
+
95
+ throw new Error(detailedMessage);
116
96
  }
117
97
 
118
- if (errorObj.error?.code === 'USER_NOT_FOUND') {
98
+ if (errorObject.error?.code === 'USER_NOT_FOUND') {
119
99
  throw new Error(
120
100
  'Your account is still being set up. Please wait a moment and try again.\n\nIf this issue persists, please contact support at support@berget.ai',
121
- )
101
+ );
122
102
  }
123
103
 
124
- if (errorObj.error?.code === 'QUOTA_EXCEEDED') {
104
+ if (errorObject.error?.code === 'QUOTA_EXCEEDED') {
125
105
  throw new Error(
126
106
  'You have reached your API key limit. Please delete existing keys or contact support to increase your quota.',
127
- )
107
+ );
128
108
  }
129
109
 
130
- if (errorObj.error?.code === 'INSUFFICIENT_PERMISSIONS') {
110
+ if (errorObject.error?.code === 'INSUFFICIENT_PERMISSIONS') {
131
111
  throw new Error(
132
112
  'Your account does not have permission to create API keys. Please contact your administrator.',
133
- )
113
+ );
134
114
  }
135
115
 
136
- if (errorObj.error?.code === 'BILLING_REQUIRED') {
116
+ if (errorObject.error?.code === 'BILLING_REQUIRED') {
137
117
  throw new Error(
138
118
  'A valid billing method is required to create API keys. Please add a payment method.',
139
- )
119
+ );
140
120
  }
141
121
  }
142
122
 
143
- throw new Error(JSON.stringify(error))
123
+ throw new Error(JSON.stringify(error));
144
124
  }
145
125
 
146
126
  if (!data) {
147
- throw new Error('No data received from server')
127
+ throw new Error('No data received from server');
148
128
  }
149
129
 
150
- return data
130
+ return data;
151
131
  } catch (error) {
152
- console.error('Failed to create API key:', error)
132
+ console.error('Failed to create API key:', error);
153
133
 
154
134
  // Add additional context for common issues
155
135
  if (error instanceof Error) {
156
136
  if (error.message.includes('ECONNREFUSED')) {
157
- throw new Error(
158
- 'Cannot connect to Berget API. Please check your internet connection.',
159
- )
137
+ throw new Error('Cannot connect to Berget API. Please check your internet connection.');
160
138
  }
161
139
 
162
140
  if (error.message.includes('ENOTFOUND')) {
163
- throw new Error(
164
- 'Cannot resolve Berget API hostname. Please check your DNS settings.',
165
- )
141
+ throw new Error('Cannot resolve Berget API hostname. Please check your DNS settings.');
166
142
  }
167
143
 
168
- if (
169
- error.message.includes('401') ||
170
- error.message.includes('Unauthorized')
171
- ) {
172
- throw new Error(
173
- 'Authentication failed. Please run `berget auth login` to log in again.',
174
- )
144
+ if (error.message.includes('401') || error.message.includes('Unauthorized')) {
145
+ throw new Error('Authentication failed. Please run `berget auth login` to log in again.');
175
146
  }
176
147
 
177
148
  if (error.message.includes('403')) {
178
149
  throw new Error(
179
150
  'Access forbidden. Your account may not have permission to create API keys.',
180
- )
151
+ );
181
152
  }
182
153
  }
183
154
 
184
- throw error
155
+ throw error;
185
156
  }
186
157
  }
187
158
 
@@ -193,49 +164,61 @@ export class ApiKeyService {
193
164
  try {
194
165
  const { error } = await this.client.DELETE('/v1/api-keys/{id}', {
195
166
  params: { path: { id } },
196
- })
197
- if (error) throw new Error(JSON.stringify(error))
198
- return true
167
+ });
168
+ if (error) throw new Error(JSON.stringify(error));
169
+ return true;
199
170
  } catch (error) {
200
- console.error('Failed to delete API key:', error)
201
- throw error
171
+ console.error('Failed to delete API key:', error);
172
+ throw error;
202
173
  }
203
174
  }
204
175
 
205
176
  /**
206
- * Rotate an API key
207
- * Command: berget api-keys rotate
177
+ * Get usage statistics for an API key
178
+ * Command: berget api-keys describe
208
179
  */
209
- public async rotate(id: string): Promise<ApiKeyResponse> {
180
+ public async describe(id: string): Promise<any> {
210
181
  try {
211
- const { data, error } = await this.client.PUT(
212
- '/v1/api-keys/{id}/rotate',
213
- {
214
- params: { path: { id } },
215
- },
216
- )
217
- if (error) throw new Error(JSON.stringify(error))
218
- return data!
182
+ const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
183
+ params: { path: { id } },
184
+ });
185
+ if (error) throw new Error(JSON.stringify(error));
186
+ return data;
219
187
  } catch (error) {
220
- console.error('Failed to rotate API key:', error)
221
- throw error
188
+ console.error('Failed to get API key usage:', error);
189
+ throw error;
222
190
  }
223
191
  }
224
192
 
225
193
  /**
226
- * Get usage statistics for an API key
227
- * Command: berget api-keys describe
194
+ * List all API keys
195
+ * Command: berget api-keys list
228
196
  */
229
- public async describe(id: string): Promise<any> {
197
+ public async list(): Promise<ApiKey[]> {
230
198
  try {
231
- const { data, error } = await this.client.GET('/v1/api-keys/{id}/usage', {
199
+ const { data, error } = await this.client.GET('/v1/api-keys');
200
+ if (error) throw error;
201
+ return data || [];
202
+ } catch (error) {
203
+ handleError('Failed to list API keys', error);
204
+ throw error;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Rotate an API key
210
+ * Command: berget api-keys rotate
211
+ */
212
+ public async rotate(id: string): Promise<ApiKeyResponse> {
213
+ try {
214
+ const { data, error } = await this.client.PUT('/v1/api-keys/{id}/rotate', {
232
215
  params: { path: { id } },
233
- })
234
- if (error) throw new Error(JSON.stringify(error))
235
- return data
216
+ });
217
+ if (error) throw new Error(JSON.stringify(error));
218
+ return data!;
236
219
  } catch (error) {
237
- console.error('Failed to get API key usage:', error)
238
- throw error
220
+ console.error('Failed to rotate API key:', error);
221
+ throw error;
239
222
  }
240
223
  }
241
224
  }