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
@@ -0,0 +1,26 @@
1
+ import { Agent } from "./types.js";
2
+
3
+ export const agent: Agent = {
4
+ config: {
5
+ name: "security",
6
+ description:
7
+ "Security specialist for pentesting, OWASP compliance, and vulnerability assessments.",
8
+ mode: "subagent",
9
+ temperature: 0.2,
10
+ top_p: 0.8,
11
+ permission: {
12
+ edit: "deny",
13
+ bash: "allow",
14
+ webfetch: "allow",
15
+ },
16
+ },
17
+ systemPrompt: `Voice: Scandinavian calm—precise, concise, confident. You are Berget Code Security agent. Expert in application security, penetration testing, and OWASP standards. Core responsibilities: Conduct security assessments and penetration tests, Validate OWASP Top 10 compliance, Review code for security vulnerabilities, Implement security headers and Content Security Policy (CSP), Audit API security, Check for sensitive data exposure, Validate input sanitization and output encoding, Assess dependency security and supply chain risks. Tools and techniques: OWASP ZAP, Burp Suite, security linters, dependency scanners, manual code review. Always provide specific, actionable security recommendations with priority levels.
18
+
19
+ GIT WORKFLOW RULES (CRITICAL):
20
+ - NEVER push directly to main branch - ALWAYS use pull requests
21
+ - NEVER use 'git add .' - ALWAYS add specific files with 'git add path/to/file'
22
+ - ALWAYS clean up test files, documentation files, and temporary artifacts before committing
23
+ - ALWAYS ensure git history maintains production quality - no test commits, no debugging code
24
+ - ALWAYS create descriptive commit messages following project conventions
25
+ - ALWAYS run tests and build before creating PR`,
26
+ };
@@ -0,0 +1,17 @@
1
+ export interface AgentConfig {
2
+ name: string;
3
+ description: string;
4
+ mode?: "primary" | "subagent";
5
+ temperature?: number;
6
+ top_p?: number;
7
+ permission?: {
8
+ edit?: string;
9
+ bash?: string;
10
+ webfetch?: string;
11
+ };
12
+ }
13
+
14
+ export interface Agent {
15
+ config: AgentConfig;
16
+ systemPrompt: string;
17
+ }
package/src/client.ts CHANGED
@@ -1,67 +1,64 @@
1
- import createClient from 'openapi-fetch'
2
- import type { paths } from './types/api'
3
- import * as fs from 'fs'
4
- import * as path from 'path'
5
- import * as os from 'os'
6
- import chalk from 'chalk'
7
- import { TokenManager } from './utils/token-manager'
8
- import { logger } from './utils/logger'
1
+ import createClient from "openapi-fetch";
2
+ import type { paths } from "./types/api";
3
+ import chalk from "chalk";
4
+ import { TokenManager } from "./utils/token-manager";
5
+ import { logger } from "./utils/logger";
9
6
 
10
7
  // API Base URL
11
8
  // Use --local flag to test against local API
12
9
  // Use --stage flag to test against stage API
13
- const isLocalMode = process.argv.includes('--local')
14
- const isStageMode = process.argv.includes('--stage')
10
+ const isLocalMode = process.argv.includes("--local");
11
+ const isStageMode = process.argv.includes("--stage");
15
12
 
16
13
  export const API_BASE_URL =
17
14
  process.env.BERGET_API_URL ||
18
- (isLocalMode ? 'http://localhost:3000' :
19
- isStageMode ? 'https://api.stage.berget.ai' :
20
- 'https://api.berget.ai') // production default
15
+ (isLocalMode
16
+ ? "http://localhost:3000"
17
+ : isStageMode
18
+ ? "https://api.stage.berget.ai"
19
+ : "https://api.berget.ai"); // production default
21
20
 
22
21
  if (isLocalMode && !process.env.BERGET_API_URL) {
23
- logger.debug('Using local API endpoint: http://localhost:3000')
22
+ logger.debug("Using local API endpoint: http://localhost:3000");
24
23
  } else if (isStageMode && !process.env.BERGET_API_URL) {
25
- logger.debug('Using stage API endpoint: https://api.stage.berget.ai')
24
+ logger.debug("Using stage API endpoint: https://api.stage.berget.ai");
26
25
  }
27
26
 
28
27
  // Create a typed client for the Berget API
29
28
  export const apiClient = createClient<paths>({
30
29
  baseUrl: API_BASE_URL,
31
30
  headers: {
32
- 'Content-Type': 'application/json',
33
- Accept: 'application/json',
31
+ "Content-Type": "application/json",
32
+ Accept: "application/json",
34
33
  },
35
- })
34
+ });
36
35
 
37
36
  // Authentication functions
38
37
  export const getAuthToken = (): string | null => {
39
- const tokenManager = TokenManager.getInstance()
40
- return tokenManager.getAccessToken()
41
- }
38
+ const tokenManager = TokenManager.getInstance();
39
+ return tokenManager.getAccessToken();
40
+ };
42
41
 
43
42
  export const saveAuthToken = (
44
43
  accessToken: string,
45
44
  refreshToken: string,
46
- expiresIn: number = 3600,
45
+ expiresIn: number = 3600
47
46
  ): void => {
48
- const tokenManager = TokenManager.getInstance()
49
- tokenManager.setTokens(accessToken, refreshToken, expiresIn)
50
- }
47
+ const tokenManager = TokenManager.getInstance();
48
+ tokenManager.setTokens(accessToken, refreshToken, expiresIn);
49
+ };
51
50
 
52
51
  export const clearAuthToken = (): void => {
53
- const tokenManager = TokenManager.getInstance()
54
- tokenManager.clearTokens()
55
- }
52
+ const tokenManager = TokenManager.getInstance();
53
+ tokenManager.clearTokens();
54
+ };
56
55
 
57
56
  // Create an authenticated client with refresh token support
58
57
  export const createAuthenticatedClient = () => {
59
- const tokenManager = TokenManager.getInstance()
58
+ const tokenManager = TokenManager.getInstance();
60
59
 
61
60
  if (!tokenManager.getAccessToken()) {
62
- logger.debug(
63
- 'No authentication token found. Please run `berget auth login` first.',
64
- )
61
+ logger.debug("No authentication token found. Please run `berget auth login` first.");
65
62
  }
66
63
 
67
64
  // Create the base client
@@ -70,268 +67,229 @@ export const createAuthenticatedClient = () => {
70
67
  headers: tokenManager.getAccessToken()
71
68
  ? {
72
69
  Authorization: `Bearer ${tokenManager.getAccessToken()}`,
73
- 'Content-Type': 'application/json',
74
- Accept: 'application/json',
70
+ "Content-Type": "application/json",
71
+ Accept: "application/json",
75
72
  }
76
73
  : {
77
- 'Content-Type': 'application/json',
78
- Accept: 'application/json',
74
+ "Content-Type": "application/json",
75
+ Accept: "application/json",
79
76
  },
80
- })
77
+ });
81
78
 
82
79
  // Wrap the client to handle token refresh
83
80
  return new Proxy(client, {
84
81
  get(target, prop: string | symbol) {
85
82
  // For HTTP methods (GET, POST, etc.), add token refresh logic
86
83
  if (
87
- typeof target[prop as keyof typeof target] === 'function' &&
88
- ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(String(prop))
84
+ typeof target[prop as keyof typeof target] === "function" &&
85
+ ["GET", "POST", "PUT", "DELETE", "PATCH"].includes(String(prop))
89
86
  ) {
90
87
  return async (...args: any[]) => {
91
88
  // Check if token is expired before making the request
92
89
  if (tokenManager.isTokenExpired() && tokenManager.getRefreshToken()) {
93
- await refreshAccessToken(tokenManager)
90
+ await refreshAccessToken(tokenManager);
94
91
  }
95
92
 
96
93
  // Update the Authorization header with the current token
97
- if (
98
- !args[1]?.headers?.Authorization &&
99
- tokenManager.getAccessToken()
100
- ) {
101
- if (!args[1]) args[1] = {}
102
- if (!args[1].headers) args[1].headers = {}
103
- args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`
94
+ if (!args[1]?.headers?.Authorization && tokenManager.getAccessToken()) {
95
+ if (!args[1]) args[1] = {};
96
+ if (!args[1].headers) args[1].headers = {};
97
+ args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
104
98
  }
105
99
 
106
100
  // Make the original request
107
- let result
101
+ let result;
108
102
  try {
109
- result = await (target[prop as keyof typeof target] as Function)(
110
- ...args,
111
- )
103
+ result = await (target[prop as keyof typeof target] as Function)(...args);
112
104
  } catch (requestError) {
113
105
  logger.debug(
114
106
  `Request error: ${
115
- requestError instanceof Error
116
- ? requestError.message
117
- : String(requestError)
118
- }`,
119
- )
107
+ requestError instanceof Error ? requestError.message : String(requestError)
108
+ }`
109
+ );
120
110
  return {
121
111
  error: {
122
112
  message: `Request failed: ${
123
- requestError instanceof Error
124
- ? requestError.message
125
- : String(requestError)
113
+ requestError instanceof Error ? requestError.message : String(requestError)
126
114
  }`,
127
115
  },
128
- }
116
+ };
129
117
  }
130
118
 
131
119
  // If we get an auth error, try to refresh the token and retry
132
120
  if (result.error) {
133
121
  // Detect various forms of authentication errors
134
- let isAuthError = false
122
+ let isAuthError = false;
135
123
 
136
124
  try {
137
125
  // Standard 401 Unauthorized
138
- if (
139
- typeof result.error === 'object' &&
140
- result.error.status === 401
141
- ) {
142
- isAuthError = true
126
+ if (typeof result.error === "object" && result.error.status === 401) {
127
+ isAuthError = true;
143
128
  }
144
129
  // OAuth specific errors
145
130
  else if (
146
131
  result.error.error &&
147
- (result.error.error.code === 'invalid_token' ||
148
- result.error.error.code === 'token_expired' ||
149
- result.error.error.message === 'Invalid API key' ||
150
- result.error.error.message?.toLowerCase().includes('token') ||
151
- result.error.error.message
152
- ?.toLowerCase()
153
- .includes('unauthorized'))
132
+ (result.error.error.code === "invalid_token" ||
133
+ result.error.error.code === "token_expired" ||
134
+ result.error.error.message === "Invalid API key" ||
135
+ result.error.error.message?.toLowerCase().includes("token") ||
136
+ result.error.error.message?.toLowerCase().includes("unauthorized"))
154
137
  ) {
155
- isAuthError = true
138
+ isAuthError = true;
156
139
  }
157
140
  // Message-based detection as fallback
158
141
  else if (
159
- typeof result.error === 'string' &&
160
- (result.error.toLowerCase().includes('unauthorized') ||
161
- result.error.toLowerCase().includes('token') ||
162
- result.error.toLowerCase().includes('auth'))
142
+ typeof result.error === "string" &&
143
+ (result.error.toLowerCase().includes("unauthorized") ||
144
+ result.error.toLowerCase().includes("token") ||
145
+ result.error.toLowerCase().includes("auth"))
163
146
  ) {
164
- isAuthError = true
147
+ isAuthError = true;
165
148
  }
166
- } catch (parseError) {
149
+ } catch {
167
150
  // If we can't parse the error structure, do a simple string check
168
- const errorStr = String(result.error)
151
+ const errorStr = String(result.error);
169
152
  if (
170
- errorStr.toLowerCase().includes('unauthorized') ||
171
- errorStr.toLowerCase().includes('token') ||
172
- errorStr.toLowerCase().includes('auth')
153
+ errorStr.toLowerCase().includes("unauthorized") ||
154
+ errorStr.toLowerCase().includes("token") ||
155
+ errorStr.toLowerCase().includes("auth")
173
156
  ) {
174
- isAuthError = true
157
+ isAuthError = true;
175
158
  }
176
159
  }
177
160
 
178
161
  if (isAuthError && tokenManager.getRefreshToken()) {
179
- logger.debug('Auth error detected, attempting token refresh')
180
- logger.debug(
181
- `Error details: ${JSON.stringify(result.error, null, 2)}`,
182
- )
162
+ logger.debug("Auth error detected, attempting token refresh");
163
+ logger.debug(`Error details: ${JSON.stringify(result.error, null, 2)}`);
183
164
 
184
- const refreshed = await refreshAccessToken(tokenManager)
165
+ const refreshed = await refreshAccessToken(tokenManager);
185
166
  if (refreshed) {
186
- logger.debug('Token refreshed successfully, retrying request')
167
+ logger.debug("Token refreshed successfully, retrying request");
187
168
 
188
169
  // Update the Authorization header with the new token
189
- if (!args[1]) args[1] = {}
190
- if (!args[1].headers) args[1].headers = {}
191
- args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`
170
+ if (!args[1]) args[1] = {};
171
+ if (!args[1].headers) args[1].headers = {};
172
+ args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`;
192
173
 
193
174
  // Retry the request
194
- return await (target[prop as keyof typeof target] as Function)(
195
- ...args,
196
- )
175
+ return await (target[prop as keyof typeof target] as Function)(...args);
197
176
  } else {
198
- logger.debug('Token refresh failed')
177
+ logger.debug("Token refresh failed");
199
178
 
200
179
  // Add a more helpful error message for users
201
- if (typeof result.error === 'object') {
180
+ if (typeof result.error === "object") {
202
181
  result.error.userMessage =
203
- 'Your session has expired. Please run `berget auth login` to log in again.'
182
+ "Your session has expired. Please run `berget auth login` to log in again.";
204
183
  }
205
184
  }
206
185
  }
207
186
  }
208
187
 
209
- return result
210
- }
188
+ return result;
189
+ };
211
190
  }
212
191
 
213
192
  // For other properties, just return the original
214
- return target[prop as keyof typeof target]
193
+ return target[prop as keyof typeof target];
215
194
  },
216
- })
217
- }
195
+ });
196
+ };
218
197
 
219
198
  // Keycloak configuration for token refresh (must match auth-service.ts)
220
- const KEYCLOAK_URL = (isStageMode || isLocalMode)
221
- ? 'https://keycloak.stage.berget.ai'
222
- : 'https://keycloak.berget.ai'
223
- const KEYCLOAK_REALM = 'berget'
224
- const KEYCLOAK_CLIENT_ID = 'berget-code'
199
+ const KEYCLOAK_URL =
200
+ isStageMode || isLocalMode ? "https://keycloak.stage.berget.ai" : "https://keycloak.berget.ai";
201
+ const KEYCLOAK_REALM = "berget";
202
+ const KEYCLOAK_CLIENT_ID = "berget-code";
225
203
 
226
204
  // Helper function to refresh the access token
227
- async function refreshAccessToken(
228
- tokenManager: TokenManager,
229
- ): Promise<boolean> {
205
+ async function refreshAccessToken(tokenManager: TokenManager): Promise<boolean> {
230
206
  try {
231
- const refreshToken = tokenManager.getRefreshToken()
232
- if (!refreshToken) return false
207
+ const refreshToken = tokenManager.getRefreshToken();
208
+ if (!refreshToken) return false;
233
209
 
234
- logger.debug('Attempting to refresh access token')
210
+ logger.debug("Attempting to refresh access token");
235
211
 
236
212
  // Refresh directly against Keycloak (berget-code is a public PKCE client)
237
213
  try {
238
214
  const response = await fetch(
239
215
  `${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token`,
240
216
  {
241
- method: 'POST',
217
+ method: "POST",
242
218
  headers: {
243
- 'Content-Type': 'application/x-www-form-urlencoded',
219
+ "Content-Type": "application/x-www-form-urlencoded",
244
220
  },
245
221
  body: new URLSearchParams({
246
- grant_type: 'refresh_token',
222
+ grant_type: "refresh_token",
247
223
  client_id: KEYCLOAK_CLIENT_ID,
248
224
  refresh_token: refreshToken,
249
225
  }),
250
- },
251
- )
226
+ }
227
+ );
252
228
 
253
229
  // Handle HTTP errors
254
230
  if (!response.ok) {
255
- logger.debug(
256
- `Token refresh error: HTTP ${response.status} ${response.statusText}`,
257
- )
231
+ logger.debug(`Token refresh error: HTTP ${response.status} ${response.statusText}`);
258
232
 
259
233
  // Check if the refresh token itself is expired or invalid
260
234
  if (response.status === 401 || response.status === 403) {
261
235
  console.warn(
262
- chalk.yellow(
263
- 'Your refresh token has expired. Please run `berget auth login` again.',
264
- ),
265
- )
236
+ chalk.yellow("Your refresh token has expired. Please run `berget auth login` again.")
237
+ );
266
238
  // Clear tokens if unauthorized - they're invalid
267
- tokenManager.clearTokens()
239
+ tokenManager.clearTokens();
268
240
  } else {
269
241
  console.warn(
270
- chalk.yellow(
271
- `Failed to refresh token: ${response.status} ${response.statusText}`,
272
- ),
273
- )
242
+ chalk.yellow(`Failed to refresh token: ${response.status} ${response.statusText}`)
243
+ );
274
244
  }
275
- return false
245
+ return false;
276
246
  }
277
247
 
278
248
  // Parse the response
279
- const contentType = response.headers.get('content-type')
280
- if (!contentType || !contentType.includes('application/json')) {
281
- console.warn(
282
- chalk.yellow(`Unexpected content type in response: ${contentType}`),
283
- )
284
- return false
249
+ const contentType = response.headers.get("content-type");
250
+ if (!contentType || !contentType.includes("application/json")) {
251
+ console.warn(chalk.yellow(`Unexpected content type in response: ${contentType}`));
252
+ return false;
285
253
  }
286
254
 
287
- const data = await response.json()
255
+ const data = await response.json();
288
256
 
289
257
  // Validate the response data
290
258
  if (!data || !data.token) {
291
- console.warn(
292
- chalk.yellow(
293
- 'Invalid token response. Please run `berget auth login` again.',
294
- ),
295
- )
296
- return false
259
+ console.warn(chalk.yellow("Invalid token response. Please run `berget auth login` again."));
260
+ return false;
297
261
  }
298
262
 
299
- logger.debug('Token refreshed successfully')
263
+ logger.debug("Token refreshed successfully");
300
264
 
301
265
  // Update the token
302
- tokenManager.updateAccessToken(data.token, data.expires_in || 3600)
266
+ tokenManager.updateAccessToken(data.token, data.expires_in || 3600);
303
267
 
304
268
  // If a new refresh token was provided, update that too
305
269
  if (data.refresh_token) {
306
- tokenManager.setTokens(
307
- data.token,
308
- data.refresh_token,
309
- data.expires_in || 3600,
310
- )
311
- logger.debug('Refresh token also updated')
270
+ tokenManager.setTokens(data.token, data.refresh_token, data.expires_in || 3600);
271
+ logger.debug("Refresh token also updated");
312
272
  }
313
273
  } catch (fetchError) {
314
274
  console.warn(
315
275
  chalk.yellow(
316
276
  `Failed to refresh token: ${
317
- fetchError instanceof Error
318
- ? fetchError.message
319
- : String(fetchError)
320
- }`,
321
- ),
322
- )
323
- return false
277
+ fetchError instanceof Error ? fetchError.message : String(fetchError)
278
+ }`
279
+ )
280
+ );
281
+ return false;
324
282
  }
325
283
 
326
- return true
284
+ return true;
327
285
  } catch (error) {
328
286
  console.warn(
329
287
  chalk.yellow(
330
288
  `Failed to refresh authentication token: ${
331
289
  error instanceof Error ? error.message : String(error)
332
- }`,
333
- ),
334
- )
335
- return false
290
+ }`
291
+ )
292
+ );
293
+ return false;
336
294
  }
337
295
  }