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,224 +1,213 @@
1
- import * as fs from 'fs'
2
- import * as path from 'path'
3
- import * as os from 'os'
4
- import chalk from 'chalk'
5
- import { ApiKeyService } from '../services/api-key-service'
6
- import readline from 'readline'
7
- import { logger } from './logger'
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import readline from 'node:readline';
5
+
6
+ import { ApiKeyService } from '../services/api-key-service';
7
+ import { logger } from './logger';
8
8
 
9
9
  interface DefaultApiKeyData {
10
- id: string
11
- name: string
12
- prefix: string
13
- key: string
10
+ id: string;
11
+ key: string;
12
+ name: string;
13
+ prefix: string;
14
14
  }
15
15
 
16
16
  /**
17
17
  * Manages the default API key for chat commands
18
18
  */
19
19
  export class DefaultApiKeyManager {
20
- private static instance: DefaultApiKeyManager
21
- private configFilePath: string
22
- private defaultApiKey: DefaultApiKeyData | null = null
20
+ private static instance: DefaultApiKeyManager;
21
+ private configFilePath: string;
22
+ private defaultApiKey: DefaultApiKeyData | null = null;
23
23
 
24
24
  private constructor() {
25
25
  // Set up config file path in user's home directory
26
- const bergetDir = path.join(os.homedir(), '.berget')
26
+ const bergetDir = path.join(os.homedir(), '.berget');
27
27
  if (!fs.existsSync(bergetDir)) {
28
- fs.mkdirSync(bergetDir, { recursive: true })
28
+ fs.mkdirSync(bergetDir, { recursive: true });
29
29
  }
30
- this.configFilePath = path.join(bergetDir, 'default-api-key.json')
31
- this.loadConfig()
30
+ this.configFilePath = path.join(bergetDir, 'default-api-key.json');
31
+ this.loadConfig();
32
32
  }
33
33
 
34
34
  public static getInstance(): DefaultApiKeyManager {
35
35
  if (!DefaultApiKeyManager.instance) {
36
- DefaultApiKeyManager.instance = new DefaultApiKeyManager()
37
- }
38
- return DefaultApiKeyManager.instance
39
- }
40
-
41
- /**
42
- * Load default API key from file
43
- */
44
- private loadConfig(): void {
45
- try {
46
- if (fs.existsSync(this.configFilePath)) {
47
- const data = fs.readFileSync(this.configFilePath, 'utf8')
48
- this.defaultApiKey = JSON.parse(data)
49
- }
50
- } catch (error) {
51
- logger.debug('Failed to load default API key configuration')
52
- this.defaultApiKey = null
36
+ DefaultApiKeyManager.instance = new DefaultApiKeyManager();
53
37
  }
38
+ return DefaultApiKeyManager.instance;
54
39
  }
55
40
 
56
41
  /**
57
- * Save default API key to file
58
- */
59
- private saveConfig(): void {
60
- try {
61
- if (this.defaultApiKey) {
62
- fs.writeFileSync(
63
- this.configFilePath,
64
- JSON.stringify(this.defaultApiKey, null, 2),
65
- )
66
- // Set file permissions to be readable only by the owner
67
- fs.chmodSync(this.configFilePath, 0o600)
68
- } else {
69
- // If default API key is null, remove the file
70
- if (fs.existsSync(this.configFilePath)) {
71
- fs.unlinkSync(this.configFilePath)
72
- }
73
- }
74
- } catch (error) {
75
- logger.debug('Failed to save default API key configuration')
76
- }
77
- }
78
-
79
- /**
80
- * Set the default API key
42
+ * Clear the default API key
81
43
  */
82
- public setDefaultApiKey(
83
- id: string,
84
- name: string,
85
- prefix: string,
86
- key: string,
87
- ): void {
88
- this.defaultApiKey = { id, name, prefix, key }
89
- this.saveConfig()
44
+ public clearDefaultApiKey(): void {
45
+ this.defaultApiKey = null;
46
+ this.saveConfig();
90
47
  }
91
48
 
92
49
  /**
93
50
  * Get the default API key string
94
51
  */
95
- public getDefaultApiKey(): string | null {
96
- return this.defaultApiKey?.key || null
52
+ public getDefaultApiKey(): null | string {
53
+ return this.defaultApiKey?.key || null;
97
54
  }
98
55
 
99
56
  /**
100
57
  * Get the default API key data object
101
58
  */
102
59
  public getDefaultApiKeyData(): DefaultApiKeyData | null {
103
- return this.defaultApiKey
104
- }
105
-
106
- /**
107
- * Clear the default API key
108
- */
109
- public clearDefaultApiKey(): void {
110
- this.defaultApiKey = null
111
- this.saveConfig()
60
+ return this.defaultApiKey;
112
61
  }
113
62
 
114
63
  /**
115
64
  * Prompts the user to select a default API key if none is set
116
65
  * @returns The selected API key or null if none was selected
117
66
  */
118
- public async promptForDefaultApiKey(): Promise<string | null> {
67
+ public async promptForDefaultApiKey(): Promise<null | string> {
119
68
  try {
120
- logger.debug('promptForDefaultApiKey called')
69
+ logger.debug('promptForDefaultApiKey called');
121
70
 
122
71
  // If we already have a default API key, return it
123
72
  if (this.defaultApiKey) {
124
- logger.debug('Using existing default API key')
125
- return this.defaultApiKey.key
73
+ logger.debug('Using existing default API key');
74
+ return this.defaultApiKey.key;
126
75
  }
127
76
 
128
- logger.debug('No default API key found, getting ApiKeyService')
77
+ logger.debug('No default API key found, getting ApiKeyService');
129
78
 
130
- const apiKeyService = ApiKeyService.getInstance()
79
+ const apiKeyService = ApiKeyService.getInstance();
131
80
 
132
81
  // Get all API keys
133
- let apiKeys
82
+ let apiKeys;
134
83
  try {
135
- logger.debug('Calling apiKeyService.list()')
84
+ logger.debug('Calling apiKeyService.list()');
136
85
 
137
- apiKeys = await apiKeyService.list()
86
+ apiKeys = await apiKeyService.list();
138
87
 
139
- logger.debug(`Got ${apiKeys ? apiKeys.length : 0} API keys`)
88
+ logger.debug(`Got ${apiKeys ? apiKeys.length : 0} API keys`);
140
89
 
141
90
  if (!apiKeys || apiKeys.length === 0) {
142
- logger.warn('No API keys found. Create one with:')
143
- logger.info(' berget api-keys create --name "My Key"')
144
- return null
91
+ logger.warn('No API keys found. Create one with:');
92
+ logger.info(' berget api-keys create --name "My Key"');
93
+ return null;
145
94
  }
146
95
  } catch (error) {
147
96
  // Check if this is an authentication error
148
- const errorMessage =
149
- error instanceof Error ? error.message : String(error)
97
+ const errorMessage = error instanceof Error ? error.message : String(error);
150
98
  const isAuthError =
151
99
  errorMessage.includes('Unauthorized') ||
152
100
  errorMessage.includes('Authentication failed') ||
153
- errorMessage.includes('AUTH_FAILED')
101
+ errorMessage.includes('AUTH_FAILED');
154
102
 
155
103
  if (isAuthError) {
156
- logger.warn(
157
- 'Authentication required. Please run `berget auth login` first.',
158
- )
104
+ logger.warn('Authentication required. Please run `berget auth login` first.');
159
105
  } else {
160
- logger.error('Error fetching API keys:')
106
+ logger.error('Error fetching API keys:');
161
107
  if (error instanceof Error) {
162
- logger.error(error.message)
163
- logger.debug(`API key list error: ${error.message}`)
164
- logger.debug(`Stack: ${error.stack}`)
108
+ logger.error(error.message);
109
+ logger.debug(`API key list error: ${error.message}`);
110
+ logger.debug(`Stack: ${error.stack}`);
165
111
  }
166
112
  }
167
- return null
113
+ return null;
168
114
  }
169
115
 
170
- logger.info('Select an API key to use as default:')
116
+ logger.info('Select an API key to use as default:');
171
117
 
172
118
  // Display available API keys
173
- apiKeys.forEach((key, index) => {
174
- logger.log(` ${index + 1}. ${key.name} (${key.prefix}...)`)
175
- })
119
+ for (const [index, key] of apiKeys.entries()) {
120
+ logger.log(` ${index + 1}. ${key.name} (${key.prefix}...)`);
121
+ }
176
122
 
177
123
  // Create readline interface for user input
178
124
  const rl = readline.createInterface({
179
125
  input: process.stdin,
180
126
  output: process.stdout,
181
- })
127
+ });
182
128
 
183
129
  // Prompt for selection
184
130
  const selection = await new Promise<number>((resolve) => {
185
131
  rl.question('Enter number (or press Enter to cancel): ', (answer) => {
186
- rl.close()
187
- const num = parseInt(answer.trim(), 10)
188
- if (isNaN(num) || num < 1 || num > apiKeys.length) {
189
- resolve(-1) // Invalid selection
132
+ rl.close();
133
+ const number_ = Number.parseInt(answer.trim(), 10);
134
+ if (isNaN(number_) || number_ < 1 || number_ > apiKeys.length) {
135
+ resolve(-1); // Invalid selection
190
136
  } else {
191
- resolve(num - 1) // Convert to zero-based index
137
+ resolve(number_ - 1); // Convert to zero-based index
192
138
  }
193
- })
194
- })
139
+ });
140
+ });
195
141
 
196
142
  if (selection === -1) {
197
- logger.warn('No API key selected')
198
- return null
143
+ logger.warn('No API key selected');
144
+ return null;
199
145
  }
200
146
 
201
- const selectedKey = apiKeys[selection]
147
+ const selectedKey = apiKeys[selection];
202
148
 
203
149
  // Create a new API key with the selected name
204
150
  const newKey = await apiKeyService.create({
205
- name: `CLI Default (copy of ${selectedKey.name})`,
206
151
  description: 'Created automatically by the Berget CLI for default use',
207
- })
152
+ name: `CLI Default (copy of ${selectedKey.name})`,
153
+ });
208
154
 
209
155
  // Save the new key as default
210
156
  this.setDefaultApiKey(
211
157
  newKey.id.toString(),
212
158
  newKey.name,
213
- newKey.key.substring(0, 8), // Use first 8 chars as prefix
159
+ newKey.key.slice(0, 8), // Use first 8 chars as prefix
214
160
  newKey.key,
215
- )
161
+ );
216
162
 
217
- logger.success(`✓ Default API key set to: ${newKey.name}`)
218
- return newKey.key
163
+ logger.success(`✓ Default API key set to: ${newKey.name}`);
164
+ return newKey.key;
219
165
  } catch (error) {
220
- logger.error('Failed to set default API key:', error)
221
- return null
166
+ logger.error('Failed to set default API key:', error);
167
+ return null;
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Set the default API key
173
+ */
174
+ public setDefaultApiKey(id: string, name: string, prefix: string, key: string): void {
175
+ this.defaultApiKey = { id, key, name, prefix };
176
+ this.saveConfig();
177
+ }
178
+
179
+ /**
180
+ * Load default API key from file
181
+ */
182
+ private loadConfig(): void {
183
+ try {
184
+ if (fs.existsSync(this.configFilePath)) {
185
+ const data = fs.readFileSync(this.configFilePath, 'utf8');
186
+ this.defaultApiKey = JSON.parse(data);
187
+ }
188
+ } catch {
189
+ logger.debug('Failed to load default API key configuration');
190
+ this.defaultApiKey = null;
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Save default API key to file
196
+ */
197
+ private saveConfig(): void {
198
+ try {
199
+ if (this.defaultApiKey) {
200
+ fs.writeFileSync(this.configFilePath, JSON.stringify(this.defaultApiKey, null, 2));
201
+ // Set file permissions to be readable only by the owner
202
+ fs.chmodSync(this.configFilePath, 0o600);
203
+ } else {
204
+ // If default API key is null, remove the file
205
+ if (fs.existsSync(this.configFilePath)) {
206
+ fs.unlinkSync(this.configFilePath);
207
+ }
208
+ }
209
+ } catch {
210
+ logger.debug('Failed to save default API key configuration');
222
211
  }
223
212
  }
224
213
  }
@@ -1,98 +1,94 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import { writeFile } from 'fs/promises'
4
- import chalk from 'chalk'
5
- import dotenv from 'dotenv'
1
+ import chalk from 'chalk';
2
+ import dotenv from 'dotenv';
3
+ import fs from 'node:fs';
4
+ import { writeFile } from 'node:fs/promises';
5
+ import path from 'node:path';
6
6
 
7
7
  export interface EnvUpdateOptions {
8
- envPath?: string
9
- key: string
10
- value: string
11
- comment?: string
12
- force?: boolean
8
+ comment?: string;
9
+ envPath?: string;
10
+ force?: boolean;
11
+ key: string;
12
+ value: string;
13
+ }
14
+
15
+ /**
16
+ * Checks if a .env file exists and contains a specific key
17
+ */
18
+ export function hasEnvKey(
19
+ environmentPath: string = path.join(process.cwd(), '.env'),
20
+ key: string,
21
+ ): boolean {
22
+ if (!fs.existsSync(environmentPath)) {
23
+ return false;
24
+ }
25
+
26
+ try {
27
+ const content = fs.readFileSync(environmentPath, 'utf8');
28
+ const parsed = dotenv.parse(content);
29
+ return key in parsed;
30
+ } catch {
31
+ return false;
32
+ }
13
33
  }
14
34
 
15
35
  /**
16
36
  * Safely updates .env file without overwriting existing keys
17
37
  * Uses dotenv for proper parsing and formatting
18
38
  */
19
- export async function updateEnvFile(
20
- options: EnvUpdateOptions,
21
- ): Promise<boolean> {
39
+ export async function updateEnvFile(options: EnvUpdateOptions): Promise<boolean> {
22
40
  const {
23
- envPath = path.join(process.cwd(), '.env'),
24
- key,
25
- value,
26
41
  comment,
42
+ envPath: environmentPath = path.join(process.cwd(), '.env'),
27
43
  force = false,
28
- } = options
44
+ key,
45
+ value,
46
+ } = options;
29
47
 
30
48
  try {
31
- let existingContent = ''
32
- let parsed: Record<string, string> = {}
49
+ let existingContent = '';
50
+ let parsed: Record<string, string> = {};
33
51
 
34
52
  // Read existing .env file if it exists
35
- if (fs.existsSync(envPath)) {
36
- existingContent = fs.readFileSync(envPath, 'utf8')
37
- parsed = dotenv.parse(existingContent)
53
+ if (fs.existsSync(environmentPath)) {
54
+ existingContent = fs.readFileSync(environmentPath, 'utf8');
55
+ parsed = dotenv.parse(existingContent);
38
56
  }
39
57
 
40
58
  // Check if key already exists and we're not forcing
41
59
  if (parsed[key] && !force) {
42
- console.log(
43
- chalk.yellow(`⚠ ${key} already exists in .env - leaving unchanged`),
44
- )
45
- return false
60
+ console.log(chalk.yellow(`⚠ ${key} already exists in .env - leaving unchanged`));
61
+ return false;
46
62
  }
47
63
 
48
64
  // Update the parsed object
49
- parsed[key] = value
65
+ parsed[key] = value;
50
66
 
51
67
  // Generate new .env content
52
- let newContent = ''
68
+ let newContent = '';
53
69
 
54
70
  // Add comment at the top if this is a new file
55
71
  if (!existingContent && comment) {
56
- newContent += `# ${comment}\n`
72
+ newContent += `# ${comment}\n`;
57
73
  }
58
74
 
59
75
  // Convert parsed object back to .env format
60
- for (const [envKey, envValue] of Object.entries(parsed)) {
61
- newContent += `${envKey}=${envValue}\n`
76
+ for (const [environmentKey, environmentValue] of Object.entries(parsed)) {
77
+ newContent += `${environmentKey}=${environmentValue}\n`;
62
78
  }
63
79
 
64
80
  // Write the updated content
65
- await writeFile(envPath, newContent.trim() + '\n')
81
+ await writeFile(environmentPath, newContent.trim() + '\n');
66
82
 
67
83
  if (existingContent) {
68
- console.log(chalk.green(`✓ Updated .env with ${key}`))
84
+ console.log(chalk.green(`✓ Updated .env with ${key}`));
69
85
  } else {
70
- console.log(chalk.green(`✓ Created .env with ${key}`))
86
+ console.log(chalk.green(`✓ Created .env with ${key}`));
71
87
  }
72
88
 
73
- return true
89
+ return true;
74
90
  } catch (error) {
75
- console.error(chalk.red(`Failed to update .env file:`))
76
- throw error
77
- }
78
- }
79
-
80
- /**
81
- * Checks if a .env file exists and contains a specific key
82
- */
83
- export function hasEnvKey(
84
- envPath: string = path.join(process.cwd(), '.env'),
85
- key: string,
86
- ): boolean {
87
- if (!fs.existsSync(envPath)) {
88
- return false
89
- }
90
-
91
- try {
92
- const content = fs.readFileSync(envPath, 'utf8')
93
- const parsed = dotenv.parse(content)
94
- return key in parsed
95
- } catch {
96
- return false
91
+ console.error(chalk.red(`Failed to update .env file:`));
92
+ throw error;
97
93
  }
98
94
  }