berget 2.2.5 → 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 (148) hide show
  1. package/.github/workflows/publish.yml +8 -8
  2. package/.github/workflows/test.yml +12 -6
  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 +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 +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 +50 -0
  30. package/dist/src/commands/code/__tests__/fake-file-store.js +55 -0
  31. package/dist/src/commands/code/__tests__/fake-prompter.js +133 -0
  32. package/dist/src/commands/code/__tests__/setup-flow.test.js +505 -0
  33. package/dist/src/commands/code/adapters/clack-prompter.js +81 -0
  34. package/dist/src/commands/code/adapters/fs-file-store.js +80 -0
  35. package/dist/src/commands/code/adapters/spawn-command-runner.js +53 -0
  36. package/dist/src/commands/code/auth-sync.js +283 -0
  37. package/dist/src/commands/code/errors.js +27 -0
  38. package/dist/src/commands/code/ports/auth-services.js +2 -0
  39. package/dist/src/commands/code/ports/command-runner.js +2 -0
  40. package/dist/src/commands/code/ports/file-store.js +2 -0
  41. package/dist/src/commands/code/ports/prompter.js +2 -0
  42. package/dist/src/commands/code/setup.js +533 -0
  43. package/dist/src/commands/code.js +223 -779
  44. package/dist/src/commands/models.js +13 -15
  45. package/dist/src/commands/users.js +6 -8
  46. package/dist/src/constants/command-structure.js +116 -114
  47. package/dist/src/services/api-key-service.js +43 -48
  48. package/dist/src/services/auth-service.js +60 -299
  49. package/dist/src/services/browser-auth.js +278 -0
  50. package/dist/src/services/chat-service.js +78 -91
  51. package/dist/src/services/cluster-service.js +6 -6
  52. package/dist/src/services/collaborator-service.js +5 -8
  53. package/dist/src/services/flux-service.js +5 -8
  54. package/dist/src/services/helm-service.js +5 -8
  55. package/dist/src/services/kubectl-service.js +7 -10
  56. package/dist/src/utils/config-checker.js +5 -5
  57. package/dist/src/utils/config-loader.js +25 -25
  58. package/dist/src/utils/default-api-key.js +23 -23
  59. package/dist/src/utils/env-manager.js +7 -7
  60. package/dist/src/utils/error-handler.js +60 -61
  61. package/dist/src/utils/logger.js +7 -7
  62. package/dist/src/utils/markdown-renderer.js +2 -2
  63. package/dist/src/utils/opencode-validator.js +17 -20
  64. package/dist/src/utils/token-manager.js +38 -11
  65. package/dist/tests/commands/chat.test.js +24 -24
  66. package/dist/tests/commands/code.test.js +169 -138
  67. package/dist/tests/utils/config-loader.test.js +114 -114
  68. package/dist/tests/utils/env-manager.test.js +57 -57
  69. package/dist/tests/utils/opencode-validator.test.js +44 -43
  70. package/dist/vitest.config.js +1 -1
  71. package/eslint.config.mjs +47 -0
  72. package/index.ts +42 -48
  73. package/package.json +30 -2
  74. package/src/agents/app.ts +27 -0
  75. package/src/agents/backend.ts +24 -0
  76. package/src/agents/devops.ts +33 -0
  77. package/src/agents/frontend.ts +24 -0
  78. package/src/agents/fullstack.ts +24 -0
  79. package/src/agents/index.ts +71 -0
  80. package/src/agents/quality.ts +69 -0
  81. package/src/agents/security.ts +26 -0
  82. package/src/agents/types.ts +17 -0
  83. package/src/client.ts +125 -167
  84. package/src/commands/api-keys.ts +261 -358
  85. package/src/commands/auth.ts +24 -30
  86. package/src/commands/autocomplete.ts +12 -12
  87. package/src/commands/billing.ts +22 -27
  88. package/src/commands/chat.ts +230 -323
  89. package/src/commands/clusters.ts +33 -33
  90. package/src/commands/code/__tests__/auth-sync.test.ts +481 -0
  91. package/src/commands/code/__tests__/fake-api-key-service.ts +13 -0
  92. package/src/commands/code/__tests__/fake-auth-service.ts +50 -0
  93. package/src/commands/code/__tests__/fake-command-runner.ts +44 -0
  94. package/src/commands/code/__tests__/fake-file-store.ts +44 -0
  95. package/src/commands/code/__tests__/fake-prompter.ts +121 -0
  96. package/src/commands/code/__tests__/setup-flow.test.ts +628 -0
  97. package/src/commands/code/adapters/clack-prompter.ts +55 -0
  98. package/src/commands/code/adapters/fs-file-store.ts +37 -0
  99. package/src/commands/code/adapters/spawn-command-runner.ts +40 -0
  100. package/src/commands/code/auth-sync.ts +329 -0
  101. package/src/commands/code/errors.ts +23 -0
  102. package/src/commands/code/ports/auth-services.ts +14 -0
  103. package/src/commands/code/ports/command-runner.ts +10 -0
  104. package/src/commands/code/ports/file-store.ts +7 -0
  105. package/src/commands/code/ports/prompter.ts +29 -0
  106. package/src/commands/code/setup.ts +630 -0
  107. package/src/commands/code.ts +335 -1074
  108. package/src/commands/index.ts +19 -19
  109. package/src/commands/models.ts +32 -37
  110. package/src/commands/users.ts +15 -22
  111. package/src/constants/command-structure.ts +120 -140
  112. package/src/services/api-key-service.ts +96 -113
  113. package/src/services/auth-service.ts +92 -339
  114. package/src/services/browser-auth.ts +296 -0
  115. package/src/services/chat-service.ts +246 -279
  116. package/src/services/cluster-service.ts +29 -32
  117. package/src/services/collaborator-service.ts +13 -18
  118. package/src/services/flux-service.ts +16 -18
  119. package/src/services/helm-service.ts +16 -18
  120. package/src/services/kubectl-service.ts +12 -14
  121. package/src/types/api.d.ts +924 -926
  122. package/src/types/json.d.ts +3 -3
  123. package/src/utils/config-checker.ts +10 -10
  124. package/src/utils/config-loader.ts +110 -127
  125. package/src/utils/default-api-key.ts +81 -93
  126. package/src/utils/env-manager.ts +36 -40
  127. package/src/utils/error-handler.ts +83 -78
  128. package/src/utils/logger.ts +41 -41
  129. package/src/utils/markdown-renderer.ts +11 -11
  130. package/src/utils/opencode-validator.ts +51 -56
  131. package/src/utils/token-manager.ts +84 -64
  132. package/templates/agents/app.md +23 -0
  133. package/templates/agents/backend.md +23 -0
  134. package/templates/agents/devops.md +30 -0
  135. package/templates/agents/frontend.md +25 -0
  136. package/templates/agents/fullstack.md +23 -0
  137. package/templates/agents/quality.md +69 -0
  138. package/templates/agents/security.md +21 -0
  139. package/tests/commands/chat.test.ts +60 -70
  140. package/tests/commands/code.test.ts +346 -345
  141. package/tests/utils/config-loader.test.ts +260 -260
  142. package/tests/utils/env-manager.test.ts +127 -134
  143. package/tests/utils/opencode-validator.test.ts +65 -69
  144. package/tsconfig.json +2 -2
  145. package/vitest.config.ts +3 -3
  146. package/AGENTS.md +0 -374
  147. package/TODO.md +0 -19
  148. package/opencode.json +0 -146
@@ -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,54 +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', () => {
90
+ it("should validate the current opencode.json file", () => {
91
+ let currentConfig;
96
92
  try {
97
- const currentConfig = JSON.parse(readFileSync('opencode.json', 'utf8'))
93
+ currentConfig = JSON.parse(readFileSync("opencode.json", "utf8"));
94
+ } catch (error) {
95
+ // Skip when opencode.json is not present (e.g. in CI or clean checkouts)
96
+ console.log("Skipping: opencode.json not found:", error);
97
+ return;
98
+ }
98
99
 
99
- // Apply fixes to handle common issues
100
- const fixedConfig = fixOpenCodeConfig(currentConfig)
100
+ // Apply fixes to handle common issues
101
+ const fixedConfig = fixOpenCodeConfig(currentConfig);
101
102
 
102
- // Validate the fixed config
103
- const result = validateOpenCodeConfig(fixedConfig)
103
+ // Validate the fixed config
104
+ const result = validateOpenCodeConfig(fixedConfig);
104
105
 
105
- // The fixed config should be valid according to the JSON Schema
106
- expect(result.valid).toBe(true)
106
+ // The fixed config should be valid according to the JSON Schema
107
+ expect(result.valid).toBe(true);
107
108
 
108
- if (!result.valid) {
109
- console.log('Fixed opencode.json validation errors:')
110
- result.errors?.forEach((err) => console.log(` - ${err}`))
111
- }
112
- } catch (error) {
113
- // If we can't read the file, that's ok for this test
114
- console.log('Could not read opencode.json for testing:', error)
115
- expect.fail('Should be able to read opencode.json')
109
+ if (!result.valid) {
110
+ console.log("Fixed opencode.json validation errors:");
111
+ result.errors?.forEach(err => console.log(` - ${err}`));
116
112
  }
117
- })
118
- })
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
+ });