berget 2.0.3 → 2.0.5

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.
@@ -50,17 +50,80 @@ class ApiKeyService {
50
50
  * Command: berget api-keys create
51
51
  */
52
52
  create(options) {
53
+ var _a, _b, _c, _d;
53
54
  return __awaiter(this, void 0, void 0, function* () {
54
55
  try {
56
+ // Validate input before sending request
57
+ if (!options.name || options.name.trim().length === 0) {
58
+ throw new Error('API key name is required and cannot be empty');
59
+ }
60
+ if (options.name.length > 100) {
61
+ throw new Error('API key name must be 100 characters or less');
62
+ }
63
+ if (options.description && options.description.length > 500) {
64
+ throw new Error('API key description must be 500 characters or less');
65
+ }
55
66
  const { data, error } = yield this.client.POST('/v1/api-keys', {
56
67
  body: options,
57
68
  });
58
- if (error)
69
+ if (error) {
70
+ // Enhanced error handling with specific troubleshooting
71
+ // Handle specific error cases
72
+ if (typeof error === 'object' && error !== null) {
73
+ const errorObj = error;
74
+ if (((_a = errorObj.error) === null || _a === void 0 ? void 0 : _a.code) === 'API_KEY_CREATION_FAILED') {
75
+ let detailedMessage = 'Failed to create API key. This could be due to:\n';
76
+ detailedMessage += '• Account limits or quota restrictions\n';
77
+ detailedMessage +=
78
+ '• Insufficient permissions for API key creation\n';
79
+ detailedMessage += '• Temporary server issues\n';
80
+ detailedMessage += '• Billing or subscription issues\n\n';
81
+ detailedMessage += 'Troubleshooting steps:\n';
82
+ detailedMessage +=
83
+ '1. Check if you have reached your API key limit\n';
84
+ detailedMessage +=
85
+ '2. Verify your account has API key creation permissions\n';
86
+ detailedMessage += '3. Check your billing status and subscription\n';
87
+ detailedMessage +=
88
+ '4. Try again in a few minutes if this is a temporary issue\n';
89
+ detailedMessage += '5. Contact support if the problem persists';
90
+ throw new Error(detailedMessage);
91
+ }
92
+ if (((_b = errorObj.error) === null || _b === void 0 ? void 0 : _b.code) === 'QUOTA_EXCEEDED') {
93
+ throw new Error('You have reached your API key limit. Please delete existing keys or contact support to increase your quota.');
94
+ }
95
+ if (((_c = errorObj.error) === null || _c === void 0 ? void 0 : _c.code) === 'INSUFFICIENT_PERMISSIONS') {
96
+ throw new Error('Your account does not have permission to create API keys. Please contact your administrator.');
97
+ }
98
+ if (((_d = errorObj.error) === null || _d === void 0 ? void 0 : _d.code) === 'BILLING_REQUIRED') {
99
+ throw new Error('A valid billing method is required to create API keys. Please add a payment method.');
100
+ }
101
+ }
59
102
  throw new Error(JSON.stringify(error));
103
+ }
104
+ if (!data) {
105
+ throw new Error('No data received from server');
106
+ }
60
107
  return data;
61
108
  }
62
109
  catch (error) {
63
110
  console.error('Failed to create API key:', error);
111
+ // Add additional context for common issues
112
+ if (error instanceof Error) {
113
+ if (error.message.includes('ECONNREFUSED')) {
114
+ throw new Error('Cannot connect to Berget API. Please check your internet connection.');
115
+ }
116
+ if (error.message.includes('ENOTFOUND')) {
117
+ throw new Error('Cannot resolve Berget API hostname. Please check your DNS settings.');
118
+ }
119
+ if (error.message.includes('401') ||
120
+ error.message.includes('Unauthorized')) {
121
+ throw new Error('Authentication failed. Please run `berget auth login` to log in again.');
122
+ }
123
+ if (error.message.includes('403')) {
124
+ throw new Error('Access forbidden. Your account may not have permission to create API keys.');
125
+ }
126
+ }
64
127
  throw error;
65
128
  }
66
129
  });
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.getProviderModels = exports.getModelConfig = exports.getAllAgentConfigs = exports.getAgentConfig = exports.getConfigLoader = exports.ConfigLoader = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const logger_1 = require("./logger");
30
+ class ConfigLoader {
31
+ constructor(configPath) {
32
+ this.config = null;
33
+ // Default to opencode.json in current working directory
34
+ this.configPath = configPath || path.join(process.cwd(), 'opencode.json');
35
+ }
36
+ static getInstance(configPath) {
37
+ if (!ConfigLoader.instance) {
38
+ ConfigLoader.instance = new ConfigLoader(configPath);
39
+ }
40
+ return ConfigLoader.instance;
41
+ }
42
+ /**
43
+ * Load configuration from opencode.json
44
+ */
45
+ loadConfig() {
46
+ if (this.config) {
47
+ return this.config;
48
+ }
49
+ try {
50
+ if (!fs.existsSync(this.configPath)) {
51
+ throw new Error(`Configuration file not found: ${this.configPath}`);
52
+ }
53
+ const configContent = fs.readFileSync(this.configPath, 'utf8');
54
+ this.config = JSON.parse(configContent);
55
+ logger_1.logger.debug(`Loaded configuration from ${this.configPath}`);
56
+ return this.config;
57
+ }
58
+ catch (error) {
59
+ logger_1.logger.error(`Failed to load configuration from ${this.configPath}:`, error);
60
+ throw new Error(`Failed to load configuration: ${error instanceof Error ? error.message : String(error)}`);
61
+ }
62
+ }
63
+ /**
64
+ * Get agent configuration by name
65
+ */
66
+ getAgentConfig(agentName) {
67
+ var _a;
68
+ const config = this.loadConfig();
69
+ return ((_a = config.agent) === null || _a === void 0 ? void 0 : _a[agentName]) || null;
70
+ }
71
+ /**
72
+ * Get all agent configurations
73
+ */
74
+ getAllAgentConfigs() {
75
+ const config = this.loadConfig();
76
+ return config.agent || {};
77
+ }
78
+ /**
79
+ * Get model configuration
80
+ */
81
+ getModelConfig() {
82
+ const config = this.loadConfig();
83
+ // Extract from config or fall back to defaults
84
+ const primary = config.model || 'berget/deepseek-r1';
85
+ const small = config.small_model || 'berget/gpt-oss';
86
+ return { primary, small };
87
+ }
88
+ /**
89
+ * Get provider model configuration
90
+ */
91
+ getProviderModels() {
92
+ var _a, _b;
93
+ const config = this.loadConfig();
94
+ // Extract from provider configuration
95
+ if ((_b = (_a = config.provider) === null || _a === void 0 ? void 0 : _a.berget) === null || _b === void 0 ? void 0 : _b.models) {
96
+ return config.provider.berget.models;
97
+ }
98
+ // Fallback to defaults
99
+ return {
100
+ 'deepseek-r1': {
101
+ name: 'GLM-4.6',
102
+ limit: { output: 4000, context: 90000 }
103
+ },
104
+ 'gpt-oss': {
105
+ name: 'GPT-OSS',
106
+ limit: { output: 4000, context: 128000 }
107
+ },
108
+ 'llama-8b': {
109
+ name: 'llama-3.1-8b',
110
+ limit: { output: 4000, context: 128000 }
111
+ }
112
+ };
113
+ }
114
+ /**
115
+ * Get command configurations
116
+ */
117
+ getCommandConfigs() {
118
+ const config = this.loadConfig();
119
+ return config.command || {};
120
+ }
121
+ /**
122
+ * Get watcher configuration
123
+ */
124
+ getWatcherConfig() {
125
+ const config = this.loadConfig();
126
+ return config.watcher || { ignore: ['node_modules', 'dist', '.git', 'coverage'] };
127
+ }
128
+ /**
129
+ * Get provider configuration
130
+ */
131
+ getProviderConfig() {
132
+ const config = this.loadConfig();
133
+ return config.provider || {};
134
+ }
135
+ /**
136
+ * Check if an agent exists
137
+ */
138
+ hasAgent(agentName) {
139
+ return agentName in this.getAllAgentConfigs();
140
+ }
141
+ /**
142
+ * Get list of all available agent names
143
+ */
144
+ getAgentNames() {
145
+ return Object.keys(this.getAllAgentConfigs());
146
+ }
147
+ /**
148
+ * Get list of primary agents (mode: 'primary')
149
+ */
150
+ getPrimaryAgentNames() {
151
+ const agents = this.getAllAgentConfigs();
152
+ return Object.keys(agents).filter(name => agents[name].mode === 'primary');
153
+ }
154
+ /**
155
+ * Get list of subagents (mode: 'subagent')
156
+ */
157
+ getSubagentNames() {
158
+ const agents = this.getAllAgentConfigs();
159
+ return Object.keys(agents).filter(name => agents[name].mode === 'subagent');
160
+ }
161
+ /**
162
+ * Reload configuration from file
163
+ */
164
+ reloadConfig() {
165
+ this.config = null;
166
+ return this.loadConfig();
167
+ }
168
+ /**
169
+ * Set custom configuration path (for testing or different environments)
170
+ */
171
+ setConfigPath(configPath) {
172
+ this.configPath = configPath;
173
+ this.config = null; // Force reload
174
+ }
175
+ /**
176
+ * Get the current configuration path
177
+ */
178
+ getConfigPath() {
179
+ return this.configPath;
180
+ }
181
+ }
182
+ exports.ConfigLoader = ConfigLoader;
183
+ /**
184
+ * Convenience function to get the config loader instance
185
+ */
186
+ function getConfigLoader(configPath) {
187
+ return ConfigLoader.getInstance(configPath);
188
+ }
189
+ exports.getConfigLoader = getConfigLoader;
190
+ /**
191
+ * Convenience function to get agent configuration
192
+ */
193
+ function getAgentConfig(agentName, configPath) {
194
+ return getConfigLoader(configPath).getAgentConfig(agentName);
195
+ }
196
+ exports.getAgentConfig = getAgentConfig;
197
+ /**
198
+ * Convenience function to get all agent configurations
199
+ */
200
+ function getAllAgentConfigs(configPath) {
201
+ return getConfigLoader(configPath).getAllAgentConfigs();
202
+ }
203
+ exports.getAllAgentConfigs = getAllAgentConfigs;
204
+ /**
205
+ * Convenience function to get model configuration
206
+ */
207
+ function getModelConfig(configPath) {
208
+ return getConfigLoader(configPath).getModelConfig();
209
+ }
210
+ exports.getModelConfig = getModelConfig;
211
+ /**
212
+ * Convenience function to get provider models
213
+ */
214
+ function getProviderModels(configPath) {
215
+ return getConfigLoader(configPath).getProviderModels();
216
+ }
217
+ exports.getProviderModels = getProviderModels;
@@ -9,44 +9,120 @@ const chalk_1 = __importDefault(require("chalk"));
9
9
  * Formats and prints error messages in a consistent way
10
10
  */
11
11
  function handleError(message, error) {
12
- console.error(chalk_1.default.red(`Error: ${message}`));
12
+ console.error(chalk_1.default.red(`❌ Error: ${message}`));
13
+ let errorDetails = '';
14
+ let errorCode = '';
15
+ let errorType = '';
13
16
  // If the error is a string (like JSON.stringify(error))
14
17
  if (typeof error === 'string') {
15
18
  try {
16
19
  // Try to parse it as JSON
17
20
  const parsedError = JSON.parse(error);
18
21
  if (parsedError.error) {
19
- console.error(chalk_1.default.dim(`Details: ${parsedError.error}`));
20
- if (parsedError.code) {
21
- console.error(chalk_1.default.dim(`Code: ${parsedError.code}`));
22
- }
22
+ errorDetails = parsedError.error.message || parsedError.error;
23
+ errorCode = parsedError.error.code || parsedError.code;
24
+ errorType = parsedError.error.type || '';
23
25
  }
24
26
  else {
25
- console.error(chalk_1.default.dim(`Details: ${error}`));
27
+ errorDetails = error;
26
28
  }
27
29
  }
28
30
  catch (_a) {
29
31
  // If it's not valid JSON, just print the string
30
- console.error(chalk_1.default.dim(`Details: ${error}`));
32
+ errorDetails = error;
31
33
  }
32
34
  }
33
35
  else if (error && error.message) {
34
36
  // If it's an Error object
35
- console.error(chalk_1.default.dim(`Details: ${error.message}`));
36
- }
37
- // Check for authentication errors
38
- if ((typeof error === 'string' &&
39
- (error.includes('Unauthorized') ||
40
- error.includes('Authentication failed'))) ||
41
- (error &&
42
- error.message &&
43
- (error.message.includes('Unauthorized') ||
44
- error.message.includes('Authentication failed'))) ||
45
- (error &&
46
- error.code &&
47
- (error.code === 401 || error.code === 'AUTH_FAILED'))) {
48
- console.error(chalk_1.default.yellow('\nYou need to be logged in to use this command.'));
49
- console.error(chalk_1.default.yellow('Run `berget auth login` to authenticate.'));
37
+ errorDetails = error.message;
38
+ errorCode = error.code;
39
+ errorType = error.type;
50
40
  }
41
+ // Print error details
42
+ if (errorDetails) {
43
+ console.error(chalk_1.default.dim(`📝 Details: ${errorDetails}`));
44
+ }
45
+ if (errorCode) {
46
+ console.error(chalk_1.default.dim(`🔢 Code: ${errorCode}`));
47
+ }
48
+ // Provide helpful troubleshooting based on error type
49
+ provideTroubleshootingTips(errorType, errorCode, errorDetails);
51
50
  }
52
51
  exports.handleError = handleError;
52
+ /**
53
+ * Provides helpful troubleshooting tips based on error type
54
+ */
55
+ function provideTroubleshootingTips(errorType, errorCode, errorDetails) {
56
+ console.error(chalk_1.default.blue('\n💡 Troubleshooting tips:'));
57
+ // Authentication errors
58
+ if (errorType === 'authentication_error' ||
59
+ errorCode === 'AUTH_FAILED' ||
60
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('Unauthorized')) ||
61
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('Authentication failed'))) {
62
+ console.error(chalk_1.default.yellow(' 🔐 Authentication issue detected:'));
63
+ console.error(chalk_1.default.white(' • Run `berget auth login` to log in'));
64
+ console.error(chalk_1.default.white(' • Check if your session has expired'));
65
+ console.error(chalk_1.default.white(' • Verify you have the correct permissions'));
66
+ }
67
+ // Network/connection errors
68
+ if ((errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('fetch failed')) ||
69
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('ECONNREFUSED')) ||
70
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('ENOTFOUND')) ||
71
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('network'))) {
72
+ console.error(chalk_1.default.yellow(' 🌐 Network issue detected:'));
73
+ console.error(chalk_1.default.white(' • Check your internet connection'));
74
+ console.error(chalk_1.default.white(' • Verify you can reach api.berget.ai'));
75
+ console.error(chalk_1.default.white(' • Try again in a few minutes'));
76
+ console.error(chalk_1.default.white(' • Check if any firewall is blocking the request'));
77
+ }
78
+ // API key errors
79
+ if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('API_KEY')) ||
80
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('API key')) ||
81
+ errorType === 'invalid_request_error') {
82
+ console.error(chalk_1.default.yellow(' 🔑 API key issue detected:'));
83
+ console.error(chalk_1.default.white(' • Run `berget api-keys list` to check your keys'));
84
+ console.error(chalk_1.default.white(' • Create a new key with `berget api-keys create --name "My Key"`'));
85
+ console.error(chalk_1.default.white(' • Set a default key with `berget api-keys set-default <id>`'));
86
+ console.error(chalk_1.default.white(' • Check if your API key has expired'));
87
+ }
88
+ // Rate limiting
89
+ if (errorCode === 'RATE_LIMIT_EXCEEDED' ||
90
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('rate limit')) ||
91
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('too many requests'))) {
92
+ console.error(chalk_1.default.yellow(' ⏱️ Rate limit exceeded:'));
93
+ console.error(chalk_1.default.white(' • Wait a few minutes before trying again'));
94
+ console.error(chalk_1.default.white(' • Consider upgrading your plan for higher limits'));
95
+ console.error(chalk_1.default.white(' • Use `berget billing get-usage` to check your usage'));
96
+ }
97
+ // Server errors
98
+ if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('SERVER_ERROR')) ||
99
+ errorType === 'server_error' ||
100
+ (errorCode && parseInt(errorCode) >= 500)) {
101
+ console.error(chalk_1.default.yellow(' 🖥️ Server issue detected:'));
102
+ console.error(chalk_1.default.white(' • This is a temporary problem on our end'));
103
+ console.error(chalk_1.default.white(' • Try again in a few minutes'));
104
+ console.error(chalk_1.default.white(' • Check status.berget.ai for service status'));
105
+ console.error(chalk_1.default.white(' • Contact support if the problem persists'));
106
+ }
107
+ // Cluster errors
108
+ if ((errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('CLUSTERS')) ||
109
+ (errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('cluster'))) {
110
+ console.error(chalk_1.default.yellow(' 🏗️ Cluster issue detected:'));
111
+ console.error(chalk_1.default.white(' • Clusters may be temporarily unavailable'));
112
+ console.error(chalk_1.default.white(' • Try again later or contact support'));
113
+ console.error(chalk_1.default.white(' • Check your cluster permissions'));
114
+ }
115
+ // Generic fallback
116
+ if (!(errorType === null || errorType === void 0 ? void 0 : errorType.includes('authentication')) &&
117
+ !(errorDetails === null || errorDetails === void 0 ? void 0 : errorDetails.includes('fetch failed')) &&
118
+ !(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('API_KEY')) &&
119
+ !(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('RATE_LIMIT')) &&
120
+ !(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('SERVER_ERROR')) &&
121
+ !(errorCode === null || errorCode === void 0 ? void 0 : errorCode.includes('CLUSTERS'))) {
122
+ console.error(chalk_1.default.yellow(' ❓ General issue:'));
123
+ console.error(chalk_1.default.white(' • Try running the command with --debug for more info'));
124
+ console.error(chalk_1.default.white(' • Check your configuration with `berget auth whoami`'));
125
+ console.error(chalk_1.default.white(' • Contact support if the problem persists'));
126
+ }
127
+ console.error(chalk_1.default.dim('\nNeed more help? Visit https://docs.berget.ai or contact support@berget.ai'));
128
+ }
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const vitest_1 = require("vitest");
27
+ const config_loader_1 = require("../../src/utils/config-loader");
28
+ const path = __importStar(require("path"));
29
+ const fs_1 = require("fs");
30
+ (0, vitest_1.describe)('ConfigLoader Singleton Pattern', () => {
31
+ const testConfigPath = path.join(process.cwd(), 'test-config.json');
32
+ const testConfigPath2 = path.join(process.cwd(), 'test-config2.json');
33
+ const testConfig = {
34
+ $schema: 'https://opencode.ai/config.json',
35
+ username: 'test-user',
36
+ model: 'test-model',
37
+ agent: {
38
+ test: {
39
+ model: 'test-model',
40
+ temperature: 0.5,
41
+ mode: 'primary',
42
+ permission: { edit: 'allow', bash: 'allow', webfetch: 'allow' },
43
+ description: 'Test agent',
44
+ prompt: 'Test prompt'
45
+ }
46
+ }
47
+ };
48
+ (0, vitest_1.beforeEach)(() => {
49
+ // Clean up any existing test files
50
+ if ((0, fs_1.existsSync)(testConfigPath))
51
+ (0, fs_1.unlinkSync)(testConfigPath);
52
+ if ((0, fs_1.existsSync)(testConfigPath2))
53
+ (0, fs_1.unlinkSync)(testConfigPath2);
54
+ config_loader_1.ConfigLoader.instance = null;
55
+ });
56
+ (0, vitest_1.afterEach)(() => {
57
+ // Clean up test files
58
+ if ((0, fs_1.existsSync)(testConfigPath))
59
+ (0, fs_1.unlinkSync)(testConfigPath);
60
+ if ((0, fs_1.existsSync)(testConfigPath2))
61
+ (0, fs_1.unlinkSync)(testConfigPath2);
62
+ config_loader_1.ConfigLoader.instance = null;
63
+ });
64
+ (0, vitest_1.it)('should create singleton instance on first call', () => {
65
+ const instance1 = config_loader_1.ConfigLoader.getInstance(testConfigPath);
66
+ const instance2 = config_loader_1.ConfigLoader.getInstance();
67
+ (0, vitest_1.expect)(instance1).toBe(instance2);
68
+ (0, vitest_1.expect)(instance1.getConfigPath()).toBe(testConfigPath);
69
+ });
70
+ (0, vitest_1.it)('should ignore configPath parameter after first instantiation', () => {
71
+ const instance1 = config_loader_1.ConfigLoader.getInstance(testConfigPath);
72
+ const instance2 = config_loader_1.ConfigLoader.getInstance(testConfigPath2); // Should be ignored
73
+ (0, vitest_1.expect)(instance1).toBe(instance2);
74
+ (0, vitest_1.expect)(instance1.getConfigPath()).toBe(testConfigPath); // Still uses first path
75
+ });
76
+ (0, vitest_1.it)('should load and cache configuration', () => {
77
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(testConfig));
78
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
79
+ const config1 = loader.loadConfig();
80
+ const config2 = loader.loadConfig();
81
+ (0, vitest_1.expect)(config1).toBe(config2); // Same object reference (cached)
82
+ (0, vitest_1.expect)(config1.username).toBe('test-user');
83
+ });
84
+ (0, vitest_1.it)('should reload configuration when reloadConfig is called', () => {
85
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(testConfig));
86
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
87
+ const config1 = loader.loadConfig();
88
+ // Modify file
89
+ const modifiedConfig = Object.assign(Object.assign({}, testConfig), { username: 'modified-user' });
90
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(modifiedConfig));
91
+ const config2 = loader.loadConfig(); // Should still be cached
92
+ (0, vitest_1.expect)(config2).toBe(config1);
93
+ (0, vitest_1.expect)(config2.username).toBe('test-user');
94
+ const config3 = loader.reloadConfig(); // Should reload
95
+ (0, vitest_1.expect)(config3).not.toBe(config1);
96
+ (0, vitest_1.expect)(config3.username).toBe('modified-user');
97
+ });
98
+ (0, vitest_1.it)('should change config path and clear cache with setConfigPath', () => {
99
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(testConfig));
100
+ (0, fs_1.writeFileSync)(testConfigPath2, JSON.stringify(Object.assign(Object.assign({}, testConfig), { username: 'user2' })));
101
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
102
+ const config1 = loader.loadConfig();
103
+ (0, vitest_1.expect)(config1.username).toBe('test-user');
104
+ loader.setConfigPath(testConfigPath2);
105
+ const config2 = loader.loadConfig();
106
+ (0, vitest_1.expect)(config2.username).toBe('user2');
107
+ (0, vitest_1.expect)(loader.getConfigPath()).toBe(testConfigPath2);
108
+ });
109
+ (0, vitest_1.it)('should throw error when config file does not exist', () => {
110
+ const loader = config_loader_1.ConfigLoader.getInstance('/nonexistent/config.json');
111
+ (0, vitest_1.expect)(() => loader.loadConfig()).toThrow('Configuration file not found');
112
+ });
113
+ (0, vitest_1.it)('should throw error when config file has invalid JSON', () => {
114
+ (0, fs_1.writeFileSync)(testConfigPath, 'invalid json content');
115
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
116
+ (0, vitest_1.expect)(() => loader.loadConfig()).toThrow('Invalid JSON in configuration file');
117
+ });
118
+ (0, vitest_1.it)('should provide fallback model configuration with warning', () => {
119
+ const minimalConfig = { username: 'test' }; // No model settings
120
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(minimalConfig));
121
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
122
+ const modelConfig = loader.getModelConfig();
123
+ (0, vitest_1.expect)(modelConfig.primary).toBe('berget/deepseek-r1');
124
+ (0, vitest_1.expect)(modelConfig.small).toBe('berget/gpt-oss');
125
+ });
126
+ (0, vitest_1.it)('should provide fallback provider models with warning', () => {
127
+ const minimalConfig = { username: 'test' }; // No provider settings
128
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(minimalConfig));
129
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
130
+ const providerModels = loader.getProviderModels();
131
+ (0, vitest_1.expect)(providerModels['deepseek-r1']).toBeDefined();
132
+ (0, vitest_1.expect)(providerModels['gpt-oss']).toBeDefined();
133
+ (0, vitest_1.expect)(providerModels['llama-8b']).toBeDefined();
134
+ });
135
+ (0, vitest_1.it)('should provide fallback watcher configuration with warning', () => {
136
+ const minimalConfig = { username: 'test' }; // No watcher settings
137
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(minimalConfig));
138
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
139
+ const watcherConfig = loader.getWatcherConfig();
140
+ (0, vitest_1.expect)(watcherConfig.ignore).toContain('node_modules');
141
+ (0, vitest_1.expect)(watcherConfig.ignore).toContain('dist');
142
+ (0, vitest_1.expect)(watcherConfig.ignore).toContain('.git');
143
+ (0, vitest_1.expect)(watcherConfig.ignore).toContain('coverage');
144
+ });
145
+ (0, vitest_1.it)('should use actual configuration when provided', () => {
146
+ const fullConfig = Object.assign(Object.assign({}, testConfig), { model: 'custom-primary-model', small_model: 'custom-small-model', provider: {
147
+ berget: {
148
+ models: {
149
+ 'custom-model': {
150
+ name: 'Custom Model',
151
+ limit: { output: 2000, context: 4000 }
152
+ }
153
+ }
154
+ }
155
+ }, watcher: {
156
+ ignore: ['custom-ignore']
157
+ } });
158
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(fullConfig));
159
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
160
+ const modelConfig = loader.getModelConfig();
161
+ (0, vitest_1.expect)(modelConfig.primary).toBe('custom-primary-model');
162
+ (0, vitest_1.expect)(modelConfig.small).toBe('custom-small-model');
163
+ const providerModels = loader.getProviderModels();
164
+ (0, vitest_1.expect)(providerModels['custom-model']).toBeDefined();
165
+ (0, vitest_1.expect)(providerModels['custom-model'].name).toBe('Custom Model');
166
+ const watcherConfig = loader.getWatcherConfig();
167
+ (0, vitest_1.expect)(watcherConfig.ignore).toEqual(['custom-ignore']);
168
+ });
169
+ (0, vitest_1.it)('should maintain consistent getter method behavior', () => {
170
+ (0, fs_1.writeFileSync)(testConfigPath, JSON.stringify(testConfig));
171
+ const loader = config_loader_1.ConfigLoader.getInstance(testConfigPath);
172
+ // All getter methods should use the same cached config
173
+ const agentConfig = loader.getAgentConfig('test');
174
+ const allAgents = loader.getAllAgentConfigs();
175
+ const commandConfigs = loader.getCommandConfigs();
176
+ const providerConfig = loader.getProviderConfig();
177
+ (0, vitest_1.expect)(agentConfig).toBeDefined();
178
+ (0, vitest_1.expect)(allAgents.test).toBeDefined();
179
+ (0, vitest_1.expect)(commandConfigs).toEqual({});
180
+ (0, vitest_1.expect)(providerConfig).toEqual({});
181
+ });
182
+ });