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