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