berget 2.2.7 → 2.2.9
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/.github/workflows/publish.yml +6 -6
- package/.github/workflows/test.yml +1 -1
- package/.prettierrc +5 -3
- package/dist/index.js +24 -25
- package/dist/package.json +7 -3
- package/dist/src/agents/app.js +8 -8
- package/dist/src/agents/backend.js +3 -3
- package/dist/src/agents/devops.js +8 -8
- package/dist/src/agents/frontend.js +3 -3
- package/dist/src/agents/fullstack.js +3 -3
- package/dist/src/agents/index.js +18 -18
- package/dist/src/agents/quality.js +8 -8
- package/dist/src/agents/security.js +8 -8
- package/dist/src/client.js +115 -127
- package/dist/src/commands/api-keys.js +181 -202
- package/dist/src/commands/auth.js +16 -25
- package/dist/src/commands/autocomplete.js +8 -8
- package/dist/src/commands/billing.js +10 -19
- package/dist/src/commands/chat.js +139 -170
- package/dist/src/commands/clusters.js +21 -30
- package/dist/src/commands/code/__tests__/auth-sync.test.js +189 -186
- package/dist/src/commands/code/__tests__/fake-api-key-service.js +3 -13
- package/dist/src/commands/code/__tests__/fake-auth-service.js +21 -29
- package/dist/src/commands/code/__tests__/fake-command-runner.js +22 -33
- package/dist/src/commands/code/__tests__/fake-file-store.js +19 -41
- package/dist/src/commands/code/__tests__/fake-prompter.js +81 -97
- package/dist/src/commands/code/__tests__/setup-flow.test.js +295 -295
- package/dist/src/commands/code/adapters/clack-prompter.js +15 -32
- package/dist/src/commands/code/adapters/fs-file-store.js +25 -44
- package/dist/src/commands/code/adapters/spawn-command-runner.js +27 -41
- package/dist/src/commands/code/auth-sync.js +215 -228
- package/dist/src/commands/code/errors.js +15 -12
- package/dist/src/commands/code/setup.js +390 -425
- package/dist/src/commands/code.js +279 -294
- package/dist/src/commands/index.js +5 -5
- package/dist/src/commands/models.js +16 -25
- package/dist/src/commands/users.js +9 -18
- package/dist/src/constants/command-structure.js +138 -138
- package/dist/src/services/api-key-service.js +132 -152
- package/dist/src/services/auth-service.js +81 -95
- package/dist/src/services/browser-auth.js +121 -131
- package/dist/src/services/chat-service.js +369 -386
- package/dist/src/services/cluster-service.js +47 -62
- package/dist/src/services/collaborator-service.js +9 -21
- package/dist/src/services/flux-service.js +13 -25
- package/dist/src/services/helm-service.js +9 -21
- package/dist/src/services/kubectl-service.js +15 -29
- package/dist/src/utils/config-checker.js +8 -8
- package/dist/src/utils/config-loader.js +109 -109
- package/dist/src/utils/default-api-key.js +129 -139
- package/dist/src/utils/env-manager.js +55 -66
- package/dist/src/utils/error-handler.js +62 -62
- package/dist/src/utils/logger.js +74 -67
- package/dist/src/utils/markdown-renderer.js +28 -28
- package/dist/src/utils/opencode-validator.js +67 -69
- package/dist/src/utils/token-manager.js +67 -65
- package/dist/tests/commands/chat.test.js +30 -39
- package/dist/tests/commands/code.test.js +186 -195
- package/dist/tests/utils/config-loader.test.js +107 -107
- package/dist/tests/utils/env-manager.test.js +81 -90
- package/dist/tests/utils/opencode-validator.test.js +42 -41
- package/dist/vitest.config.js +1 -1
- package/eslint.config.mjs +65 -30
- package/index.ts +30 -31
- package/package.json +7 -3
- package/src/agents/app.ts +9 -9
- package/src/agents/backend.ts +4 -4
- package/src/agents/devops.ts +9 -9
- package/src/agents/frontend.ts +4 -4
- package/src/agents/fullstack.ts +4 -4
- package/src/agents/index.ts +27 -25
- package/src/agents/quality.ts +9 -9
- package/src/agents/security.ts +9 -9
- package/src/agents/types.ts +10 -10
- package/src/client.ts +85 -77
- package/src/commands/api-keys.ts +180 -185
- package/src/commands/auth.ts +15 -14
- package/src/commands/autocomplete.ts +10 -10
- package/src/commands/billing.ts +13 -12
- package/src/commands/chat.ts +145 -142
- package/src/commands/clusters.ts +20 -19
- package/src/commands/code/__tests__/auth-sync.test.ts +176 -175
- package/src/commands/code/__tests__/fake-api-key-service.ts +2 -2
- package/src/commands/code/__tests__/fake-auth-service.ts +18 -18
- package/src/commands/code/__tests__/fake-command-runner.ts +28 -22
- package/src/commands/code/__tests__/fake-file-store.ts +15 -15
- package/src/commands/code/__tests__/fake-prompter.ts +86 -85
- package/src/commands/code/__tests__/setup-flow.test.ts +253 -251
- package/src/commands/code/adapters/clack-prompter.ts +32 -30
- package/src/commands/code/adapters/fs-file-store.ts +18 -17
- package/src/commands/code/adapters/spawn-command-runner.ts +20 -15
- package/src/commands/code/auth-sync.ts +210 -210
- package/src/commands/code/errors.ts +11 -11
- package/src/commands/code/ports/auth-services.ts +7 -7
- package/src/commands/code/ports/command-runner.ts +2 -2
- package/src/commands/code/ports/file-store.ts +3 -3
- package/src/commands/code/ports/prompter.ts +13 -13
- package/src/commands/code/setup.ts +408 -406
- package/src/commands/code.ts +288 -287
- package/src/commands/index.ts +11 -10
- package/src/commands/models.ts +19 -18
- package/src/commands/users.ts +11 -10
- package/src/constants/command-structure.ts +159 -159
- package/src/services/api-key-service.ts +85 -85
- package/src/services/auth-service.ts +55 -54
- package/src/services/browser-auth.ts +62 -62
- package/src/services/chat-service.ts +170 -171
- package/src/services/cluster-service.ts +28 -28
- package/src/services/collaborator-service.ts +6 -6
- package/src/services/flux-service.ts +17 -17
- package/src/services/helm-service.ts +11 -11
- package/src/services/kubectl-service.ts +12 -12
- package/src/types/api.d.ts +1933 -1933
- package/src/types/json.d.ts +1 -1
- package/src/utils/config-checker.ts +7 -7
- package/src/utils/config-loader.ts +130 -129
- package/src/utils/default-api-key.ts +81 -80
- package/src/utils/env-manager.ts +37 -37
- package/src/utils/error-handler.ts +64 -64
- package/src/utils/logger.ts +72 -66
- package/src/utils/markdown-renderer.ts +28 -28
- package/src/utils/opencode-validator.ts +72 -71
- package/src/utils/token-manager.ts +69 -68
- package/tests/commands/chat.test.ts +32 -31
- package/tests/commands/code.test.ts +182 -181
- package/tests/utils/config-loader.test.ts +111 -110
- package/tests/utils/env-manager.test.ts +83 -79
- package/tests/utils/opencode-validator.test.ts +43 -42
- package/tsconfig.json +2 -1
- package/vitest.config.ts +2 -2
|
@@ -5,13 +5,13 @@ 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
|
-
vitest_1.vi.mock(
|
|
13
|
-
(0, vitest_1.describe)(
|
|
14
|
-
const testConfigPath =
|
|
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)(
|
|
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)(
|
|
32
|
-
(0, vitest_1.it)(
|
|
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:
|
|
36
|
-
small:
|
|
35
|
+
primary: 'berget/glm-4.7',
|
|
36
|
+
small: 'berget/gpt-oss',
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
|
-
(0, vitest_1.it)(
|
|
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:
|
|
43
|
-
small:
|
|
42
|
+
primary: 'berget/glm-4.7',
|
|
43
|
+
small: 'berget/gpt-oss',
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
|
-
(0, vitest_1.describe)(
|
|
48
|
-
(0, vitest_1.it)(
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
'glm-4.7': {
|
|
52
|
+
limit: { context: 90000, output: 4000 },
|
|
53
|
+
name: 'GLM-4.7',
|
|
54
54
|
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
limit: { output: 4000, context: 128000 },
|
|
55
|
+
'gpt-oss': {
|
|
56
|
+
limit: { context: 128000, output: 4000 },
|
|
58
57
|
modalities: {
|
|
59
|
-
input: [
|
|
60
|
-
output: [
|
|
58
|
+
input: ['text', 'image'],
|
|
59
|
+
output: ['text'],
|
|
61
60
|
},
|
|
61
|
+
name: 'GPT-OSS',
|
|
62
62
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
'llama-8b': {
|
|
64
|
+
limit: { context: 128000, output: 4000 },
|
|
65
|
+
name: 'llama-3.1-8b',
|
|
66
66
|
},
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
|
-
(0, vitest_1.it)(
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
'glm-4.7': {
|
|
73
|
+
limit: { context: 90000, output: 4000 },
|
|
74
|
+
name: 'GLM-4.7',
|
|
75
75
|
},
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
limit: { output: 4000, context: 128000 },
|
|
76
|
+
'gpt-oss': {
|
|
77
|
+
limit: { context: 128000, output: 4000 },
|
|
79
78
|
modalities: {
|
|
80
|
-
input: [
|
|
81
|
-
output: [
|
|
79
|
+
input: ['text', 'image'],
|
|
80
|
+
output: ['text'],
|
|
82
81
|
},
|
|
82
|
+
name: 'GPT-OSS',
|
|
83
83
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
'llama-8b': {
|
|
85
|
+
limit: { context: 128000, output: 4000 },
|
|
86
|
+
name: 'llama-3.1-8b',
|
|
87
87
|
},
|
|
88
88
|
});
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
|
-
(0, vitest_1.describe)(
|
|
92
|
-
(0, vitest_1.it)(
|
|
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)(
|
|
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)(
|
|
102
|
-
(0, vitest_1.it)(
|
|
103
|
-
const agent = configLoader.getAgentConfig(
|
|
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)(
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
mode: "primary",
|
|
112
|
+
mode: 'primary',
|
|
113
|
+
model: 'custom-agent-model',
|
|
117
114
|
permission: {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
webfetch:
|
|
115
|
+
bash: 'allow',
|
|
116
|
+
edit: 'allow',
|
|
117
|
+
webfetch: 'allow',
|
|
121
118
|
},
|
|
119
|
+
temperature: 0.5,
|
|
122
120
|
},
|
|
123
121
|
},
|
|
124
122
|
command: {
|
|
125
123
|
test: {
|
|
126
|
-
description:
|
|
124
|
+
description: 'Test command',
|
|
127
125
|
},
|
|
128
126
|
},
|
|
129
|
-
|
|
130
|
-
ignore: ["custom-ignore"],
|
|
131
|
-
},
|
|
127
|
+
model: 'custom-model',
|
|
132
128
|
provider: {
|
|
133
129
|
berget: {
|
|
134
130
|
models: {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
'custom-model': {
|
|
132
|
+
limit: { context: 160000, output: 8000 },
|
|
133
|
+
name: 'Custom Model',
|
|
138
134
|
},
|
|
139
135
|
},
|
|
140
136
|
},
|
|
141
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);
|
|
145
145
|
mockFs.readFileSync.mockReturnValue(JSON.stringify(mockConfig));
|
|
146
146
|
});
|
|
147
|
-
(0, vitest_1.describe)(
|
|
148
|
-
(0, vitest_1.it)(
|
|
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:
|
|
152
|
-
small:
|
|
151
|
+
primary: 'custom-model',
|
|
152
|
+
small: 'custom-small-model',
|
|
153
153
|
});
|
|
154
154
|
});
|
|
155
155
|
});
|
|
156
|
-
(0, vitest_1.describe)(
|
|
157
|
-
(0, vitest_1.it)(
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
'custom-model': {
|
|
161
|
+
limit: { context: 160000, output: 8000 },
|
|
162
|
+
name: 'Custom Model',
|
|
163
163
|
},
|
|
164
164
|
});
|
|
165
165
|
});
|
|
166
166
|
});
|
|
167
|
-
(0, vitest_1.describe)(
|
|
168
|
-
(0, vitest_1.it)(
|
|
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)(
|
|
174
|
-
(0, vitest_1.it)(
|
|
175
|
-
const agent = configLoader.getAgentConfig(
|
|
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)(
|
|
179
|
-
const agent = configLoader.getAgentConfig(
|
|
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)(
|
|
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(
|
|
187
|
+
mockFs.readFileSync.mockReturnValue('invalid json {');
|
|
188
188
|
});
|
|
189
|
-
(0, vitest_1.it)(
|
|
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:
|
|
193
|
-
small:
|
|
192
|
+
primary: 'berget/glm-4.7',
|
|
193
|
+
small: 'berget/gpt-oss',
|
|
194
194
|
});
|
|
195
195
|
});
|
|
196
|
-
(0, vitest_1.it)(
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
'glm-4.7': {
|
|
200
|
+
limit: { context: 90000, output: 4000 },
|
|
201
|
+
name: 'GLM-4.7',
|
|
202
202
|
},
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
limit: { output: 4000, context: 128000 },
|
|
203
|
+
'gpt-oss': {
|
|
204
|
+
limit: { context: 128000, output: 4000 },
|
|
206
205
|
modalities: {
|
|
207
|
-
input: [
|
|
208
|
-
output: [
|
|
206
|
+
input: ['text', 'image'],
|
|
207
|
+
output: ['text'],
|
|
209
208
|
},
|
|
209
|
+
name: 'GPT-OSS',
|
|
210
210
|
},
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
211
|
+
'llama-8b': {
|
|
212
|
+
limit: { context: 128000, output: 4000 },
|
|
213
|
+
name: 'llama-3.1-8b',
|
|
214
214
|
},
|
|
215
215
|
});
|
|
216
216
|
});
|
|
217
|
-
(0, vitest_1.it)(
|
|
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)(
|
|
223
|
-
(0, vitest_1.it)(
|
|
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)(
|
|
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(
|
|
232
|
-
const loader2 = config_loader_1.ConfigLoader.getInstance(
|
|
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)(
|
|
238
|
-
(0, vitest_1.it)(
|
|
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(
|
|
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:
|
|
249
|
-
small:
|
|
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(
|
|
252
|
+
(0, vitest_1.expect)(configLoader.getAgentConfig('fullstack')).toBeNull();
|
|
253
253
|
});
|
|
254
|
-
(0, vitest_1.it)(
|
|
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:
|
|
262
|
-
small:
|
|
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
|
});
|
|
@@ -1,148 +1,139 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
4
|
};
|
|
14
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
7
|
+
const promises_1 = require("node:fs/promises");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
15
9
|
const vitest_1 = require("vitest");
|
|
16
|
-
const fs_1 = __importDefault(require("fs"));
|
|
17
|
-
const promises_1 = require("fs/promises");
|
|
18
|
-
const path_1 = __importDefault(require("path"));
|
|
19
10
|
const env_manager_1 = require("../../src/utils/env-manager");
|
|
20
|
-
vitest_1.vi.mock(
|
|
21
|
-
vitest_1.vi.mock(
|
|
22
|
-
vitest_1.vi.mock(
|
|
23
|
-
const mockFs = vitest_1.vi.mocked(
|
|
11
|
+
vitest_1.vi.mock('fs');
|
|
12
|
+
vitest_1.vi.mock('fs/promises');
|
|
13
|
+
vitest_1.vi.mock('path');
|
|
14
|
+
const mockFs = vitest_1.vi.mocked(node_fs_1.default);
|
|
24
15
|
const mockWriteFile = vitest_1.vi.mocked(promises_1.writeFile);
|
|
25
|
-
const mockPath = vitest_1.vi.mocked(
|
|
26
|
-
(0, vitest_1.describe)(
|
|
27
|
-
const
|
|
28
|
-
const testCwd =
|
|
16
|
+
const mockPath = vitest_1.vi.mocked(node_path_1.default);
|
|
17
|
+
(0, vitest_1.describe)('env-manager', () => {
|
|
18
|
+
const testEnvironmentPath = '/test/.env';
|
|
19
|
+
const testCwd = '/test';
|
|
29
20
|
(0, vitest_1.beforeEach)(() => {
|
|
30
21
|
vitest_1.vi.clearAllMocks();
|
|
31
|
-
mockPath.join.mockReturnValue(
|
|
32
|
-
vitest_1.vi.spyOn(process,
|
|
22
|
+
mockPath.join.mockReturnValue(testEnvironmentPath);
|
|
23
|
+
vitest_1.vi.spyOn(process, 'cwd').mockReturnValue(testCwd);
|
|
33
24
|
});
|
|
34
25
|
(0, vitest_1.afterEach)(() => {
|
|
35
26
|
vitest_1.vi.restoreAllMocks();
|
|
36
27
|
});
|
|
37
|
-
(0, vitest_1.describe)(
|
|
38
|
-
(0, vitest_1.it)(
|
|
28
|
+
(0, vitest_1.describe)('updateEnvFile', () => {
|
|
29
|
+
(0, vitest_1.it)('should create a new .env file with the key when file does not exist', async () => {
|
|
39
30
|
mockFs.existsSync.mockReturnValue(false);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
32
|
+
comment: 'Test comment',
|
|
33
|
+
key: 'TEST_KEY',
|
|
34
|
+
value: 'test_value',
|
|
44
35
|
});
|
|
45
|
-
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(
|
|
46
|
-
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(
|
|
47
|
-
})
|
|
48
|
-
(0, vitest_1.it)(
|
|
49
|
-
const existingContent =
|
|
36
|
+
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
37
|
+
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvironmentPath, '# Test comment\nTEST_KEY=test_value\n');
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)('should append to existing .env file when key does not exist', async () => {
|
|
40
|
+
const existingContent = 'EXISTING_KEY=existing_value\n';
|
|
50
41
|
mockFs.existsSync.mockReturnValue(true);
|
|
51
42
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
44
|
+
comment: 'Test comment',
|
|
45
|
+
key: 'NEW_KEY',
|
|
46
|
+
value: 'new_value',
|
|
56
47
|
});
|
|
57
|
-
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(
|
|
58
|
-
})
|
|
59
|
-
(0, vitest_1.it)(
|
|
60
|
-
const existingContent =
|
|
48
|
+
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvironmentPath, 'EXISTING_KEY=existing_value\nNEW_KEY=new_value\n');
|
|
49
|
+
});
|
|
50
|
+
(0, vitest_1.it)('should not update when key already exists and force is false', async () => {
|
|
51
|
+
const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
|
|
61
52
|
mockFs.existsSync.mockReturnValue(true);
|
|
62
53
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
63
|
-
const consoleSpy = vitest_1.vi.spyOn(console,
|
|
64
|
-
|
|
65
|
-
key:
|
|
66
|
-
value:
|
|
54
|
+
const consoleSpy = vitest_1.vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
55
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
56
|
+
key: 'TEST_KEY',
|
|
57
|
+
value: 'new_value',
|
|
67
58
|
});
|
|
68
|
-
(0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining(
|
|
59
|
+
(0, vitest_1.expect)(consoleSpy).toHaveBeenCalledWith(vitest_1.expect.stringContaining('TEST_KEY already exists in .env - leaving unchanged'));
|
|
69
60
|
(0, vitest_1.expect)(mockWriteFile).not.toHaveBeenCalled();
|
|
70
61
|
consoleSpy.mockRestore();
|
|
71
|
-
})
|
|
72
|
-
(0, vitest_1.it)(
|
|
73
|
-
const existingContent =
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('should update existing key when force is true', async () => {
|
|
64
|
+
const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
|
|
74
65
|
mockFs.existsSync.mockReturnValue(true);
|
|
75
66
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
76
|
-
|
|
77
|
-
key: "TEST_KEY",
|
|
78
|
-
value: "new_value",
|
|
67
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
79
68
|
force: true,
|
|
69
|
+
key: 'TEST_KEY',
|
|
70
|
+
value: 'new_value',
|
|
80
71
|
});
|
|
81
|
-
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(
|
|
82
|
-
})
|
|
83
|
-
(0, vitest_1.it)(
|
|
72
|
+
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvironmentPath, 'EXISTING_KEY=existing_value\nTEST_KEY=new_value\n');
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)('should handle complex values with quotes and special characters', async () => {
|
|
84
75
|
mockFs.existsSync.mockReturnValue(false);
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
77
|
+
comment: 'Complex test',
|
|
78
|
+
key: 'COMPLEX_KEY',
|
|
87
79
|
value: 'value with "quotes" and $special',
|
|
88
|
-
comment: "Complex test",
|
|
89
80
|
});
|
|
90
|
-
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(
|
|
91
|
-
})
|
|
92
|
-
(0, vitest_1.it)(
|
|
93
|
-
const customPath =
|
|
81
|
+
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(testEnvironmentPath, '# Complex test\nCOMPLEX_KEY=value with "quotes" and $special\n');
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)('should use custom env path when provided', async () => {
|
|
84
|
+
const customPath = '/custom/.env';
|
|
94
85
|
mockFs.existsSync.mockReturnValue(false);
|
|
95
|
-
|
|
86
|
+
await (0, env_manager_1.updateEnvFile)({
|
|
96
87
|
envPath: customPath,
|
|
97
|
-
key:
|
|
98
|
-
value:
|
|
88
|
+
key: 'TEST_KEY',
|
|
89
|
+
value: 'test_value',
|
|
99
90
|
});
|
|
100
91
|
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(customPath);
|
|
101
|
-
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(customPath,
|
|
102
|
-
})
|
|
103
|
-
(0, vitest_1.it)(
|
|
92
|
+
(0, vitest_1.expect)(mockWriteFile).toHaveBeenCalledWith(customPath, 'TEST_KEY=test_value\n');
|
|
93
|
+
});
|
|
94
|
+
(0, vitest_1.it)('should throw error when write fails', async () => {
|
|
104
95
|
mockFs.existsSync.mockReturnValue(false);
|
|
105
|
-
mockWriteFile.mockRejectedValue(new Error(
|
|
106
|
-
|
|
107
|
-
key:
|
|
108
|
-
value:
|
|
109
|
-
})).rejects.toThrow(
|
|
110
|
-
})
|
|
96
|
+
mockWriteFile.mockRejectedValue(new Error('Write error'));
|
|
97
|
+
await (0, vitest_1.expect)((0, env_manager_1.updateEnvFile)({
|
|
98
|
+
key: 'TEST_KEY',
|
|
99
|
+
value: 'test_value',
|
|
100
|
+
})).rejects.toThrow('Write error');
|
|
101
|
+
});
|
|
111
102
|
});
|
|
112
|
-
(0, vitest_1.describe)(
|
|
113
|
-
(0, vitest_1.it)(
|
|
103
|
+
(0, vitest_1.describe)('hasEnvKey', () => {
|
|
104
|
+
(0, vitest_1.it)('should return false when .env file does not exist', () => {
|
|
114
105
|
mockFs.existsSync.mockReturnValue(false);
|
|
115
|
-
const result = (0, env_manager_1.hasEnvKey)(
|
|
106
|
+
const result = (0, env_manager_1.hasEnvKey)(testEnvironmentPath, 'TEST_KEY');
|
|
116
107
|
(0, vitest_1.expect)(result).toBe(false);
|
|
117
|
-
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(
|
|
108
|
+
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
118
109
|
(0, vitest_1.expect)(mockFs.readFileSync).not.toHaveBeenCalled();
|
|
119
110
|
});
|
|
120
|
-
(0, vitest_1.it)(
|
|
121
|
-
const existingContent =
|
|
111
|
+
(0, vitest_1.it)('should return true when key exists in .env file', () => {
|
|
112
|
+
const existingContent = 'KEY1=value1\nTEST_KEY=test_value\nKEY2=value2\n';
|
|
122
113
|
mockFs.existsSync.mockReturnValue(true);
|
|
123
114
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
124
|
-
const result = (0, env_manager_1.hasEnvKey)(
|
|
115
|
+
const result = (0, env_manager_1.hasEnvKey)(testEnvironmentPath, 'TEST_KEY');
|
|
125
116
|
(0, vitest_1.expect)(result).toBe(true);
|
|
126
117
|
});
|
|
127
|
-
(0, vitest_1.it)(
|
|
128
|
-
const existingContent =
|
|
118
|
+
(0, vitest_1.it)('should return false when key does not exist in .env file', () => {
|
|
119
|
+
const existingContent = 'KEY1=value1\nKEY2=value2\n';
|
|
129
120
|
mockFs.existsSync.mockReturnValue(true);
|
|
130
121
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
131
|
-
const result = (0, env_manager_1.hasEnvKey)(
|
|
122
|
+
const result = (0, env_manager_1.hasEnvKey)(testEnvironmentPath, 'TEST_KEY');
|
|
132
123
|
(0, vitest_1.expect)(result).toBe(false);
|
|
133
124
|
});
|
|
134
|
-
(0, vitest_1.it)(
|
|
125
|
+
(0, vitest_1.it)('should return false when .env file is malformed', () => {
|
|
135
126
|
mockFs.existsSync.mockReturnValue(true);
|
|
136
127
|
mockFs.readFileSync.mockImplementation(() => {
|
|
137
|
-
throw new Error(
|
|
128
|
+
throw new Error('Read error');
|
|
138
129
|
});
|
|
139
|
-
const result = (0, env_manager_1.hasEnvKey)(
|
|
130
|
+
const result = (0, env_manager_1.hasEnvKey)(testEnvironmentPath, 'TEST_KEY');
|
|
140
131
|
(0, vitest_1.expect)(result).toBe(false);
|
|
141
132
|
});
|
|
142
|
-
(0, vitest_1.it)(
|
|
133
|
+
(0, vitest_1.it)('should use default path when not provided', () => {
|
|
143
134
|
mockFs.existsSync.mockReturnValue(false);
|
|
144
|
-
(0, env_manager_1.hasEnvKey)(undefined,
|
|
145
|
-
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(
|
|
135
|
+
(0, env_manager_1.hasEnvKey)(undefined, 'TEST_KEY');
|
|
136
|
+
(0, vitest_1.expect)(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
146
137
|
});
|
|
147
138
|
});
|
|
148
139
|
});
|