berget 2.2.7 → 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.
- 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 +5 -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 +195 -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 +7 -7
- 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 +50 -30
- package/index.ts +30 -31
- package/package.json +5 -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 +190 -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 +169 -170
- 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 +6 -6
- 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
|
@@ -1,192 +1,196 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { updateEnvFile, hasEnvKey } from "../../src/utils/env-manager";
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import {
|
|
7
|
+
hasEnvKey as hasEnvironmentKey,
|
|
8
|
+
updateEnvFile as updateEnvironmentFile,
|
|
9
|
+
} from '../../src/utils/env-manager';
|
|
10
|
+
|
|
11
|
+
vi.mock('fs');
|
|
12
|
+
vi.mock('fs/promises');
|
|
13
|
+
vi.mock('path');
|
|
10
14
|
|
|
11
15
|
const mockFs = vi.mocked(fs);
|
|
12
16
|
const mockWriteFile = vi.mocked(writeFile);
|
|
13
17
|
const mockPath = vi.mocked(path);
|
|
14
18
|
|
|
15
|
-
describe(
|
|
16
|
-
const
|
|
17
|
-
const testCwd =
|
|
19
|
+
describe('env-manager', () => {
|
|
20
|
+
const testEnvironmentPath = '/test/.env';
|
|
21
|
+
const testCwd = '/test';
|
|
18
22
|
|
|
19
23
|
beforeEach(() => {
|
|
20
24
|
vi.clearAllMocks();
|
|
21
|
-
mockPath.join.mockReturnValue(
|
|
22
|
-
vi.spyOn(process,
|
|
25
|
+
mockPath.join.mockReturnValue(testEnvironmentPath);
|
|
26
|
+
vi.spyOn(process, 'cwd').mockReturnValue(testCwd);
|
|
23
27
|
});
|
|
24
28
|
|
|
25
29
|
afterEach(() => {
|
|
26
30
|
vi.restoreAllMocks();
|
|
27
31
|
});
|
|
28
32
|
|
|
29
|
-
describe(
|
|
30
|
-
it(
|
|
33
|
+
describe('updateEnvFile', () => {
|
|
34
|
+
it('should create a new .env file with the key when file does not exist', async () => {
|
|
31
35
|
mockFs.existsSync.mockReturnValue(false);
|
|
32
36
|
|
|
33
|
-
await
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
await updateEnvironmentFile({
|
|
38
|
+
comment: 'Test comment',
|
|
39
|
+
key: 'TEST_KEY',
|
|
40
|
+
value: 'test_value',
|
|
37
41
|
});
|
|
38
42
|
|
|
39
|
-
expect(mockFs.existsSync).toHaveBeenCalledWith(
|
|
43
|
+
expect(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
40
44
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
testEnvironmentPath,
|
|
46
|
+
'# Test comment\nTEST_KEY=test_value\n',
|
|
43
47
|
);
|
|
44
48
|
});
|
|
45
49
|
|
|
46
|
-
it(
|
|
47
|
-
const existingContent =
|
|
50
|
+
it('should append to existing .env file when key does not exist', async () => {
|
|
51
|
+
const existingContent = 'EXISTING_KEY=existing_value\n';
|
|
48
52
|
mockFs.existsSync.mockReturnValue(true);
|
|
49
53
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
50
54
|
|
|
51
|
-
await
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
await updateEnvironmentFile({
|
|
56
|
+
comment: 'Test comment',
|
|
57
|
+
key: 'NEW_KEY',
|
|
58
|
+
value: 'new_value',
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
testEnvironmentPath,
|
|
63
|
+
'EXISTING_KEY=existing_value\nNEW_KEY=new_value\n',
|
|
60
64
|
);
|
|
61
65
|
});
|
|
62
66
|
|
|
63
|
-
it(
|
|
64
|
-
const existingContent =
|
|
67
|
+
it('should not update when key already exists and force is false', async () => {
|
|
68
|
+
const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
|
|
65
69
|
mockFs.existsSync.mockReturnValue(true);
|
|
66
70
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
67
71
|
|
|
68
|
-
const consoleSpy = vi.spyOn(console,
|
|
72
|
+
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
69
73
|
|
|
70
|
-
await
|
|
71
|
-
key:
|
|
72
|
-
value:
|
|
74
|
+
await updateEnvironmentFile({
|
|
75
|
+
key: 'TEST_KEY',
|
|
76
|
+
value: 'new_value',
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
expect(consoleSpy).toHaveBeenCalledWith(
|
|
76
|
-
expect.stringContaining(
|
|
80
|
+
expect.stringContaining('TEST_KEY already exists in .env - leaving unchanged'),
|
|
77
81
|
);
|
|
78
82
|
expect(mockWriteFile).not.toHaveBeenCalled();
|
|
79
83
|
|
|
80
84
|
consoleSpy.mockRestore();
|
|
81
85
|
});
|
|
82
86
|
|
|
83
|
-
it(
|
|
84
|
-
const existingContent =
|
|
87
|
+
it('should update existing key when force is true', async () => {
|
|
88
|
+
const existingContent = 'EXISTING_KEY=existing_value\nTEST_KEY=old_value\n';
|
|
85
89
|
mockFs.existsSync.mockReturnValue(true);
|
|
86
90
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
87
91
|
|
|
88
|
-
await
|
|
89
|
-
key: "TEST_KEY",
|
|
90
|
-
value: "new_value",
|
|
92
|
+
await updateEnvironmentFile({
|
|
91
93
|
force: true,
|
|
94
|
+
key: 'TEST_KEY',
|
|
95
|
+
value: 'new_value',
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
testEnvironmentPath,
|
|
100
|
+
'EXISTING_KEY=existing_value\nTEST_KEY=new_value\n',
|
|
97
101
|
);
|
|
98
102
|
});
|
|
99
103
|
|
|
100
|
-
it(
|
|
104
|
+
it('should handle complex values with quotes and special characters', async () => {
|
|
101
105
|
mockFs.existsSync.mockReturnValue(false);
|
|
102
106
|
|
|
103
|
-
await
|
|
104
|
-
|
|
107
|
+
await updateEnvironmentFile({
|
|
108
|
+
comment: 'Complex test',
|
|
109
|
+
key: 'COMPLEX_KEY',
|
|
105
110
|
value: 'value with "quotes" and $special',
|
|
106
|
-
comment: "Complex test",
|
|
107
111
|
});
|
|
108
112
|
|
|
109
113
|
expect(mockWriteFile).toHaveBeenCalledWith(
|
|
110
|
-
|
|
111
|
-
'# Complex test\nCOMPLEX_KEY=value with "quotes" and $special\n'
|
|
114
|
+
testEnvironmentPath,
|
|
115
|
+
'# Complex test\nCOMPLEX_KEY=value with "quotes" and $special\n',
|
|
112
116
|
);
|
|
113
117
|
});
|
|
114
118
|
|
|
115
|
-
it(
|
|
116
|
-
const customPath =
|
|
119
|
+
it('should use custom env path when provided', async () => {
|
|
120
|
+
const customPath = '/custom/.env';
|
|
117
121
|
mockFs.existsSync.mockReturnValue(false);
|
|
118
122
|
|
|
119
|
-
await
|
|
123
|
+
await updateEnvironmentFile({
|
|
120
124
|
envPath: customPath,
|
|
121
|
-
key:
|
|
122
|
-
value:
|
|
125
|
+
key: 'TEST_KEY',
|
|
126
|
+
value: 'test_value',
|
|
123
127
|
});
|
|
124
128
|
|
|
125
129
|
expect(mockFs.existsSync).toHaveBeenCalledWith(customPath);
|
|
126
|
-
expect(mockWriteFile).toHaveBeenCalledWith(customPath,
|
|
130
|
+
expect(mockWriteFile).toHaveBeenCalledWith(customPath, 'TEST_KEY=test_value\n');
|
|
127
131
|
});
|
|
128
132
|
|
|
129
|
-
it(
|
|
133
|
+
it('should throw error when write fails', async () => {
|
|
130
134
|
mockFs.existsSync.mockReturnValue(false);
|
|
131
|
-
mockWriteFile.mockRejectedValue(new Error(
|
|
135
|
+
mockWriteFile.mockRejectedValue(new Error('Write error'));
|
|
132
136
|
|
|
133
137
|
await expect(
|
|
134
|
-
|
|
135
|
-
key:
|
|
136
|
-
value:
|
|
137
|
-
})
|
|
138
|
-
).rejects.toThrow(
|
|
138
|
+
updateEnvironmentFile({
|
|
139
|
+
key: 'TEST_KEY',
|
|
140
|
+
value: 'test_value',
|
|
141
|
+
}),
|
|
142
|
+
).rejects.toThrow('Write error');
|
|
139
143
|
});
|
|
140
144
|
});
|
|
141
145
|
|
|
142
|
-
describe(
|
|
143
|
-
it(
|
|
146
|
+
describe('hasEnvKey', () => {
|
|
147
|
+
it('should return false when .env file does not exist', () => {
|
|
144
148
|
mockFs.existsSync.mockReturnValue(false);
|
|
145
149
|
|
|
146
|
-
const result =
|
|
150
|
+
const result = hasEnvironmentKey(testEnvironmentPath, 'TEST_KEY');
|
|
147
151
|
|
|
148
152
|
expect(result).toBe(false);
|
|
149
|
-
expect(mockFs.existsSync).toHaveBeenCalledWith(
|
|
153
|
+
expect(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
150
154
|
expect(mockFs.readFileSync).not.toHaveBeenCalled();
|
|
151
155
|
});
|
|
152
156
|
|
|
153
|
-
it(
|
|
154
|
-
const existingContent =
|
|
157
|
+
it('should return true when key exists in .env file', () => {
|
|
158
|
+
const existingContent = 'KEY1=value1\nTEST_KEY=test_value\nKEY2=value2\n';
|
|
155
159
|
mockFs.existsSync.mockReturnValue(true);
|
|
156
160
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
157
161
|
|
|
158
|
-
const result =
|
|
162
|
+
const result = hasEnvironmentKey(testEnvironmentPath, 'TEST_KEY');
|
|
159
163
|
|
|
160
164
|
expect(result).toBe(true);
|
|
161
165
|
});
|
|
162
166
|
|
|
163
|
-
it(
|
|
164
|
-
const existingContent =
|
|
167
|
+
it('should return false when key does not exist in .env file', () => {
|
|
168
|
+
const existingContent = 'KEY1=value1\nKEY2=value2\n';
|
|
165
169
|
mockFs.existsSync.mockReturnValue(true);
|
|
166
170
|
mockFs.readFileSync.mockReturnValue(existingContent);
|
|
167
171
|
|
|
168
|
-
const result =
|
|
172
|
+
const result = hasEnvironmentKey(testEnvironmentPath, 'TEST_KEY');
|
|
169
173
|
|
|
170
174
|
expect(result).toBe(false);
|
|
171
175
|
});
|
|
172
176
|
|
|
173
|
-
it(
|
|
177
|
+
it('should return false when .env file is malformed', () => {
|
|
174
178
|
mockFs.existsSync.mockReturnValue(true);
|
|
175
179
|
mockFs.readFileSync.mockImplementation(() => {
|
|
176
|
-
throw new Error(
|
|
180
|
+
throw new Error('Read error');
|
|
177
181
|
});
|
|
178
182
|
|
|
179
|
-
const result =
|
|
183
|
+
const result = hasEnvironmentKey(testEnvironmentPath, 'TEST_KEY');
|
|
180
184
|
|
|
181
185
|
expect(result).toBe(false);
|
|
182
186
|
});
|
|
183
187
|
|
|
184
|
-
it(
|
|
188
|
+
it('should use default path when not provided', () => {
|
|
185
189
|
mockFs.existsSync.mockReturnValue(false);
|
|
186
190
|
|
|
187
|
-
|
|
191
|
+
hasEnvironmentKey(undefined, 'TEST_KEY');
|
|
188
192
|
|
|
189
|
-
expect(mockFs.existsSync).toHaveBeenCalledWith(
|
|
193
|
+
expect(mockFs.existsSync).toHaveBeenCalledWith(testEnvironmentPath);
|
|
190
194
|
});
|
|
191
195
|
});
|
|
192
196
|
});
|
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { readFileSync } from "fs";
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { fixOpenCodeConfig, validateOpenCodeConfig } from '../../src/utils/opencode-validator';
|
|
5
|
+
|
|
6
|
+
describe('OpenCode Validator', () => {
|
|
7
|
+
it('should validate a correct OpenCode configuration', () => {
|
|
7
8
|
const validConfig = {
|
|
8
|
-
$schema:
|
|
9
|
-
username: "test-user",
|
|
10
|
-
model: "gpt-4",
|
|
9
|
+
$schema: 'https://opencode.ai/config.json',
|
|
11
10
|
agent: {
|
|
12
11
|
test: {
|
|
13
|
-
model:
|
|
14
|
-
temperature: 0.7,
|
|
15
|
-
prompt: "Test agent",
|
|
12
|
+
model: 'gpt-4',
|
|
16
13
|
permission: {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
webfetch:
|
|
14
|
+
bash: 'allow',
|
|
15
|
+
edit: 'allow',
|
|
16
|
+
webfetch: 'allow',
|
|
20
17
|
},
|
|
18
|
+
prompt: 'Test agent',
|
|
19
|
+
temperature: 0.7,
|
|
21
20
|
},
|
|
22
21
|
},
|
|
22
|
+
model: 'gpt-4',
|
|
23
|
+
username: 'test-user',
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
const result = validateOpenCodeConfig(validConfig);
|
|
@@ -27,22 +28,22 @@ describe("OpenCode Validator", () => {
|
|
|
27
28
|
expect(result.errors).toBeUndefined();
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
it(
|
|
31
|
+
it('should reject invalid configuration', () => {
|
|
31
32
|
const invalidConfig = {
|
|
32
|
-
username: 123, // Should be string
|
|
33
|
-
model: "gpt-4",
|
|
34
33
|
agent: {
|
|
35
34
|
test: {
|
|
36
|
-
model:
|
|
37
|
-
temperature: "high", // Should be number
|
|
38
|
-
prompt: "Test agent",
|
|
35
|
+
model: 'gpt-4',
|
|
39
36
|
permission: {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
webfetch:
|
|
37
|
+
bash: 'allow',
|
|
38
|
+
edit: 'invalid', // Should be enum value
|
|
39
|
+
webfetch: 'allow',
|
|
43
40
|
},
|
|
41
|
+
prompt: 'Test agent',
|
|
42
|
+
temperature: 'high', // Should be number
|
|
44
43
|
},
|
|
45
44
|
},
|
|
45
|
+
model: 'gpt-4',
|
|
46
|
+
username: 123, // Should be string
|
|
46
47
|
};
|
|
47
48
|
|
|
48
49
|
const result = validateOpenCodeConfig(invalidConfig);
|
|
@@ -51,49 +52,49 @@ describe("OpenCode Validator", () => {
|
|
|
51
52
|
expect(result.errors!.length).toBeGreaterThan(0);
|
|
52
53
|
});
|
|
53
54
|
|
|
54
|
-
it(
|
|
55
|
+
it('should fix common configuration issues', () => {
|
|
55
56
|
const configWithIssues = {
|
|
56
|
-
username: "test-user",
|
|
57
|
-
model: "gpt-4",
|
|
58
|
-
tools: {
|
|
59
|
-
compact: { threshold: 80000 }, // Should be boolean
|
|
60
|
-
},
|
|
61
57
|
maxTokens: 4000, // Invalid property
|
|
58
|
+
model: 'gpt-4',
|
|
62
59
|
provider: {
|
|
63
60
|
berget: {
|
|
64
61
|
models: {
|
|
65
|
-
|
|
66
|
-
name: "Test Model",
|
|
67
|
-
maxTokens: 4000, // Should be moved to limit.context
|
|
62
|
+
'test-model': {
|
|
68
63
|
contextWindow: 8000, // Should be moved to limit.context
|
|
64
|
+
maxTokens: 4000, // Should be moved to limit.context
|
|
65
|
+
name: 'Test Model',
|
|
69
66
|
},
|
|
70
67
|
},
|
|
71
68
|
},
|
|
72
69
|
},
|
|
70
|
+
tools: {
|
|
71
|
+
compact: { threshold: 80_000 }, // Should be boolean
|
|
72
|
+
},
|
|
73
|
+
username: 'test-user',
|
|
73
74
|
};
|
|
74
75
|
|
|
75
76
|
const fixed = fixOpenCodeConfig(configWithIssues);
|
|
76
77
|
|
|
77
78
|
// tools.compact should be boolean
|
|
78
|
-
expect(typeof fixed.tools.compact).toBe(
|
|
79
|
+
expect(typeof fixed.tools.compact).toBe('boolean');
|
|
79
80
|
|
|
80
81
|
// maxTokens should be removed
|
|
81
82
|
expect(fixed.maxTokens).toBeUndefined();
|
|
82
83
|
|
|
83
84
|
// maxTokens and contextWindow should be moved to limit.context
|
|
84
|
-
expect(fixed.provider.berget.models[
|
|
85
|
-
expect(fixed.provider.berget.models[
|
|
86
|
-
expect(fixed.provider.berget.models[
|
|
87
|
-
expect(fixed.provider.berget.models[
|
|
85
|
+
expect(fixed.provider.berget.models['test-model'].limit).toBeDefined();
|
|
86
|
+
expect(fixed.provider.berget.models['test-model'].limit.context).toBe(8000);
|
|
87
|
+
expect(fixed.provider.berget.models['test-model'].maxTokens).toBeUndefined();
|
|
88
|
+
expect(fixed.provider.berget.models['test-model'].contextWindow).toBeUndefined();
|
|
88
89
|
});
|
|
89
90
|
|
|
90
|
-
it(
|
|
91
|
+
it('should validate the current opencode.json file', () => {
|
|
91
92
|
let currentConfig;
|
|
92
93
|
try {
|
|
93
|
-
currentConfig = JSON.parse(readFileSync(
|
|
94
|
+
currentConfig = JSON.parse(readFileSync('opencode.json', 'utf8'));
|
|
94
95
|
} catch (error) {
|
|
95
96
|
// Skip when opencode.json is not present (e.g. in CI or clean checkouts)
|
|
96
|
-
console.log(
|
|
97
|
+
console.log('Skipping: opencode.json not found:', error);
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -107,8 +108,8 @@ describe("OpenCode Validator", () => {
|
|
|
107
108
|
expect(result.valid).toBe(true);
|
|
108
109
|
|
|
109
110
|
if (!result.valid) {
|
|
110
|
-
console.log(
|
|
111
|
-
result.errors
|
|
111
|
+
console.log('Fixed opencode.json validation errors:');
|
|
112
|
+
if (result.errors) for (const error of result.errors) console.log(` - ${error}`);
|
|
112
113
|
}
|
|
113
114
|
});
|
|
114
115
|
});
|
package/tsconfig.json
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
|
12
12
|
|
|
13
13
|
/* Language and Environment */
|
|
14
|
-
"target": "
|
|
14
|
+
"target": "ES2022",
|
|
15
|
+
"lib": ["ES2022"],
|
|
15
16
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
|
16
17
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
|
17
18
|
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|