berget 2.2.6 → 2.2.8

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 (145) hide show
  1. package/.github/workflows/publish.yml +2 -2
  2. package/.github/workflows/test.yml +10 -4
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +7 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +10 -11
  9. package/dist/package.json +30 -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 +97 -117
  20. package/dist/src/commands/api-keys.js +75 -90
  21. package/dist/src/commands/auth.js +7 -16
  22. package/dist/src/commands/autocomplete.js +1 -1
  23. package/dist/src/commands/billing.js +6 -17
  24. package/dist/src/commands/chat.js +68 -101
  25. package/dist/src/commands/clusters.js +9 -18
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +351 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +13 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +47 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +21 -34
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +20 -33
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +83 -57
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +359 -92
  33. package/dist/src/commands/code/adapters/clack-prompter.js +15 -22
  34. package/dist/src/commands/code/adapters/fs-file-store.js +26 -40
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -37
  36. package/dist/src/commands/code/auth-sync.js +270 -0
  37. package/dist/src/commands/code/errors.js +12 -9
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/setup.js +387 -281
  40. package/dist/src/commands/code.js +205 -332
  41. package/dist/src/commands/index.js +5 -5
  42. package/dist/src/commands/models.js +6 -17
  43. package/dist/src/commands/users.js +5 -16
  44. package/dist/src/constants/command-structure.js +104 -104
  45. package/dist/src/services/api-key-service.js +132 -157
  46. package/dist/src/services/auth-service.js +89 -342
  47. package/dist/src/services/browser-auth.js +268 -0
  48. package/dist/src/services/chat-service.js +371 -401
  49. package/dist/src/services/cluster-service.js +47 -62
  50. package/dist/src/services/collaborator-service.js +10 -25
  51. package/dist/src/services/flux-service.js +14 -29
  52. package/dist/src/services/helm-service.js +10 -25
  53. package/dist/src/services/kubectl-service.js +16 -33
  54. package/dist/src/utils/config-checker.js +3 -3
  55. package/dist/src/utils/config-loader.js +95 -95
  56. package/dist/src/utils/default-api-key.js +124 -134
  57. package/dist/src/utils/env-manager.js +55 -66
  58. package/dist/src/utils/error-handler.js +20 -21
  59. package/dist/src/utils/logger.js +72 -65
  60. package/dist/src/utils/markdown-renderer.js +27 -27
  61. package/dist/src/utils/opencode-validator.js +63 -68
  62. package/dist/src/utils/token-manager.js +74 -45
  63. package/dist/tests/commands/chat.test.js +16 -25
  64. package/dist/tests/commands/code.test.js +95 -104
  65. package/dist/tests/utils/config-loader.test.js +48 -48
  66. package/dist/tests/utils/env-manager.test.js +43 -52
  67. package/dist/tests/utils/opencode-validator.test.js +22 -21
  68. package/dist/vitest.config.js +1 -1
  69. package/eslint.config.mjs +67 -0
  70. package/index.ts +35 -42
  71. package/package.json +30 -2
  72. package/src/agents/app.ts +27 -0
  73. package/src/agents/backend.ts +24 -0
  74. package/src/agents/devops.ts +33 -0
  75. package/src/agents/frontend.ts +24 -0
  76. package/src/agents/fullstack.ts +24 -0
  77. package/src/agents/index.ts +73 -0
  78. package/src/agents/quality.ts +69 -0
  79. package/src/agents/security.ts +26 -0
  80. package/src/agents/types.ts +17 -0
  81. package/src/client.ts +118 -152
  82. package/src/commands/api-keys.ts +241 -333
  83. package/src/commands/auth.ts +22 -27
  84. package/src/commands/autocomplete.ts +9 -9
  85. package/src/commands/billing.ts +20 -24
  86. package/src/commands/chat.ts +248 -338
  87. package/src/commands/clusters.ts +27 -26
  88. package/src/commands/code/__tests__/auth-sync.test.ts +482 -0
  89. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  90. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  91. package/src/commands/code/__tests__/fake-command-runner.ts +45 -42
  92. package/src/commands/code/__tests__/fake-file-store.ts +32 -23
  93. package/src/commands/code/__tests__/fake-prompter.ts +116 -77
  94. package/src/commands/code/__tests__/setup-flow.test.ts +624 -268
  95. package/src/commands/code/adapters/clack-prompter.ts +53 -39
  96. package/src/commands/code/adapters/fs-file-store.ts +32 -27
  97. package/src/commands/code/adapters/spawn-command-runner.ts +38 -29
  98. package/src/commands/code/auth-sync.ts +329 -0
  99. package/src/commands/code/errors.ts +18 -18
  100. package/src/commands/code/ports/auth-services.ts +14 -0
  101. package/src/commands/code/ports/command-runner.ts +8 -4
  102. package/src/commands/code/ports/file-store.ts +5 -4
  103. package/src/commands/code/ports/prompter.ts +24 -18
  104. package/src/commands/code/setup.ts +570 -340
  105. package/src/commands/code.ts +338 -539
  106. package/src/commands/index.ts +20 -19
  107. package/src/commands/models.ts +28 -32
  108. package/src/commands/users.ts +15 -21
  109. package/src/constants/command-structure.ts +134 -157
  110. package/src/services/api-key-service.ts +105 -122
  111. package/src/services/auth-service.ts +99 -345
  112. package/src/services/browser-auth.ts +296 -0
  113. package/src/services/chat-service.ts +265 -299
  114. package/src/services/cluster-service.ts +42 -45
  115. package/src/services/collaborator-service.ts +14 -19
  116. package/src/services/flux-service.ts +23 -25
  117. package/src/services/helm-service.ts +19 -21
  118. package/src/services/kubectl-service.ts +17 -19
  119. package/src/types/api.d.ts +1905 -1907
  120. package/src/types/json.d.ts +2 -2
  121. package/src/utils/config-checker.ts +10 -10
  122. package/src/utils/config-loader.ts +162 -178
  123. package/src/utils/default-api-key.ts +114 -125
  124. package/src/utils/env-manager.ts +53 -57
  125. package/src/utils/error-handler.ts +61 -56
  126. package/src/utils/logger.ts +79 -73
  127. package/src/utils/markdown-renderer.ts +31 -31
  128. package/src/utils/opencode-validator.ts +85 -89
  129. package/src/utils/token-manager.ts +108 -87
  130. package/templates/agents/app.md +1 -0
  131. package/templates/agents/backend.md +1 -0
  132. package/templates/agents/devops.md +2 -0
  133. package/templates/agents/frontend.md +1 -0
  134. package/templates/agents/fullstack.md +1 -0
  135. package/templates/agents/quality.md +45 -40
  136. package/templates/agents/security.md +1 -0
  137. package/tests/commands/chat.test.ts +53 -62
  138. package/tests/commands/code.test.ts +265 -310
  139. package/tests/utils/config-loader.test.ts +189 -188
  140. package/tests/utils/env-manager.test.ts +110 -113
  141. package/tests/utils/opencode-validator.test.ts +52 -56
  142. package/tsconfig.json +4 -3
  143. package/vitest.config.ts +3 -3
  144. package/AGENTS.md +0 -374
  145. package/TODO.md +0 -19
@@ -22,22 +22,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
25
  Object.defineProperty(exports, "__esModule", { value: true });
35
- const vitest_1 = require("vitest");
36
26
  const commander_1 = require("commander");
27
+ const fs = __importStar(require("node:fs"));
28
+ const promises_1 = require("node:fs/promises");
29
+ const vitest_1 = require("vitest");
37
30
  const code_1 = require("../../src/commands/code");
38
31
  const api_key_service_1 = require("../../src/services/api-key-service");
39
- const fs = __importStar(require("fs"));
40
- const promises_1 = require("fs/promises");
41
32
  const env_manager_1 = require("../../src/utils/env-manager");
42
33
  // Mock dependencies
43
34
  vitest_1.vi.mock('../../src/services/api-key-service');
@@ -57,8 +48,8 @@ vitest_1.vi.mock('child_process', () => ({
57
48
  }));
58
49
  vitest_1.vi.mock('readline', () => ({
59
50
  createInterface: vitest_1.vi.fn(() => ({
60
- question: vitest_1.vi.fn(),
61
51
  close: vitest_1.vi.fn(),
52
+ question: vitest_1.vi.fn(),
62
53
  })),
63
54
  }));
64
55
  (0, vitest_1.describe)('Code Commands', () => {
@@ -95,35 +86,35 @@ vitest_1.vi.mock('readline', () => ({
95
86
  (0, vitest_1.describe)('code init command', () => {
96
87
  (0, vitest_1.it)('should register init command with correct description', () => {
97
88
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
98
- const initCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'init');
89
+ const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
99
90
  (0, vitest_1.expect)(initCommand).toBeDefined();
100
- (0, vitest_1.expect)(initCommand === null || initCommand === void 0 ? void 0 : initCommand.description()).toBe('Initialize project for AI coding assistant');
91
+ (0, vitest_1.expect)(initCommand?.description()).toBe('Initialize project for AI coding assistant');
101
92
  });
102
93
  (0, vitest_1.it)('should have name, force, and yes options', () => {
103
94
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
104
- const initCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'init');
95
+ const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
105
96
  (0, vitest_1.expect)(initCommand).toBeDefined();
106
- const nameOption = initCommand === null || initCommand === void 0 ? void 0 : initCommand.options.find((opt) => opt.long === '--name');
107
- const forceOption = initCommand === null || initCommand === void 0 ? void 0 : initCommand.options.find((opt) => opt.long === '--force');
108
- const yesOption = initCommand === null || initCommand === void 0 ? void 0 : initCommand.options.find((opt) => opt.long === '--yes');
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');
109
100
  (0, vitest_1.expect)(nameOption).toBeDefined();
110
- (0, vitest_1.expect)(nameOption === null || nameOption === void 0 ? void 0 : nameOption.description).toContain('Project name');
101
+ (0, vitest_1.expect)(nameOption?.description).toContain('Project name');
111
102
  (0, vitest_1.expect)(forceOption).toBeDefined();
112
- (0, vitest_1.expect)(forceOption === null || forceOption === void 0 ? void 0 : forceOption.description).toContain('Overwrite existing configuration');
103
+ (0, vitest_1.expect)(forceOption?.description).toContain('Overwrite existing configuration');
113
104
  (0, vitest_1.expect)(yesOption).toBeDefined();
114
- (0, vitest_1.expect)(yesOption === null || yesOption === void 0 ? void 0 : yesOption.description).toContain('Automatically answer yes');
105
+ (0, vitest_1.expect)(yesOption?.description).toContain('Automatically answer yes');
115
106
  });
116
107
  (0, vitest_1.it)('should check if opencode is installed', () => {
117
108
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
118
- const initCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'init');
109
+ const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
119
110
  (0, vitest_1.expect)(initCommand).toBeDefined();
120
111
  // The command should attempt to spawn opencode --version
121
112
  // This is tested implicitly through the spawn mock
122
113
  });
123
- (0, vitest_1.it)('should list existing API keys and allow selection', () => __awaiter(void 0, void 0, void 0, function* () {
114
+ (0, vitest_1.it)('should list existing API keys and allow selection', async () => {
124
115
  // Mock successful opencode installation check
125
- mockSpawn.mockImplementation((command, args) => {
126
- if (command === 'opencode' && args[0] === '--version') {
116
+ mockSpawn.mockImplementation((command, arguments_) => {
117
+ if (command === 'opencode' && arguments_[0] === '--version') {
127
118
  return {
128
119
  on: vitest_1.vi.fn().mockImplementation((event, callback) => {
129
120
  if (event === 'close')
@@ -136,31 +127,31 @@ vitest_1.vi.mock('readline', () => ({
136
127
  // Mock existing API keys
137
128
  const mockExistingKeys = [
138
129
  {
130
+ created: '2023-01-01T00:00:00.000Z',
139
131
  id: 1,
132
+ lastUsed: null,
140
133
  name: 'existing-key-1',
141
134
  prefix: 'sk_ber',
142
- created: '2023-01-01T00:00:00.000Z',
143
- lastUsed: null,
144
135
  },
145
136
  {
137
+ created: '2023-01-02T00:00:00.000Z',
146
138
  id: 2,
139
+ lastUsed: '2023-01-03T00:00:00.000Z',
147
140
  name: 'existing-key-2',
148
141
  prefix: 'sk_ber',
149
- created: '2023-01-02T00:00:00.000Z',
150
- lastUsed: '2023-01-03T00:00:00.000Z',
151
142
  },
152
143
  ];
153
144
  mockApiKeyService.list.mockResolvedValue(mockExistingKeys);
154
145
  // Mock file operations
155
146
  mockFs.existsSync.mockReturnValue(false);
156
- mockFsPromises.writeFile.mockResolvedValue(undefined);
147
+ mockFsPromises.writeFile.mockResolvedValue();
157
148
  // Verify that the list method is called
158
149
  (0, vitest_1.expect)(mockApiKeyService.list).toBeDefined();
159
- }));
160
- (0, vitest_1.it)('should create new API key with project-based naming', () => __awaiter(void 0, void 0, void 0, function* () {
150
+ });
151
+ (0, vitest_1.it)('should create new API key with project-based naming', async () => {
161
152
  // Mock successful opencode installation check
162
- mockSpawn.mockImplementation((command, args) => {
163
- if (command === 'opencode' && args[0] === '--version') {
153
+ mockSpawn.mockImplementation((command, arguments_) => {
154
+ if (command === 'opencode' && arguments_[0] === '--version') {
164
155
  return {
165
156
  on: vitest_1.vi.fn().mockImplementation((event, callback) => {
166
157
  if (event === 'close')
@@ -175,33 +166,33 @@ vitest_1.vi.mock('readline', () => ({
175
166
  // Mock successful API key creation
176
167
  const mockApiKeyData = {
177
168
  id: 123,
178
- name: 'opencode-testproject-1234567890',
179
169
  key: 'test-api-key-12345',
170
+ name: 'opencode-testproject-1234567890',
180
171
  };
181
172
  mockApiKeyService.create.mockResolvedValue(mockApiKeyData);
182
173
  // Mock file operations
183
174
  mockFs.existsSync.mockReturnValue(false);
184
- mockFsPromises.writeFile.mockResolvedValue(undefined);
175
+ mockFsPromises.writeFile.mockResolvedValue();
185
176
  // Verify that the create method is available
186
177
  (0, vitest_1.expect)(mockApiKeyService.create).toBeDefined();
187
- }));
188
- (0, vitest_1.it)('should create opencode.json with correct structure', () => __awaiter(void 0, void 0, void 0, function* () {
178
+ });
179
+ (0, vitest_1.it)('should create opencode.json with correct structure', async () => {
189
180
  // This tests the expected config structure
190
181
  const expectedConfig = {
191
- model: 'berget/glm-4-6',
192
182
  apiKey: 'test-api-key',
183
+ created: vitest_1.expect.any(String),
184
+ model: 'berget/glm-4-6',
193
185
  projectName: 'testproject',
194
186
  provider: 'berget',
195
- created: vitest_1.expect.any(String),
196
187
  version: '1.0.0',
197
188
  };
198
189
  (0, vitest_1.expect)(expectedConfig.model).toBe('berget/glm-4-6');
199
190
  (0, vitest_1.expect)(expectedConfig.provider).toBe('berget');
200
191
  (0, vitest_1.expect)(expectedConfig.version).toBe('1.0.0');
201
- }));
192
+ });
202
193
  (0, vitest_1.it)('should handle existing config file', () => {
203
194
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
204
- const initCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'init');
195
+ const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
205
196
  (0, vitest_1.expect)(initCommand).toBeDefined();
206
197
  // Should check if opencode.json exists before proceeding
207
198
  (0, vitest_1.expect)(mockFs.existsSync).toBeDefined();
@@ -210,39 +201,39 @@ vitest_1.vi.mock('readline', () => ({
210
201
  (0, vitest_1.describe)('code run command', () => {
211
202
  (0, vitest_1.it)('should register run command with correct description', () => {
212
203
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
213
- const runCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'run');
204
+ const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
214
205
  (0, vitest_1.expect)(runCommand).toBeDefined();
215
- (0, vitest_1.expect)(runCommand === null || runCommand === void 0 ? void 0 : runCommand.description()).toBe('Run AI coding assistant');
206
+ (0, vitest_1.expect)(runCommand?.description()).toBe('Run AI coding assistant');
216
207
  });
217
208
  (0, vitest_1.it)('should accept prompt argument and model, no-config, and yes options', () => {
218
209
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
219
- const runCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'run');
210
+ const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
220
211
  (0, vitest_1.expect)(runCommand).toBeDefined();
221
- const modelOption = runCommand === null || runCommand === void 0 ? void 0 : runCommand.options.find((opt) => opt.long === '--model');
222
- const noConfigOption = runCommand === null || runCommand === void 0 ? void 0 : runCommand.options.find((opt) => opt.long === '--no-config');
223
- const yesOption = runCommand === null || runCommand === void 0 ? void 0 : runCommand.options.find((opt) => opt.long === '--yes');
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');
224
215
  (0, vitest_1.expect)(modelOption).toBeDefined();
225
- (0, vitest_1.expect)(modelOption === null || modelOption === void 0 ? void 0 : modelOption.description).toContain('Model to use');
216
+ (0, vitest_1.expect)(modelOption?.description).toContain('Model to use');
226
217
  (0, vitest_1.expect)(noConfigOption).toBeDefined();
227
- (0, vitest_1.expect)(noConfigOption === null || noConfigOption === void 0 ? void 0 : noConfigOption.description).toContain('Run without loading project config');
218
+ (0, vitest_1.expect)(noConfigOption?.description).toContain('Run without loading project config');
228
219
  (0, vitest_1.expect)(yesOption).toBeDefined();
229
- (0, vitest_1.expect)(yesOption === null || yesOption === void 0 ? void 0 : yesOption.description).toContain('Automatically answer yes');
220
+ (0, vitest_1.expect)(yesOption?.description).toContain('Automatically answer yes');
230
221
  });
231
- (0, vitest_1.it)('should load configuration from opencode.json', () => __awaiter(void 0, void 0, void 0, function* () {
222
+ (0, vitest_1.it)('should load configuration from opencode.json', async () => {
232
223
  const mockConfig = {
233
- model: 'berget/glm-4-6',
234
224
  apiKey: 'test-api-key',
225
+ created: '2023-01-01T00:00:00.000Z',
226
+ model: 'berget/glm-4-6',
235
227
  projectName: 'testproject',
236
228
  provider: 'berget',
237
- created: '2023-01-01T00:00:00.000Z',
238
229
  version: '1.0.0',
239
230
  };
240
231
  // Mock file exists and contains config
241
232
  mockFs.existsSync.mockReturnValue(true);
242
233
  mockFsPromises.readFile.mockResolvedValue(JSON.stringify(mockConfig));
243
234
  // Mock successful opencode check
244
- mockSpawn.mockImplementation((command, args) => {
245
- if (command === 'opencode' && args[0] === '--version') {
235
+ mockSpawn.mockImplementation((command, arguments_) => {
236
+ if (command === 'opencode' && arguments_[0] === '--version') {
246
237
  return {
247
238
  on: vitest_1.vi.fn().mockImplementation((event, callback) => {
248
239
  if (event === 'close')
@@ -256,17 +247,17 @@ vitest_1.vi.mock('readline', () => ({
256
247
  (0, vitest_1.expect)(mockConfig.model).toBe('berget/glm-4-6');
257
248
  (0, vitest_1.expect)(mockConfig.apiKey).toBe('test-api-key');
258
249
  (0, vitest_1.expect)(mockConfig.projectName).toBe('testproject');
259
- }));
250
+ });
260
251
  (0, vitest_1.it)('should spawn opencode with correct arguments', () => {
261
252
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
262
- const runCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'run');
253
+ const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
263
254
  (0, vitest_1.expect)(runCommand).toBeDefined();
264
255
  // Should spawn opencode with appropriate arguments
265
256
  (0, vitest_1.expect)(mockSpawn).toBeDefined();
266
257
  });
267
258
  (0, vitest_1.it)('should handle missing configuration file', () => {
268
259
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
269
- const runCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'run');
260
+ const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
270
261
  (0, vitest_1.expect)(runCommand).toBeDefined();
271
262
  // Should check if opencode.json exists
272
263
  (0, vitest_1.expect)(mockFs.existsSync).toBeDefined();
@@ -279,8 +270,8 @@ vitest_1.vi.mock('readline', () => ({
279
270
  });
280
271
  (0, vitest_1.it)('should offer to install opencode if not found', () => {
281
272
  // Mock opencode not installed
282
- mockSpawn.mockImplementation((command, args) => {
283
- if (command === 'opencode' && args[0] === '--version') {
273
+ mockSpawn.mockImplementation((command, arguments_) => {
274
+ if (command === 'opencode' && arguments_[0] === '--version') {
284
275
  return {
285
276
  on: vitest_1.vi.fn().mockImplementation((event, callback) => {
286
277
  if (event === 'close')
@@ -301,19 +292,19 @@ vitest_1.vi.mock('readline', () => ({
301
292
  (0, vitest_1.describe)('automation support', () => {
302
293
  (0, vitest_1.it)('should support -y flag for automated initialization', () => {
303
294
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
304
- const initCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'init');
295
+ const initCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'init');
305
296
  (0, vitest_1.expect)(initCommand).toBeDefined();
306
- const yesOption = initCommand === null || initCommand === void 0 ? void 0 : initCommand.options.find((opt) => opt.long === '--yes');
297
+ const yesOption = initCommand?.options.find((opt) => opt.long === '--yes');
307
298
  (0, vitest_1.expect)(yesOption).toBeDefined();
308
- (0, vitest_1.expect)(yesOption === null || yesOption === void 0 ? void 0 : yesOption.description).toContain('automation');
299
+ (0, vitest_1.expect)(yesOption?.description).toContain('automation');
309
300
  });
310
301
  (0, vitest_1.it)('should support -y flag for automated run', () => {
311
302
  const codeCommand = program.commands.find((cmd) => cmd.name() === 'code');
312
- const runCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'run');
303
+ const runCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'run');
313
304
  (0, vitest_1.expect)(runCommand).toBeDefined();
314
- const yesOption = runCommand === null || runCommand === void 0 ? void 0 : runCommand.options.find((opt) => opt.long === '--yes');
305
+ const yesOption = runCommand?.options.find((opt) => opt.long === '--yes');
315
306
  (0, vitest_1.expect)(yesOption).toBeDefined();
316
- (0, vitest_1.expect)(yesOption === null || yesOption === void 0 ? void 0 : yesOption.description).toContain('automation');
307
+ (0, vitest_1.expect)(yesOption?.description).toContain('automation');
317
308
  });
318
309
  (0, vitest_1.it)('should use BERGET_API_KEY environment variable in automation mode', () => {
319
310
  // Test that environment variable is used when -y flag is set
@@ -324,65 +315,65 @@ vitest_1.vi.mock('readline', () => ({
324
315
  });
325
316
  });
326
317
  (0, vitest_1.describe)('.env file handling', () => {
327
- let mockUpdateEnvFile;
318
+ let mockUpdateEnvironmentFile;
328
319
  (0, vitest_1.beforeEach)(() => {
329
- mockUpdateEnvFile = vitest_1.vi.mocked(env_manager_1.updateEnvFile);
320
+ mockUpdateEnvironmentFile = vitest_1.vi.mocked(env_manager_1.updateEnvFile);
330
321
  });
331
- (0, vitest_1.it)('should call updateEnvFile when creating new project', () => __awaiter(void 0, void 0, void 0, function* () {
332
- mockUpdateEnvFile.mockResolvedValue(true);
322
+ (0, vitest_1.it)('should call updateEnvFile when creating new project', async () => {
323
+ mockUpdateEnvironmentFile.mockResolvedValue(true);
333
324
  mockFs.existsSync.mockReturnValue(false); // .env doesn't exist
334
- mockFsPromises.writeFile.mockResolvedValue(undefined);
325
+ mockFsPromises.writeFile.mockResolvedValue();
335
326
  // This would be tested by actually calling the init command
336
327
  // For now we verify the mock is properly set up
337
- (0, vitest_1.expect)(mockUpdateEnvFile).toBeDefined();
338
- }));
339
- (0, vitest_1.it)('should not overwrite existing BERGET_API_KEY in .env', () => __awaiter(void 0, void 0, void 0, function* () {
328
+ (0, vitest_1.expect)(mockUpdateEnvironmentFile).toBeDefined();
329
+ });
330
+ (0, vitest_1.it)('should not overwrite existing BERGET_API_KEY in .env', async () => {
340
331
  const consoleSpy = vitest_1.vi.spyOn(console, 'log').mockImplementation(() => { });
341
332
  // Mock existing .env with BERGET_API_KEY
342
333
  mockFs.existsSync.mockReturnValue(true);
343
334
  mockFs.readFileSync.mockReturnValue('BERGET_API_KEY=existing_key\nOTHER_KEY=value\n');
344
335
  // Mock updateEnvFile to simulate the check
345
- mockUpdateEnvFile.mockImplementation((options) => __awaiter(void 0, void 0, void 0, function* () {
336
+ mockUpdateEnvironmentFile.mockImplementation(async (options) => {
346
337
  if (options.key === 'BERGET_API_KEY' && !options.force) {
347
338
  console.log(`⚠ ${options.key} already exists in .env - leaving unchanged`);
348
339
  return false;
349
340
  }
350
341
  return true;
351
- }));
352
- yield (0, env_manager_1.updateEnvFile)({
342
+ });
343
+ await (0, env_manager_1.updateEnvFile)({
353
344
  key: 'BERGET_API_KEY',
354
345
  value: 'new_key',
355
346
  });
356
347
  (0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('BERGET_API_KEY already exists in .env - leaving unchanged'));
357
348
  consoleSpy.mockRestore();
358
- }));
359
- (0, vitest_1.it)('should add new key to existing .env file', () => __awaiter(void 0, void 0, void 0, function* () {
349
+ });
350
+ (0, vitest_1.it)('should add new key to existing .env file', async () => {
360
351
  mockFs.existsSync.mockReturnValue(true);
361
352
  mockFs.readFileSync.mockReturnValue('EXISTING_KEY=value\n');
362
- mockUpdateEnvFile.mockResolvedValue(true);
363
- yield (0, env_manager_1.updateEnvFile)({
353
+ mockUpdateEnvironmentFile.mockResolvedValue(true);
354
+ await (0, env_manager_1.updateEnvFile)({
355
+ comment: 'Berget AI Configuration',
364
356
  key: 'BERGET_API_KEY',
365
357
  value: 'new_api_key',
366
- comment: 'Berget AI Configuration',
367
358
  });
368
- (0, vitest_1.expect)(mockUpdateEnvFile).toHaveBeenCalledWith({
359
+ (0, vitest_1.expect)(mockUpdateEnvironmentFile).toHaveBeenCalledWith({
360
+ comment: 'Berget AI Configuration',
369
361
  key: 'BERGET_API_KEY',
370
362
  value: 'new_api_key',
371
- comment: 'Berget AI Configuration',
372
363
  });
373
- }));
374
- (0, vitest_1.it)('should create new .env file when none exists', () => __awaiter(void 0, void 0, void 0, function* () {
364
+ });
365
+ (0, vitest_1.it)('should create new .env file when none exists', async () => {
375
366
  mockFs.existsSync.mockReturnValue(false);
376
- mockUpdateEnvFile.mockResolvedValue(true);
377
- yield (0, env_manager_1.updateEnvFile)({
367
+ mockUpdateEnvironmentFile.mockResolvedValue(true);
368
+ await (0, env_manager_1.updateEnvFile)({
378
369
  key: 'BERGET_API_KEY',
379
370
  value: 'new_api_key',
380
371
  });
381
- (0, vitest_1.expect)(mockUpdateEnvFile).toHaveBeenCalledWith({
372
+ (0, vitest_1.expect)(mockUpdateEnvironmentFile).toHaveBeenCalledWith({
382
373
  key: 'BERGET_API_KEY',
383
374
  value: 'new_api_key',
384
375
  });
385
- }));
376
+ });
386
377
  });
387
378
  (0, vitest_1.describe)('error handling', () => {
388
379
  (0, vitest_1.it)('should handle API key creation failures', () => {
@@ -402,26 +393,26 @@ vitest_1.vi.mock('readline', () => ({
402
393
  });
403
394
  (0, vitest_1.expect)(mockSpawn).toBeDefined();
404
395
  });
405
- (0, vitest_1.it)('should handle .env update failures', () => __awaiter(void 0, void 0, void 0, function* () {
406
- const mockUpdateEnvFile = vitest_1.vi.mocked(env_manager_1.updateEnvFile);
407
- mockUpdateEnvFile.mockRejectedValue(new Error('Env update failed'));
408
- yield (0, vitest_1.expect)((0, env_manager_1.updateEnvFile)({
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)({
409
400
  key: 'TEST_KEY',
410
401
  value: 'test_value',
411
402
  })).rejects.toThrow('Env update failed');
412
- }));
403
+ });
413
404
  });
414
405
  (0, vitest_1.describe)('experimental features', () => {
415
- let originalEnv;
406
+ let originalEnvironment;
416
407
  (0, vitest_1.beforeEach)(() => {
417
- originalEnv = process.env.BERGET_EXPERIMENTAL;
408
+ originalEnvironment = process.env.BERGET_EXPERIMENTAL;
418
409
  });
419
410
  (0, vitest_1.afterEach)(() => {
420
- if (originalEnv === undefined) {
411
+ if (originalEnvironment === undefined) {
421
412
  delete process.env.BERGET_EXPERIMENTAL;
422
413
  }
423
414
  else {
424
- process.env.BERGET_EXPERIMENTAL = originalEnv;
415
+ process.env.BERGET_EXPERIMENTAL = originalEnvironment;
425
416
  }
426
417
  });
427
418
  (0, vitest_1.it)('should NOT show setup command when BERGET_EXPERIMENTAL is not set', () => {
@@ -429,7 +420,7 @@ vitest_1.vi.mock('readline', () => ({
429
420
  const freshProgram = new commander_1.Command();
430
421
  (0, code_1.registerCodeCommands)(freshProgram);
431
422
  const codeCommand = freshProgram.commands.find((cmd) => cmd.name() === 'code');
432
- const setupCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'setup');
423
+ const setupCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'setup');
433
424
  (0, vitest_1.expect)(setupCommand).toBeUndefined();
434
425
  });
435
426
  (0, vitest_1.it)('should show setup command when BERGET_EXPERIMENTAL is set', () => {
@@ -437,9 +428,9 @@ vitest_1.vi.mock('readline', () => ({
437
428
  const freshProgram = new commander_1.Command();
438
429
  (0, code_1.registerCodeCommands)(freshProgram);
439
430
  const codeCommand = freshProgram.commands.find((cmd) => cmd.name() === 'code');
440
- const setupCommand = codeCommand === null || codeCommand === void 0 ? void 0 : codeCommand.commands.find((cmd) => cmd.name() === 'setup');
431
+ const setupCommand = codeCommand?.commands.find((cmd) => cmd.name() === 'setup');
441
432
  (0, vitest_1.expect)(setupCommand).toBeDefined();
442
- (0, vitest_1.expect)(setupCommand === null || setupCommand === void 0 ? void 0 : setupCommand.description()).toBe('Interactive setup for Berget AI coding tools');
433
+ (0, vitest_1.expect)(setupCommand?.description()).toBe('Interactive setup for Berget AI coding tools');
443
434
  });
444
435
  });
445
436
  });
@@ -5,9 +5,9 @@ const config_loader_1 = require("../../src/utils/config-loader");
5
5
  // Mock fs module
6
6
  const mockFs = vitest_1.vi.hoisted(() => ({
7
7
  existsSync: vitest_1.vi.fn(),
8
+ mkdirSync: vitest_1.vi.fn(),
8
9
  readFileSync: vitest_1.vi.fn(),
9
10
  writeFileSync: vitest_1.vi.fn(),
10
- mkdirSync: vitest_1.vi.fn(),
11
11
  }));
12
12
  vitest_1.vi.mock('fs', () => mockFs);
13
13
  (0, vitest_1.describe)('ConfigLoader', () => {
@@ -33,14 +33,14 @@ vitest_1.vi.mock('fs', () => mockFs);
33
33
  const modelConfig = configLoader.getModelConfig();
34
34
  (0, vitest_1.expect)(modelConfig).toEqual({
35
35
  primary: 'berget/glm-4.7',
36
- small: 'berget/gpt-oss'
36
+ small: 'berget/gpt-oss',
37
37
  });
38
38
  });
39
39
  (0, vitest_1.it)('should return default values when using convenience function', () => {
40
40
  const modelConfig = (0, config_loader_1.getModelConfig)(testConfigPath);
41
41
  (0, vitest_1.expect)(modelConfig).toEqual({
42
42
  primary: 'berget/glm-4.7',
43
- small: 'berget/gpt-oss'
43
+ small: 'berget/gpt-oss',
44
44
  });
45
45
  });
46
46
  });
@@ -49,42 +49,42 @@ vitest_1.vi.mock('fs', () => mockFs);
49
49
  const models = configLoader.getProviderModels();
50
50
  (0, vitest_1.expect)(models).toEqual({
51
51
  'glm-4.7': {
52
+ limit: { context: 90000, output: 4000 },
52
53
  name: 'GLM-4.7',
53
- limit: { output: 4000, context: 90000 }
54
54
  },
55
55
  'gpt-oss': {
56
- name: 'GPT-OSS',
57
- limit: { output: 4000, context: 128000 },
56
+ limit: { context: 128000, output: 4000 },
58
57
  modalities: {
59
58
  input: ['text', 'image'],
60
- output: ['text']
61
- }
59
+ output: ['text'],
60
+ },
61
+ name: 'GPT-OSS',
62
62
  },
63
63
  'llama-8b': {
64
+ limit: { context: 128000, output: 4000 },
64
65
  name: 'llama-3.1-8b',
65
- limit: { output: 4000, context: 128000 }
66
- }
66
+ },
67
67
  });
68
68
  });
69
69
  (0, vitest_1.it)('should return default provider models when using convenience function', () => {
70
70
  const models = (0, config_loader_1.getProviderModels)(testConfigPath);
71
71
  (0, vitest_1.expect)(models).toEqual({
72
72
  'glm-4.7': {
73
+ limit: { context: 90000, output: 4000 },
73
74
  name: 'GLM-4.7',
74
- limit: { output: 4000, context: 90000 }
75
75
  },
76
76
  'gpt-oss': {
77
- name: 'GPT-OSS',
78
- limit: { output: 4000, context: 128000 },
77
+ limit: { context: 128000, output: 4000 },
79
78
  modalities: {
80
79
  input: ['text', 'image'],
81
- output: ['text']
82
- }
80
+ output: ['text'],
81
+ },
82
+ name: 'GPT-OSS',
83
83
  },
84
84
  'llama-8b': {
85
+ limit: { context: 128000, output: 4000 },
85
86
  name: 'llama-3.1-8b',
86
- limit: { output: 4000, context: 128000 }
87
- }
87
+ },
88
88
  });
89
89
  });
90
90
  });
@@ -107,38 +107,38 @@ vitest_1.vi.mock('fs', () => mockFs);
107
107
  });
108
108
  (0, vitest_1.describe)('when config file exists', () => {
109
109
  const mockConfig = {
110
- model: 'custom-model',
111
- small_model: 'custom-small-model',
112
110
  agent: {
113
111
  fullstack: {
114
- model: 'custom-agent-model',
115
- temperature: 0.5,
116
112
  mode: 'primary',
113
+ model: 'custom-agent-model',
117
114
  permission: {
118
- edit: 'allow',
119
115
  bash: 'allow',
120
- webfetch: 'allow'
121
- }
122
- }
116
+ edit: 'allow',
117
+ webfetch: 'allow',
118
+ },
119
+ temperature: 0.5,
120
+ },
123
121
  },
124
122
  command: {
125
123
  test: {
126
- description: 'Test command'
127
- }
128
- },
129
- watcher: {
130
- ignore: ['custom-ignore']
124
+ description: 'Test command',
125
+ },
131
126
  },
127
+ model: 'custom-model',
132
128
  provider: {
133
129
  berget: {
134
130
  models: {
135
131
  'custom-model': {
132
+ limit: { context: 160000, output: 8000 },
136
133
  name: 'Custom Model',
137
- limit: { output: 8000, context: 160000 }
138
- }
139
- }
140
- }
141
- }
134
+ },
135
+ },
136
+ },
137
+ },
138
+ small_model: 'custom-small-model',
139
+ watcher: {
140
+ ignore: ['custom-ignore'],
141
+ },
142
142
  };
143
143
  (0, vitest_1.beforeEach)(() => {
144
144
  mockFs.existsSync.mockReturnValue(true);
@@ -149,7 +149,7 @@ vitest_1.vi.mock('fs', () => mockFs);
149
149
  const modelConfig = configLoader.getModelConfig();
150
150
  (0, vitest_1.expect)(modelConfig).toEqual({
151
151
  primary: 'custom-model',
152
- small: 'custom-small-model'
152
+ small: 'custom-small-model',
153
153
  });
154
154
  });
155
155
  });
@@ -158,9 +158,9 @@ vitest_1.vi.mock('fs', () => mockFs);
158
158
  const models = configLoader.getProviderModels();
159
159
  (0, vitest_1.expect)(models).toEqual({
160
160
  'custom-model': {
161
+ limit: { context: 160000, output: 8000 },
161
162
  name: 'Custom Model',
162
- limit: { output: 8000, context: 160000 }
163
- }
163
+ },
164
164
  });
165
165
  });
166
166
  });
@@ -190,28 +190,28 @@ vitest_1.vi.mock('fs', () => mockFs);
190
190
  const modelConfig = configLoader.getModelConfig();
191
191
  (0, vitest_1.expect)(modelConfig).toEqual({
192
192
  primary: 'berget/glm-4.7',
193
- small: 'berget/gpt-oss'
193
+ small: 'berget/gpt-oss',
194
194
  });
195
195
  });
196
196
  (0, vitest_1.it)('should fall back to defaults for getProviderModels', () => {
197
197
  const models = configLoader.getProviderModels();
198
198
  (0, vitest_1.expect)(models).toEqual({
199
199
  'glm-4.7': {
200
+ limit: { context: 90000, output: 4000 },
200
201
  name: 'GLM-4.7',
201
- limit: { output: 4000, context: 90000 }
202
202
  },
203
203
  'gpt-oss': {
204
- name: 'GPT-OSS',
205
- limit: { output: 4000, context: 128000 },
204
+ limit: { context: 128000, output: 4000 },
206
205
  modalities: {
207
206
  input: ['text', 'image'],
208
- output: ['text']
209
- }
207
+ output: ['text'],
208
+ },
209
+ name: 'GPT-OSS',
210
210
  },
211
211
  'llama-8b': {
212
+ limit: { context: 128000, output: 4000 },
212
213
  name: 'llama-3.1-8b',
213
- limit: { output: 4000, context: 128000 }
214
- }
214
+ },
215
215
  });
216
216
  });
217
217
  (0, vitest_1.it)('should fall back to defaults for getAllAgentConfigs', () => {
@@ -246,7 +246,7 @@ vitest_1.vi.mock('fs', () => mockFs);
246
246
  // And return sensible defaults
247
247
  (0, vitest_1.expect)(configLoader.getModelConfig()).toEqual({
248
248
  primary: 'berget/glm-4.7',
249
- small: 'berget/gpt-oss'
249
+ small: 'berget/gpt-oss',
250
250
  });
251
251
  (0, vitest_1.expect)(configLoader.getAllAgentConfigs()).toEqual({});
252
252
  (0, vitest_1.expect)(configLoader.getAgentConfig('fullstack')).toBeNull();
@@ -259,7 +259,7 @@ vitest_1.vi.mock('fs', () => mockFs);
259
259
  (0, vitest_1.expect)(() => (0, config_loader_1.getAllAgentConfigs)(testConfigPath)).not.toThrow();
260
260
  (0, vitest_1.expect)((0, config_loader_1.getModelConfig)(testConfigPath)).toEqual({
261
261
  primary: 'berget/glm-4.7',
262
- small: 'berget/gpt-oss'
262
+ small: 'berget/gpt-oss',
263
263
  });
264
264
  (0, vitest_1.expect)((0, config_loader_1.getAllAgentConfigs)(testConfigPath)).toEqual({});
265
265
  });