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,22 +1,22 @@
1
- import { Command } from 'commander'
2
- import chalk from 'chalk'
3
- import readline from 'readline'
4
- import { COMMAND_GROUPS, SUBCOMMANDS } from '../constants/command-structure'
5
- import { handleError } from '../utils/error-handler'
6
- import { runSetupCommand } from './code/setup'
7
- import * as fs from 'fs'
8
- import { readFile, writeFile } from 'fs/promises'
9
- import path from 'path'
10
- import { spawn } from 'child_process'
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import readline from "readline";
4
+ import { COMMAND_GROUPS, SUBCOMMANDS } from "../constants/command-structure";
5
+ import { handleError } from "../utils/error-handler";
6
+ import { runSetupCommand } from "./code/setup";
7
+ import * as fs from "fs";
8
+ import { readFile, writeFile } from "fs/promises";
9
+ import path from "path";
10
+ import { spawn } from "child_process";
11
11
 
12
12
  /**
13
13
  * Check if current directory has git
14
14
  */
15
15
  function hasGit(): boolean {
16
16
  try {
17
- return fs.existsSync(path.join(process.cwd(), '.git'))
17
+ return fs.existsSync(path.join(process.cwd(), ".git"));
18
18
  } catch {
19
- return false
19
+ return false;
20
20
  }
21
21
  }
22
22
 
@@ -25,50 +25,20 @@ function hasGit(): boolean {
25
25
  */
26
26
  async function confirm(question: string, autoYes = false): Promise<boolean> {
27
27
  if (autoYes) {
28
- return true
28
+ return true;
29
29
  }
30
30
 
31
- return new Promise((resolve) => {
31
+ return new Promise(resolve => {
32
32
  const rl = readline.createInterface({
33
33
  input: process.stdin,
34
34
  output: process.stdout,
35
- })
36
-
37
- rl.question(question, (answer) => {
38
- rl.close()
39
- resolve(
40
- answer.toLowerCase() === 'y' ||
41
- answer.toLowerCase() === 'yes' ||
42
- answer === ''
43
- )
44
- })
45
- })
46
- }
47
-
35
+ });
48
36
 
49
- /**
50
- * Helper function to get user input
51
- */
52
- async function getInput(
53
- question: string,
54
- defaultValue: string,
55
- autoYes = false
56
- ): Promise<string> {
57
- if (autoYes) {
58
- return defaultValue
59
- }
60
-
61
- const rl = readline.createInterface({
62
- input: process.stdin,
63
- output: process.stdout,
64
- })
65
-
66
- return new Promise<string>((resolve) => {
67
- rl.question(question, (answer) => {
68
- rl.close()
69
- resolve(answer.trim() || defaultValue)
70
- })
71
- })
37
+ rl.question(question, answer => {
38
+ rl.close();
39
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes" || answer === "");
40
+ });
41
+ });
72
42
  }
73
43
 
74
44
  /**
@@ -76,175 +46,84 @@ async function getInput(
76
46
  */
77
47
  function getProjectName(): string {
78
48
  try {
79
- const packageJsonPath = path.join(process.cwd(), 'package.json')
49
+ const packageJsonPath = path.join(process.cwd(), "package.json");
80
50
  if (fs.existsSync(packageJsonPath)) {
81
- const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8')
82
- const packageJson = JSON.parse(packageJsonContent)
83
- return packageJson.name || path.basename(process.cwd())
51
+ const packageJsonContent = fs.readFileSync(packageJsonPath, "utf8");
52
+ const packageJson = JSON.parse(packageJsonContent);
53
+ return packageJson.name || path.basename(process.cwd());
84
54
  }
85
- } catch (error) {
55
+ } catch {
86
56
  // Ignore error and fallback to directory name
87
57
  }
88
- return path.basename(process.cwd())
58
+ return path.basename(process.cwd());
89
59
  }
90
60
 
91
61
  /**
92
62
  * Get the path to the bundled agent templates directory
93
63
  */
94
64
  function getAgentTemplatesDir(): string {
95
- return path.resolve(__dirname, '../../templates/agents')
96
- }
97
-
98
- /**
99
- * Parse a markdown agent file with YAML frontmatter into an agent config object
100
- */
101
- function parseAgentMarkdown(content: string): Record<string, any> {
102
- const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/)
103
- if (!frontmatterMatch) {
104
- throw new Error('Invalid agent markdown: missing frontmatter')
105
- }
106
-
107
- const yamlStr = frontmatterMatch[1]
108
- const promptBody = frontmatterMatch[2].trim()
109
-
110
- const config: Record<string, any> = { prompt: promptBody }
111
-
112
- for (const line of yamlStr.split('\n')) {
113
- const trimmed = line.trim()
114
- if (!trimmed || trimmed.startsWith('#')) continue
115
-
116
- const colonIdx = trimmed.indexOf(':')
117
- if (colonIdx === -1) continue
118
-
119
- const key = trimmed.substring(0, colonIdx).trim()
120
- const value = trimmed.substring(colonIdx + 1).trim()
121
-
122
- if (key === 'permission') continue
123
-
124
- if (value === 'true') {
125
- config[key] = true
126
- } else if (value === 'false') {
127
- config[key] = false
128
- } else if (!isNaN(Number(value)) && value !== '') {
129
- config[key] = Number(value)
130
- } else {
131
- config[key] = value
132
- }
133
- }
134
-
135
- const permission: Record<string, string> = {}
136
- const permMatch = yamlStr.match(/permission:\s*\n((?:\s+\w+:.*\n?)*)/)
137
- if (permMatch) {
138
- for (const permLine of permMatch[1].split('\n')) {
139
- const permTrimmed = permLine.trim()
140
- if (!permTrimmed) continue
141
- const permColonIdx = permTrimmed.indexOf(':')
142
- if (permColonIdx === -1) continue
143
- const permKey = permTrimmed.substring(0, permColonIdx).trim()
144
- const permValue = permTrimmed.substring(permColonIdx + 1).trim()
145
- if (permKey && permValue) {
146
- permission[permKey] = permValue
147
- }
148
- }
149
- }
150
- if (Object.keys(permission).length > 0) {
151
- config.permission = permission
152
- }
153
-
154
- return config
155
- }
156
-
157
- /**
158
- * Load the latest agent configuration from bundled markdown templates
159
- */
160
- async function loadLatestAgentConfig(): Promise<any> {
161
- const templatesDir = getAgentTemplatesDir()
162
- const agents: Record<string, any> = {}
163
-
164
- const files = fs.readdirSync(templatesDir).filter((f) => f.endsWith('.md'))
165
-
166
- for (const file of files) {
167
- const agentName = path.basename(file, '.md')
168
- const filePath = path.join(templatesDir, file)
169
- const content = fs.readFileSync(filePath, 'utf8')
170
-
171
- try {
172
- agents[agentName] = parseAgentMarkdown(content)
173
- } catch (error) {
174
- console.warn(
175
- chalk.yellow(`Warning: Failed to parse agent template ${file}: ${error}`)
176
- )
177
- }
178
- }
179
-
180
- return agents
65
+ return path.resolve(__dirname, "../../templates/agents");
181
66
  }
182
67
 
183
68
  /**
184
69
  * Check if opencode is installed
185
70
  */
186
71
  function checkOpencodeInstalled(): Promise<boolean> {
187
- return new Promise((resolve) => {
188
- const child = spawn('which', ['opencode'], {
189
- stdio: 'pipe',
190
- })
191
-
192
- child.on('close', (code) => {
193
- resolve(code === 0)
194
- })
195
-
196
- child.on('error', () => {
197
- resolve(false)
198
- })
199
- })
72
+ return new Promise(resolve => {
73
+ const child = spawn("which", ["opencode"], {
74
+ stdio: "pipe",
75
+ });
76
+
77
+ child.on("close", code => {
78
+ resolve(code === 0);
79
+ });
80
+
81
+ child.on("error", () => {
82
+ resolve(false);
83
+ });
84
+ });
200
85
  }
201
86
 
202
87
  /**
203
88
  * Install opencode via npm
204
89
  */
205
90
  async function installOpencode(): Promise<boolean> {
206
- console.log(chalk.cyan('Installing OpenCode via npm...'))
91
+ console.log(chalk.cyan("Installing OpenCode via npm..."));
207
92
 
208
93
  try {
209
94
  await new Promise<void>((resolve, reject) => {
210
- const install = spawn('npm', ['install', '-g', 'opencode-ai@1.3'], {
211
- stdio: 'inherit',
212
- })
95
+ const install = spawn("npm", ["install", "-g", "opencode-ai@1.3"], {
96
+ stdio: "inherit",
97
+ });
213
98
 
214
- install.on('close', (code) => {
99
+ install.on("close", code => {
215
100
  if (code === 0) {
216
- console.log(chalk.green('✓ OpenCode installed successfully!'))
217
- resolve()
101
+ console.log(chalk.green("✓ OpenCode installed successfully!"));
102
+ resolve();
218
103
  } else {
219
- reject(new Error(`Installation failed with code ${code}`))
104
+ reject(new Error(`Installation failed with code ${code}`));
220
105
  }
221
- })
106
+ });
222
107
 
223
- install.on('error', reject)
224
- })
108
+ install.on("error", reject);
109
+ });
225
110
 
226
111
  // Verify installation
227
- const opencodeInstalled = await checkOpencodeInstalled()
112
+ const opencodeInstalled = await checkOpencodeInstalled();
228
113
  if (!opencodeInstalled) {
229
- console.log(
230
- chalk.yellow('Installation completed but opencode command not found.')
231
- )
232
- console.log(
233
- chalk.yellow(
234
- 'You may need to restart your terminal or check your PATH.'
235
- )
236
- )
237
- return false
114
+ console.log(chalk.yellow("Installation completed but opencode command not found."));
115
+ console.log(chalk.yellow("You may need to restart your terminal or check your PATH."));
116
+ return false;
238
117
  }
239
118
 
240
- return true
119
+ return true;
241
120
  } catch (error) {
242
- console.error(chalk.red('Failed to install OpenCode:'))
243
- console.error(error instanceof Error ? error.message : String(error))
244
- console.log(chalk.blue('\nAlternative installation methods:'))
245
- console.log(chalk.blue(' curl -fsSL https://opencode.ai/install | sh'))
246
- console.log(chalk.blue(' Or visit: https://opencode.ai/docs'))
247
- return false
121
+ console.error(chalk.red("Failed to install OpenCode:"));
122
+ console.error(error instanceof Error ? error.message : String(error));
123
+ console.log(chalk.blue("\nAlternative installation methods:"));
124
+ console.log(chalk.blue(" curl -fsSL https://opencode.ai/install | sh"));
125
+ console.log(chalk.blue(" Or visit: https://opencode.ai/docs"));
126
+ return false;
248
127
  }
249
128
  }
250
129
 
@@ -252,36 +131,27 @@ async function installOpencode(): Promise<boolean> {
252
131
  * Ensure opencode is installed, offering to install if not
253
132
  */
254
133
  async function ensureOpencodeInstalled(autoYes = false): Promise<boolean> {
255
- let opencodeInstalled = await checkOpencodeInstalled()
134
+ let opencodeInstalled = await checkOpencodeInstalled();
256
135
  if (!opencodeInstalled) {
257
136
  if (!autoYes) {
258
- console.log(chalk.red('OpenCode is not installed.'))
259
- console.log(
260
- chalk.blue('OpenCode is required for the AI coding assistant.')
261
- )
137
+ console.log(chalk.red("OpenCode is not installed."));
138
+ console.log(chalk.blue("OpenCode is required for the AI coding assistant."));
262
139
  }
263
140
 
264
- if (
265
- await confirm(
266
- 'Would you like to install OpenCode automatically? (Y/n): ',
267
- autoYes
268
- )
269
- ) {
270
- opencodeInstalled = await installOpencode()
141
+ if (await confirm("Would you like to install OpenCode automatically? (Y/n): ", autoYes)) {
142
+ opencodeInstalled = await installOpencode();
271
143
  } else {
272
144
  if (!autoYes) {
273
- console.log(chalk.blue('\nInstallation cancelled.'))
145
+ console.log(chalk.blue("\nInstallation cancelled."));
274
146
  console.log(
275
- chalk.blue(
276
- 'To install manually: curl -fsSL https://opencode.ai/install | bash'
277
- )
278
- )
279
- console.log(chalk.blue('Or visit: https://opencode.ai/docs'))
147
+ chalk.blue("To install manually: curl -fsSL https://opencode.ai/install | bash")
148
+ );
149
+ console.log(chalk.blue("Or visit: https://opencode.ai/docs"));
280
150
  }
281
151
  }
282
152
  }
283
153
 
284
- return opencodeInstalled
154
+ return opencodeInstalled;
285
155
  }
286
156
 
287
157
  /**
@@ -290,462 +160,396 @@ async function ensureOpencodeInstalled(autoYes = false): Promise<boolean> {
290
160
  export function registerCodeCommands(program: Command): void {
291
161
  const code = program
292
162
  .command(COMMAND_GROUPS.CODE)
293
- .description('AI-powered coding assistant with OpenCode')
163
+ .description("AI-powered coding assistant with OpenCode");
294
164
 
295
165
  if (process.env.BERGET_EXPERIMENTAL) {
296
166
  code
297
- .command('setup')
298
- .description('Interactive setup for Berget AI coding tools')
167
+ .command("setup")
168
+ .description("Interactive setup for Berget AI coding tools")
299
169
  .action(async () => {
300
170
  try {
301
- await runSetupCommand()
171
+ await runSetupCommand();
302
172
  } catch (error) {
303
- handleError('Setup failed', error)
173
+ handleError("Setup failed", error);
304
174
  }
305
- })
175
+ });
306
176
  }
307
177
 
308
178
  code
309
179
  .command(SUBCOMMANDS.CODE.INIT)
310
- .description('Initialize project for AI coding assistant')
311
- .option('-n, --name <name>', 'Project name (defaults to directory name)')
312
- .option('-f, --force', 'Overwrite existing configuration')
313
- .option(
314
- '-y, --yes',
315
- 'Automatically answer yes to all prompts (for automation)'
316
- )
317
- .action(async (options) => {
180
+ .description("Initialize project for AI coding assistant")
181
+ .option("-n, --name <name>", "Project name (defaults to directory name)")
182
+ .option("-f, --force", "Overwrite existing configuration")
183
+ .option("-y, --yes", "Automatically answer yes to all prompts (for automation)")
184
+ .action(async options => {
318
185
  try {
319
- const projectName = options.name || getProjectName()
320
- const configPath = path.join(process.cwd(), 'opencode.json')
186
+ const projectName = options.name || getProjectName();
187
+ const configPath = path.join(process.cwd(), "opencode.json");
321
188
 
322
189
  // Check if already initialized
323
190
  if (fs.existsSync(configPath) && !options.force) {
324
191
  if (!options.yes) {
325
- console.log(
326
- chalk.yellow('Project already initialized for OpenCode.')
327
- )
328
- console.log(chalk.dim(`Config file: ${configPath}`))
192
+ console.log(chalk.yellow("Project already initialized for OpenCode."));
193
+ console.log(chalk.dim(`Config file: ${configPath}`));
329
194
  }
330
195
 
331
- if (
332
- await confirm('Do you want to reinitialize? (Y/n): ', options.yes)
333
- ) {
196
+ if (await confirm("Do you want to reinitialize? (Y/n): ", options.yes)) {
334
197
  // Continue with reinitialization
335
198
  } else {
336
- return
199
+ return;
337
200
  }
338
201
  }
339
202
 
340
203
  // Ensure opencode is installed
341
204
  if (!(await ensureOpencodeInstalled(options.yes))) {
342
- return
205
+ return;
343
206
  }
344
207
 
345
- console.log(
346
- chalk.cyan(`Initializing OpenCode for project: ${projectName}`)
347
- )
208
+ console.log(chalk.cyan(`Initializing OpenCode for project: ${projectName}`));
348
209
 
349
210
  const config = {
350
- $schema: 'https://opencode.ai/config.json',
351
- plugin: ['@bergetai/opencode-auth@1.0.16'],
352
- }
211
+ $schema: "https://opencode.ai/config.json",
212
+ plugin: ["@bergetai/opencode-auth@1.0.16"],
213
+ };
353
214
 
354
- const agentsDir = path.join(process.cwd(), '.opencode', 'agents')
355
- const templatesDir = getAgentTemplatesDir()
215
+ const agentsDir = path.join(process.cwd(), ".opencode", "agents");
216
+ const templatesDir = getAgentTemplatesDir();
356
217
 
357
218
  if (!options.yes) {
358
- console.log(chalk.blue('\nAbout to create configuration files:'))
359
- console.log(chalk.dim(`Config: ${configPath}`))
360
- console.log(chalk.dim(`Agents: ${agentsDir}/`))
361
- console.log(
362
- chalk.dim('This will configure OpenCode with the Berget auth plugin.')
363
- )
219
+ console.log(chalk.blue("\nAbout to create configuration files:"));
220
+ console.log(chalk.dim(`Config: ${configPath}`));
221
+ console.log(chalk.dim(`Agents: ${agentsDir}/`));
222
+ console.log(chalk.dim("This will configure OpenCode with the Berget auth plugin."));
364
223
  }
365
224
 
366
- if (
367
- await confirm('\nCreate configuration files? (Y/n): ', options.yes)
368
- ) {
225
+ if (await confirm("\nCreate configuration files? (Y/n): ", options.yes)) {
369
226
  try {
370
- await writeFile(configPath, JSON.stringify(config, null, 2))
371
- console.log(chalk.green('✓ Created opencode.json'))
372
- console.log(chalk.dim(' Plugin: @bergetai/opencode-auth'))
373
-
374
- fs.mkdirSync(agentsDir, { recursive: true })
375
- const templateFiles = fs
376
- .readdirSync(templatesDir)
377
- .filter((f) => f.endsWith('.md'))
227
+ await writeFile(configPath, JSON.stringify(config, null, 2));
228
+ console.log(chalk.green("✓ Created opencode.json"));
229
+ console.log(chalk.dim(" Plugin: @bergetai/opencode-auth"));
230
+
231
+ fs.mkdirSync(agentsDir, { recursive: true });
232
+ const templateFiles = fs.readdirSync(templatesDir).filter(f => f.endsWith(".md"));
378
233
  for (const file of templateFiles) {
379
- const src = path.join(templatesDir, file)
380
- const dest = path.join(agentsDir, file)
381
- fs.copyFileSync(src, dest)
234
+ const src = path.join(templatesDir, file);
235
+ const dest = path.join(agentsDir, file);
236
+ fs.copyFileSync(src, dest);
382
237
  }
383
238
  console.log(
384
239
  chalk.green(
385
240
  `✓ Created ${templateFiles.length} agent definitions in .opencode/agents/`
386
241
  )
387
- )
242
+ );
388
243
  } catch (error) {
389
- console.error(chalk.red('Failed to create config files:'))
390
- handleError('Config file creation failed', error)
391
- return
244
+ console.error(chalk.red("Failed to create config files:"));
245
+ handleError("Config file creation failed", error);
246
+ return;
392
247
  }
393
248
  } else {
394
- console.log(chalk.yellow('Configuration file creation cancelled.'))
395
- return
249
+ console.log(chalk.yellow("Configuration file creation cancelled."));
250
+ return;
396
251
  }
397
252
 
398
- console.log(chalk.green('\n✅ Project initialized successfully!'))
399
- console.log(chalk.blue('\nNext steps:'))
400
- console.log(chalk.cyan(' 1. Run: opencode'))
401
- console.log(chalk.cyan(' 2. Type: /connect'))
402
- console.log(chalk.cyan(' 3. Choose your auth method:'))
403
- console.log(chalk.dim(' • "Login with Berget" — Berget Code team members (SSO)'))
404
- console.log(chalk.dim(' • "Enter API Key" — API key users (console.berget.ai)'))
253
+ console.log(chalk.green("\n✅ Project initialized successfully!"));
254
+ console.log(chalk.blue("\nNext steps:"));
255
+ console.log(chalk.cyan(" 1. Run: opencode"));
256
+ console.log(chalk.cyan(" 2. Type: /connect"));
257
+ console.log(chalk.cyan(" 3. Choose your auth method:"));
258
+ console.log(chalk.dim(' • "Login with Berget" — Berget Code team members (SSO)'));
259
+ console.log(chalk.dim(' • "Enter API Key" — API key users (console.berget.ai)'));
405
260
  } catch (error) {
406
- handleError('Failed to initialize project', error)
261
+ handleError("Failed to initialize project", error);
407
262
  }
408
- })
263
+ });
409
264
 
410
265
  code
411
266
  .command(SUBCOMMANDS.CODE.RUN)
412
- .description('Run AI coding assistant')
413
- .argument('[prompt]', 'Prompt to send directly to OpenCode')
414
- .option('-m, --model <model>', 'Model to use (overrides config)')
415
- .option('-a, --analysis', 'Use fast analysis model for context building')
416
- .option('--no-config', 'Run without loading project config')
417
- .option(
418
- '-y, --yes',
419
- 'Automatically answer yes to all prompts (for automation)'
420
- )
267
+ .description("Run AI coding assistant")
268
+ .argument("[prompt]", "Prompt to send directly to OpenCode")
269
+ .option("-m, --model <model>", "Model to use (overrides config)")
270
+ .option("-a, --analysis", "Use fast analysis model for context building")
271
+ .option("--no-config", "Run without loading project config")
272
+ .option("-y, --yes", "Automatically answer yes to all prompts (for automation)")
421
273
  .action(async (prompt: string, options: any) => {
422
274
  try {
423
- const configPath = path.join(process.cwd(), 'opencode.json')
275
+ const configPath = path.join(process.cwd(), "opencode.json");
424
276
 
425
277
  // Ensure opencode is installed
426
278
  if (!(await ensureOpencodeInstalled(options.yes))) {
427
- return
279
+ return;
428
280
  }
429
281
 
430
- let config: any = null
282
+ let config: any = null;
431
283
  if (!options.noConfig && fs.existsSync(configPath)) {
432
284
  try {
433
- const configContent = await readFile(configPath, 'utf8')
434
- config = JSON.parse(configContent)
435
- console.log(
436
- chalk.dim(`Loaded config for project: ${config.projectName}`)
437
- )
285
+ const configContent = await readFile(configPath, "utf8");
286
+ config = JSON.parse(configContent);
287
+ console.log(chalk.dim(`Loaded config for project: ${config.projectName}`));
438
288
  console.log(
439
- chalk.dim(
440
- `Models: Analysis=${config.analysisModel}, Build=${config.buildModel}`
441
- )
442
- )
443
- } catch (error) {
444
- console.log(chalk.yellow('Warning: Failed to load opencode.json'))
289
+ chalk.dim(`Models: Analysis=${config.analysisModel}, Build=${config.buildModel}`)
290
+ );
291
+ } catch {
292
+ console.log(chalk.yellow("Warning: Failed to load opencode.json"));
445
293
  }
446
294
  }
447
295
 
448
296
  if (!config) {
449
- console.log(chalk.yellow('No project configuration found.'))
297
+ console.log(chalk.yellow("No project configuration found."));
450
298
  console.log(
451
299
  chalk.blue(
452
- `Run ${chalk.bold(
453
- `berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`
454
- )} first.`
300
+ `Run ${chalk.bold(`berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`)} first.`
455
301
  )
456
- )
457
- return
302
+ );
303
+ return;
458
304
  }
459
305
 
460
306
  // Prepare opencode command
461
- const env = { ...process.env }
462
- const opencodeArgs: string[] = []
307
+ const env = { ...process.env };
308
+ const opencodeArgs: string[] = [];
463
309
 
464
310
  // Read --stage and --local from root program options
465
311
  // (these flags are registered at program level, not subcommand level)
466
- const isStage = process.argv.includes('--stage')
467
- const isLocal = process.argv.includes('--local')
312
+ const isStage = process.argv.includes("--stage");
313
+ const isLocal = process.argv.includes("--local");
468
314
 
469
315
  if (isStage) {
470
- console.log(chalk.cyan('Using Berget stage environment'))
471
- env.BERGET_API_URL = 'https://api.stage.berget.ai'
472
- env.BERGET_INFERENCE_URL = 'https://api.stage.berget.ai/v1'
316
+ console.log(chalk.cyan("Using Berget stage environment"));
317
+ env.BERGET_API_URL = "https://api.stage.berget.ai";
318
+ env.BERGET_INFERENCE_URL = "https://api.stage.berget.ai/v1";
473
319
  } else if (isLocal) {
474
- console.log(chalk.cyan('Using local development environment'))
475
- env.BERGET_API_URL = 'http://localhost:3000'
476
- env.BERGET_INFERENCE_URL = 'http://localhost:3000/v1'
320
+ console.log(chalk.cyan("Using local development environment"));
321
+ env.BERGET_API_URL = "http://localhost:3000";
322
+ env.BERGET_INFERENCE_URL = "http://localhost:3000/v1";
477
323
  }
478
324
 
479
325
  if (prompt) {
480
- opencodeArgs.push('run', prompt)
326
+ opencodeArgs.push("run", prompt);
481
327
  }
482
328
 
483
329
  // Choose model based on analysis flag or override
484
- let selectedModel = options.model || config.buildModel
330
+ let selectedModel = options.model || config.buildModel;
485
331
  if (options.analysis && !options.model) {
486
- selectedModel = config.analysisModel
332
+ selectedModel = config.analysisModel;
487
333
  }
488
334
 
489
335
  if (selectedModel) {
490
- opencodeArgs.push('--model', selectedModel)
336
+ opencodeArgs.push("--model", selectedModel);
491
337
  }
492
338
 
493
- console.log(chalk.cyan('Starting OpenCode...'))
339
+ console.log(chalk.cyan("Starting OpenCode..."));
494
340
 
495
341
  // Spawn opencode process
496
- const opencode = spawn('opencode', opencodeArgs, {
497
- stdio: 'inherit',
342
+ const opencode = spawn("opencode", opencodeArgs, {
343
+ stdio: "inherit",
498
344
  env: env,
499
- })
345
+ });
500
346
 
501
- opencode.on('close', (code) => {
347
+ opencode.on("close", code => {
502
348
  if (code !== 0) {
503
- console.log(chalk.red(`OpenCode exited with code ${code}`))
349
+ console.log(chalk.red(`OpenCode exited with code ${code}`));
504
350
  }
505
- })
351
+ });
506
352
 
507
- opencode.on('error', (error) => {
508
- console.error(chalk.red('Failed to start OpenCode:'))
509
- console.error(error.message)
510
- })
353
+ opencode.on("error", error => {
354
+ console.error(chalk.red("Failed to start OpenCode:"));
355
+ console.error(error.message);
356
+ });
511
357
  } catch (error) {
512
- handleError('Failed to run OpenCode', error)
358
+ handleError("Failed to run OpenCode", error);
513
359
  }
514
- })
360
+ });
515
361
 
516
362
  code
517
363
  .command(SUBCOMMANDS.CODE.SERVE)
518
- .description('Start OpenCode web server')
519
- .option('-p, --port <port>', 'Port to run the server on (default: 3000)')
520
- .option(
521
- '-h, --host <host>',
522
- 'Host to bind the server to (default: localhost)'
523
- )
524
- .option(
525
- '-y, --yes',
526
- 'Automatically answer yes to all prompts (for automation)'
527
- )
528
- .action(async (options) => {
364
+ .description("Start OpenCode web server")
365
+ .option("-p, --port <port>", "Port to run the server on (default: 3000)")
366
+ .option("-h, --host <host>", "Host to bind the server to (default: localhost)")
367
+ .option("-y, --yes", "Automatically answer yes to all prompts (for automation)")
368
+ .action(async options => {
529
369
  try {
530
370
  // Ensure opencode is installed
531
371
  if (!(await ensureOpencodeInstalled(options.yes))) {
532
- return
372
+ return;
533
373
  }
534
374
 
535
- console.log(chalk.cyan('🚀 Starting OpenCode web server...'))
375
+ console.log(chalk.cyan("🚀 Starting OpenCode web server..."));
536
376
 
537
377
  // Prepare opencode serve command
538
- const serveArgs: string[] = ['serve']
378
+ const serveArgs: string[] = ["serve"];
539
379
 
540
380
  if (options.port) {
541
- serveArgs.push('--port', options.port)
381
+ serveArgs.push("--port", options.port);
542
382
  }
543
383
 
544
384
  if (options.host) {
545
- serveArgs.push('--host', options.host)
385
+ serveArgs.push("--host", options.host);
546
386
  }
547
387
 
548
388
  // Spawn opencode serve process
549
- const opencode = spawn('opencode', serveArgs, {
550
- stdio: 'inherit',
551
- })
389
+ const opencode = spawn("opencode", serveArgs, {
390
+ stdio: "inherit",
391
+ });
552
392
 
553
- opencode.on('close', (code) => {
393
+ opencode.on("close", code => {
554
394
  if (code !== 0) {
555
- console.log(chalk.red(`OpenCode server exited with code ${code}`))
395
+ console.log(chalk.red(`OpenCode server exited with code ${code}`));
556
396
  }
557
- })
397
+ });
558
398
 
559
- opencode.on('error', (error) => {
560
- console.error(chalk.red('Failed to start OpenCode server:'))
561
- console.error(error.message)
562
- })
399
+ opencode.on("error", error => {
400
+ console.error(chalk.red("Failed to start OpenCode server:"));
401
+ console.error(error.message);
402
+ });
563
403
  } catch (error) {
564
- handleError('Failed to start OpenCode server', error)
404
+ handleError("Failed to start OpenCode server", error);
565
405
  }
566
- })
406
+ });
567
407
 
568
408
  code
569
409
  .command(SUBCOMMANDS.CODE.UPDATE)
570
- .description('Update OpenCode and agents to latest versions')
571
- .option('-f, --force', 'Force update even if already latest')
572
- .option(
573
- '-y, --yes',
574
- 'Automatically answer yes to all prompts (for automation)'
575
- )
576
- .action(async (options) => {
410
+ .description("Update OpenCode and agents to latest versions")
411
+ .option("-f, --force", "Force update even if already latest")
412
+ .option("-y, --yes", "Automatically answer yes to all prompts (for automation)")
413
+ .action(async options => {
577
414
  try {
578
- console.log(chalk.cyan('🔄 Updating OpenCode configuration...'))
415
+ console.log(chalk.cyan("🔄 Updating OpenCode configuration..."));
579
416
 
580
417
  // Ensure opencode is installed first
581
418
  if (!(await ensureOpencodeInstalled(options.yes))) {
582
- return
419
+ return;
583
420
  }
584
421
 
585
- const configPath = path.join(process.cwd(), 'opencode.json')
422
+ const configPath = path.join(process.cwd(), "opencode.json");
586
423
 
587
424
  // Check if project is initialized
588
425
  if (!fs.existsSync(configPath)) {
589
- console.log(chalk.red('❌ No OpenCode configuration found.'))
426
+ console.log(chalk.red("❌ No OpenCode configuration found."));
590
427
  console.log(
591
428
  chalk.blue(
592
- `Run ${chalk.bold(
593
- `berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`
594
- )} first.`
429
+ `Run ${chalk.bold(`berget ${COMMAND_GROUPS.CODE} ${SUBCOMMANDS.CODE.INIT}`)} first.`
595
430
  )
596
- )
597
- return
431
+ );
432
+ return;
598
433
  }
599
434
 
600
435
  // Read current configuration
601
- let currentConfig: any
436
+ let currentConfig: any;
602
437
  try {
603
- const configContent = await readFile(configPath, 'utf8')
604
- currentConfig = JSON.parse(configContent)
438
+ const configContent = await readFile(configPath, "utf8");
439
+ currentConfig = JSON.parse(configContent);
605
440
  } catch (error) {
606
- console.error(chalk.red('Failed to read current opencode.json:'))
607
- handleError('Config read failed', error)
608
- return
441
+ console.error(chalk.red("Failed to read current opencode.json:"));
442
+ handleError("Config read failed", error);
443
+ return;
609
444
  }
610
445
 
611
- console.log(chalk.blue('📋 Current configuration:'))
446
+ console.log(chalk.blue("📋 Current configuration:"));
612
447
  if (currentConfig.model) {
613
- console.log(chalk.dim(` Model: ${currentConfig.model}`))
448
+ console.log(chalk.dim(` Model: ${currentConfig.model}`));
614
449
  }
615
450
 
616
- const agentsDir = path.join(process.cwd(), '.opencode', 'agents')
617
- const templatesDir = getAgentTemplatesDir()
618
- const templateFiles = fs
619
- .readdirSync(templatesDir)
620
- .filter((f) => f.endsWith('.md'))
621
-
622
- const latestConfig = {
623
- $schema: 'https://opencode.ai/config.json',
624
- plugin: ['@bergetai/opencode-auth@1.0.16'],
625
- }
451
+ const agentsDir = path.join(process.cwd(), ".opencode", "agents");
452
+ const templatesDir = getAgentTemplatesDir();
453
+ const templateFiles = fs.readdirSync(templatesDir).filter(f => f.endsWith(".md"));
626
454
 
627
455
  // Check if agent definitions need updating
628
- let agentsNeedUpdate = false
629
- const existingAgentFiles = fs.existsSync(agentsDir)
630
- ? fs.readdirSync(agentsDir).filter((f) => f.endsWith('.md'))
631
- : []
456
+ let agentsNeedUpdate = false;
632
457
 
633
458
  for (const file of templateFiles) {
634
- const src = path.join(templatesDir, file)
635
- const dest = path.join(agentsDir, file)
459
+ const src = path.join(templatesDir, file);
460
+ const dest = path.join(agentsDir, file);
636
461
  if (!fs.existsSync(dest)) {
637
- agentsNeedUpdate = true
638
- break
462
+ agentsNeedUpdate = true;
463
+ break;
639
464
  }
640
- const srcContent = fs.readFileSync(src, 'utf8')
641
- const destContent = fs.readFileSync(dest, 'utf8')
465
+ const srcContent = fs.readFileSync(src, "utf8");
466
+ const destContent = fs.readFileSync(dest, "utf8");
642
467
  if (srcContent !== destContent) {
643
- agentsNeedUpdate = true
644
- break
468
+ agentsNeedUpdate = true;
469
+ break;
645
470
  }
646
471
  }
647
472
 
648
473
  // Check if opencode.json still has inline agent config (needs migration)
649
- const needsMigration = !!currentConfig.agent
474
+ const needsMigration = !!currentConfig.agent;
650
475
 
651
476
  if (!agentsNeedUpdate && !needsMigration && !options.force) {
652
- console.log(chalk.green('✅ Already using the latest configuration!'))
653
- return
477
+ console.log(chalk.green("✅ Already using the latest configuration!"));
478
+ return;
654
479
  }
655
480
 
656
481
  if (agentsNeedUpdate || needsMigration) {
657
- console.log(chalk.blue('\n🔄 Updates available:'))
482
+ console.log(chalk.blue("\n🔄 Updates available:"));
658
483
 
659
484
  if (needsMigration) {
660
- console.log(
661
- chalk.cyan(' • Migrate agents from opencode.json to .opencode/agents/')
662
- )
485
+ console.log(chalk.cyan(" • Migrate agents from opencode.json to .opencode/agents/"));
663
486
  }
664
487
 
665
488
  if (agentsNeedUpdate) {
666
- console.log(chalk.cyan(' • Latest agent prompts and improvements'))
489
+ console.log(chalk.cyan(" • Latest agent prompts and improvements"));
667
490
  }
668
491
  }
669
492
 
670
493
  if (options.force) {
671
- console.log(chalk.yellow('🔧 Force update requested'))
494
+ console.log(chalk.yellow("🔧 Force update requested"));
672
495
  }
673
496
 
674
497
  if (!options.yes) {
675
498
  console.log(
676
- chalk.blue(
677
- '\nThis will update your agent definitions and OpenCode configuration.'
678
- )
679
- )
499
+ chalk.blue("\nThis will update your agent definitions and OpenCode configuration.")
500
+ );
680
501
 
681
- const hasGitRepo = hasGit()
502
+ const hasGitRepo = hasGit();
682
503
  if (!hasGitRepo) {
683
- console.log(
684
- chalk.yellow(
685
- '⚠️ No .git repository detected - backup will be created'
686
- )
687
- )
504
+ console.log(chalk.yellow("⚠️ No .git repository detected - backup will be created"));
688
505
  } else {
689
- console.log(
690
- chalk.green('✓ Git repository detected - changes are tracked')
691
- )
506
+ console.log(chalk.green("✓ Git repository detected - changes are tracked"));
692
507
  }
693
508
  }
694
509
 
695
- if (
696
- await confirm('\nProceed with update? (Y/n): ', options.yes)
697
- ) {
510
+ if (await confirm("\nProceed with update? (Y/n): ", options.yes)) {
698
511
  try {
699
- let backupPath: string | null = null
512
+ let backupPath: string | null = null;
700
513
 
701
514
  if (!hasGit()) {
702
- backupPath = `${configPath}.backup.${Date.now()}`
703
- await writeFile(
704
- backupPath,
705
- JSON.stringify(currentConfig, null, 2)
706
- )
515
+ backupPath = `${configPath}.backup.${Date.now()}`;
516
+ await writeFile(backupPath, JSON.stringify(currentConfig, null, 2));
707
517
  console.log(
708
- chalk.green(
709
- `✓ Backed up current config to ${path.basename(backupPath)}`
710
- )
711
- )
518
+ chalk.green(`✓ Backed up current config to ${path.basename(backupPath)}`)
519
+ );
712
520
  }
713
521
 
714
522
  // Remove inline agent section from opencode.json if present
715
523
  if (currentConfig.agent) {
716
- delete currentConfig.agent
717
- await writeFile(configPath, JSON.stringify(currentConfig, null, 2))
718
- console.log(
719
- chalk.green('✓ Removed inline agent config from opencode.json')
720
- )
524
+ delete currentConfig.agent;
525
+ await writeFile(configPath, JSON.stringify(currentConfig, null, 2));
526
+ console.log(chalk.green("✓ Removed inline agent config from opencode.json"));
721
527
  }
722
528
 
723
529
  // Sync agent markdown files from templates
724
- fs.mkdirSync(agentsDir, { recursive: true })
725
- let updatedCount = 0
530
+ fs.mkdirSync(agentsDir, { recursive: true });
531
+ let updatedCount = 0;
726
532
  for (const file of templateFiles) {
727
- const src = path.join(templatesDir, file)
728
- const dest = path.join(agentsDir, file)
729
- const agentName = path.basename(file, '.md')
533
+ const src = path.join(templatesDir, file);
534
+ const dest = path.join(agentsDir, file);
535
+ const agentName = path.basename(file, ".md");
730
536
 
731
537
  if (
732
538
  !fs.existsSync(dest) ||
733
- fs.readFileSync(src, 'utf8') !== fs.readFileSync(dest, 'utf8')
539
+ fs.readFileSync(src, "utf8") !== fs.readFileSync(dest, "utf8")
734
540
  ) {
735
- fs.copyFileSync(src, dest)
736
- updatedCount++
737
- console.log(chalk.cyan(` • Updated agent: ${agentName}`))
541
+ fs.copyFileSync(src, dest);
542
+ updatedCount++;
543
+ console.log(chalk.cyan(` • Updated agent: ${agentName}`));
738
544
  }
739
545
  }
740
546
 
741
547
  if (updatedCount > 0) {
742
- console.log(
743
- chalk.green(`✓ Updated ${updatedCount} agent definition(s)`)
744
- )
548
+ console.log(chalk.green(`✓ Updated ${updatedCount} agent definition(s)`));
745
549
  }
746
550
 
747
551
  // Update AGENTS.md if it doesn't exist
748
- const agentsMdPath = path.join(process.cwd(), 'AGENTS.md')
552
+ const agentsMdPath = path.join(process.cwd(), "AGENTS.md");
749
553
  if (!fs.existsSync(agentsMdPath)) {
750
554
  const agentsMdContent = `# Berget Code Agents
751
555
 
@@ -795,35 +599,29 @@ See https://opencode.ai/docs/agents/ for available options.
795
599
  ---
796
600
 
797
601
  *Updated by berget code update*
798
- `
602
+ `;
799
603
 
800
- await writeFile(agentsMdPath, agentsMdContent)
801
- console.log(chalk.green('✓ Created AGENTS.md documentation'))
604
+ await writeFile(agentsMdPath, agentsMdContent);
605
+ console.log(chalk.green("✓ Created AGENTS.md documentation"));
802
606
  }
803
607
 
804
- console.log(chalk.green('\n✅ Update completed successfully!'))
608
+ console.log(chalk.green("\n✅ Update completed successfully!"));
805
609
  } catch (error) {
806
- console.error(chalk.red('Failed to update configuration:'))
807
- handleError('Update failed', error)
610
+ console.error(chalk.red("Failed to update configuration:"));
611
+ handleError("Update failed", error);
808
612
 
809
613
  try {
810
- await writeFile(
811
- configPath,
812
- JSON.stringify(currentConfig, null, 2)
813
- )
814
- console.log(
815
- chalk.yellow('📁 Restored original configuration from backup')
816
- )
817
- } catch (restoreError) {
818
- console.error(chalk.red('Failed to restore backup:'))
614
+ await writeFile(configPath, JSON.stringify(currentConfig, null, 2));
615
+ console.log(chalk.yellow("📁 Restored original configuration from backup"));
616
+ } catch {
617
+ console.error(chalk.red("Failed to restore backup:"));
819
618
  }
820
619
  }
821
620
  } else {
822
- console.log(chalk.yellow('Update cancelled.'))
621
+ console.log(chalk.yellow("Update cancelled."));
823
622
  }
824
- } catch (error) {
825
- handleError('Failed to update OpenCode configuration', error)
623
+ } catch {
624
+ console.error(chalk.red("Failed to update OpenCode configuration"));
826
625
  }
827
- })
626
+ });
828
627
  }
829
-