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