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,146 +1,151 @@
1
- import chalk from 'chalk'
1
+ import chalk from "chalk";
2
2
 
3
3
  /**
4
4
  * Formats and prints error messages in a consistent way
5
5
  */
6
6
  export function handleError(message: string, error: any): void {
7
- console.error(chalk.red(`❌ Error: ${message}`))
7
+ console.error(chalk.red(`❌ Error: ${message}`));
8
8
 
9
- let errorDetails = ''
10
- let errorCode = ''
11
- let errorType = ''
9
+ let errorDetails = "";
10
+ let errorCode = "";
11
+ let errorType = "";
12
12
 
13
13
  // If the error is a string (like JSON.stringify(error))
14
- if (typeof error === 'string') {
14
+ if (typeof error === "string") {
15
15
  try {
16
16
  // Try to parse it as JSON
17
- const parsedError = JSON.parse(error)
17
+ const parsedError = JSON.parse(error);
18
18
  if (parsedError.error) {
19
- errorDetails = parsedError.error.message || parsedError.error
20
- errorCode = parsedError.error.code || parsedError.code
21
- errorType = parsedError.error.type || ''
19
+ errorDetails = parsedError.error.message || parsedError.error;
20
+ errorCode = parsedError.error.code || parsedError.code;
21
+ errorType = parsedError.error.type || "";
22
22
  } else {
23
- errorDetails = error
23
+ errorDetails = error;
24
24
  }
25
25
  } catch {
26
26
  // If it's not valid JSON, just print the string
27
- errorDetails = error
27
+ errorDetails = error;
28
28
  }
29
29
  } else if (error && error.message) {
30
30
  // If it's an Error object
31
- errorDetails = error.message
32
- errorCode = error.code
33
- errorType = error.type
31
+ errorDetails = error.message;
32
+ errorCode = error.code;
33
+ errorType = error.type;
34
34
  }
35
35
 
36
36
  // Print error details
37
37
  if (errorDetails) {
38
- console.error(chalk.dim(`📝 Details: ${errorDetails}`))
38
+ console.error(chalk.dim(`📝 Details: ${errorDetails}`));
39
39
  }
40
40
  if (errorCode) {
41
- console.error(chalk.dim(`🔢 Code: ${errorCode}`))
41
+ console.error(chalk.dim(`🔢 Code: ${errorCode}`));
42
42
  }
43
43
 
44
44
  // Provide helpful troubleshooting based on error type
45
- provideTroubleshootingTips(errorType, errorCode, errorDetails)
45
+ provideTroubleshootingTips(errorType, errorCode, errorDetails);
46
46
  }
47
47
 
48
48
  /**
49
49
  * Provides helpful troubleshooting tips based on error type
50
50
  */
51
- function provideTroubleshootingTips(errorType: string, errorCode: string, errorDetails: string): void {
52
- console.error(chalk.blue('\n💡 Troubleshooting tips:'))
51
+ function provideTroubleshootingTips(
52
+ errorType: string,
53
+ errorCode: string,
54
+ errorDetails: string
55
+ ): void {
56
+ console.error(chalk.blue("\n💡 Troubleshooting tips:"));
53
57
 
54
58
  // Authentication errors
55
59
  if (
56
- errorType === 'authentication_error' ||
57
- errorCode === 'AUTH_FAILED' ||
58
- errorDetails?.includes('Unauthorized') ||
59
- errorDetails?.includes('Authentication failed')
60
+ errorType === "authentication_error" ||
61
+ errorCode === "AUTH_FAILED" ||
62
+ errorDetails?.includes("Unauthorized") ||
63
+ errorDetails?.includes("Authentication failed")
60
64
  ) {
61
- console.error(chalk.yellow(' 🔐 Authentication issue detected:'))
62
- console.error(chalk.white(' • Run `berget auth login` to log in'))
63
- console.error(chalk.white(' • Check if your session has expired'))
64
- console.error(chalk.white(' • Verify you have the correct permissions'))
65
+ console.error(chalk.yellow(" 🔐 Authentication issue detected:"));
66
+ console.error(chalk.white(" • Run `berget auth login` to log in"));
67
+ console.error(chalk.white(" • Check if your session has expired"));
68
+ console.error(chalk.white(" • Verify you have the correct permissions"));
65
69
  }
66
70
 
67
71
  // Network/connection errors
68
72
  if (
69
- errorDetails?.includes('fetch failed') ||
70
- errorDetails?.includes('ECONNREFUSED') ||
71
- errorDetails?.includes('ENOTFOUND') ||
72
- errorDetails?.includes('network')
73
+ errorDetails?.includes("fetch failed") ||
74
+ errorDetails?.includes("ECONNREFUSED") ||
75
+ errorDetails?.includes("ENOTFOUND") ||
76
+ errorDetails?.includes("network")
73
77
  ) {
74
- console.error(chalk.yellow(' 🌐 Network issue detected:'))
75
- console.error(chalk.white(' • Check your internet connection'))
76
- console.error(chalk.white(' • Verify you can reach api.berget.ai'))
77
- console.error(chalk.white(' • Try again in a few minutes'))
78
- console.error(chalk.white(' • Check if any firewall is blocking the request'))
78
+ console.error(chalk.yellow(" 🌐 Network issue detected:"));
79
+ console.error(chalk.white(" • Check your internet connection"));
80
+ console.error(chalk.white(" • Verify you can reach api.berget.ai"));
81
+ console.error(chalk.white(" • Try again in a few minutes"));
82
+ console.error(chalk.white(" • Check if any firewall is blocking the request"));
79
83
  }
80
84
 
81
85
  // API key errors
82
86
  if (
83
- errorCode?.includes('API_KEY') ||
84
- errorDetails?.includes('API key') ||
85
- errorType === 'invalid_request_error'
87
+ errorCode?.includes("API_KEY") ||
88
+ errorDetails?.includes("API key") ||
89
+ errorType === "invalid_request_error"
86
90
  ) {
87
- console.error(chalk.yellow(' 🔑 API key issue detected:'))
88
- console.error(chalk.white(' • Run `berget api-keys list` to check your keys'))
89
- console.error(chalk.white(' • Create a new key with `berget api-keys create --name "My Key"`'))
90
- console.error(chalk.white(' • Set a default key with `berget api-keys set-default <id>`'))
91
- console.error(chalk.white(' • Check if your API key has expired'))
91
+ console.error(chalk.yellow(" 🔑 API key issue detected:"));
92
+ console.error(chalk.white(" • Run `berget api-keys list` to check your keys"));
93
+ console.error(
94
+ chalk.white(' • Create a new key with `berget api-keys create --name "My Key"`')
95
+ );
96
+ console.error(chalk.white(" • Set a default key with `berget api-keys set-default <id>`"));
97
+ console.error(chalk.white(" • Check if your API key has expired"));
92
98
  }
93
99
 
94
100
  // Rate limiting
95
101
  if (
96
- errorCode === 'RATE_LIMIT_EXCEEDED' ||
97
- errorDetails?.includes('rate limit') ||
98
- errorDetails?.includes('too many requests')
102
+ errorCode === "RATE_LIMIT_EXCEEDED" ||
103
+ errorDetails?.includes("rate limit") ||
104
+ errorDetails?.includes("too many requests")
99
105
  ) {
100
- console.error(chalk.yellow(' ⏱️ Rate limit exceeded:'))
101
- console.error(chalk.white(' • Wait a few minutes before trying again'))
102
- console.error(chalk.white(' • Consider upgrading your plan for higher limits'))
103
- console.error(chalk.white(' • Use `berget billing get-usage` to check your usage'))
106
+ console.error(chalk.yellow(" ⏱️ Rate limit exceeded:"));
107
+ console.error(chalk.white(" • Wait a few minutes before trying again"));
108
+ console.error(chalk.white(" • Consider upgrading your plan for higher limits"));
109
+ console.error(chalk.white(" • Use `berget billing get-usage` to check your usage"));
104
110
  }
105
111
 
106
112
  // Server errors
107
113
  if (
108
- errorCode?.includes('SERVER_ERROR') ||
109
- errorType === 'server_error' ||
114
+ errorCode?.includes("SERVER_ERROR") ||
115
+ errorType === "server_error" ||
110
116
  (errorCode && parseInt(errorCode) >= 500)
111
117
  ) {
112
- console.error(chalk.yellow(' 🖥️ Server issue detected:'))
113
- console.error(chalk.white(' • This is a temporary problem on our end'))
114
- console.error(chalk.white(' • Try again in a few minutes'))
115
- console.error(chalk.white(' • Check status.berget.ai for service status'))
116
- console.error(chalk.white(' • Contact support if the problem persists'))
118
+ console.error(chalk.yellow(" 🖥️ Server issue detected:"));
119
+ console.error(chalk.white(" • This is a temporary problem on our end"));
120
+ console.error(chalk.white(" • Try again in a few minutes"));
121
+ console.error(chalk.white(" • Check status.berget.ai for service status"));
122
+ console.error(chalk.white(" • Contact support if the problem persists"));
117
123
  }
118
124
 
119
125
  // Cluster errors
120
- if (
121
- errorCode?.includes('CLUSTERS') ||
122
- errorDetails?.includes('cluster')
123
- ) {
124
- console.error(chalk.yellow(' 🏗️ Cluster issue detected:'))
125
- console.error(chalk.white(' • Clusters may be temporarily unavailable'))
126
- console.error(chalk.white(' • Try again later or contact support'))
127
- console.error(chalk.white(' • Check your cluster permissions'))
126
+ if (errorCode?.includes("CLUSTERS") || errorDetails?.includes("cluster")) {
127
+ console.error(chalk.yellow(" 🏗️ Cluster issue detected:"));
128
+ console.error(chalk.white(" • Clusters may be temporarily unavailable"));
129
+ console.error(chalk.white(" • Try again later or contact support"));
130
+ console.error(chalk.white(" Check your cluster permissions"));
128
131
  }
129
132
 
130
133
  // Generic fallback
131
134
  if (
132
- !errorType?.includes('authentication') &&
133
- !errorDetails?.includes('fetch failed') &&
134
- !errorCode?.includes('API_KEY') &&
135
- !errorCode?.includes('RATE_LIMIT') &&
136
- !errorCode?.includes('SERVER_ERROR') &&
137
- !errorCode?.includes('CLUSTERS')
135
+ !errorType?.includes("authentication") &&
136
+ !errorDetails?.includes("fetch failed") &&
137
+ !errorCode?.includes("API_KEY") &&
138
+ !errorCode?.includes("RATE_LIMIT") &&
139
+ !errorCode?.includes("SERVER_ERROR") &&
140
+ !errorCode?.includes("CLUSTERS")
138
141
  ) {
139
- console.error(chalk.yellow(' ❓ General issue:'))
140
- console.error(chalk.white(' • Try running the command with --debug for more info'))
141
- console.error(chalk.white(' • Check your configuration with `berget auth whoami`'))
142
- console.error(chalk.white(' • Contact support if the problem persists'))
142
+ console.error(chalk.yellow(" ❓ General issue:"));
143
+ console.error(chalk.white(" • Try running the command with --debug for more info"));
144
+ console.error(chalk.white(" • Check your configuration with `berget auth whoami`"));
145
+ console.error(chalk.white(" • Contact support if the problem persists"));
143
146
  }
144
147
 
145
- console.error(chalk.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'))
148
+ console.error(
149
+ chalk.dim("\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai")
150
+ );
146
151
  }
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk'
1
+ import chalk from "chalk";
2
2
 
3
3
  /**
4
4
  * Log levels in order of increasing verbosity
@@ -15,25 +15,25 @@ export enum LogLevel {
15
15
  * Logger class for centralized logging with configurable log levels
16
16
  */
17
17
  export class Logger {
18
- private static instance: Logger
19
- private logLevel: LogLevel = LogLevel.INFO // Default log level
18
+ private static instance: Logger;
19
+ private logLevel: LogLevel = LogLevel.INFO; // Default log level
20
20
 
21
21
  private constructor() {
22
22
  // Set log level from environment variable or command line argument
23
23
  if (process.env.LOG_LEVEL) {
24
- this.setLogLevelFromString(process.env.LOG_LEVEL)
25
- } else if (process.argv.includes('--debug')) {
26
- this.logLevel = LogLevel.DEBUG
27
- } else if (process.argv.includes('--quiet')) {
28
- this.logLevel = LogLevel.ERROR
24
+ this.setLogLevelFromString(process.env.LOG_LEVEL);
25
+ } else if (process.argv.includes("--debug")) {
26
+ this.logLevel = LogLevel.DEBUG;
27
+ } else if (process.argv.includes("--quiet")) {
28
+ this.logLevel = LogLevel.ERROR;
29
29
  }
30
30
  }
31
31
 
32
32
  public static getInstance(): Logger {
33
33
  if (!Logger.instance) {
34
- Logger.instance = new Logger()
34
+ Logger.instance = new Logger();
35
35
  }
36
- return Logger.instance
36
+ return Logger.instance;
37
37
  }
38
38
 
39
39
  /**
@@ -41,24 +41,24 @@ export class Logger {
41
41
  */
42
42
  private setLogLevelFromString(level: string): void {
43
43
  switch (level.toLowerCase()) {
44
- case 'none':
45
- this.logLevel = LogLevel.NONE
46
- break
47
- case 'error':
48
- this.logLevel = LogLevel.ERROR
49
- break
50
- case 'warn':
51
- this.logLevel = LogLevel.WARN
52
- break
53
- case 'info':
54
- this.logLevel = LogLevel.INFO
55
- break
56
- case 'debug':
57
- this.logLevel = LogLevel.DEBUG
58
- break
44
+ case "none":
45
+ this.logLevel = LogLevel.NONE;
46
+ break;
47
+ case "error":
48
+ this.logLevel = LogLevel.ERROR;
49
+ break;
50
+ case "warn":
51
+ this.logLevel = LogLevel.WARN;
52
+ break;
53
+ case "info":
54
+ this.logLevel = LogLevel.INFO;
55
+ break;
56
+ case "debug":
57
+ this.logLevel = LogLevel.DEBUG;
58
+ break;
59
59
  default:
60
60
  // Invalid log level, keep default
61
- console.warn(`Invalid log level: ${level}. Using default (INFO).`)
61
+ console.warn(`Invalid log level: ${level}. Using default (INFO).`);
62
62
  }
63
63
  }
64
64
 
@@ -66,14 +66,14 @@ export class Logger {
66
66
  * Set the log level
67
67
  */
68
68
  public setLogLevel(level: LogLevel): void {
69
- this.logLevel = level
69
+ this.logLevel = level;
70
70
  }
71
71
 
72
72
  /**
73
73
  * Get the current log level
74
74
  */
75
75
  public getLogLevel(): LogLevel {
76
- return this.logLevel
76
+ return this.logLevel;
77
77
  }
78
78
 
79
79
  /**
@@ -82,9 +82,9 @@ export class Logger {
82
82
  public debug(message: string, ...args: any[]): void {
83
83
  if (this.logLevel >= LogLevel.DEBUG) {
84
84
  if (args.length > 0) {
85
- console.log(chalk.yellow(`DEBUG: ${message}`), ...args)
85
+ console.log(chalk.yellow(`DEBUG: ${message}`), ...args);
86
86
  } else {
87
- console.log(chalk.yellow(`DEBUG: ${message}`))
87
+ console.log(chalk.yellow(`DEBUG: ${message}`));
88
88
  }
89
89
  }
90
90
  }
@@ -95,9 +95,9 @@ export class Logger {
95
95
  public info(message: string, ...args: any[]): void {
96
96
  if (this.logLevel >= LogLevel.INFO) {
97
97
  if (args.length > 0) {
98
- console.log(chalk.blue(message), ...args)
98
+ console.log(chalk.blue(message), ...args);
99
99
  } else {
100
- console.log(chalk.blue(message))
100
+ console.log(chalk.blue(message));
101
101
  }
102
102
  }
103
103
  }
@@ -108,9 +108,9 @@ export class Logger {
108
108
  public warn(message: string, ...args: any[]): void {
109
109
  if (this.logLevel >= LogLevel.WARN) {
110
110
  if (args.length > 0) {
111
- console.log(chalk.yellow(message), ...args)
111
+ console.log(chalk.yellow(message), ...args);
112
112
  } else {
113
- console.log(chalk.yellow(message))
113
+ console.log(chalk.yellow(message));
114
114
  }
115
115
  }
116
116
  }
@@ -121,9 +121,9 @@ export class Logger {
121
121
  public error(message: string, ...args: any[]): void {
122
122
  if (this.logLevel >= LogLevel.ERROR) {
123
123
  if (args.length > 0) {
124
- console.error(chalk.red(message), ...args)
124
+ console.error(chalk.red(message), ...args);
125
125
  } else {
126
- console.error(chalk.red(message))
126
+ console.error(chalk.red(message));
127
127
  }
128
128
  }
129
129
  }
@@ -134,9 +134,9 @@ export class Logger {
134
134
  public success(message: string, ...args: any[]): void {
135
135
  if (this.logLevel >= LogLevel.INFO) {
136
136
  if (args.length > 0) {
137
- console.log(chalk.green(message), ...args)
137
+ console.log(chalk.green(message), ...args);
138
138
  } else {
139
- console.log(chalk.green(message))
139
+ console.log(chalk.green(message));
140
140
  }
141
141
  }
142
142
  }
@@ -147,13 +147,13 @@ export class Logger {
147
147
  public log(message: string, ...args: any[]): void {
148
148
  if (this.logLevel >= LogLevel.INFO) {
149
149
  if (args.length > 0) {
150
- console.log(message, ...args)
150
+ console.log(message, ...args);
151
151
  } else {
152
- console.log(message)
152
+ console.log(message);
153
153
  }
154
154
  }
155
155
  }
156
156
  }
157
157
 
158
158
  // Export a singleton instance for easy import
159
- export const logger = Logger.getInstance()
159
+ export const logger = Logger.getInstance();
@@ -1,6 +1,6 @@
1
- import { marked } from 'marked'
2
- import TerminalRenderer from 'marked-terminal'
3
- import chalk from 'chalk'
1
+ import { marked } from "marked";
2
+ import TerminalRenderer from "marked-terminal";
3
+ import chalk from "chalk";
4
4
 
5
5
  // Configure marked to use the terminal renderer
6
6
  marked.setOptions({
@@ -20,7 +20,7 @@ marked.setOptions({
20
20
  // Customize code block rendering
21
21
  codespan: chalk.cyan,
22
22
  }),
23
- })
23
+ });
24
24
 
25
25
  /**
26
26
  * Render markdown text to terminal-friendly formatted text
@@ -28,15 +28,15 @@ marked.setOptions({
28
28
  * @returns Formatted text for terminal display
29
29
  */
30
30
  export function renderMarkdown(markdown: string): string {
31
- if (!markdown) return ''
31
+ if (!markdown) return "";
32
32
 
33
33
  try {
34
34
  // Convert markdown to terminal-friendly text
35
- return marked(markdown)
35
+ return marked(markdown);
36
36
  } catch (error) {
37
37
  // If rendering fails, return the original text
38
- console.error(`Error rendering markdown: ${error}`)
39
- return markdown
38
+ console.error(`Error rendering markdown: ${error}`);
39
+ return markdown;
40
40
  }
41
41
  }
42
42
 
@@ -46,7 +46,7 @@ export function renderMarkdown(markdown: string): string {
46
46
  * @returns True if the text contains markdown formatting
47
47
  */
48
48
  export function containsMarkdown(text: string): boolean {
49
- if (!text) return false
49
+ if (!text) return false;
50
50
 
51
51
  // Check for common markdown patterns
52
52
  const markdownPatterns = [
@@ -62,7 +62,7 @@ export function containsMarkdown(text: string): boolean {
62
62
  /\|.*\|.*\|/, // Tables
63
63
  /^---+$/m, // Horizontal rules
64
64
  /^===+$/m, // Alternative headers
65
- ]
65
+ ];
66
66
 
67
- return markdownPatterns.some((pattern) => pattern.test(text))
67
+ return markdownPatterns.some(pattern => pattern.test(text));
68
68
  }
@@ -1,20 +1,20 @@
1
- import Ajv from 'ajv'
2
- import addFormats from 'ajv-formats'
3
- import { readFileSync } from 'fs'
4
- import { join } from 'path'
5
- import { dirname } from 'path'
1
+ import Ajv from "ajv";
2
+ import addFormats from "ajv-formats";
3
+ import { readFileSync } from "fs";
4
+ import { join } from "path";
5
+ import { dirname } from "path";
6
6
 
7
7
  // Load the official OpenCode JSON Schema
8
- const __dirname = dirname(__filename)
9
- const schemaPath = join(__dirname, '..', 'schemas', 'opencode-schema.json')
8
+ const __dirname = dirname(__filename);
9
+ const schemaPath = join(__dirname, "..", "schemas", "opencode-schema.json");
10
10
 
11
- let ajv: Ajv
12
- let openCodeSchema: any
13
- let validateFunction: any
11
+ let ajv: Ajv;
12
+ let openCodeSchema: any;
13
+ let validateFunction: any;
14
14
 
15
15
  try {
16
- const schemaContent = readFileSync(schemaPath, 'utf-8')
17
- openCodeSchema = JSON.parse(schemaContent)
16
+ const schemaContent = readFileSync(schemaPath, "utf-8");
17
+ openCodeSchema = JSON.parse(schemaContent);
18
18
 
19
19
  // Initialize AJV with formats and options
20
20
  ajv = new Ajv({
@@ -23,48 +23,48 @@ try {
23
23
  strict: false,
24
24
  allowUnionTypes: true,
25
25
  removeAdditional: false,
26
- })
26
+ });
27
27
 
28
28
  // Add JSON Schema formats
29
- addFormats(ajv)
29
+ addFormats(ajv);
30
30
 
31
31
  // Compile the schema
32
- validateFunction = ajv.compile(openCodeSchema)
32
+ validateFunction = ajv.compile(openCodeSchema);
33
33
  } catch (error) {
34
- console.error('Failed to load OpenCode schema:', error)
35
- throw new Error('Could not initialize OpenCode validator')
34
+ console.error("Failed to load OpenCode schema:", error);
35
+ throw new Error("Could not initialize OpenCode validator");
36
36
  }
37
37
 
38
- export type OpenCodeConfig = any
38
+ export type OpenCodeConfig = any;
39
39
 
40
40
  /**
41
41
  * Validate OpenCode configuration against the official JSON Schema
42
42
  */
43
43
  export function validateOpenCodeConfig(config: any): {
44
- valid: boolean
45
- errors?: string[]
44
+ valid: boolean;
45
+ errors?: string[];
46
46
  } {
47
47
  try {
48
48
  if (!validateFunction) {
49
- return { valid: false, errors: ['Schema validator not initialized'] }
49
+ return { valid: false, errors: ["Schema validator not initialized"] };
50
50
  }
51
51
 
52
- const isValid = validateFunction(config)
52
+ const isValid = validateFunction(config);
53
53
 
54
54
  if (isValid) {
55
- return { valid: true }
55
+ return { valid: true };
56
56
  } else {
57
57
  const errors = validateFunction.errors?.map((err: any) => {
58
- const path = err.instancePath || err.schemaPath || 'root'
59
- const message = err.message || 'Unknown error'
60
- return `${path}: ${message}`
61
- }) || ['Unknown validation error']
58
+ const path = err.instancePath || err.schemaPath || "root";
59
+ const message = err.message || "Unknown error";
60
+ return `${path}: ${message}`;
61
+ }) || ["Unknown validation error"];
62
62
 
63
- return { valid: false, errors }
63
+ return { valid: false, errors };
64
64
  }
65
65
  } catch (error) {
66
- console.error('Validation error:', error)
67
- return { valid: false, errors: ['Validation process failed'] }
66
+ console.error("Validation error:", error);
67
+ return { valid: false, errors: ["Validation process failed"] };
68
68
  }
69
69
  }
70
70
 
@@ -72,63 +72,58 @@ export function validateOpenCodeConfig(config: any): {
72
72
  * Fix common OpenCode configuration issues
73
73
  */
74
74
  export function fixOpenCodeConfig(config: any): OpenCodeConfig {
75
- const fixed = { ...config }
75
+ const fixed = { ...config };
76
76
 
77
77
  // Fix tools.compact - should be boolean, not object
78
- if (fixed.tools && typeof fixed.tools.compact === 'object') {
79
- console.warn('⚠️ Converting tools.compact from object to boolean')
78
+ if (fixed.tools && typeof fixed.tools.compact === "object") {
79
+ console.warn("⚠️ Converting tools.compact from object to boolean");
80
80
  // If it has properties, assume it should be enabled
81
- fixed.tools.compact = true
81
+ fixed.tools.compact = true;
82
82
  }
83
83
 
84
84
  // Remove invalid properties
85
- const invalidProps = ['maxTokens', 'contextWindow']
86
- invalidProps.forEach((prop) => {
85
+ const invalidProps = ["maxTokens", "contextWindow"];
86
+ invalidProps.forEach(prop => {
87
87
  if (fixed[prop] !== undefined) {
88
- console.warn(`⚠️ Removing invalid property: ${prop}`)
89
- delete fixed[prop]
88
+ console.warn(`⚠️ Removing invalid property: ${prop}`);
89
+ delete fixed[prop];
90
90
  }
91
- })
91
+ });
92
92
 
93
93
  // Fix provider models with invalid properties
94
94
  if (fixed.provider) {
95
95
  Object.values(fixed.provider).forEach((provider: any) => {
96
96
  if (provider?.models) {
97
97
  Object.values(provider.models).forEach((model: any) => {
98
- if (model && typeof model === 'object') {
98
+ if (model && typeof model === "object") {
99
99
  // Move maxTokens/contextWindow to proper structure if needed
100
100
  if (model.maxTokens || model.contextWindow) {
101
- if (!model.limit) model.limit = {}
101
+ if (!model.limit) model.limit = {};
102
102
 
103
103
  // Use the larger of maxTokens/contextWindow for context
104
- const contextValues = [
105
- model.maxTokens,
106
- model.contextWindow,
107
- ].filter(Boolean)
104
+ const contextValues = [model.maxTokens, model.contextWindow].filter(Boolean);
108
105
  if (contextValues.length > 0) {
109
- const newContext = Math.max(...contextValues)
106
+ const newContext = Math.max(...contextValues);
110
107
  if (!model.limit.context || newContext > model.limit.context) {
111
- model.limit.context = newContext
108
+ model.limit.context = newContext;
112
109
  }
113
110
  }
114
111
 
115
112
  // Set a reasonable default for output if not present
116
113
  // (typically 1/4 to 1/8 of context window)
117
114
  if (!model.limit.output && model.limit.context) {
118
- model.limit.output = Math.floor(model.limit.context / 4)
115
+ model.limit.output = Math.floor(model.limit.context / 4);
119
116
  }
120
117
 
121
- delete model.maxTokens
122
- delete model.contextWindow
123
- console.warn(
124
- '⚠️ Moved maxTokens/contextWindow to limit.context/output',
125
- )
118
+ delete model.maxTokens;
119
+ delete model.contextWindow;
120
+ console.warn("⚠️ Moved maxTokens/contextWindow to limit.context/output");
126
121
  }
127
122
  }
128
- })
123
+ });
129
124
  }
130
- })
125
+ });
131
126
  }
132
127
 
133
- return fixed
128
+ return fixed;
134
129
  }