berget 2.2.11 → 2.2.12
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.
- package/dist/package.json +1 -1
- package/dist/src/commands/code/__tests__/setup-flow.test.js +34 -34
- package/dist/src/commands/code/auth-sync.js +3 -3
- package/dist/src/commands/code/{setup.js → init.js} +17 -29
- package/dist/src/commands/code.js +5 -553
- package/dist/src/constants/command-structure.js +1 -9
- package/dist/src/services/auth-service.js +1 -1
- package/dist/tests/commands/code.test.js +4 -415
- package/package.json +1 -1
- package/src/commands/code/__tests__/setup-flow.test.ts +36 -36
- package/src/commands/code/auth-sync.ts +3 -3
- package/src/commands/code/{setup.ts → init.ts} +14 -26
- package/src/commands/code.ts +5 -608
- package/src/constants/command-structure.ts +1 -11
- package/src/services/auth-service.ts +1 -1
- package/tests/commands/code.test.ts +5 -483
- package/templates/agents/app.md +0 -23
- package/templates/agents/backend.md +0 -23
- package/templates/agents/devops.md +0 -30
- package/templates/agents/frontend.md +0 -25
- package/templates/agents/fullstack.md +0 -23
- package/templates/agents/quality.md +0 -69
- package/templates/agents/security.md +0 -21
|
@@ -1,436 +1,25 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
3
|
const commander_1 = require("commander");
|
|
27
|
-
const fs = __importStar(require("node:fs"));
|
|
28
|
-
const promises_1 = require("node:fs/promises");
|
|
29
4
|
const vitest_1 = require("vitest");
|
|
30
5
|
const code_1 = require("../../src/commands/code");
|
|
31
|
-
const api_key_service_1 = require("../../src/services/api-key-service");
|
|
32
|
-
const env_manager_1 = require("../../src/utils/env-manager");
|
|
33
|
-
// Mock dependencies
|
|
34
|
-
vitest_1.vi.mock('../../src/services/api-key-service');
|
|
35
|
-
vitest_1.vi.mock('fs', () => ({
|
|
36
|
-
default: {
|
|
37
|
-
existsSync: vitest_1.vi.fn(),
|
|
38
|
-
readFileSync: vitest_1.vi.fn(),
|
|
39
|
-
},
|
|
40
|
-
}));
|
|
41
|
-
vitest_1.vi.mock('fs/promises', () => ({
|
|
42
|
-
readFile: vitest_1.vi.fn(),
|
|
43
|
-
writeFile: vitest_1.vi.fn(),
|
|
44
|
-
}));
|
|
45
|
-
vitest_1.vi.mock('../../src/utils/env-manager');
|
|
46
|
-
vitest_1.vi.mock('child_process', () => ({
|
|
47
|
-
spawn: vitest_1.vi.fn(),
|
|
48
|
-
}));
|
|
49
|
-
vitest_1.vi.mock('readline', () => ({
|
|
50
|
-
createInterface: vitest_1.vi.fn(() => ({
|
|
51
|
-
close: vitest_1.vi.fn(),
|
|
52
|
-
question: vitest_1.vi.fn(),
|
|
53
|
-
})),
|
|
54
|
-
}));
|
|
55
6
|
(0, vitest_1.describe)('Code Commands', () => {
|
|
56
7
|
let program;
|
|
57
|
-
let mockApiKeyService;
|
|
58
|
-
let mockFs;
|
|
59
|
-
let mockFsPromises;
|
|
60
|
-
let mockSpawn;
|
|
61
8
|
(0, vitest_1.beforeEach)(() => {
|
|
62
9
|
program = new commander_1.Command();
|
|
63
|
-
// Mock ApiKeyService
|
|
64
|
-
mockApiKeyService = {
|
|
65
|
-
create: vitest_1.vi.fn(),
|
|
66
|
-
list: vitest_1.vi.fn(),
|
|
67
|
-
rotate: vitest_1.vi.fn(),
|
|
68
|
-
};
|
|
69
|
-
vitest_1.vi.mocked(api_key_service_1.ApiKeyService.getInstance).mockReturnValue(mockApiKeyService);
|
|
70
|
-
// Mock fs
|
|
71
|
-
mockFs = vitest_1.vi.mocked(fs);
|
|
72
|
-
mockFs.existsSync = vitest_1.vi.fn();
|
|
73
|
-
mockFs.readFileSync = vitest_1.vi.fn();
|
|
74
|
-
// Mock fs/promises
|
|
75
|
-
mockFsPromises = vitest_1.vi.mocked({ readFile: promises_1.readFile, writeFile: promises_1.writeFile });
|
|
76
|
-
mockFsPromises.readFile = vitest_1.vi.fn();
|
|
77
|
-
mockFsPromises.writeFile = vitest_1.vi.fn();
|
|
78
|
-
// Mock spawn
|
|
79
|
-
mockSpawn = vitest_1.vi.fn();
|
|
80
|
-
vitest_1.vi.doMock('child_process', () => ({ spawn: mockSpawn }));
|
|
81
10
|
(0, code_1.registerCodeCommands)(program);
|
|
82
11
|
});
|
|
83
|
-
(0, vitest_1.afterEach)(() => {
|
|
84
|
-
vitest_1.vi.clearAllMocks();
|
|
85
|
-
});
|
|
86
12
|
(0, vitest_1.describe)('code init command', () => {
|
|
87
13
|
(0, vitest_1.it)('should register init command with correct description', () => {
|
|
88
14
|
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
89
15
|
const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
|
|
90
16
|
(0, vitest_1.expect)(initCommand).toBeDefined();
|
|
91
|
-
(0, vitest_1.expect)(initCommand?.description()).toBe('
|
|
92
|
-
});
|
|
93
|
-
(0, vitest_1.it)('should have name, force, and yes options', () => {
|
|
94
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
95
|
-
const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
|
|
96
|
-
(0, vitest_1.expect)(initCommand).toBeDefined();
|
|
97
|
-
const nameOption = initCommand?.options.find((opt) => opt.long === '--name');
|
|
98
|
-
const forceOption = initCommand?.options.find((opt) => opt.long === '--force');
|
|
99
|
-
const yesOption = initCommand?.options.find((opt) => opt.long === '--yes');
|
|
100
|
-
(0, vitest_1.expect)(nameOption).toBeDefined();
|
|
101
|
-
(0, vitest_1.expect)(nameOption?.description).toContain('Project name');
|
|
102
|
-
(0, vitest_1.expect)(forceOption).toBeDefined();
|
|
103
|
-
(0, vitest_1.expect)(forceOption?.description).toContain('Overwrite existing configuration');
|
|
104
|
-
(0, vitest_1.expect)(yesOption).toBeDefined();
|
|
105
|
-
(0, vitest_1.expect)(yesOption?.description).toContain('Automatically answer yes');
|
|
106
|
-
});
|
|
107
|
-
(0, vitest_1.it)('should check if opencode is installed', () => {
|
|
108
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
109
|
-
const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
|
|
110
|
-
(0, vitest_1.expect)(initCommand).toBeDefined();
|
|
111
|
-
// The command should attempt to spawn opencode --version
|
|
112
|
-
// This is tested implicitly through the spawn mock
|
|
113
|
-
});
|
|
114
|
-
(0, vitest_1.it)('should list existing API keys and allow selection', async () => {
|
|
115
|
-
// Mock successful opencode installation check
|
|
116
|
-
mockSpawn.mockImplementation((command, arguments_) => {
|
|
117
|
-
if (command === 'opencode' && arguments_[0] === '--version') {
|
|
118
|
-
return {
|
|
119
|
-
on: vitest_1.vi.fn().mockImplementation((event, callback) => {
|
|
120
|
-
if (event === 'close')
|
|
121
|
-
callback(0);
|
|
122
|
-
}),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
return { on: vitest_1.vi.fn() };
|
|
126
|
-
});
|
|
127
|
-
// Mock existing API keys
|
|
128
|
-
const mockExistingKeys = [
|
|
129
|
-
{
|
|
130
|
-
created: '2023-01-01T00:00:00.000Z',
|
|
131
|
-
id: 1,
|
|
132
|
-
lastUsed: null,
|
|
133
|
-
name: 'existing-key-1',
|
|
134
|
-
prefix: 'sk_ber',
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
created: '2023-01-02T00:00:00.000Z',
|
|
138
|
-
id: 2,
|
|
139
|
-
lastUsed: '2023-01-03T00:00:00.000Z',
|
|
140
|
-
name: 'existing-key-2',
|
|
141
|
-
prefix: 'sk_ber',
|
|
142
|
-
},
|
|
143
|
-
];
|
|
144
|
-
mockApiKeyService.list.mockResolvedValue(mockExistingKeys);
|
|
145
|
-
// Mock file operations
|
|
146
|
-
mockFs.existsSync.mockReturnValue(false);
|
|
147
|
-
mockFsPromises.writeFile.mockResolvedValue();
|
|
148
|
-
// Verify that the list method is called
|
|
149
|
-
(0, vitest_1.expect)(mockApiKeyService.list).toBeDefined();
|
|
17
|
+
(0, vitest_1.expect)(initCommand?.description()).toBe('Interactive setup for Berget AI coding tools');
|
|
150
18
|
});
|
|
151
|
-
(0, vitest_1.it)('should
|
|
152
|
-
// Mock successful opencode installation check
|
|
153
|
-
mockSpawn.mockImplementation((command, arguments_) => {
|
|
154
|
-
if (command === 'opencode' && arguments_[0] === '--version') {
|
|
155
|
-
return {
|
|
156
|
-
on: vitest_1.vi.fn().mockImplementation((event, callback) => {
|
|
157
|
-
if (event === 'close')
|
|
158
|
-
callback(0);
|
|
159
|
-
}),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
return { on: vitest_1.vi.fn() };
|
|
163
|
-
});
|
|
164
|
-
// Mock no existing keys
|
|
165
|
-
mockApiKeyService.list.mockResolvedValue([]);
|
|
166
|
-
// Mock successful API key creation
|
|
167
|
-
const mockApiKeyData = {
|
|
168
|
-
id: 123,
|
|
169
|
-
key: 'test-api-key-12345',
|
|
170
|
-
name: 'opencode-testproject-1234567890',
|
|
171
|
-
};
|
|
172
|
-
mockApiKeyService.create.mockResolvedValue(mockApiKeyData);
|
|
173
|
-
// Mock file operations
|
|
174
|
-
mockFs.existsSync.mockReturnValue(false);
|
|
175
|
-
mockFsPromises.writeFile.mockResolvedValue();
|
|
176
|
-
// Verify that the create method is available
|
|
177
|
-
(0, vitest_1.expect)(mockApiKeyService.create).toBeDefined();
|
|
178
|
-
});
|
|
179
|
-
(0, vitest_1.it)('should create opencode.json with correct structure', async () => {
|
|
180
|
-
// This tests the expected config structure
|
|
181
|
-
const expectedConfig = {
|
|
182
|
-
apiKey: 'test-api-key',
|
|
183
|
-
created: vitest_1.expect.any(String),
|
|
184
|
-
model: 'berget/glm-4-6',
|
|
185
|
-
projectName: 'testproject',
|
|
186
|
-
provider: 'berget',
|
|
187
|
-
version: '1.0.0',
|
|
188
|
-
};
|
|
189
|
-
(0, vitest_1.expect)(expectedConfig.model).toBe('berget/glm-4-6');
|
|
190
|
-
(0, vitest_1.expect)(expectedConfig.provider).toBe('berget');
|
|
191
|
-
(0, vitest_1.expect)(expectedConfig.version).toBe('1.0.0');
|
|
192
|
-
});
|
|
193
|
-
(0, vitest_1.it)('should handle existing config file', () => {
|
|
19
|
+
(0, vitest_1.it)('should not have any other subcommands', () => {
|
|
194
20
|
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
195
|
-
|
|
196
|
-
(0, vitest_1.expect)(
|
|
197
|
-
// Should check if opencode.json exists before proceeding
|
|
198
|
-
(0, vitest_1.expect)(mockFs.existsSync).toBeDefined();
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
(0, vitest_1.describe)('code run command', () => {
|
|
202
|
-
(0, vitest_1.it)('should register run command with correct description', () => {
|
|
203
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
204
|
-
const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
|
|
205
|
-
(0, vitest_1.expect)(runCommand).toBeDefined();
|
|
206
|
-
(0, vitest_1.expect)(runCommand?.description()).toBe('Run AI coding assistant');
|
|
207
|
-
});
|
|
208
|
-
(0, vitest_1.it)('should accept prompt argument and model, no-config, and yes options', () => {
|
|
209
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
210
|
-
const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
|
|
211
|
-
(0, vitest_1.expect)(runCommand).toBeDefined();
|
|
212
|
-
const modelOption = runCommand?.options.find((opt) => opt.long === '--model');
|
|
213
|
-
const noConfigOption = runCommand?.options.find((opt) => opt.long === '--no-config');
|
|
214
|
-
const yesOption = runCommand?.options.find((opt) => opt.long === '--yes');
|
|
215
|
-
(0, vitest_1.expect)(modelOption).toBeDefined();
|
|
216
|
-
(0, vitest_1.expect)(modelOption?.description).toContain('Model to use');
|
|
217
|
-
(0, vitest_1.expect)(noConfigOption).toBeDefined();
|
|
218
|
-
(0, vitest_1.expect)(noConfigOption?.description).toContain('Run without loading project config');
|
|
219
|
-
(0, vitest_1.expect)(yesOption).toBeDefined();
|
|
220
|
-
(0, vitest_1.expect)(yesOption?.description).toContain('Automatically answer yes');
|
|
221
|
-
});
|
|
222
|
-
(0, vitest_1.it)('should load configuration from opencode.json', async () => {
|
|
223
|
-
const mockConfig = {
|
|
224
|
-
apiKey: 'test-api-key',
|
|
225
|
-
created: '2023-01-01T00:00:00.000Z',
|
|
226
|
-
model: 'berget/glm-4-6',
|
|
227
|
-
projectName: 'testproject',
|
|
228
|
-
provider: 'berget',
|
|
229
|
-
version: '1.0.0',
|
|
230
|
-
};
|
|
231
|
-
// Mock file exists and contains config
|
|
232
|
-
mockFs.existsSync.mockReturnValue(true);
|
|
233
|
-
mockFsPromises.readFile.mockResolvedValue(JSON.stringify(mockConfig));
|
|
234
|
-
// Mock successful opencode check
|
|
235
|
-
mockSpawn.mockImplementation((command, arguments_) => {
|
|
236
|
-
if (command === 'opencode' && arguments_[0] === '--version') {
|
|
237
|
-
return {
|
|
238
|
-
on: vitest_1.vi.fn().mockImplementation((event, callback) => {
|
|
239
|
-
if (event === 'close')
|
|
240
|
-
callback(0);
|
|
241
|
-
}),
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
return { on: vitest_1.vi.fn() };
|
|
245
|
-
});
|
|
246
|
-
// Verify config structure expectations
|
|
247
|
-
(0, vitest_1.expect)(mockConfig.model).toBe('berget/glm-4-6');
|
|
248
|
-
(0, vitest_1.expect)(mockConfig.apiKey).toBe('test-api-key');
|
|
249
|
-
(0, vitest_1.expect)(mockConfig.projectName).toBe('testproject');
|
|
250
|
-
});
|
|
251
|
-
(0, vitest_1.it)('should spawn opencode with correct arguments', () => {
|
|
252
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
253
|
-
const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
|
|
254
|
-
(0, vitest_1.expect)(runCommand).toBeDefined();
|
|
255
|
-
// Should spawn opencode with appropriate arguments
|
|
256
|
-
(0, vitest_1.expect)(mockSpawn).toBeDefined();
|
|
257
|
-
});
|
|
258
|
-
(0, vitest_1.it)('should handle missing configuration file', () => {
|
|
259
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
260
|
-
const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
|
|
261
|
-
(0, vitest_1.expect)(runCommand).toBeDefined();
|
|
262
|
-
// Should check if opencode.json exists
|
|
263
|
-
(0, vitest_1.expect)(mockFs.existsSync).toBeDefined();
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
(0, vitest_1.describe)('opencode installation', () => {
|
|
267
|
-
(0, vitest_1.it)('should check if opencode is installed', () => {
|
|
268
|
-
// The spawn function should be called with opencode --version
|
|
269
|
-
(0, vitest_1.expect)(mockSpawn).toBeDefined();
|
|
270
|
-
});
|
|
271
|
-
(0, vitest_1.it)('should offer to install opencode if not found', () => {
|
|
272
|
-
// Mock opencode not installed
|
|
273
|
-
mockSpawn.mockImplementation((command, arguments_) => {
|
|
274
|
-
if (command === 'opencode' && arguments_[0] === '--version') {
|
|
275
|
-
return {
|
|
276
|
-
on: vitest_1.vi.fn().mockImplementation((event, callback) => {
|
|
277
|
-
if (event === 'close')
|
|
278
|
-
callback(1); // Non-zero exit code
|
|
279
|
-
}),
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
return { on: vitest_1.vi.fn() };
|
|
283
|
-
});
|
|
284
|
-
// Should handle the case where opencode is not installed
|
|
285
|
-
(0, vitest_1.expect)(mockSpawn).toBeDefined();
|
|
286
|
-
});
|
|
287
|
-
(0, vitest_1.it)('should install opencode via npm if user agrees', () => {
|
|
288
|
-
// Should spawn npm install -g opencode-ai
|
|
289
|
-
(0, vitest_1.expect)(mockSpawn).toBeDefined();
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
(0, vitest_1.describe)('automation support', () => {
|
|
293
|
-
(0, vitest_1.it)('should support -y flag for automated initialization', () => {
|
|
294
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
295
|
-
const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
|
|
296
|
-
(0, vitest_1.expect)(initCommand).toBeDefined();
|
|
297
|
-
const yesOption = initCommand?.options.find((opt) => opt.long === '--yes');
|
|
298
|
-
(0, vitest_1.expect)(yesOption).toBeDefined();
|
|
299
|
-
(0, vitest_1.expect)(yesOption?.description).toContain('automation');
|
|
300
|
-
});
|
|
301
|
-
(0, vitest_1.it)('should support -y flag for automated run', () => {
|
|
302
|
-
const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
|
|
303
|
-
const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
|
|
304
|
-
(0, vitest_1.expect)(runCommand).toBeDefined();
|
|
305
|
-
const yesOption = runCommand?.options.find((opt) => opt.long === '--yes');
|
|
306
|
-
(0, vitest_1.expect)(yesOption).toBeDefined();
|
|
307
|
-
(0, vitest_1.expect)(yesOption?.description).toContain('automation');
|
|
308
|
-
});
|
|
309
|
-
(0, vitest_1.it)('should use BERGET_API_KEY environment variable in automation mode', () => {
|
|
310
|
-
// Test that environment variable is used when -y flag is set
|
|
311
|
-
process.env.BERGET_API_KEY = 'test-env-key';
|
|
312
|
-
(0, vitest_1.expect)(process.env.BERGET_API_KEY).toBe('test-env-key');
|
|
313
|
-
// Clean up
|
|
314
|
-
delete process.env.BERGET_API_KEY;
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
(0, vitest_1.describe)('.env file handling', () => {
|
|
318
|
-
let mockUpdateEnvironmentFile;
|
|
319
|
-
(0, vitest_1.beforeEach)(() => {
|
|
320
|
-
mockUpdateEnvironmentFile = vitest_1.vi.mocked(env_manager_1.updateEnvFile);
|
|
321
|
-
});
|
|
322
|
-
(0, vitest_1.it)('should call updateEnvFile when creating new project', async () => {
|
|
323
|
-
mockUpdateEnvironmentFile.mockResolvedValue(true);
|
|
324
|
-
mockFs.existsSync.mockReturnValue(false); // .env doesn't exist
|
|
325
|
-
mockFsPromises.writeFile.mockResolvedValue();
|
|
326
|
-
// This would be tested by actually calling the init command
|
|
327
|
-
// For now we verify the mock is properly set up
|
|
328
|
-
(0, vitest_1.expect)(mockUpdateEnvironmentFile).toBeDefined();
|
|
329
|
-
});
|
|
330
|
-
(0, vitest_1.it)('should not overwrite existing BERGET_API_KEY in .env', async () => {
|
|
331
|
-
const consoleSpy = vitest_1.vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
332
|
-
// Mock existing .env with BERGET_API_KEY
|
|
333
|
-
mockFs.existsSync.mockReturnValue(true);
|
|
334
|
-
mockFs.readFileSync.mockReturnValue('BERGET_API_KEY=existing_key\nOTHER_KEY=value\n');
|
|
335
|
-
// Mock updateEnvFile to simulate the check
|
|
336
|
-
mockUpdateEnvironmentFile.mockImplementation(async (options) => {
|
|
337
|
-
if (options.key === 'BERGET_API_KEY' && !options.force) {
|
|
338
|
-
console.log(`⚠ ${options.key} already exists in .env - leaving unchanged`);
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
return true;
|
|
342
|
-
});
|
|
343
|
-
await (0, env_manager_1.updateEnvFile)({
|
|
344
|
-
key: 'BERGET_API_KEY',
|
|
345
|
-
value: 'new_key',
|
|
346
|
-
});
|
|
347
|
-
(0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('BERGET_API_KEY already exists in .env - leaving unchanged'));
|
|
348
|
-
consoleSpy.mockRestore();
|
|
349
|
-
});
|
|
350
|
-
(0, vitest_1.it)('should add new key to existing .env file', async () => {
|
|
351
|
-
mockFs.existsSync.mockReturnValue(true);
|
|
352
|
-
mockFs.readFileSync.mockReturnValue('EXISTING_KEY=value\n');
|
|
353
|
-
mockUpdateEnvironmentFile.mockResolvedValue(true);
|
|
354
|
-
await (0, env_manager_1.updateEnvFile)({
|
|
355
|
-
comment: 'Berget AI Configuration',
|
|
356
|
-
key: 'BERGET_API_KEY',
|
|
357
|
-
value: 'new_api_key',
|
|
358
|
-
});
|
|
359
|
-
(0, vitest_1.expect)(mockUpdateEnvironmentFile).toHaveBeenCalledWith({
|
|
360
|
-
comment: 'Berget AI Configuration',
|
|
361
|
-
key: 'BERGET_API_KEY',
|
|
362
|
-
value: 'new_api_key',
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
(0, vitest_1.it)('should create new .env file when none exists', async () => {
|
|
366
|
-
mockFs.existsSync.mockReturnValue(false);
|
|
367
|
-
mockUpdateEnvironmentFile.mockResolvedValue(true);
|
|
368
|
-
await (0, env_manager_1.updateEnvFile)({
|
|
369
|
-
key: 'BERGET_API_KEY',
|
|
370
|
-
value: 'new_api_key',
|
|
371
|
-
});
|
|
372
|
-
(0, vitest_1.expect)(mockUpdateEnvironmentFile).toHaveBeenCalledWith({
|
|
373
|
-
key: 'BERGET_API_KEY',
|
|
374
|
-
value: 'new_api_key',
|
|
375
|
-
});
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
(0, vitest_1.describe)('error handling', () => {
|
|
379
|
-
(0, vitest_1.it)('should handle API key creation failures', () => {
|
|
380
|
-
// Mock API key service to throw error
|
|
381
|
-
mockApiKeyService.create.mockRejectedValue(new Error('API Error'));
|
|
382
|
-
(0, vitest_1.expect)(mockApiKeyService.create).toBeDefined();
|
|
383
|
-
});
|
|
384
|
-
(0, vitest_1.it)('should handle file system errors', () => {
|
|
385
|
-
// Mock file operations to throw errors
|
|
386
|
-
mockFsPromises.writeFile.mockRejectedValue(new Error('File write error'));
|
|
387
|
-
(0, vitest_1.expect)(mockFsPromises.writeFile).toBeDefined();
|
|
388
|
-
});
|
|
389
|
-
(0, vitest_1.it)('should handle spawn errors', () => {
|
|
390
|
-
// Mock spawn to throw error
|
|
391
|
-
mockSpawn.mockImplementation(() => {
|
|
392
|
-
throw new Error('Command not found');
|
|
393
|
-
});
|
|
394
|
-
(0, vitest_1.expect)(mockSpawn).toBeDefined();
|
|
395
|
-
});
|
|
396
|
-
(0, vitest_1.it)('should handle .env update failures', async () => {
|
|
397
|
-
const mockUpdateEnvironmentFile = vitest_1.vi.mocked(env_manager_1.updateEnvFile);
|
|
398
|
-
mockUpdateEnvironmentFile.mockRejectedValue(new Error('Env update failed'));
|
|
399
|
-
await (0, vitest_1.expect)((0, env_manager_1.updateEnvFile)({
|
|
400
|
-
key: 'TEST_KEY',
|
|
401
|
-
value: 'test_value',
|
|
402
|
-
})).rejects.toThrow('Env update failed');
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
(0, vitest_1.describe)('experimental features', () => {
|
|
406
|
-
let originalEnvironment;
|
|
407
|
-
(0, vitest_1.beforeEach)(() => {
|
|
408
|
-
originalEnvironment = process.env.BERGET_EXPERIMENTAL;
|
|
409
|
-
});
|
|
410
|
-
(0, vitest_1.afterEach)(() => {
|
|
411
|
-
if (originalEnvironment === undefined) {
|
|
412
|
-
delete process.env.BERGET_EXPERIMENTAL;
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
process.env.BERGET_EXPERIMENTAL = originalEnvironment;
|
|
416
|
-
}
|
|
417
|
-
});
|
|
418
|
-
(0, vitest_1.it)('should NOT show setup command when BERGET_EXPERIMENTAL is not set', () => {
|
|
419
|
-
delete process.env.BERGET_EXPERIMENTAL;
|
|
420
|
-
const freshProgram = new commander_1.Command();
|
|
421
|
-
(0, code_1.registerCodeCommands)(freshProgram);
|
|
422
|
-
const codeCommand = freshProgram.commands.find((cmd) => cmd.name() === 'code');
|
|
423
|
-
const setupCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'setup');
|
|
424
|
-
(0, vitest_1.expect)(setupCommand).toBeUndefined();
|
|
425
|
-
});
|
|
426
|
-
(0, vitest_1.it)('should show setup command when BERGET_EXPERIMENTAL is set', () => {
|
|
427
|
-
process.env.BERGET_EXPERIMENTAL = '1';
|
|
428
|
-
const freshProgram = new commander_1.Command();
|
|
429
|
-
(0, code_1.registerCodeCommands)(freshProgram);
|
|
430
|
-
const codeCommand = freshProgram.commands.find((cmd) => cmd.name() === 'code');
|
|
431
|
-
const setupCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'setup');
|
|
432
|
-
(0, vitest_1.expect)(setupCommand).toBeDefined();
|
|
433
|
-
(0, vitest_1.expect)(setupCommand?.description()).toBe('Interactive setup for Berget AI coding tools');
|
|
21
|
+
(0, vitest_1.expect)(codeCommand?.commands).toHaveLength(1);
|
|
22
|
+
(0, vitest_1.expect)(codeCommand?.commands[0]?.name()).toBe('init');
|
|
434
23
|
});
|
|
435
24
|
});
|
|
436
25
|
});
|