berget 2.2.6 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/.github/workflows/publish.yml +6 -6
  2. package/.github/workflows/test.yml +11 -5
  3. package/.husky/pre-commit +1 -0
  4. package/.prettierignore +15 -0
  5. package/.prettierrc +5 -3
  6. package/CONTRIBUTING.md +38 -0
  7. package/README.md +2 -148
  8. package/dist/index.js +21 -21
  9. package/dist/package.json +28 -2
  10. package/dist/src/agents/app.js +28 -0
  11. package/dist/src/agents/backend.js +25 -0
  12. package/dist/src/agents/devops.js +34 -0
  13. package/dist/src/agents/frontend.js +25 -0
  14. package/dist/src/agents/fullstack.js +25 -0
  15. package/dist/src/agents/index.js +61 -0
  16. package/dist/src/agents/quality.js +70 -0
  17. package/dist/src/agents/security.js +26 -0
  18. package/dist/src/agents/types.js +2 -0
  19. package/dist/src/client.js +54 -62
  20. package/dist/src/commands/api-keys.js +132 -140
  21. package/dist/src/commands/auth.js +9 -9
  22. package/dist/src/commands/autocomplete.js +9 -9
  23. package/dist/src/commands/billing.js +7 -9
  24. package/dist/src/commands/chat.js +90 -92
  25. package/dist/src/commands/clusters.js +12 -12
  26. package/dist/src/commands/code/__tests__/auth-sync.test.js +348 -0
  27. package/dist/src/commands/code/__tests__/fake-api-key-service.js +23 -0
  28. package/dist/src/commands/code/__tests__/fake-auth-service.js +55 -0
  29. package/dist/src/commands/code/__tests__/fake-command-runner.js +5 -7
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +9 -0
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +60 -18
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +374 -107
  33. package/dist/src/commands/code/adapters/clack-prompter.js +10 -0
  34. package/dist/src/commands/code/adapters/fs-file-store.js +8 -3
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +15 -11
  36. package/dist/src/commands/code/auth-sync.js +283 -0
  37. package/dist/src/commands/code/errors.js +4 -4
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/setup.js +234 -93
  40. package/dist/src/commands/code.js +139 -251
  41. package/dist/src/commands/models.js +13 -15
  42. package/dist/src/commands/users.js +6 -8
  43. package/dist/src/constants/command-structure.js +116 -116
  44. package/dist/src/services/api-key-service.js +43 -48
  45. package/dist/src/services/auth-service.js +60 -299
  46. package/dist/src/services/browser-auth.js +278 -0
  47. package/dist/src/services/chat-service.js +78 -91
  48. package/dist/src/services/cluster-service.js +6 -6
  49. package/dist/src/services/collaborator-service.js +5 -8
  50. package/dist/src/services/flux-service.js +5 -8
  51. package/dist/src/services/helm-service.js +5 -8
  52. package/dist/src/services/kubectl-service.js +7 -10
  53. package/dist/src/utils/config-checker.js +5 -5
  54. package/dist/src/utils/config-loader.js +25 -25
  55. package/dist/src/utils/default-api-key.js +23 -23
  56. package/dist/src/utils/env-manager.js +7 -7
  57. package/dist/src/utils/error-handler.js +60 -61
  58. package/dist/src/utils/logger.js +7 -7
  59. package/dist/src/utils/markdown-renderer.js +2 -2
  60. package/dist/src/utils/opencode-validator.js +17 -20
  61. package/dist/src/utils/token-manager.js +38 -11
  62. package/dist/tests/commands/chat.test.js +24 -24
  63. package/dist/tests/commands/code.test.js +147 -147
  64. package/dist/tests/utils/config-loader.test.js +114 -114
  65. package/dist/tests/utils/env-manager.test.js +57 -57
  66. package/dist/tests/utils/opencode-validator.test.js +33 -33
  67. package/dist/vitest.config.js +1 -1
  68. package/eslint.config.mjs +47 -0
  69. package/index.ts +42 -48
  70. package/package.json +28 -2
  71. package/src/agents/app.ts +27 -0
  72. package/src/agents/backend.ts +24 -0
  73. package/src/agents/devops.ts +33 -0
  74. package/src/agents/frontend.ts +24 -0
  75. package/src/agents/fullstack.ts +24 -0
  76. package/src/agents/index.ts +71 -0
  77. package/src/agents/quality.ts +69 -0
  78. package/src/agents/security.ts +26 -0
  79. package/src/agents/types.ts +17 -0
  80. package/src/client.ts +125 -167
  81. package/src/commands/api-keys.ts +261 -358
  82. package/src/commands/auth.ts +24 -30
  83. package/src/commands/autocomplete.ts +12 -12
  84. package/src/commands/billing.ts +22 -27
  85. package/src/commands/chat.ts +230 -323
  86. package/src/commands/clusters.ts +33 -33
  87. package/src/commands/code/__tests__/auth-sync.test.ts +481 -0
  88. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  89. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  90. package/src/commands/code/__tests__/fake-command-runner.ts +39 -42
  91. package/src/commands/code/__tests__/fake-file-store.ts +32 -23
  92. package/src/commands/code/__tests__/fake-prompter.ts +107 -69
  93. package/src/commands/code/__tests__/setup-flow.test.ts +624 -270
  94. package/src/commands/code/adapters/clack-prompter.ts +50 -38
  95. package/src/commands/code/adapters/fs-file-store.ts +31 -27
  96. package/src/commands/code/adapters/spawn-command-runner.ts +33 -29
  97. package/src/commands/code/auth-sync.ts +329 -0
  98. package/src/commands/code/errors.ts +15 -15
  99. package/src/commands/code/ports/auth-services.ts +14 -0
  100. package/src/commands/code/ports/command-runner.ts +8 -4
  101. package/src/commands/code/ports/file-store.ts +5 -4
  102. package/src/commands/code/ports/prompter.ts +24 -18
  103. package/src/commands/code/setup.ts +545 -317
  104. package/src/commands/code.ts +271 -473
  105. package/src/commands/index.ts +19 -19
  106. package/src/commands/models.ts +32 -37
  107. package/src/commands/users.ts +15 -22
  108. package/src/constants/command-structure.ts +119 -142
  109. package/src/services/api-key-service.ts +96 -113
  110. package/src/services/auth-service.ts +92 -339
  111. package/src/services/browser-auth.ts +296 -0
  112. package/src/services/chat-service.ts +246 -279
  113. package/src/services/cluster-service.ts +29 -32
  114. package/src/services/collaborator-service.ts +13 -18
  115. package/src/services/flux-service.ts +16 -18
  116. package/src/services/helm-service.ts +16 -18
  117. package/src/services/kubectl-service.ts +12 -14
  118. package/src/types/api.d.ts +924 -926
  119. package/src/types/json.d.ts +3 -3
  120. package/src/utils/config-checker.ts +10 -10
  121. package/src/utils/config-loader.ts +110 -127
  122. package/src/utils/default-api-key.ts +81 -93
  123. package/src/utils/env-manager.ts +36 -40
  124. package/src/utils/error-handler.ts +83 -78
  125. package/src/utils/logger.ts +41 -41
  126. package/src/utils/markdown-renderer.ts +11 -11
  127. package/src/utils/opencode-validator.ts +51 -56
  128. package/src/utils/token-manager.ts +84 -64
  129. package/templates/agents/app.md +1 -0
  130. package/templates/agents/backend.md +1 -0
  131. package/templates/agents/devops.md +2 -0
  132. package/templates/agents/frontend.md +1 -0
  133. package/templates/agents/fullstack.md +1 -0
  134. package/templates/agents/quality.md +45 -40
  135. package/templates/agents/security.md +1 -0
  136. package/tests/commands/chat.test.ts +60 -70
  137. package/tests/commands/code.test.ts +330 -376
  138. package/tests/utils/config-loader.test.ts +260 -260
  139. package/tests/utils/env-manager.test.ts +127 -134
  140. package/tests/utils/opencode-validator.test.ts +58 -63
  141. package/tsconfig.json +2 -2
  142. package/vitest.config.ts +3 -3
  143. package/AGENTS.md +0 -374
  144. package/TODO.md +0 -19
@@ -9,9 +9,9 @@ const mockFs = vitest_1.vi.hoisted(() => ({
9
9
  writeFileSync: vitest_1.vi.fn(),
10
10
  mkdirSync: vitest_1.vi.fn(),
11
11
  }));
12
- vitest_1.vi.mock('fs', () => mockFs);
13
- (0, vitest_1.describe)('ConfigLoader', () => {
14
- const testConfigPath = '/tmp/test-opencode.json';
12
+ vitest_1.vi.mock("fs", () => mockFs);
13
+ (0, vitest_1.describe)("ConfigLoader", () => {
14
+ const testConfigPath = "/tmp/test-opencode.json";
15
15
  let configLoader;
16
16
  (0, vitest_1.beforeEach)(() => {
17
17
  // Reset mocks and clear singleton
@@ -24,242 +24,242 @@ vitest_1.vi.mock('fs', () => mockFs);
24
24
  vitest_1.vi.clearAllMocks();
25
25
  config_loader_1.ConfigLoader.clearInstance();
26
26
  });
27
- (0, vitest_1.describe)('when config file does not exist', () => {
27
+ (0, vitest_1.describe)("when config file does not exist", () => {
28
28
  (0, vitest_1.beforeEach)(() => {
29
29
  mockFs.existsSync.mockReturnValue(false);
30
30
  });
31
- (0, vitest_1.describe)('getModelConfig', () => {
32
- (0, vitest_1.it)('should return default values when config file does not exist', () => {
31
+ (0, vitest_1.describe)("getModelConfig", () => {
32
+ (0, vitest_1.it)("should return default values when config file does not exist", () => {
33
33
  const modelConfig = configLoader.getModelConfig();
34
34
  (0, vitest_1.expect)(modelConfig).toEqual({
35
- primary: 'berget/glm-4.7',
36
- small: 'berget/gpt-oss'
35
+ primary: "berget/glm-4.7",
36
+ small: "berget/gpt-oss",
37
37
  });
38
38
  });
39
- (0, vitest_1.it)('should return default values when using convenience function', () => {
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
- primary: 'berget/glm-4.7',
43
- small: 'berget/gpt-oss'
42
+ primary: "berget/glm-4.7",
43
+ small: "berget/gpt-oss",
44
44
  });
45
45
  });
46
46
  });
47
- (0, vitest_1.describe)('getProviderModels', () => {
48
- (0, vitest_1.it)('should return default provider models when config file does not exist', () => {
47
+ (0, vitest_1.describe)("getProviderModels", () => {
48
+ (0, vitest_1.it)("should return default provider models when config file does not exist", () => {
49
49
  const models = configLoader.getProviderModels();
50
50
  (0, vitest_1.expect)(models).toEqual({
51
- 'glm-4.7': {
52
- name: 'GLM-4.7',
53
- limit: { output: 4000, context: 90000 }
51
+ "glm-4.7": {
52
+ name: "GLM-4.7",
53
+ limit: { output: 4000, context: 90000 },
54
54
  },
55
- 'gpt-oss': {
56
- name: 'GPT-OSS',
55
+ "gpt-oss": {
56
+ name: "GPT-OSS",
57
57
  limit: { output: 4000, context: 128000 },
58
58
  modalities: {
59
- input: ['text', 'image'],
60
- output: ['text']
61
- }
59
+ input: ["text", "image"],
60
+ output: ["text"],
61
+ },
62
+ },
63
+ "llama-8b": {
64
+ name: "llama-3.1-8b",
65
+ limit: { output: 4000, context: 128000 },
62
66
  },
63
- 'llama-8b': {
64
- name: 'llama-3.1-8b',
65
- limit: { output: 4000, context: 128000 }
66
- }
67
67
  });
68
68
  });
69
- (0, vitest_1.it)('should return default provider models when using convenience function', () => {
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
- 'glm-4.7': {
73
- name: 'GLM-4.7',
74
- limit: { output: 4000, context: 90000 }
72
+ "glm-4.7": {
73
+ name: "GLM-4.7",
74
+ limit: { output: 4000, context: 90000 },
75
75
  },
76
- 'gpt-oss': {
77
- name: 'GPT-OSS',
76
+ "gpt-oss": {
77
+ name: "GPT-OSS",
78
78
  limit: { output: 4000, context: 128000 },
79
79
  modalities: {
80
- input: ['text', 'image'],
81
- output: ['text']
82
- }
80
+ input: ["text", "image"],
81
+ output: ["text"],
82
+ },
83
+ },
84
+ "llama-8b": {
85
+ name: "llama-3.1-8b",
86
+ limit: { output: 4000, context: 128000 },
83
87
  },
84
- 'llama-8b': {
85
- name: 'llama-3.1-8b',
86
- limit: { output: 4000, context: 128000 }
87
- }
88
88
  });
89
89
  });
90
90
  });
91
- (0, vitest_1.describe)('getAllAgentConfigs', () => {
92
- (0, vitest_1.it)('should return empty object when config file does not exist', () => {
91
+ (0, vitest_1.describe)("getAllAgentConfigs", () => {
92
+ (0, vitest_1.it)("should return empty object when config file does not exist", () => {
93
93
  const agents = configLoader.getAllAgentConfigs();
94
94
  (0, vitest_1.expect)(agents).toEqual({});
95
95
  });
96
- (0, vitest_1.it)('should return empty object when using convenience function', () => {
96
+ (0, vitest_1.it)("should return empty object when using convenience function", () => {
97
97
  const agents = (0, config_loader_1.getAllAgentConfigs)(testConfigPath);
98
98
  (0, vitest_1.expect)(agents).toEqual({});
99
99
  });
100
100
  });
101
- (0, vitest_1.describe)('getAgentConfig', () => {
102
- (0, vitest_1.it)('should return null when config file does not exist', () => {
103
- const agent = configLoader.getAgentConfig('fullstack');
101
+ (0, vitest_1.describe)("getAgentConfig", () => {
102
+ (0, vitest_1.it)("should return null when config file does not exist", () => {
103
+ const agent = configLoader.getAgentConfig("fullstack");
104
104
  (0, vitest_1.expect)(agent).toBeNull();
105
105
  });
106
106
  });
107
107
  });
108
- (0, vitest_1.describe)('when config file exists', () => {
108
+ (0, vitest_1.describe)("when config file exists", () => {
109
109
  const mockConfig = {
110
- model: 'custom-model',
111
- small_model: 'custom-small-model',
110
+ model: "custom-model",
111
+ small_model: "custom-small-model",
112
112
  agent: {
113
113
  fullstack: {
114
- model: 'custom-agent-model',
114
+ model: "custom-agent-model",
115
115
  temperature: 0.5,
116
- mode: 'primary',
116
+ mode: "primary",
117
117
  permission: {
118
- edit: 'allow',
119
- bash: 'allow',
120
- webfetch: 'allow'
121
- }
122
- }
118
+ edit: "allow",
119
+ bash: "allow",
120
+ webfetch: "allow",
121
+ },
122
+ },
123
123
  },
124
124
  command: {
125
125
  test: {
126
- description: 'Test command'
127
- }
126
+ description: "Test command",
127
+ },
128
128
  },
129
129
  watcher: {
130
- ignore: ['custom-ignore']
130
+ ignore: ["custom-ignore"],
131
131
  },
132
132
  provider: {
133
133
  berget: {
134
134
  models: {
135
- 'custom-model': {
136
- name: 'Custom Model',
137
- limit: { output: 8000, context: 160000 }
138
- }
139
- }
140
- }
141
- }
135
+ "custom-model": {
136
+ name: "Custom Model",
137
+ limit: { output: 8000, context: 160000 },
138
+ },
139
+ },
140
+ },
141
+ },
142
142
  };
143
143
  (0, vitest_1.beforeEach)(() => {
144
144
  mockFs.existsSync.mockReturnValue(true);
145
145
  mockFs.readFileSync.mockReturnValue(JSON.stringify(mockConfig));
146
146
  });
147
- (0, vitest_1.describe)('getModelConfig', () => {
148
- (0, vitest_1.it)('should return values from config file', () => {
147
+ (0, vitest_1.describe)("getModelConfig", () => {
148
+ (0, vitest_1.it)("should return values from config file", () => {
149
149
  const modelConfig = configLoader.getModelConfig();
150
150
  (0, vitest_1.expect)(modelConfig).toEqual({
151
- primary: 'custom-model',
152
- small: 'custom-small-model'
151
+ primary: "custom-model",
152
+ small: "custom-small-model",
153
153
  });
154
154
  });
155
155
  });
156
- (0, vitest_1.describe)('getProviderModels', () => {
157
- (0, vitest_1.it)('should return models from config file', () => {
156
+ (0, vitest_1.describe)("getProviderModels", () => {
157
+ (0, vitest_1.it)("should return models from config file", () => {
158
158
  const models = configLoader.getProviderModels();
159
159
  (0, vitest_1.expect)(models).toEqual({
160
- 'custom-model': {
161
- name: 'Custom Model',
162
- limit: { output: 8000, context: 160000 }
163
- }
160
+ "custom-model": {
161
+ name: "Custom Model",
162
+ limit: { output: 8000, context: 160000 },
163
+ },
164
164
  });
165
165
  });
166
166
  });
167
- (0, vitest_1.describe)('getAllAgentConfigs', () => {
168
- (0, vitest_1.it)('should return agents from config file', () => {
167
+ (0, vitest_1.describe)("getAllAgentConfigs", () => {
168
+ (0, vitest_1.it)("should return agents from config file", () => {
169
169
  const agents = configLoader.getAllAgentConfigs();
170
170
  (0, vitest_1.expect)(agents).toEqual(mockConfig.agent);
171
171
  });
172
172
  });
173
- (0, vitest_1.describe)('getAgentConfig', () => {
174
- (0, vitest_1.it)('should return specific agent from config file', () => {
175
- const agent = configLoader.getAgentConfig('fullstack');
173
+ (0, vitest_1.describe)("getAgentConfig", () => {
174
+ (0, vitest_1.it)("should return specific agent from config file", () => {
175
+ const agent = configLoader.getAgentConfig("fullstack");
176
176
  (0, vitest_1.expect)(agent).toEqual(mockConfig.agent.fullstack);
177
177
  });
178
- (0, vitest_1.it)('should return null for non-existent agent', () => {
179
- const agent = configLoader.getAgentConfig('nonexistent');
178
+ (0, vitest_1.it)("should return null for non-existent agent", () => {
179
+ const agent = configLoader.getAgentConfig("nonexistent");
180
180
  (0, vitest_1.expect)(agent).toBeNull();
181
181
  });
182
182
  });
183
183
  });
184
- (0, vitest_1.describe)('when config file is invalid JSON', () => {
184
+ (0, vitest_1.describe)("when config file is invalid JSON", () => {
185
185
  (0, vitest_1.beforeEach)(() => {
186
186
  mockFs.existsSync.mockReturnValue(true);
187
- mockFs.readFileSync.mockReturnValue('invalid json {');
187
+ mockFs.readFileSync.mockReturnValue("invalid json {");
188
188
  });
189
- (0, vitest_1.it)('should fall back to defaults for getModelConfig', () => {
189
+ (0, vitest_1.it)("should fall back to defaults for getModelConfig", () => {
190
190
  const modelConfig = configLoader.getModelConfig();
191
191
  (0, vitest_1.expect)(modelConfig).toEqual({
192
- primary: 'berget/glm-4.7',
193
- small: 'berget/gpt-oss'
192
+ primary: "berget/glm-4.7",
193
+ small: "berget/gpt-oss",
194
194
  });
195
195
  });
196
- (0, vitest_1.it)('should fall back to defaults for getProviderModels', () => {
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
- 'glm-4.7': {
200
- name: 'GLM-4.7',
201
- limit: { output: 4000, context: 90000 }
199
+ "glm-4.7": {
200
+ name: "GLM-4.7",
201
+ limit: { output: 4000, context: 90000 },
202
202
  },
203
- 'gpt-oss': {
204
- name: 'GPT-OSS',
203
+ "gpt-oss": {
204
+ name: "GPT-OSS",
205
205
  limit: { output: 4000, context: 128000 },
206
206
  modalities: {
207
- input: ['text', 'image'],
208
- output: ['text']
209
- }
207
+ input: ["text", "image"],
208
+ output: ["text"],
209
+ },
210
+ },
211
+ "llama-8b": {
212
+ name: "llama-3.1-8b",
213
+ limit: { output: 4000, context: 128000 },
210
214
  },
211
- 'llama-8b': {
212
- name: 'llama-3.1-8b',
213
- limit: { output: 4000, context: 128000 }
214
- }
215
215
  });
216
216
  });
217
- (0, vitest_1.it)('should fall back to defaults for getAllAgentConfigs', () => {
217
+ (0, vitest_1.it)("should fall back to defaults for getAllAgentConfigs", () => {
218
218
  const agents = configLoader.getAllAgentConfigs();
219
219
  (0, vitest_1.expect)(agents).toEqual({});
220
220
  });
221
221
  });
222
- (0, vitest_1.describe)('singleton pattern', () => {
223
- (0, vitest_1.it)('should return the same instance for same path', () => {
222
+ (0, vitest_1.describe)("singleton pattern", () => {
223
+ (0, vitest_1.it)("should return the same instance for same path", () => {
224
224
  config_loader_1.ConfigLoader.clearInstance();
225
225
  const loader1 = config_loader_1.ConfigLoader.getInstance(testConfigPath);
226
226
  const loader2 = config_loader_1.ConfigLoader.getInstance(testConfigPath);
227
227
  (0, vitest_1.expect)(loader1).toBe(loader2);
228
228
  });
229
- (0, vitest_1.it)('should return the same instance even for different paths (true singleton)', () => {
229
+ (0, vitest_1.it)("should return the same instance even for different paths (true singleton)", () => {
230
230
  config_loader_1.ConfigLoader.clearInstance();
231
- const loader1 = config_loader_1.ConfigLoader.getInstance('/path1/config.json');
232
- const loader2 = config_loader_1.ConfigLoader.getInstance('/path2/config.json');
231
+ const loader1 = config_loader_1.ConfigLoader.getInstance("/path1/config.json");
232
+ const loader2 = config_loader_1.ConfigLoader.getInstance("/path2/config.json");
233
233
  // ConfigLoader is a true singleton - it returns the same instance regardless of path
234
234
  (0, vitest_1.expect)(loader1).toBe(loader2);
235
235
  });
236
236
  });
237
- (0, vitest_1.describe)('init scenario regression tests', () => {
238
- (0, vitest_1.it)('should handle missing config file during init scenario', () => {
237
+ (0, vitest_1.describe)("init scenario regression tests", () => {
238
+ (0, vitest_1.it)("should handle missing config file during init scenario", () => {
239
239
  // This test specifically verifies the fix for the init issue
240
240
  mockFs.existsSync.mockReturnValue(false);
241
241
  // All these methods should work without throwing errors
242
242
  (0, vitest_1.expect)(() => configLoader.getModelConfig()).not.toThrow();
243
243
  (0, vitest_1.expect)(() => configLoader.getProviderModels()).not.toThrow();
244
244
  (0, vitest_1.expect)(() => configLoader.getAllAgentConfigs()).not.toThrow();
245
- (0, vitest_1.expect)(() => configLoader.getAgentConfig('fullstack')).not.toThrow();
245
+ (0, vitest_1.expect)(() => configLoader.getAgentConfig("fullstack")).not.toThrow();
246
246
  // And return sensible defaults
247
247
  (0, vitest_1.expect)(configLoader.getModelConfig()).toEqual({
248
- primary: 'berget/glm-4.7',
249
- small: 'berget/gpt-oss'
248
+ primary: "berget/glm-4.7",
249
+ small: "berget/gpt-oss",
250
250
  });
251
251
  (0, vitest_1.expect)(configLoader.getAllAgentConfigs()).toEqual({});
252
- (0, vitest_1.expect)(configLoader.getAgentConfig('fullstack')).toBeNull();
252
+ (0, vitest_1.expect)(configLoader.getAgentConfig("fullstack")).toBeNull();
253
253
  });
254
- (0, vitest_1.it)('should work with convenience functions during init scenario', () => {
254
+ (0, vitest_1.it)("should work with convenience functions during init scenario", () => {
255
255
  // This test verifies that convenience functions also work during init
256
256
  mockFs.existsSync.mockReturnValue(false);
257
257
  (0, vitest_1.expect)(() => (0, config_loader_1.getModelConfig)(testConfigPath)).not.toThrow();
258
258
  (0, vitest_1.expect)(() => (0, config_loader_1.getProviderModels)(testConfigPath)).not.toThrow();
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
- primary: 'berget/glm-4.7',
262
- small: 'berget/gpt-oss'
261
+ primary: "berget/glm-4.7",
262
+ small: "berget/gpt-oss",
263
263
  });
264
264
  (0, vitest_1.expect)((0, config_loader_1.getAllAgentConfigs)(testConfigPath)).toEqual({});
265
265
  });
@@ -17,131 +17,131 @@ const fs_1 = __importDefault(require("fs"));
17
17
  const promises_1 = require("fs/promises");
18
18
  const path_1 = __importDefault(require("path"));
19
19
  const env_manager_1 = require("../../src/utils/env-manager");
20
- vitest_1.vi.mock('fs');
21
- vitest_1.vi.mock('fs/promises');
22
- vitest_1.vi.mock('path');
20
+ vitest_1.vi.mock("fs");
21
+ vitest_1.vi.mock("fs/promises");
22
+ vitest_1.vi.mock("path");
23
23
  const mockFs = vitest_1.vi.mocked(fs_1.default);
24
24
  const mockWriteFile = vitest_1.vi.mocked(promises_1.writeFile);
25
25
  const mockPath = vitest_1.vi.mocked(path_1.default);
26
- (0, vitest_1.describe)('env-manager', () => {
27
- const testEnvPath = '/test/.env';
28
- const testCwd = '/test';
26
+ (0, vitest_1.describe)("env-manager", () => {
27
+ const testEnvPath = "/test/.env";
28
+ const testCwd = "/test";
29
29
  (0, vitest_1.beforeEach)(() => {
30
30
  vitest_1.vi.clearAllMocks();
31
31
  mockPath.join.mockReturnValue(testEnvPath);
32
- vitest_1.vi.spyOn(process, 'cwd').mockReturnValue(testCwd);
32
+ vitest_1.vi.spyOn(process, "cwd").mockReturnValue(testCwd);
33
33
  });
34
34
  (0, vitest_1.afterEach)(() => {
35
35
  vitest_1.vi.restoreAllMocks();
36
36
  });
37
- (0, vitest_1.describe)('updateEnvFile', () => {
38
- (0, vitest_1.it)('should create a new .env file with the key when file does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
37
+ (0, vitest_1.describe)("updateEnvFile", () => {
38
+ (0, vitest_1.it)("should create a new .env file with the key when file does not exist", () => __awaiter(void 0, void 0, void 0, function* () {
39
39
  mockFs.existsSync.mockReturnValue(false);
40
40
  yield (0, env_manager_1.updateEnvFile)({
41
- key: 'TEST_KEY',
42
- value: 'test_value',
43
- comment: 'Test comment',
41
+ key: "TEST_KEY",
42
+ value: "test_value",
43
+ comment: "Test comment",
44
44
  });
45
45
  (0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvPath);
46
- (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, '# Test comment\nTEST_KEY=test_value\n');
46
+ (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, "# Test comment\nTEST_KEY=test_value\n");
47
47
  }));
48
- (0, vitest_1.it)('should append to existing .env file when key does not exist', () => __awaiter(void 0, void 0, void 0, function* () {
49
- const existingContent = 'EXISTING_KEY=existing_value\n';
48
+ (0, vitest_1.it)("should append to existing .env file when key does not exist", () => __awaiter(void 0, void 0, void 0, function* () {
49
+ const existingContent = "EXISTING_KEY=existing_value\n";
50
50
  mockFs.existsSync.mockReturnValue(true);
51
51
  mockFs.readFileSync.mockReturnValue(existingContent);
52
52
  yield (0, env_manager_1.updateEnvFile)({
53
- key: 'NEW_KEY',
54
- value: 'new_value',
55
- comment: 'Test comment',
53
+ key: "NEW_KEY",
54
+ value: "new_value",
55
+ comment: "Test comment",
56
56
  });
57
- (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, 'EXISTING_KEY=existing_value\nNEW_KEY=new_value\n');
57
+ (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, "EXISTING_KEY=existing_value\nNEW_KEY=new_value\n");
58
58
  }));
59
- (0, vitest_1.it)('should not update when key already exists and force is false', () => __awaiter(void 0, void 0, void 0, function* () {
60
- const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
59
+ (0, vitest_1.it)("should not update when key already exists and force is false", () => __awaiter(void 0, void 0, void 0, function* () {
60
+ const existingContent = "EXISTING_KEY=existing_value\nTEST_KEY=old_value\n";
61
61
  mockFs.existsSync.mockReturnValue(true);
62
62
  mockFs.readFileSync.mockReturnValue(existingContent);
63
- const consoleSpy = vitest_1.vi.spyOn(console, 'log').mockImplementation(() => { });
63
+ const consoleSpy = vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
64
64
  yield (0, env_manager_1.updateEnvFile)({
65
- key: 'TEST_KEY',
66
- value: 'new_value',
65
+ key: "TEST_KEY",
66
+ value: "new_value",
67
67
  });
68
- (0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('TEST_KEY already exists in .env - leaving unchanged'));
68
+ (0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining("TEST_KEY already exists in .env - leaving unchanged"));
69
69
  (0, vitest_1.expect)(mockWriteFile).not.toHaveBeenCalled();
70
70
  consoleSpy.mockRestore();
71
71
  }));
72
- (0, vitest_1.it)('should update existing key when force is true', () => __awaiter(void 0, void 0, void 0, function* () {
73
- const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
72
+ (0, vitest_1.it)("should update existing key when force is true", () => __awaiter(void 0, void 0, void 0, function* () {
73
+ const existingContent = "EXISTING_KEY=existing_value\nTEST_KEY=old_value\n";
74
74
  mockFs.existsSync.mockReturnValue(true);
75
75
  mockFs.readFileSync.mockReturnValue(existingContent);
76
76
  yield (0, env_manager_1.updateEnvFile)({
77
- key: 'TEST_KEY',
78
- value: 'new_value',
77
+ key: "TEST_KEY",
78
+ value: "new_value",
79
79
  force: true,
80
80
  });
81
- (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, 'EXISTING_KEY=existing_value\nTEST_KEY=new_value\n');
81
+ (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, "EXISTING_KEY=existing_value\nTEST_KEY=new_value\n");
82
82
  }));
83
- (0, vitest_1.it)('should handle complex values with quotes and special characters', () => __awaiter(void 0, void 0, void 0, function* () {
83
+ (0, vitest_1.it)("should handle complex values with quotes and special characters", () => __awaiter(void 0, void 0, void 0, function* () {
84
84
  mockFs.existsSync.mockReturnValue(false);
85
85
  yield (0, env_manager_1.updateEnvFile)({
86
- key: 'COMPLEX_KEY',
86
+ key: "COMPLEX_KEY",
87
87
  value: 'value with "quotes" and $special',
88
- comment: 'Complex test',
88
+ comment: "Complex test",
89
89
  });
90
90
  (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvPath, '# Complex test\nCOMPLEX_KEY=value with "quotes" and $special\n');
91
91
  }));
92
- (0, vitest_1.it)('should use custom env path when provided', () => __awaiter(void 0, void 0, void 0, function* () {
93
- const customPath = '/custom/.env';
92
+ (0, vitest_1.it)("should use custom env path when provided", () => __awaiter(void 0, void 0, void 0, function* () {
93
+ const customPath = "/custom/.env";
94
94
  mockFs.existsSync.mockReturnValue(false);
95
95
  yield (0, env_manager_1.updateEnvFile)({
96
96
  envPath: customPath,
97
- key: 'TEST_KEY',
98
- value: 'test_value',
97
+ key: "TEST_KEY",
98
+ value: "test_value",
99
99
  });
100
100
  (0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(customPath);
101
- (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(customPath, 'TEST_KEY=test_value\n');
101
+ (0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(customPath, "TEST_KEY=test_value\n");
102
102
  }));
103
- (0, vitest_1.it)('should throw error when write fails', () => __awaiter(void 0, void 0, void 0, function* () {
103
+ (0, vitest_1.it)("should throw error when write fails", () => __awaiter(void 0, void 0, void 0, function* () {
104
104
  mockFs.existsSync.mockReturnValue(false);
105
- mockWriteFile.mockRejectedValue(new Error('Write error'));
105
+ mockWriteFile.mockRejectedValue(new Error("Write error"));
106
106
  yield (0, vitest_1.expect)((0, env_manager_1.updateEnvFile)({
107
- key: 'TEST_KEY',
108
- value: 'test_value',
109
- })).rejects.toThrow('Write error');
107
+ key: "TEST_KEY",
108
+ value: "test_value",
109
+ })).rejects.toThrow("Write error");
110
110
  }));
111
111
  });
112
- (0, vitest_1.describe)('hasEnvKey', () => {
113
- (0, vitest_1.it)('should return false when .env file does not exist', () => {
112
+ (0, vitest_1.describe)("hasEnvKey", () => {
113
+ (0, vitest_1.it)("should return false when .env file does not exist", () => {
114
114
  mockFs.existsSync.mockReturnValue(false);
115
- const result = (0, env_manager_1.hasEnvKey)(testEnvPath, 'TEST_KEY');
115
+ const result = (0, env_manager_1.hasEnvKey)(testEnvPath, "TEST_KEY");
116
116
  (0, vitest_1.expect)(result).toBe(false);
117
117
  (0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvPath);
118
118
  (0, vitest_1.expect)(mockFs.readFileSync).not.toHaveBeenCalled();
119
119
  });
120
- (0, vitest_1.it)('should return true when key exists in .env file', () => {
121
- const existingContent = 'KEY1=value1\nTEST_KEY=test_value\nKEY2=value2\n';
120
+ (0, vitest_1.it)("should return true when key exists in .env file", () => {
121
+ const existingContent = "KEY1=value1\nTEST_KEY=test_value\nKEY2=value2\n";
122
122
  mockFs.existsSync.mockReturnValue(true);
123
123
  mockFs.readFileSync.mockReturnValue(existingContent);
124
- const result = (0, env_manager_1.hasEnvKey)(testEnvPath, 'TEST_KEY');
124
+ const result = (0, env_manager_1.hasEnvKey)(testEnvPath, "TEST_KEY");
125
125
  (0, vitest_1.expect)(result).toBe(true);
126
126
  });
127
- (0, vitest_1.it)('should return false when key does not exist in .env file', () => {
128
- const existingContent = 'KEY1=value1\nKEY2=value2\n';
127
+ (0, vitest_1.it)("should return false when key does not exist in .env file", () => {
128
+ const existingContent = "KEY1=value1\nKEY2=value2\n";
129
129
  mockFs.existsSync.mockReturnValue(true);
130
130
  mockFs.readFileSync.mockReturnValue(existingContent);
131
- const result = (0, env_manager_1.hasEnvKey)(testEnvPath, 'TEST_KEY');
131
+ const result = (0, env_manager_1.hasEnvKey)(testEnvPath, "TEST_KEY");
132
132
  (0, vitest_1.expect)(result).toBe(false);
133
133
  });
134
- (0, vitest_1.it)('should return false when .env file is malformed', () => {
134
+ (0, vitest_1.it)("should return false when .env file is malformed", () => {
135
135
  mockFs.existsSync.mockReturnValue(true);
136
136
  mockFs.readFileSync.mockImplementation(() => {
137
- throw new Error('Read error');
137
+ throw new Error("Read error");
138
138
  });
139
- const result = (0, env_manager_1.hasEnvKey)(testEnvPath, 'TEST_KEY');
139
+ const result = (0, env_manager_1.hasEnvKey)(testEnvPath, "TEST_KEY");
140
140
  (0, vitest_1.expect)(result).toBe(false);
141
141
  });
142
- (0, vitest_1.it)('should use default path when not provided', () => {
142
+ (0, vitest_1.it)("should use default path when not provided", () => {
143
143
  mockFs.existsSync.mockReturnValue(false);
144
- (0, env_manager_1.hasEnvKey)(undefined, 'TEST_KEY');
144
+ (0, env_manager_1.hasEnvKey)(undefined, "TEST_KEY");
145
145
  (0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvPath);
146
146
  });
147
147
  });